Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dadf9e3d authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "qbt1000: Add support for fingerprint gestures"

parents d7f5502d 0d48e5ab
Loading
Loading
Loading
Loading
+187 −53
Original line number Diff line number Diff line
@@ -42,9 +42,9 @@
#define QBT1000_IN_DEV_NAME "qbt1000_key_input"
#define QBT1000_IN_DEV_VERSION 0x0100
#define MAX_FW_EVENTS 128
#define FP_APP_CMD_RX_IPC 132
#define FW_MAX_IPC_MSG_DATA_SIZE 0x500
#define IPC_MSG_ID_CBGE_REQUIRED 29
#define SEND_TZ_CMD_RETRY_CNT 10
#define SEND_TZ_CMD_DELAY 50

/*
 * shared buffer size - init with max value,
@@ -53,6 +53,27 @@
static uint32_t g_app_buf_size = SZ_256K;
static char const *const FP_APP_NAME = "fingerpr";

enum fp_app_cmd {
	FP_APP_CMD_RX_IPC = 132,

};

enum ipc_msg_id {
	IPC_MSG_ID_CBGE_REQUIRED = 29,
	IPC_MSG_ID_GESTURE_SWIPE_DOWN = 50,
	IPC_MSG_ID_GESTURE_SWIPE_UP = 51,
	IPC_MSG_ID_GESTURE_SWIPE_LEFT = 52,
	IPC_MSG_ID_GESTURE_SWIPE_RIGHT = 53,
	IPC_MSG_ID_GESTURE_LONG_PRESS = 54,
	IPC_MSG_ID_FINGER_ON_SENSOR = 55,
	IPC_MSG_ID_FINGER_OFF_SENSOR = 56,
};

enum fd_indication_mode {
	FD_IND_MODE_BIOMETRIC = 0,
	FD_IND_MODE_GESTURES,
};

struct finger_detect_gpio {
	int gpio;
	int active_low;
@@ -93,6 +114,9 @@ struct qbt1000_drvdata {
	wait_queue_head_t read_wait_queue;
	struct qseecom_handle *app_handle;
	struct qseecom_handle *fp_app_handle;
	enum fd_indication_mode fd_ind_mode;
	bool ipc_is_stale;
	bool gestures_enabled;
};

/*
@@ -129,7 +153,9 @@ struct ipc_msg_type_to_fw_event {

/* mapping between firmware IPC message types to HLOS firmware events */
struct ipc_msg_type_to_fw_event g_msg_to_event[] = {
		{IPC_MSG_ID_CBGE_REQUIRED, FW_EVENT_CBGE_REQUIRED}
		{IPC_MSG_ID_CBGE_REQUIRED, FW_EVENT_CBGE_REQUIRED},
		{IPC_MSG_ID_FINGER_ON_SENSOR, FW_EVENT_FINGER_DOWN},
		{IPC_MSG_ID_FINGER_OFF_SENSOR, FW_EVENT_FINGER_UP},
};

