blob: 0eef1240de6b78868cc2a9cdd482ba0f6b069492 [file] [log] [blame]
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kfifo.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/semaphore.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/muic/muic.h>
#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");