#include #include #include #include #include #include #include #include #include #include #include "muic-internal.h" #include "muic_apis.h" #include "muic_coagent.h" struct kfifo fifo; struct coagent { struct mutex co_mutex; struct task_struct *co_thread; int co_number; muic_data_t *pmuic; /* context for MUIC */ struct kfifo fifo; struct semaphore read_sem; bool is_active; }; static struct coagent base_coagent; extern bool muic_is_online(void); void coagent_update_ctx(muic_data_t *pmuic) { struct coagent *pco = &base_coagent; pr_info("%s\n", __func__); pco->pmuic = pmuic; } static int coagent_cmd_gamepad(struct coagent *pco, int status) { pr_info("%s: status=[%s]\n", __func__, (status == COA_STATUS_OK) ? "OK" : "NOK"); if (!muic_is_online()) { pr_info("%s: MUIC is not online.\n", __func__); return -1; } if (!pco->pmuic) { pr_info("%s: MUIC ctx is not ready.\n", __func__); return -1; } if ((pco->pmuic->attached_dev != ATTACHED_DEV_GAMEPAD_MUIC) && (pco->pmuic->attached_dev != ATTACHED_DEV_OTG_MUIC)) { pr_info("%s: Abnormal state for USB's gampad Noti. [%d]\n", __func__, pco->pmuic->attached_dev); return -1; } if (status == COA_STATUS_OK) { if (get_adc_scan_mode(pco->pmuic) != ADC_SCANMODE_CONTINUOUS) { /* The interrupts occurred during mode change will be discarded. */ pco->pmuic->discard_interrupt = true; set_adc_scan_mode(pco->pmuic, ADC_SCANMODE_CONTINUOUS); msleep(200); pco->pmuic->discard_interrupt = false; } } else pr_info("%s: discarded.\n", __func__); return 0; } static int coagent_cmd_handler(struct coagent *pco, int cmd, int param) { switch (cmd) { case COA_GAMEPAD_STATUS: coagent_cmd_gamepad(pco, param); break; default: break; } return 0; } int coagent_in(unsigned int *pbuf) { struct coagent *pco = &base_coagent; kfifo_in(&(pco->fifo), pbuf, 1); up(&(pco->read_sem)); return 0; } int coagent_out(unsigned int *pbuf) { struct coagent *pco = &base_coagent; unsigned int ret = 0; ret = kfifo_out(&(pco->fifo), pbuf, 1); return ret; } bool coagent_alive(void) { struct coagent *pco = &base_coagent; return pco->is_active; } static int __init init_fifo_test(void) { struct coagent *pco = &base_coagent; unsigned int i; unsigned int val; pr_info("%s: fifo module insert\n", __func__); if (kfifo_alloc(&(pco->fifo), 1024, GFP_KERNEL)) { pr_warn("%s: error kfifo_alloc\n", __func__); return -ENOMEM; } pr_info("%s: queue size:%u\n", __func__, kfifo_size(&(pco->fifo))); pr_info("%s: queue_available1: %u\n", __func__, kfifo_avail(&(pco->fifo))); /* enqueue */ for (i=0; i<2; i++) { val = 5 + i; val |= (4 + i) << COAGENT_PARAM_BITS; coagent_in(&val); } pr_info("%s: queue len: %u\n", __func__, kfifo_len(&(pco->fifo))); pr_info("%s: queue_available: %u\n", __func__, kfifo_avail(&(pco->fifo))); return 0; } static void __exit exit_fifo_test(void) { struct coagent *pco = &base_coagent; kfifo_free(&(pco->fifo)); pr_info("%s: fifo module removed\n", __func__); } static int coagent_thread(void *data) { struct coagent *pco = (struct coagent *)data; uint i = 0; int r; unsigned int rx_data = 0, cmd = 0, param = 0; pr_info("%s: %dth thread is running...\n", __func__, pco->co_number); sema_init(&(pco->read_sem), 1); init_fifo_test(); pco->is_active = true; for(;;) { r = down_interruptible(&(pco->read_sem)); if (r < 0) { pr_info("%s: down_interruptible error\n", __func__); goto out_error; } r = coagent_out(&rx_data); if ( r != 1) { pr_info("%s: The copied item is not one(%d)\n", __func__, r); continue; } cmd = COAGENT_CMD(rx_data); param = COAGENT_PARAM(rx_data); pr_info("%s: [%2d - %d/%d] cmd=%d, param=%d\n", __func__, i++, kfifo_len(&(pco->fifo)), kfifo_avail(&(pco->fifo)), cmd, param); coagent_cmd_handler(pco, cmd, param); } out_error: pr_info("%s: End\n", __func__); return 0; } static int create_coagent_thread(struct coagent *pco) { int error = 0; pr_info("%s:\n", __func__); pco->co_thread = kthread_create(coagent_thread, pco, "coagent%d", ++pco->co_number); if (IS_ERR(pco->co_thread)) { pr_info("%s: Error\n", __func__); error = PTR_ERR(pco->co_thread); goto out_clr; } wake_up_process(pco->co_thread); out_clr: return error; } static int __init init_coagent(void) { create_coagent_thread(&base_coagent); return 0; } static void __exit exit_coagent(void) { exit_fifo_test(); } module_init(init_coagent); module_exit(exit_fifo_test); MODULE_LICENSE("GPL");