/**
@@ -524,9 +550,7 @@ static long qbt1000_ioctl(
			pr_err("failed copy from user space %d\n", rc);
			goto end;
		}

		drvdata->fd_gpio.key_code = set_fd_key.key_code;

		break;
	}
	case QBT1000_CONFIGURE_POWER_KEY:
@@ -542,7 +566,27 @@ static long qbt1000_ioctl(
		}

		drvdata->fd_gpio.power_key_enabled = power_key.enable;
		break;
	}
	case QBT1000_ENABLE_GESTURES:
	{
		struct qbt1000_enable_gestures enable_gestures;

		if (copy_from_user(&enable_gestures, priv_arg,
			sizeof(enable_gestures))
				!= 0) {
			rc = -EFAULT;
			pr_err("failed copy from user space %d\n", rc);
			goto end;
		}

		if (enable_gestures.enable) {
			drvdata->fd_ind_mode = FD_IND_MODE_GESTURES;
			drvdata->gestures_enabled = true;
		} else {
			drvdata->fd_ind_mode = FD_IND_MODE_BIOMETRIC;
			drvdata->gestures_enabled = false;
		}
		break;
	}
	default:
@@ -729,6 +773,18 @@ static int qbt1000_create_input_device(struct qbt1000_drvdata *drvdata)
		BIT_MASK(KEY_VOLUMEDOWN);
	drvdata->in_dev->keybit[BIT_WORD(KEY_POWER)] |=
		BIT_MASK(KEY_POWER);
	drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_UP)] |=
		BIT_MASK(KEY_FP_GESTURE_UP);
	drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_DOWN)] |=
		BIT_MASK(KEY_FP_GESTURE_DOWN);
	drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_LEFT)] |=
		BIT_MASK(KEY_FP_GESTURE_LEFT);
	drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_RIGHT)] |=
		BIT_MASK(KEY_FP_GESTURE_RIGHT);
	drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_LONG_PRESS)] |=
		BIT_MASK(KEY_FP_GESTURE_LONG_PRESS);
	drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_TAP)] |=
		BIT_MASK(KEY_FP_GESTURE_TAP);

	input_set_abs_params(drvdata->in_dev, ABS_X,
			     0,
@@ -768,14 +824,10 @@ static void purge_finger_events(struct qbt1000_drvdata *drvdata)
	}
}

static void qbt1000_gpio_report_event(struct qbt1000_drvdata *drvdata)
static void gpio_report_event(struct qbt1000_drvdata *drvdata, int state)
{
	int state;
	struct fw_event_desc fw_event;

	state = (__gpio_get_value(drvdata->fd_gpio.gpio) ? 1 : 0)
		^ drvdata->fd_gpio.active_low;

	if (drvdata->fd_gpio.event_reported
		  && state == drvdata->fd_gpio.last_gpio_state)
		return;
@@ -785,20 +837,31 @@ static void qbt1000_gpio_report_event(struct qbt1000_drvdata *drvdata)
	drvdata->fd_gpio.event_reported = 1;
	drvdata->fd_gpio.last_gpio_state = state;

	if (drvdata->fd_gpio.key_code) {
		input_event(drvdata->in_dev, EV_KEY,
			drvdata->fd_gpio.key_code, !!state);
	if (drvdata->fd_ind_mode == FD_IND_MODE_GESTURES) {
		pr_debug("tap detected\n");
		/*
		 * If a gesture IPC was sent but not yet decrypted and
		 * dealt with mark it as stale and don't report it
		 */
		drvdata->ipc_is_stale = true;
		input_event(drvdata->in_dev,
				EV_KEY, KEY_FP_GESTURE_TAP, 1);
		input_sync(drvdata->in_dev);
	}

		input_event(drvdata->in_dev,
				EV_KEY, KEY_FP_GESTURE_TAP, 0);
		input_sync(drvdata->in_dev);
	} else if (drvdata->fd_ind_mode == FD_IND_MODE_BIOMETRIC) {
		if (state && drvdata->fd_gpio.power_key_enabled) {
			input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 1);
			input_sync(drvdata->in_dev);
			input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 0);
			input_sync(drvdata->in_dev);
		} else if (!drvdata->gestures_enabled) {
			input_event(drvdata->in_dev, EV_KEY,
				drvdata->fd_gpio.key_code, !!state);
			input_sync(drvdata->in_dev);
		}

	fw_event.ev = (state ? FW_EVENT_FINGER_DOWN : FW_EVENT_FINGER_UP);
		fw_event.ev = state ? FW_EVENT_FINGER_DOWN : FW_EVENT_FINGER_UP;

		mutex_lock(&drvdata->fw_events_mutex);

@@ -817,8 +880,19 @@ static void qbt1000_gpio_report_event(struct qbt1000_drvdata *drvdata)

		mutex_unlock(&drvdata->fw_events_mutex);
		wake_up_interruptible(&drvdata->read_wait_queue);
	} else {
		pr_err("invalid mode %d\n", drvdata->fd_ind_mode);
	}
}

