qbt1000: Add changes to support VOLUMEDOWN and CBGE

Add changes to qbt1000 fingerprint driver to enable
input device to report KEY_VOLUMEDOWN when a finger
is detected. Add changes for supporting CBGE with
retry logic and multiple IPC messages.

Change-Id: I29a52c516a8f9216abc623ca3bfaebe19f89eaa3
Signed-off-by: Abir Ghosh <abirg@codeaurora.org>
This commit is contained in:
Abir Ghosh 2016-11-09 18:05:13 +02:00
parent a49bb61510
commit c9cf0e7a71

View file

@ -12,6 +12,7 @@
#define pr_fmt(fmt) "qbt1000:%s: " fmt, __func__ #define pr_fmt(fmt) "qbt1000:%s: " fmt, __func__
#include <linux/delay.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/fs.h> #include <linux/fs.h>
@ -105,10 +106,14 @@ struct qbt1000_drvdata {
*/ */
struct fw_ipc_cmd { struct fw_ipc_cmd {
uint32_t status; uint32_t status;
uint32_t numMsgs;
uint8_t msg_data[FW_MAX_IPC_MSG_DATA_SIZE];
};
struct fw_ipc_header {
uint32_t msg_type; uint32_t msg_type;
uint32_t msg_len; uint32_t msg_len;
uint32_t resp_needed; uint32_t resp_needed;
uint8_t msg_data[FW_MAX_IPC_MSG_DATA_SIZE];
}; };
/* /*
@ -352,7 +357,14 @@ static int qbt1000_open(struct inode *inode, struct file *file)
*/ */
static int qbt1000_release(struct inode *inode, struct file *file) static int qbt1000_release(struct inode *inode, struct file *file)
{ {
struct qbt1000_drvdata *drvdata = file->private_data; struct qbt1000_drvdata *drvdata;
if (!file->private_data) {
pr_err("Null pointer passed in file->private_data");
return -EINVAL;
}
drvdata = file->private_data;
atomic_inc(&drvdata->available); atomic_inc(&drvdata->available);
return 0; return 0;
@ -374,6 +386,11 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
void __user *priv_arg = (void __user *)arg; void __user *priv_arg = (void __user *)arg;
struct qbt1000_drvdata *drvdata; struct qbt1000_drvdata *drvdata;
if (!file->private_data) {
pr_err("Null pointer passed in file->private_data");
return -EINVAL;
}
drvdata = file->private_data; drvdata = file->private_data;
if (IS_ERR(priv_arg)) { if (IS_ERR(priv_arg)) {
@ -789,6 +806,8 @@ static int qbt1000_create_input_device(struct qbt1000_drvdata *drvdata)
BIT_MASK(KEY_HOMEPAGE); BIT_MASK(KEY_HOMEPAGE);
drvdata->in_dev->keybit[BIT_WORD(KEY_CAMERA)] |= drvdata->in_dev->keybit[BIT_WORD(KEY_CAMERA)] |=
BIT_MASK(KEY_CAMERA); BIT_MASK(KEY_CAMERA);
drvdata->in_dev->keybit[BIT_WORD(KEY_VOLUMEDOWN)] |=
BIT_MASK(KEY_VOLUMEDOWN);
drvdata->in_dev->keybit[BIT_WORD(KEY_POWER)] |= drvdata->in_dev->keybit[BIT_WORD(KEY_POWER)] |=
BIT_MASK(KEY_POWER); BIT_MASK(KEY_POWER);
@ -917,11 +936,14 @@ static irqreturn_t qbt1000_gpio_isr(int irq, void *dev_id)
*/ */
static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id) static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
{ {
uint8_t *msg_buffer;
struct fw_ipc_cmd *rx_cmd; struct fw_ipc_cmd *rx_cmd;
int i; struct fw_ipc_header *header;
int i, j;
uint32_t rxipc = FP_APP_CMD_RX_IPC; uint32_t rxipc = FP_APP_CMD_RX_IPC;
struct qbt1000_drvdata *drvdata = (struct qbt1000_drvdata *)dev_id; struct qbt1000_drvdata *drvdata = (struct qbt1000_drvdata *)dev_id;
int rc = 0; int rc = 0;
uint32_t retry_count = 10;
pm_stay_awake(drvdata->dev); pm_stay_awake(drvdata->dev);
@ -933,18 +955,25 @@ static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
goto end; goto end;
} }
pr_debug("firmware interrupt received (irq %d)\n", irq);
if (!drvdata->fp_app_handle) if (!drvdata->fp_app_handle)
goto end; goto end;
/* while (retry_count > 0) {
* send the TZ command to fetch the message from firmware /*
* TZ will process the message if it can * send the TZ command to fetch the message from firmware
*/ * TZ will process the message if it can
rc = send_tz_cmd(drvdata, drvdata->fp_app_handle, 0, */
&rxipc, sizeof(rxipc), rc = send_tz_cmd(drvdata, drvdata->fp_app_handle, 0,
(void *)&rx_cmd, sizeof(*rx_cmd)); &rxipc, sizeof(rxipc),
(void *)&rx_cmd, sizeof(*rx_cmd));
if (rc < 0) {
msleep(50); /* sleep for 50ms before retry */
retry_count -= 1;
continue;
} else {
break;
}
}
if (rc < 0) { if (rc < 0) {
pr_err("failure sending tz cmd %d\n", rxipc); pr_err("failure sending tz cmd %d\n", rxipc);
@ -956,29 +985,35 @@ static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
goto end; goto end;
} }
/* msg_buffer = rx_cmd->msg_data;
* given the IPC message type, search for a corresponding event for the
* driver client. If found, add to the events FIFO
*/
for (i = 0; i < ARRAY_SIZE(g_msg_to_event); i++) {
if (g_msg_to_event[i].msg_type == rx_cmd->msg_type) {
enum qbt1000_fw_event ev = g_msg_to_event[i].fw_event;
struct fw_event_desc fw_ev_desc;
mutex_lock(&drvdata->fw_events_mutex); for (j = 0; j < rx_cmd->numMsgs; j++) {
pr_debug("fw events: add %d\n", (int) ev); header = (struct fw_ipc_header *) msg_buffer;
fw_ev_desc.ev = ev; /*
* given the IPC message type, search for a corresponding event
* for the driver client. If found, add to the events FIFO
*/
for (i = 0; i < ARRAY_SIZE(g_msg_to_event); i++) {
if (g_msg_to_event[i].msg_type == header->msg_type) {
enum qbt1000_fw_event ev =
g_msg_to_event[i].fw_event;
struct fw_event_desc fw_ev_desc;
if (!kfifo_put(&drvdata->fw_events, fw_ev_desc)) mutex_lock(&drvdata->fw_events_mutex);
pr_err("fw events: fifo full, drop event %d\n", pr_debug("fw events: add %d\n", (int) ev);
(int) ev); fw_ev_desc.ev = ev;
mutex_unlock(&drvdata->fw_events_mutex); if (!kfifo_put(&drvdata->fw_events, fw_ev_desc))
wake_up_interruptible(&drvdata->read_wait_queue); pr_err("fw events: fifo full, drop event %d\n",
break; (int) ev);
mutex_unlock(&drvdata->fw_events_mutex);
break;
}
} }
msg_buffer += sizeof(*header) + header->msg_len;
} }
wake_up_interruptible(&drvdata->read_wait_queue);
end: end:
mutex_unlock(&drvdata->mutex); mutex_unlock(&drvdata->mutex);
pm_relax(drvdata->dev); pm_relax(drvdata->dev);