static void qbt1000_gpio_report_event(struct qbt1000_drvdata *drvdata)
{
	int state;

	state = (__gpio_get_value(drvdata->fd_gpio.gpio) ? 1 : 0)
		^ drvdata->fd_gpio.active_low;
	gpio_report_event(drvdata, state);
}
static void qbt1000_gpio_work_func(struct work_struct *work)
{
	struct qbt1000_drvdata *drvdata =
@@ -862,7 +936,7 @@ static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
	uint32_t rxipc = FP_APP_CMD_RX_IPC;
	struct qbt1000_drvdata *drvdata = (struct qbt1000_drvdata *)dev_id;
	int rc = 0;
	uint32_t retry_count = 10;
	uint32_t retry_count = SEND_TZ_CMD_RETRY_CNT;

	pm_stay_awake(drvdata->dev);

@@ -879,6 +953,12 @@ static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
	if (!drvdata->fp_app_handle)
		goto end;

	/*
	 * Indicate that IPC is valid (not stale)
	 * This is relevant only for gestures IPCs
	 */
	drvdata->ipc_is_stale = false;

	while (retry_count > 0) {
		/*
		 * send the TZ command to fetch the message from firmware
@@ -888,7 +968,8 @@ static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
				&rxipc, sizeof(rxipc),
				(void *)&rx_cmd, sizeof(*rx_cmd));
		if (rc < 0) {
			msleep(50); // sleep for 50ms before retry
			/* sleep before retry */
			msleep(SEND_TZ_CMD_DELAY);
			retry_count -= 1;
			continue;
		} else {
@@ -910,30 +991,78 @@ static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
	msg_buffer = rx_cmd->msg_data;

	for (j = 0; j < rx_cmd->numMsgs; j++) {
		unsigned int key_event_code = 0;

		header = (struct fw_ipc_header *) msg_buffer;

		switch (header->msg_type) {
		case IPC_MSG_ID_GESTURE_SWIPE_UP:
			key_event_code = KEY_FP_GESTURE_UP;
			break;
		case IPC_MSG_ID_GESTURE_SWIPE_DOWN:
			key_event_code = KEY_FP_GESTURE_DOWN;
			break;
		case IPC_MSG_ID_GESTURE_SWIPE_LEFT:
			key_event_code = KEY_FP_GESTURE_LEFT;
			break;
		case IPC_MSG_ID_GESTURE_SWIPE_RIGHT:
			key_event_code = KEY_FP_GESTURE_RIGHT;
			break;
		case IPC_MSG_ID_GESTURE_LONG_PRESS:
			key_event_code = KEY_FP_GESTURE_LONG_PRESS;
			break;
		default:
			key_event_code = 0;
			break;
		}

		if (key_event_code != 0) {
			pr_debug("geseture detected %d\n", key_event_code);
			/*
			 * Send gesture event if no tap arrived
			 * since the IPC was sent
			 */
			if (drvdata->ipc_is_stale == false) {
				input_event(drvdata->in_dev, EV_KEY,
						key_event_code, 1);
				input_sync(drvdata->in_dev);
				input_event(drvdata->in_dev, EV_KEY,
						key_event_code, 0);
				input_sync(drvdata->in_dev);
			}
		} else {

			/*
		 * given the IPC message type, search for a corresponding
		 * event for the driver client. If found, add to the events
		 * FIFO
			 * 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) {
				uint32_t msg_type = g_msg_to_event[i].msg_type;

				if (msg_type == header->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);
				pr_debug("fw events: add %d\n", (int) ev);
					pr_debug("fw events: add %d\n",
						(int) ev);
					fw_ev_desc.ev = ev;

				if (!kfifo_put(&drvdata->fw_events, fw_ev_desc))
					pr_err("fw events: fifo full, drop event %d\n",
					purge_finger_events(drvdata);

					if (!kfifo_put(&drvdata->fw_events,
							fw_ev_desc))
						pr_err("fw events: fifo full");
						pr_err(", drop event %d\n",
							(int) ev);

					mutex_unlock(&drvdata->fw_events_mutex);
					break;
				}
			}
		}
		msg_buffer += sizeof(*header) + header->msg_len;
	}
	wake_up_interruptible(&drvdata->read_wait_queue);
@@ -993,6 +1122,7 @@ static int setup_ipc_irq(struct platform_device *pdev,
	drvdata->fw_ipc.irq = gpio_to_irq(drvdata->fw_ipc.gpio);
	pr_debug("\nirq %d gpio %d\n",
			drvdata->fw_ipc.irq, drvdata->fw_ipc.gpio);

	if (drvdata->fw_ipc.irq < 0) {
		rc = drvdata->fw_ipc.irq;
		pr_err("no irq for gpio %d, error=%d\n",
@@ -1131,6 +1261,10 @@ static int qbt1000_probe(struct platform_device *pdev)
	if (rc < 0)
		goto end;

	drvdata->fd_ind_mode = FD_IND_MODE_BIOMETRIC;
	drvdata->ipc_is_stale = false;
	drvdata->gestures_enabled = false;

end:
	pr_debug("%s : %d\n", __func__, rc);
	return rc;
+8 −0
Original line number Diff line number Diff line
@@ -687,6 +687,14 @@
#define BTN_TRIGGER_HAPPY39		0x2e6
#define BTN_TRIGGER_HAPPY40		0x2e7

/* Custom fingerprint gestures keys */
#define KEY_FP_GESTURE_UP		0x2e8
#define KEY_FP_GESTURE_DOWN		0x2e9
#define KEY_FP_GESTURE_LEFT		0x2ea
#define KEY_FP_GESTURE_RIGHT		0x2eb
#define KEY_FP_GESTURE_LONG_PRESS	0x2ec
#define KEY_FP_GESTURE_TAP		0x2ed

/* We avoid low common keys in module aliases so they don't get huge. */
#define KEY_MIN_INTERESTING	KEY_MUTE
#define KEY_MAX			0x2ff
+10 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ enum qbt1000_commands {
	QBT1000_SET_FINGER_DETECT_KEY = 103,
	QBT1000_CONFIGURE_POWER_KEY = 104
};
#define QBT1000_ENABLE_GESTURES 105

/*
 * enum qbt1000_fw_event -
@@ -78,6 +79,15 @@ struct qbt1000_erie_event {
	uint32_t buf_len;
};

/*
 * struct qbt1000_enable_gestures -
 *      used to configure whether gestures detection is enabled or disabled
 * @enable - if non-zero, gestures detection is enabled
 */
struct qbt1000_enable_gestures {
	unsigned int enable;
};

/*
 * struct qbt1000_set_finger_detect_key -
 *      used to configure the input key which is sent on finger down/up event