* [PATCH v12 11/19] input: cyapa: add gen5 trackpad device firmware update function support
From: Dudley Du @ 2014-12-03 9:30 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1417599025-21681-1-git-send-email-dudley.dulixin@gmail.com>
Add firmware image update function supported for gen5 trackpad device,
it can be used through sysfs update_fw interface.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/Kconfig | 2 +-
drivers/input/mouse/cyapa_gen5.c | 290 +++++++++++++++++++++++++++++++++++++++
2 files changed, 291 insertions(+), 1 deletion(-)
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 366fc7a..005d69b 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -205,7 +205,7 @@ config MOUSE_BCM5974
config MOUSE_CYAPA
tristate "Cypress APA I2C Trackpad support"
- depends on I2C
+ depends on I2C && CRC_ITU_T
help
This driver adds support for Cypress All Points Addressable (APA)
I2C Trackpads, including the ones used in 2012 Samsung Chromebooks.
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index 3293ff9..eee7d0c 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -18,6 +18,7 @@
#include <linux/completion.h>
#include <linux/slab.h>
#include <linux/unaligned/access_ok.h>
+#include <linux/crc-itu-t.h>
#include "cyapa.h"
@@ -911,6 +912,86 @@ static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
return -EAGAIN;
}
+static int cyapa_gen5_bl_initiate(struct cyapa *cyapa,
+ const struct firmware *fw)
+{
+ u16 length = 0;
+ u16 data_len = 0;
+ u16 meta_data_crc = 0;
+ u16 cmd_crc = 0;
+ u8 bl_gen5_activate[18 + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE + 3];
+ int bl_gen5_activate_size = 0;
+ u8 resp_data[11];
+ int resp_len;
+ struct cyapa_tsg_bin_image *image;
+ int records_num;
+ u8 *data;
+ int error;
+
+ /* Try to dump all bufferred report data before send any command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ bl_gen5_activate_size = sizeof(bl_gen5_activate);
+ memset(bl_gen5_activate, 0, bl_gen5_activate_size);
+
+ /* Output Report Register Address[15:0] = 0004h */
+ bl_gen5_activate[0] = 0x04;
+ bl_gen5_activate[1] = 0x00;
+
+ /* Total command length[15:0] */
+ length = bl_gen5_activate_size - 2;
+ put_unaligned_le16(length, &bl_gen5_activate[2]);
+ bl_gen5_activate[4] = 0x40; /* Report ID = 40h */
+ bl_gen5_activate[5] = 0x00; /* RSVD = 00h */
+
+ bl_gen5_activate[6] = GEN5_SOP_KEY; /* SOP = 01h */
+ bl_gen5_activate[7] = 0x48; /* Command Code = 48h */
+
+ /* 8 Key bytes and block size */
+ data_len = CYAPA_TSG_BL_KEY_SIZE + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE;
+ /* Data Length[15:0] */
+ put_unaligned_le16(data_len, &bl_gen5_activate[8]);
+ bl_gen5_activate[10] = 0xa5; /* Key Byte 0 */
+ bl_gen5_activate[11] = 0x01;
+ bl_gen5_activate[12] = 0x02; /* . */
+ bl_gen5_activate[13] = 0x03; /* . */
+ bl_gen5_activate[14] = 0xff; /* . */
+ bl_gen5_activate[15] = 0xfe;
+ bl_gen5_activate[16] = 0xfd;
+ bl_gen5_activate[17] = 0x5a; /* Key Byte 7 */
+
+ /* Copy 60 bytes Meta Data Row Parameters */
+ image = (struct cyapa_tsg_bin_image *)fw->data;
+ records_num = (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) /
+ sizeof(struct cyapa_tsg_bin_image_data_record);
+ /* APP_INTEGRITY row is always the last row block */
+ data = image->records[records_num - 1].record_data;
+ memcpy(&bl_gen5_activate[18], data, CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
+
+ meta_data_crc = crc_itu_t(0xffff, &bl_gen5_activate[18],
+ CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
+ /* Meta Data CRC[15:0] */
+ put_unaligned_le16(meta_data_crc,
+ &bl_gen5_activate[18 + CYAPA_TSG_FLASH_MAP_METADATA_SIZE]);
+
+ cmd_crc = crc_itu_t(0xffff, &bl_gen5_activate[6], 4 + data_len);
+ put_unaligned_le16(cmd_crc,
+ &bl_gen5_activate[bl_gen5_activate_size - 3]); /* CRC[15:0] */
+ bl_gen5_activate[bl_gen5_activate_size - 1] = GEN5_EOP_KEY;
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ bl_gen5_activate, sizeof(bl_gen5_activate),
+ resp_data, &resp_len, 12000,
+ cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
+ if (error || resp_len != GEN5_BL_INITIATE_RESP_LEN ||
+ resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error ? error : -EAGAIN;
+
+ return 0;
+}
+
bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len)
{
if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE)
@@ -959,6 +1040,210 @@ static int cyapa_gen5_bl_exit(struct cyapa *cyapa)
return -ENODEV;
}
+static int cyapa_gen5_bl_enter(struct cyapa *cyapa)
+{
+ int error;
+ u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x01 };
+ u8 resp_data[2];
+ int resp_len;
+
+ error = cyapa_poll_state(cyapa, 500);
+ if (error < 0)
+ return error;
+ if (cyapa->gen != CYAPA_GEN5)
+ return -EINVAL;
+
+ /* Already in Gen5 BL. Skipping exit. */
+ if (cyapa->state == CYAPA_STATE_GEN5_BL)
+ return 0;
+
+ if (cyapa->state != CYAPA_STATE_GEN5_APP)
+ return -EAGAIN;
+
+ /* Try to dump all bufferred report data before send any command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ /*
+ * Send bootloader enter command to trackpad device,
+ * after enter bootloader, the response data is two bytes of 0x00 0x00.
+ */
+ resp_len = sizeof(resp_data);
+ memset(resp_data, 0, resp_len);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 5000, cyapa_gen5_sort_application_launch_data,
+ true);
+ if (error || resp_data[0] != 0x00 || resp_data[1] != 0x00)
+ return error < 0 ? error : -EAGAIN;
+
+ cyapa->state = CYAPA_STATE_GEN5_BL;
+ return 0;
+}
+
+static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw)
+{
+ int i;
+ struct cyapa_tsg_bin_image *image;
+ int flash_records_count;
+ u16 expected_app_crc;
+ u16 expected_app_integrity_crc;
+ u16 app_crc = 0;
+ u16 app_integrity_crc = 0;
+ u16 row_num;
+ u8 *data;
+ u32 app_start;
+ u16 app_len;
+ u32 img_start;
+ u16 img_len;
+ int record_index;
+ struct device *dev = &cyapa->client->dev;
+
+ image = (struct cyapa_tsg_bin_image *)fw->data;
+ flash_records_count = (fw->size -
+ sizeof(struct cyapa_tsg_bin_image_head)) /
+ sizeof(struct cyapa_tsg_bin_image_data_record);
+
+ /* APP_INTEGRITY row is always the last row block,
+ * and the row id must be 0x01ff */
+ row_num = get_unaligned_be16(
+ &image->records[flash_records_count - 1].row_number);
+ if (&image->records[flash_records_count - 1].flash_array_id != 0x00 &&
+ row_num != 0x01ff) {
+ dev_err(dev, "%s: invalid app_integrity data.\n", __func__);
+ return -EINVAL;
+ }
+ data = image->records[flash_records_count - 1].record_data;
+ app_start = get_unaligned_le32(&data[4]);
+ app_len = get_unaligned_le16(&data[8]);
+ expected_app_crc = get_unaligned_le16(&data[10]);
+ img_start = get_unaligned_le32(&data[16]);
+ img_len = get_unaligned_le16(&data[20]);
+ expected_app_integrity_crc = get_unaligned_le16(&data[60]);
+
+ if ((app_start + app_len + img_start + img_len) %
+ CYAPA_TSG_FW_ROW_SIZE) {
+ dev_err(dev, "%s: invalid image alignment.\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Verify app_integrity crc */
+ app_integrity_crc = crc_itu_t(0xffff, data,
+ CYAPA_TSG_APP_INTEGRITY_SIZE);
+ if (app_integrity_crc != expected_app_integrity_crc) {
+ dev_err(dev, "%s: invalid app_integrity crc.\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Verify application image CRC
+ */
+ record_index = app_start / CYAPA_TSG_FW_ROW_SIZE -
+ CYAPA_TSG_IMG_START_ROW_NUM;
+ data = (u8 *)&image->records[record_index].record_data;
+ app_crc = crc_itu_t(0xffff, data, CYAPA_TSG_FW_ROW_SIZE);
+ for (i = 1; i < (app_len / CYAPA_TSG_FW_ROW_SIZE); i++) {
+ data = (u8 *)&image->records[++record_index].record_data;
+ app_crc = crc_itu_t(app_crc, data, CYAPA_TSG_FW_ROW_SIZE);
+ }
+
+ if (app_crc != expected_app_crc) {
+ dev_err(dev, "%s: invalid firmware app crc check.\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cyapa_gen5_write_fw_block(struct cyapa *cyapa,
+ struct cyapa_tsg_bin_image_data_record *flash_record)
+{
+ u8 flash_array_id;
+ u16 flash_row_id;
+ u16 record_len;
+ u8 *record_data;
+ u8 cmd[144]; /* 13 + 128+ 3 */
+ u16 cmd_len;
+ u16 data_len;
+ u16 crc;
+ u8 resp_data[11];
+ int resp_len;
+ int error;
+
+ flash_array_id = flash_record->flash_array_id;
+ flash_row_id = get_unaligned_be16(&flash_record->row_number);
+ record_len = get_unaligned_be16(&flash_record->record_len);
+ record_data = flash_record->record_data;
+
+ cmd_len = sizeof(cmd) - 2; /* Not include 2 bytes regisetr address. */
+ memset(cmd, 0, cmd_len + 2);
+ cmd[0] = 0x04; /* Register address */
+ cmd[1] = 0x00;
+
+ put_unaligned_le16(cmd_len, &cmd[2]);
+ cmd[4] = 0x40; /* Report id 40h */
+ cmd[5] = 0x00;
+
+ cmd[6] = GEN5_SOP_KEY; /* SOP = 01h */
+ cmd[7] = 0x39; /* Command code = 39h */
+ /* 1 (Flash Array ID) + 2 (Flash Row ID) + 128 (flash data) */
+ data_len = 3 + record_len;
+ put_unaligned_le16(data_len, &cmd[8]);
+ cmd[10] = flash_array_id; /* Flash Array ID = 00h */
+ put_unaligned_le16(flash_row_id, &cmd[11]);
+
+ memcpy(&cmd[13], record_data, record_len);
+ crc = crc_itu_t(0xffff, &cmd[6], 4 + data_len);
+ put_unaligned_le16(crc, &cmd[2 + cmd_len - 3]);
+ cmd[2 + cmd_len - 1] = GEN5_EOP_KEY;
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
+ if (error || resp_len != GEN5_BL_BLOCK_WRITE_RESP_LEN ||
+ resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error < 0 ? error : -EAGAIN;
+
+ return 0;
+}
+
+static int cyapa_gen5_do_fw_update(struct cyapa *cyapa,
+ const struct firmware *fw)
+{
+ struct device *dev = &cyapa->client->dev;
+ struct cyapa_tsg_bin_image *image =
+ (struct cyapa_tsg_bin_image *)fw->data;
+ struct cyapa_tsg_bin_image_data_record *flash_record;
+ int flash_records_count;
+ int i;
+ int error;
+
+ /* Try to dump all bufferred data if exists before send commands. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ flash_records_count =
+ (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) /
+ sizeof(struct cyapa_tsg_bin_image_data_record);
+ /*
+ * The last flash row 0x01ff has been written through bl_initiate
+ * command, so DO NOT write flash 0x01ff to trackpad device.
+ */
+ for (i = 0; i < (flash_records_count - 1); i++) {
+ flash_record = &image->records[i];
+ error = cyapa_gen5_write_fw_block(cyapa, flash_record);
+ if (error) {
+ dev_err(dev, "%s: Gen5 FW update aborted: %d\n",
+ __func__, error);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state)
{
u8 cmd[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 };
@@ -1647,6 +1932,11 @@ static int cyapa_gen5_irq_handler(struct cyapa *cyapa)
}
const struct cyapa_dev_ops cyapa_gen5_ops = {
+ .check_fw = cyapa_gen5_check_fw,
+ .bl_enter = cyapa_gen5_bl_enter,
+ .bl_initiate = cyapa_gen5_bl_initiate,
+ .update_fw = cyapa_gen5_do_fw_update,
+
.initialize = cyapa_gen5_initialize,
.state_parse = cyapa_gen5_state_parse,
--
1.9.1
^ permalink raw reply related
* [PATCH v12 12/19] input: cyapa: add gen5 trackpad device read baseline function support
From: Dudley Du @ 2014-12-03 9:30 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1417599025-21681-1-git-send-email-dudley.dulixin@gmail.com>
Add read baseline function supported for gen5 trackpad device,
it can be used through sysfs baseline interface.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/cyapa.h | 2 +
drivers/input/mouse/cyapa_gen5.c | 621 +++++++++++++++++++++++++++++++++++++++
2 files changed, 623 insertions(+)
diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h
index eafeb79..39e7941 100644
--- a/drivers/input/mouse/cyapa.h
+++ b/drivers/input/mouse/cyapa.h
@@ -285,6 +285,8 @@ struct cyapa {
u8 y_origin; /* Y Axis Origin: 0 = top; 1 = bottom. */
int electrodes_x; /* Number of electrodes on the X Axis*/
int electrodes_y; /* Number of electrodes on the Y Axis*/
+ int electrodes_rx; /* Number of Rx electrodes */
+ int algined_electrodes_rx; /* 4 aligned */
int max_z;
/*
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index eee7d0c..ad123ae 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -1532,6 +1532,625 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
return 0;
}
+static int cyapa_gen5_resume_scanning(struct cyapa *cyapa)
+{
+ u8 cmd[7] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x04 };
+ u8 resp_data[6];
+ int resp_len;
+ int error;
+
+ /* Try to dump all bufferred data before doing command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ resp_len = 6;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, 7,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x04))
+ return -EINVAL;
+
+ /* Try to dump all bufferred data when resuming scanning. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa)
+{
+ u8 cmd[7] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x03 };
+ u8 resp_data[6];
+ int resp_len;
+ int error;
+
+ /* Try to dump all bufferred data before doing command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ resp_len = 6;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, 7,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x03))
+ return -EINVAL;
+
+ /* Try to dump all bufferred data when suspending scanning. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static s32 two_complement_to_s32(s32 value, int num_bits)
+{
+ if (value >> (num_bits - 1))
+ value |= -1 << num_bits;
+ return value;
+}
+
+static s32 cyapa_parse_structure_data(u8 data_format, u8 *buf, int buf_len)
+{
+ int data_size;
+ bool big_endian;
+ bool unsigned_type;
+ s32 value;
+
+ data_size = (data_format & 0x07);
+ big_endian = ((data_format & 0x10) == 0x00);
+ unsigned_type = ((data_format & 0x20) == 0x00);
+
+ if (buf_len < data_size)
+ return 0;
+
+ switch (data_size) {
+ case 1:
+ value = buf[0];
+ break;
+ case 2:
+ if (big_endian)
+ value = get_unaligned_be16(buf);
+ else
+ value = get_unaligned_le16(buf);
+ break;
+ case 4:
+ if (big_endian)
+ value = get_unaligned_be32(buf);
+ else
+ value = get_unaligned_le32(buf);
+ break;
+ default:
+ /* Should not happen, just as default case here. */
+ value = 0;
+ break;
+ }
+
+ if (!unsigned_type)
+ value = two_complement_to_s32(value, data_size * 8);
+
+ return value;
+}
+
+
+/*
+ * Read all the global mutual or self idac data or mutual or self local PWC
+ * data based on the @idac_data_type.
+ * If the input value of @data_size is 0, then means read global mutual or
+ * self idac data. For read global mutual idac data, @idac_max, @idac_min and
+ * @idac_ave are in order used to return the max value of global mutual idac
+ * data, the min value of global mutual idac and the average value of the
+ * global mutual idac data. For read global self idac data, @idac_max is used
+ * to return the global self cap idac data in Rx direction, @idac_min is used
+ * to return the global self cap idac data in Tx direction. @idac_ave is not
+ * used.
+ * If the input value of @data_size is not 0, than means read the mutual or
+ * self local PWC data. The @idac_max, @idac_min and @idac_ave are used to
+ * return the max, min and average value of the mutual or self local PWC data.
+ * Note, in order to raed mutual local PWC data, must read invoke this function
+ * to read the mutual global idac data firstly to set the correct Rx number
+ * value, otherwise, the read mutual idac and PWC data may not correct.
+ */
+static int cyapa_gen5_read_idac_data(struct cyapa *cyapa,
+ u8 cmd_code, u8 idac_data_type, int *data_size,
+ int *idac_max, int *idac_min, int *idac_ave)
+{
+ int i;
+ u8 cmd[12];
+ u8 resp_data[256];
+ int resp_len;
+ int read_len;
+ int value;
+ u16 offset;
+ int read_elements;
+ bool read_global_idac;
+ int sum, count, max_element_cnt;
+ int tmp_max, tmp_min, tmp_ave, tmp_sum, tmp_count;
+ int electrodes_rx, electrodes_tx;
+ int error;
+
+ if (cmd_code != GEN5_CMD_RETRIEVE_DATA_STRUCTURE ||
+ (idac_data_type != GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
+ idac_data_type != GEN5_RETRIEVE_SELF_CAP_PWC_DATA) ||
+ !data_size || !idac_max || !idac_min || !idac_ave)
+ return -EINVAL;
+
+ *idac_max = INT_MIN;
+ *idac_min = INT_MAX;
+ sum = count = tmp_count = 0;
+ electrodes_rx = electrodes_tx = 0;
+ if (*data_size == 0) {
+ /*
+ * Read global idac values firstly.
+ * Currently, no idac data exceed 4 bytes.
+ */
+ read_global_idac = true;
+ offset = 0;
+ *data_size = 4;
+ tmp_max = INT_MIN;
+ tmp_min = INT_MAX;
+ tmp_ave = tmp_sum = tmp_count = 0;
+
+ if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
+ if (cyapa->algined_electrodes_rx == 0) {
+ if (cyapa->electrodes_rx != 0) {
+ electrodes_rx = cyapa->electrodes_rx;
+ electrodes_tx = (cyapa->electrodes_x ==
+ electrodes_rx) ?
+ cyapa->electrodes_y :
+ cyapa->electrodes_x;
+ } else {
+ electrodes_tx = min(cyapa->electrodes_x,
+ cyapa->electrodes_y);
+ electrodes_rx = max(cyapa->electrodes_x,
+ cyapa->electrodes_y);
+ }
+ cyapa->algined_electrodes_rx =
+ (electrodes_rx + 3) & ~3u;
+ }
+ max_element_cnt =
+ (cyapa->algined_electrodes_rx + 7) & ~7u;
+ } else {
+ max_element_cnt = 2;
+ }
+ } else {
+ read_global_idac = false;
+ if (*data_size > 4)
+ *data_size = 4;
+ /* Calculate the start offset in bytes of local PWC data. */
+ if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
+ offset = cyapa->algined_electrodes_rx * (*data_size);
+ electrodes_tx =
+ (cyapa->electrodes_rx == cyapa->electrodes_x) ?
+ cyapa->electrodes_y : cyapa->electrodes_x;
+ max_element_cnt = ((cyapa->algined_electrodes_rx + 7) &
+ ~7u) * electrodes_tx;
+ } else if (idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
+ offset = 2;
+ max_element_cnt = cyapa->electrodes_x +
+ cyapa->electrodes_y;
+ max_element_cnt = (max_element_cnt + 3) & ~3u;
+ }
+ }
+
+ do {
+ read_elements = (256 - 10) / (*data_size);
+ read_elements = min(read_elements, max_element_cnt - count);
+ read_len = read_elements * (*data_size);
+
+ cmd[0] = 0x04;
+ cmd[1] = 0x00;
+ cmd[2] = 0x0a;
+ cmd[3] = 0x00;
+ cmd[4] = GEN5_APP_CMD_REPORT_ID;
+ cmd[5] = 0x00;
+ cmd[6] = cmd_code;
+ put_unaligned_le16(offset, &cmd[7]); /* Read Offset[15:0] */
+ put_unaligned_le16(read_len, &cmd[9]); /* Read Length[15:0] */
+ cmd[11] = idac_data_type;
+ resp_len = 10 + read_len;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, 12,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data,
+ true);
+ if (error || resp_len < 10 ||
+ !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) ||
+ resp_data[6] != idac_data_type)
+ return (error < 0) ? error : -EAGAIN;
+ read_len = get_unaligned_le16(&resp_data[7]);
+ if (read_len == 0)
+ break;
+
+ *data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
+ if (read_len < *data_size)
+ return -EINVAL;
+
+ if (read_global_idac &&
+ idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
+ /* Rx's self global idac data. */
+ *idac_max = cyapa_parse_structure_data(
+ resp_data[9], &resp_data[10],
+ *data_size);
+ /* Tx's self global idac data. */
+ *idac_min = cyapa_parse_structure_data(
+ resp_data[9],
+ &resp_data[10 + *data_size],
+ *data_size);
+ break;
+ }
+
+ /* Read mutual global idac or local mutual/self PWC data. */
+ offset += read_len;
+ for (i = 10; i < (read_len + 10); i += *data_size) {
+ value = cyapa_parse_structure_data(resp_data[9],
+ &resp_data[i], *data_size);
+ *idac_min = min(value, *idac_min);
+ *idac_max = max(value, *idac_max);
+
+ if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
+ tmp_count < cyapa->algined_electrodes_rx &&
+ read_global_idac) {
+ /*
+ * The value gap betwen global and local mutual
+ * idac data must bigger than 50%.
+ * Normally, global value bigger than 50,
+ * local values less than 10.
+ */
+ if (!tmp_ave || value > tmp_ave / 2) {
+ tmp_min = min(value, tmp_min);
+ tmp_max = max(value, tmp_max);
+ tmp_sum += value;
+ tmp_count++;
+
+ tmp_ave = tmp_sum / tmp_count;
+ }
+ }
+
+ sum += value;
+ count++;
+
+ if (count >= max_element_cnt)
+ goto out;
+ }
+ } while (true);
+
+out:
+ *idac_ave = count ? (sum / count) : 0;
+
+ if (read_global_idac &&
+ idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
+ if (tmp_count == 0)
+ return 0;
+
+ if (tmp_count == cyapa->algined_electrodes_rx) {
+ cyapa->electrodes_rx = cyapa->electrodes_rx ?
+ cyapa->electrodes_rx : electrodes_rx;
+ } else if (tmp_count == electrodes_rx) {
+ cyapa->electrodes_rx = cyapa->electrodes_rx ?
+ cyapa->electrodes_rx : electrodes_rx;
+ cyapa->algined_electrodes_rx = electrodes_rx;
+ } else {
+ cyapa->electrodes_rx = cyapa->electrodes_rx ?
+ cyapa->electrodes_rx : electrodes_tx;
+ cyapa->algined_electrodes_rx = tmp_count;
+ }
+
+ *idac_min = tmp_min;
+ *idac_max = tmp_max;
+ *idac_ave = tmp_ave;
+ }
+
+ return 0;
+}
+
+static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa,
+ int *gidac_mutual_max, int *gidac_mutual_min, int *gidac_mutual_ave,
+ int *lidac_mutual_max, int *lidac_mutual_min, int *lidac_mutual_ave)
+{
+ int error;
+ int data_size;
+
+ *gidac_mutual_max = *gidac_mutual_min = *gidac_mutual_ave = 0;
+ *lidac_mutual_max = *lidac_mutual_min = *lidac_mutual_ave = 0;
+
+ data_size = 0;
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_MUTUAL_PWC_DATA,
+ &data_size,
+ gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave);
+ if (error)
+ return error;
+
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_MUTUAL_PWC_DATA,
+ &data_size,
+ lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave);
+ return error;
+}
+
+static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa,
+ int *gidac_self_rx, int *gidac_self_tx,
+ int *lidac_self_max, int *lidac_self_min, int *lidac_self_ave)
+{
+ int error;
+ int data_size;
+
+ *gidac_self_rx = *gidac_self_tx = 0;
+ *lidac_self_max = *lidac_self_min = *lidac_self_ave = 0;
+
+ data_size = 0;
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
+ &data_size,
+ lidac_self_max, lidac_self_min, lidac_self_ave);
+ if (error)
+ return error;
+ *gidac_self_rx = *lidac_self_max;
+ *gidac_self_tx = *lidac_self_min;
+
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
+ &data_size,
+ lidac_self_max, lidac_self_min, lidac_self_ave);
+ return error;
+}
+
+static ssize_t cyapa_gen5_execute_panel_scan(struct cyapa *cyapa)
+{
+ int error;
+ u8 cmd[7];
+ u8 resp_data[6];
+ int resp_len;
+
+ cmd[0] = 0x04;
+ cmd[1] = 0x00;
+ cmd[2] = 0x05;
+ cmd[3] = 0x00;
+ cmd[4] = GEN5_APP_CMD_REPORT_ID;
+ cmd[5] = 0x00;
+ cmd[6] = GEN5_CMD_EXECUTE_PANEL_SCAN; /* Command code */
+ resp_len = 6;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, 7,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || resp_len != 6 ||
+ !VALID_CMD_RESP_HEADER(resp_data,
+ GEN5_CMD_EXECUTE_PANEL_SCAN) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error ? error : -EAGAIN;
+
+ return 0;
+}
+
+static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa,
+ u8 cmd_code, u8 raw_data_type, int raw_data_max_num,
+ int *raw_data_max, int *raw_data_min, int *raw_data_ave,
+ u8 *buffer)
+{
+ int i;
+ u8 cmd[12];
+ u8 resp_data[256]; /* Max bytes can transfer one time. */
+ int resp_len;
+ int read_elements;
+ int read_len;
+ u16 offset;
+ s32 value;
+ int sum, count;
+ int data_size;
+ s32 *intp;
+ int error;
+
+ if (cmd_code != GEN5_CMD_RETRIEVE_PANEL_SCAN ||
+ (raw_data_type > GEN5_PANEL_SCAN_SELF_DIFFCOUNT) ||
+ !raw_data_max || !raw_data_min || !raw_data_ave)
+ return -EINVAL;
+
+ intp = (s32 *)buffer;
+ *raw_data_max = INT_MIN;
+ *raw_data_min = INT_MAX;
+ sum = count = 0;
+ offset = 0;
+ read_elements = (256 - 10) / 4; /* Currently, max element size is 4. */
+ read_len = read_elements * 4;
+ do {
+ cmd[0] = 0x04;
+ cmd[1] = 0x00;
+ cmd[2] = 0x0a;
+ cmd[3] = 0x00;
+ cmd[4] = GEN5_APP_CMD_REPORT_ID;
+ cmd[5] = 0x00;
+ cmd[6] = cmd_code; /* Command code */
+ put_unaligned_le16(offset, &cmd[7]);
+ put_unaligned_le16(read_elements, &cmd[9]);
+ cmd[11] = raw_data_type;
+ resp_len = 10 + read_len;
+
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, 12,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || resp_len < 10 ||
+ !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) ||
+ resp_data[6] != raw_data_type)
+ return error ? error : -EAGAIN;
+
+ read_elements = get_unaligned_le16(&resp_data[7]);
+ if (read_elements == 0)
+ break;
+
+ data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
+ offset += read_elements;
+ if (read_elements) {
+ for (i = 10;
+ i < (read_elements * data_size + 10);
+ i += data_size) {
+ value = cyapa_parse_structure_data(resp_data[9],
+ &resp_data[i], data_size);
+ *raw_data_min = min(value, *raw_data_min);
+ *raw_data_max = max(value, *raw_data_max);
+
+ if (intp)
+ put_unaligned_le32(value, &intp[count]);
+
+ sum += value;
+ count++;
+
+ }
+ }
+
+ if (count >= raw_data_max_num)
+ break;
+
+ read_elements = (sizeof(resp_data) - 10) / data_size;
+ read_len = read_elements * data_size;
+ } while (true);
+
+ *raw_data_ave = count ? (sum / count) : 0;
+
+ return 0;
+}
+
+static ssize_t cyapa_gen5_show_baseline(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave;
+ int lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave;
+ int gidac_self_rx, gidac_self_tx;
+ int lidac_self_max, lidac_self_min, lidac_self_ave;
+ int raw_cap_mutual_max, raw_cap_mutual_min, raw_cap_mutual_ave;
+ int raw_cap_self_max, raw_cap_self_min, raw_cap_self_ave;
+ int mutual_diffdata_max, mutual_diffdata_min, mutual_diffdata_ave;
+ int self_diffdata_max, self_diffdata_min, self_diffdata_ave;
+ int mutual_baseline_max, mutual_baseline_min, mutual_baseline_ave;
+ int self_baseline_max, self_baseline_min, self_baseline_ave;
+ int error, resume_error;
+ int size;
+
+ if (cyapa->state != CYAPA_STATE_GEN5_APP)
+ return -EBUSY;
+
+ /* 1. Suspend Scanning*/
+ error = cyapa_gen5_suspend_scanning(cyapa);
+ if (error)
+ return error;
+
+ /* 2. Read global and local mutual IDAC data. */
+ gidac_self_rx = gidac_self_tx = 0;
+ error = cyapa_gen5_read_mutual_idac_data(cyapa,
+ &gidac_mutual_max, &gidac_mutual_min,
+ &gidac_mutual_ave, &lidac_mutual_max,
+ &lidac_mutual_min, &lidac_mutual_ave);
+ if (error)
+ goto resume_scanning;
+
+ /* 3. Read global and local self IDAC data. */
+ error = cyapa_gen5_read_self_idac_data(cyapa,
+ &gidac_self_rx, &gidac_self_tx,
+ &lidac_self_max, &lidac_self_min,
+ &lidac_self_ave);
+ if (error)
+ goto resume_scanning;
+
+ /* 4. Execuate panel scan. It must be executed before read data. */
+ error = cyapa_gen5_execute_panel_scan(cyapa);
+ if (error)
+ goto resume_scanning;
+
+ /* 5. Retrieve panel scan, mutual cap raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_MUTUAL_RAW_DATA,
+ cyapa->electrodes_x * cyapa->electrodes_y,
+ &raw_cap_mutual_max, &raw_cap_mutual_min,
+ &raw_cap_mutual_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 6. Retrieve panel scan, self cap raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_SELF_RAW_DATA,
+ cyapa->electrodes_x + cyapa->electrodes_y,
+ &raw_cap_self_max, &raw_cap_self_min,
+ &raw_cap_self_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 7. Retrieve panel scan, mutual cap diffcount raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT,
+ cyapa->electrodes_x * cyapa->electrodes_y,
+ &mutual_diffdata_max, &mutual_diffdata_min,
+ &mutual_diffdata_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 8. Retrieve panel scan, self cap diffcount raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_SELF_DIFFCOUNT,
+ cyapa->electrodes_x + cyapa->electrodes_y,
+ &self_diffdata_max, &self_diffdata_min,
+ &self_diffdata_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 9. Retrieve panel scan, mutual cap baseline raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_MUTUAL_BASELINE,
+ cyapa->electrodes_x * cyapa->electrodes_y,
+ &mutual_baseline_max, &mutual_baseline_min,
+ &mutual_baseline_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 10. Retrieve panel scan, self cap baseline raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_SELF_BASELINE,
+ cyapa->electrodes_x + cyapa->electrodes_y,
+ &self_baseline_max, &self_baseline_min,
+ &self_baseline_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+resume_scanning:
+ /* 11. Resume Scanning*/
+ resume_error = cyapa_gen5_resume_scanning(cyapa);
+ if (resume_error || error)
+ return resume_error ? resume_error : error;
+
+ /* 12. Output data strings */
+ size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d %d %d %d %d %d ",
+ gidac_mutual_min, gidac_mutual_max, gidac_mutual_ave,
+ lidac_mutual_min, lidac_mutual_max, lidac_mutual_ave,
+ gidac_self_rx, gidac_self_tx,
+ lidac_self_min, lidac_self_max, lidac_self_ave);
+ size += scnprintf(buf + size, PAGE_SIZE - size,
+ "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ raw_cap_mutual_min, raw_cap_mutual_max, raw_cap_mutual_ave,
+ raw_cap_self_min, raw_cap_self_max, raw_cap_self_ave,
+ mutual_diffdata_min, mutual_diffdata_max, mutual_diffdata_ave,
+ self_diffdata_min, self_diffdata_max, self_diffdata_ave,
+ mutual_baseline_min, mutual_baseline_max, mutual_baseline_ave,
+ self_baseline_min, self_baseline_max, self_baseline_ave);
+ return size;
+}
+
static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa,
u8 *buf, int len)
{
@@ -1937,6 +2556,8 @@ const struct cyapa_dev_ops cyapa_gen5_ops = {
.bl_initiate = cyapa_gen5_bl_initiate,
.update_fw = cyapa_gen5_do_fw_update,
+ .show_baseline = cyapa_gen5_show_baseline,
+
.initialize = cyapa_gen5_initialize,
.state_parse = cyapa_gen5_state_parse,
--
1.9.1
^ permalink raw reply related
* [PATCH v12 13/19] input: cyapa: add gen5 trackpad device force re-calibrate function support
From: Dudley Du @ 2014-12-03 9:30 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1417599025-21681-1-git-send-email-dudley.dulixin@gmail.com>
Add force re-calibrate function supported for gen5 trackpad device,
it can be used through sysfs calibrate interface.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/cyapa_gen5.c | 65 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index ad123ae..9d45941 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -1580,6 +1580,70 @@ static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa)
return 0;
}
+static int cyapa_gen5_calibrate_pwcs(struct cyapa *cyapa,
+ u8 calibrate_sensing_mode_type)
+{
+ u8 cmd[8];
+ u8 resp_data[6];
+ int resp_len;
+ int error;
+
+ /* Try to dump all bufferred data before doing command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ cmd[0] = 0x04;
+ cmd[1] = 0x00;
+ cmd[2] = 0x06;
+ cmd[3] = 0x00;
+ cmd[4] = GEN5_APP_CMD_REPORT_ID;
+ cmd[5] = 0x00;
+ cmd[6] = GEN5_CMD_CALIBRATE;
+ cmd[7] = calibrate_sensing_mode_type;
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 5000, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_CALIBRATE) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error < 0 ? error : -EAGAIN;
+
+ return 0;
+}
+
+static ssize_t cyapa_gen5_do_calibrate(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int error, calibrate_error;
+
+ /* 1. Suspend Scanning*/
+ error = cyapa_gen5_suspend_scanning(cyapa);
+ if (error)
+ return error;
+
+ /* 2. Do mutual capacitance fine calibrate. */
+ calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa,
+ CYAPA_SENSING_MODE_MUTUAL_CAP_FINE);
+ if (calibrate_error)
+ goto resume_scanning;
+
+ /* 3. Do self capacitance calibrate. */
+ calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa,
+ CYAPA_SENSING_MODE_SELF_CAP);
+ if (calibrate_error)
+ goto resume_scanning;
+
+resume_scanning:
+ /* 4. Resume Scanning*/
+ error = cyapa_gen5_resume_scanning(cyapa);
+ if (error || calibrate_error)
+ return error ? error : calibrate_error;
+
+ return count;
+}
+
static s32 two_complement_to_s32(s32 value, int num_bits)
{
if (value >> (num_bits - 1))
@@ -2557,6 +2621,7 @@ const struct cyapa_dev_ops cyapa_gen5_ops = {
.update_fw = cyapa_gen5_do_fw_update,
.show_baseline = cyapa_gen5_show_baseline,
+ .calibrate_store = cyapa_gen5_do_calibrate,
.initialize = cyapa_gen5_initialize,
--
1.9.1
^ permalink raw reply related
* [PATCH v12 14/19] input: cyapa: add read firmware image debugfs interface support
From: Dudley Du @ 2014-12-03 9:30 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1417599025-21681-1-git-send-email-dudley.dulixin@gmail.com>
Add read firmware image from trackpad device interface supported in cyapa
driver through debugfs read_fw interface.
Through this interface user can read out, check and backup the firmware image
of the trackpad device before any firmware update, or can use the backed image
to do firmware image recovery.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/cyapa.c | 182 +++++++++++++++++++++++++++++++++++++++++++-
drivers/input/mouse/cyapa.h | 10 +++
2 files changed, 191 insertions(+), 1 deletion(-)
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index 25b1a3e..d6eb3f2 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -14,6 +14,7 @@
* more details.
*/
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input.h>
@@ -32,10 +33,14 @@
#define CYAPA_ADAPTER_FUNC_SMBUS 2
#define CYAPA_ADAPTER_FUNC_BOTH 3
+#define CYAPA_DEBUGFS_READ_FW "read_fw"
#define CYAPA_FW_NAME "cyapa.bin"
const char unique_str[] = "CYTRA";
+/* Global root node of the cyapa debugfs directory. */
+static struct dentry *cyapa_debugfs_root;
+
static int cyapa_reinitialize(struct cyapa *cyapa);
/* Returns 0 on success, else negative errno on failure. */
@@ -617,6 +622,141 @@ out:
/*
**************************************************************
+ * debugfs interface
+ **************************************************************
+*/
+static int cyapa_debugfs_open(struct inode *inode, struct file *file)
+{
+ struct cyapa *cyapa = inode->i_private;
+ struct device *dev = &cyapa->client->dev;
+ int ret, error;
+
+ if (!cyapa)
+ return -ENODEV;
+
+ error = mutex_lock_interruptible(&cyapa->debugfs_mutex);
+ if (error)
+ return error;
+
+ if (!get_device(dev)) {
+ error = -ENODEV;
+ goto out;
+ }
+
+ file->private_data = cyapa;
+
+ if (cyapa->fw_image && cyapa->fw_image_size) {
+ error = 0;
+ goto out;
+ }
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ goto out;
+
+ /*
+ * If firmware hasn't been read yet, read it all in one pass.
+ * Subsequent opens will reuse the data in this same buffer.
+ */
+ if (cyapa->ops->read_fw) {
+ cyapa->operational = false;
+ cyapa_enable_irq_for_cmd(cyapa);
+ error = cyapa->ops->read_fw(cyapa);
+ cyapa_disable_irq_for_cmd(cyapa);
+
+ ret = cyapa_reinitialize(cyapa);
+ if (ret) {
+ dev_err(dev, "failed to redetect after read_fw: %d\n",
+ ret);
+ error = error ? error : ret;
+ }
+ } else {
+ ret = -EPERM;
+ }
+
+ mutex_unlock(&cyapa->state_sync_lock);
+out:
+ mutex_unlock(&cyapa->debugfs_mutex);
+ return error;
+}
+
+static int cyapa_debugfs_release(struct inode *inode, struct file *file)
+{
+ struct cyapa *cyapa = file->private_data;
+ int error;
+
+ if (!cyapa)
+ return 0;
+
+ error = mutex_lock_interruptible(&cyapa->debugfs_mutex);
+ if (error)
+ return error;
+ file->private_data = NULL;
+ put_device(&cyapa->client->dev);
+ mutex_unlock(&cyapa->debugfs_mutex);
+
+ return 0;
+}
+
+/* Return some bytes from the buffered firmware image, starting from *ppos */
+static ssize_t cyapa_debugfs_read_fw(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct cyapa *cyapa = file->private_data;
+
+ if (!cyapa->fw_image)
+ return -EINVAL;
+
+ if (*ppos >= cyapa->fw_image_size)
+ return 0;
+
+ if (count + *ppos > cyapa->fw_image_size)
+ count = cyapa->fw_image_size - *ppos;
+
+ if (copy_to_user(buffer, &cyapa->fw_image[*ppos], count))
+ return -EFAULT;
+
+ *ppos += count;
+ return count;
+}
+
+static const struct file_operations cyapa_read_fw_fops = {
+ .open = cyapa_debugfs_open,
+ .release = cyapa_debugfs_release,
+ .read = cyapa_debugfs_read_fw
+};
+
+static int cyapa_debugfs_init(struct cyapa *cyapa)
+{
+ struct device *dev = &cyapa->client->dev;
+
+ if (!cyapa_debugfs_root)
+ return -ENODEV;
+
+ cyapa->dentry_dev = debugfs_create_dir(kobject_name(&dev->kobj),
+ cyapa_debugfs_root);
+
+ if (!cyapa->dentry_dev)
+ return -ENODEV;
+
+ mutex_init(&cyapa->debugfs_mutex);
+
+ debugfs_create_file(CYAPA_DEBUGFS_READ_FW, S_IRUSR, cyapa->dentry_dev,
+ cyapa, &cyapa_read_fw_fops);
+
+ return 0;
+}
+
+static void cyapa_remove_debugfs(void *data)
+{
+ struct cyapa *cyapa = data;
+
+ debugfs_remove_recursive(cyapa->dentry_dev);
+ mutex_destroy(&cyapa->debugfs_mutex);
+}
+
+/*
+ **************************************************************
* sysfs interface
**************************************************************
*/
@@ -1156,6 +1296,20 @@ static int cyapa_probe(struct i2c_client *client,
return error;
}
+ error = cyapa_debugfs_init(cyapa);
+ if (error) {
+ dev_err(dev, "failed to create debugfs entries: %d\n", error);
+ return error;
+ }
+
+ error = devm_add_action(dev, cyapa_remove_debugfs, cyapa);
+ if (error) {
+ cyapa_remove_debugfs(cyapa);
+ dev_err(dev, "failed to add debugfs cleanup action :%d\n",
+ error);
+ return error;
+ }
+
#ifdef CONFIG_PM_SLEEP
if (device_can_wakeup(dev)) {
error = sysfs_merge_group(&client->dev.kobj,
@@ -1336,7 +1490,33 @@ static struct i2c_driver cyapa_driver = {
.id_table = cyapa_id_table,
};
-module_i2c_driver(cyapa_driver);
+static int __init cyapa_init(void)
+{
+ int error;
+
+ /* Create a global debugfs root for all cyapa devices */
+ cyapa_debugfs_root = debugfs_create_dir("cyapa", NULL);
+ if (cyapa_debugfs_root == ERR_PTR(-ENODEV))
+ cyapa_debugfs_root = NULL;
+
+ error = i2c_add_driver(&cyapa_driver);
+ if (error) {
+ pr_err("cyapa driver register FAILED.\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static void __exit cyapa_exit(void)
+{
+ debugfs_remove_recursive(cyapa_debugfs_root);
+
+ i2c_del_driver(&cyapa_driver);
+}
+
+module_init(cyapa_init);
+module_exit(cyapa_exit);
MODULE_DESCRIPTION("Cypress APA I2C Trackpad Driver");
MODULE_AUTHOR("Dudley Du <dudl@cypress.com>");
diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h
index 39e7941..f8eac6f 100644
--- a/drivers/input/mouse/cyapa.h
+++ b/drivers/input/mouse/cyapa.h
@@ -186,6 +186,8 @@ struct cyapa_dev_ops {
ssize_t (*calibrate_store)(struct device *,
struct device_attribute *, const char *, size_t);
+ int (*read_fw)(struct cyapa *);
+
int (*initialize)(struct cyapa *cyapa);
int (*state_parse)(struct cyapa *cyapa, u8 *reg_status, int len);
@@ -297,6 +299,14 @@ struct cyapa {
*/
struct mutex state_sync_lock;
+ /* Per-instance debugfs root */
+ struct dentry *dentry_dev;
+
+ /* Buffer to store firmware read using debugfs */
+ struct mutex debugfs_mutex;
+ u8 *fw_image;
+ size_t fw_image_size;
+
const struct cyapa_dev_ops *ops;
union cyapa_cmd_states cmd_states;
--
1.9.1
^ permalink raw reply related
* [PATCH v12 15/19] input: cyapa: add gen3 trackpad device read firmware image function support
From: Dudley Du @ 2014-12-03 9:30 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1417599025-21681-1-git-send-email-dudley.dulixin@gmail.com>
Add read firmware image function supported for gen3 trackpad device,
it can be used through debugfs read_fw interface.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/cyapa_gen3.c | 67 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
index 640b916..dd1313e 100644
--- a/drivers/input/mouse/cyapa_gen3.c
+++ b/drivers/input/mouse/cyapa_gen3.c
@@ -708,6 +708,36 @@ static int cyapa_gen3_write_fw_block(struct cyapa *cyapa,
return ret;
}
+/*
+ * A firmware block read command reads 16 bytes of data from flash starting
+ * from a given address. The 12-byte block read command has the format:
+ * <0xff> <CMD> <Key> <Addr>
+ *
+ * <0xff> - every command starts with 0xff
+ * <CMD> - the read command value is 0x3c
+ * <Key> - read commands include an 8-byte key: { 00 01 02 03 04 05 06 07 }
+ * <Addr> - Memory address (16-bit, big-endian)
+ *
+ * The command is followed by an i2c block read to read the 16 bytes of data.
+ */
+static int cyapa_gen3_read_fw_bytes(struct cyapa *cyapa, u16 addr, u8 *data)
+{
+ u8 cmd[] = { 0xff, 0x3c, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, addr >> 8, addr };
+ int ret, error;
+
+ error = cyapa_gen3_write_buffer(cyapa, cmd, sizeof(cmd));
+ if (error)
+ return error;
+
+ /* Read data buffer starting from offset 16 */
+ ret = cyapa_i2c_reg_read_block(cyapa, 16, CYAPA_FW_READ_SIZE, data);
+ if (ret != CYAPA_FW_READ_SIZE)
+ return (ret < 0) ? ret : -EIO;
+
+ return 0;
+}
+
static int cyapa_gen3_write_blocks(struct cyapa *cyapa,
size_t start_block, size_t block_count,
const u8 *image_data)
@@ -754,6 +784,41 @@ static int cyapa_gen3_do_fw_update(struct cyapa *cyapa,
return 0;
}
+/*
+ * Read the entire firmware image into ->fw_image.
+ * If the ->fw_image has already been allocated, then this function
+ * doesn't do anything and just returns 0.
+ * If an error occurs while reading the image, ->fw_image is freed, and
+ * the error is returned.
+ *
+ * The firmware is a fixed size (CYAPA_FW_SIZE), and is read out in
+ * fixed length (CYAPA_FW_READ_SIZE) chunks.
+ */
+static int cyapa_gen3_read_fw(struct cyapa *cyapa)
+{
+ int error;
+ int addr;
+
+ error = cyapa_gen3_bl_enter(cyapa);
+ if (error)
+ return error;
+
+ cyapa->fw_image = cyapa->fw_image ? cyapa->fw_image :
+ devm_kzalloc(&cyapa->client->dev, CYAPA_FW_SIZE, GFP_KERNEL);
+ if (!cyapa->fw_image)
+ return -ENOMEM;
+
+ for (addr = 0; addr < CYAPA_FW_SIZE; addr += CYAPA_FW_READ_SIZE) {
+ error = cyapa_gen3_read_fw_bytes(cyapa,
+ CYAPA_FW_HDR_START + addr, &cyapa->fw_image[addr]);
+ if (error)
+ return error;
+ }
+
+ cyapa->fw_image_size = CYAPA_FW_SIZE;
+ return 0;
+}
+
static ssize_t cyapa_gen3_do_calibrate(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -1195,6 +1260,8 @@ const struct cyapa_dev_ops cyapa_gen3_ops = {
.show_baseline = cyapa_gen3_show_baseline,
.calibrate_store = cyapa_gen3_do_calibrate,
+ .read_fw = cyapa_gen3_read_fw,
+
.state_parse = cyapa_gen3_state_parse,
.operational_check = cyapa_gen3_do_operational_check,
--
1.9.1
^ permalink raw reply related
* [PATCH v12 16/19] input: cyapa: add gen5 trackpad device read firmware image function support
From: Dudley Du @ 2014-12-03 9:30 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1417599025-21681-1-git-send-email-dudley.dulixin@gmail.com>
Add read firmware image function supported for gen5 trackpad device,
it can be used through debugfs read_fw interface.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/cyapa.h | 1 +
drivers/input/mouse/cyapa_gen5.c | 155 +++++++++++++++++++++++++++++++++++++++
2 files changed, 156 insertions(+)
diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h
index f8eac6f..8aa51af 100644
--- a/drivers/input/mouse/cyapa.h
+++ b/drivers/input/mouse/cyapa.h
@@ -304,6 +304,7 @@ struct cyapa {
/* Buffer to store firmware read using debugfs */
struct mutex debugfs_mutex;
+ struct cyapa_tsg_bin_image_head fw_img_head;
u8 *fw_image;
size_t fw_image_size;
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index 9d45941..f75461c 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -1210,6 +1210,154 @@ static int cyapa_gen5_write_fw_block(struct cyapa *cyapa,
return 0;
}
+static int cyapa_gen5_read_fw_bytes(struct cyapa *cyapa, u16 row_num, u8 *data)
+{
+ u8 cmd[16];
+ size_t cmd_len;
+ u8 resp_data[CYAPA_TSG_FW_ROW_SIZE / 2 + GEN5_MIN_BL_RESP_LENGTH];
+ int resp_len;
+ u16 offset;
+ u16 cmd_crc;
+ struct cyapa_tsg_bin_image_data_record *fw_img_record;
+ int error;
+
+ fw_img_record = (struct cyapa_tsg_bin_image_data_record *)data;
+
+ cmd[0] = 0x04; /* Register address */
+ cmd[1] = 0x00;
+ cmd[2] = 0x0e;
+ cmd[3] = 0x00;
+ cmd[4] = 0x40; /* Report id 40h */
+ cmd[5] = 0x00;
+ cmd[6] = GEN5_SOP_KEY;
+ cmd[7] = 0x3d; /* Read application image command code */
+ cmd[8] = 0x03;
+ cmd[9] = 0x00;
+ offset = row_num * CYAPA_TSG_FW_ROW_SIZE -
+ CYAPA_TSG_START_OF_APPLICATION;
+ put_unaligned_le16(offset, &cmd[10]);
+ cmd[12] = CYAPA_TSG_IMG_READ_SIZE;
+ cmd_crc = crc_itu_t(0xffff, &cmd[6], 7);
+ put_unaligned_le16(cmd_crc, &cmd[13]); /* CRC[15:0] */
+ cmd[15] = GEN5_EOP_KEY; /* EOP = 17h */
+ cmd_len = 16;
+
+ resp_len = CYAPA_TSG_IMG_READ_SIZE + GEN5_MIN_BL_RESP_LENGTH;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, cmd_len,
+ resp_data, &resp_len,
+ 50, cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
+ if (resp_len != (CYAPA_TSG_IMG_READ_SIZE + GEN5_MIN_BL_RESP_LENGTH) ||
+ error || resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error ? error : -EAGAIN;
+
+ /* Copy first 64 bytes in the row. */
+ memcpy(&fw_img_record->record_data[0], &resp_data[8],
+ CYAPA_TSG_IMG_READ_SIZE);
+
+ if (row_num == CYAPA_TSG_IMG_APP_INTEGRITY_ROW_NUM) {
+ /* Last row's rest 64 bytes are bootloader metadata,
+ * it's not allowed to be read out, will respond with error. */
+ memset(&fw_img_record->record_data[CYAPA_TSG_IMG_READ_SIZE],
+ 0, CYAPA_TSG_IMG_READ_SIZE);
+ goto skip_last_row;
+ }
+
+ /* Read next 64 bytes in the row. */
+ offset = offset + CYAPA_TSG_IMG_READ_SIZE;
+ put_unaligned_le16(offset, &cmd[10]);
+ cmd_crc = crc_itu_t(0xffff, &cmd[6], 7);
+ put_unaligned_le16(cmd_crc, &cmd[13]); /* CRC[15:0] */
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, cmd_len,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
+ if (resp_len != (CYAPA_TSG_IMG_READ_SIZE + GEN5_MIN_BL_RESP_LENGTH) ||
+ error || resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error ? error : -EAGAIN;
+
+ /* Copy last 64 bytes in the row. */
+ memcpy(&fw_img_record->record_data[CYAPA_TSG_IMG_READ_SIZE],
+ &resp_data[8], CYAPA_TSG_IMG_READ_SIZE);
+
+skip_last_row:
+ fw_img_record->flash_array_id = 0;
+ put_unaligned_be16(row_num, &fw_img_record->row_number);
+ put_unaligned_be16(CYAPA_TSG_FW_ROW_SIZE, &fw_img_record->record_len);
+
+ return 0;
+}
+
+static int cyapa_gen5_read_fw(struct cyapa *cyapa)
+{
+ int fw_img_head_size;
+ int fw_img_record_size;
+ int fw_img_size;
+ int row_index;
+ int array_index;
+ u32 img_start;
+ u16 img_len;
+ u16 img_start_row;
+ u16 img_end_row;
+ struct cyapa_tsg_bin_image_data_record app_integrity;
+ u8 *record_data;
+ int error;
+
+ error = cyapa_gen5_bl_enter(cyapa);
+ if (error)
+ return error;
+
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ fw_img_head_size = sizeof(struct cyapa_tsg_bin_image_head);
+ fw_img_record_size = sizeof(struct cyapa_tsg_bin_image_data_record);
+
+ /* Read app integrity block data. */
+ row_index = CYAPA_TSG_IMG_APP_INTEGRITY_ROW_NUM;
+ error = cyapa_gen5_read_fw_bytes(cyapa,
+ row_index, (u8 *)&app_integrity);
+ if (error)
+ return error;
+ img_start = get_unaligned_le32(&app_integrity.record_data[16]);
+ img_len = get_unaligned_le16(&app_integrity.record_data[20]);
+ if ((img_start + img_len) % CYAPA_TSG_FW_ROW_SIZE)
+ return -EINVAL;
+ img_start_row = img_start / CYAPA_TSG_FW_ROW_SIZE;
+ img_end_row = (img_start + img_len) / CYAPA_TSG_FW_ROW_SIZE - 1;
+
+ /* Allocate memory for image. */
+ fw_img_size = fw_img_head_size +
+ (img_end_row - img_start_row + 2) * fw_img_record_size;
+ cyapa->fw_image = cyapa->fw_image ? cyapa->fw_image :
+ devm_kzalloc(&cyapa->client->dev, fw_img_size, GFP_KERNEL);
+ if (!cyapa->fw_image)
+ return -ENOMEM;
+
+ /* Set image head data. */
+ memcpy(cyapa->fw_image, &cyapa->fw_img_head, fw_img_head_size);
+
+ /* Read image blocks. */
+ for (row_index = img_start_row, array_index = 0;
+ row_index <= img_end_row;
+ row_index++, array_index++) {
+ record_data = &cyapa->fw_image[fw_img_head_size +
+ array_index * fw_img_record_size];
+ error = cyapa_gen5_read_fw_bytes(cyapa, row_index, record_data);
+ if (error)
+ return error;
+ }
+
+ /* Append last app integrity block data. */
+ record_data = &cyapa->fw_image[fw_img_head_size +
+ array_index * fw_img_record_size];
+ memcpy(record_data, &app_integrity, fw_img_record_size);
+
+ cyapa->fw_image_size = fw_img_size;
+ return 0;
+}
+
static int cyapa_gen5_do_fw_update(struct cyapa *cyapa,
const struct firmware *fw)
{
@@ -2288,6 +2436,11 @@ static int cyapa_gen5_get_query_data(struct cyapa *cyapa)
if (error || resp_len < sizeof(resp_data))
return error ? error : -EIO;
+ cyapa->fw_img_head.head_size =
+ sizeof(struct cyapa_tsg_bin_image_head) - 1;
+ memcpy(&cyapa->fw_img_head.ttda_driver_major_version,
+ &resp_data[5], cyapa->fw_img_head.head_size);
+
product_family = get_unaligned_le16(&resp_data[7]);
if ((product_family & GEN5_PRODUCT_FAMILY_MASK) !=
GEN5_PRODUCT_FAMILY_TRACKPAD)
@@ -2623,6 +2776,8 @@ const struct cyapa_dev_ops cyapa_gen5_ops = {
.show_baseline = cyapa_gen5_show_baseline,
.calibrate_store = cyapa_gen5_do_calibrate,
+ .read_fw = cyapa_gen5_read_fw,
+
.initialize = cyapa_gen5_initialize,
.state_parse = cyapa_gen5_state_parse,
--
1.9.1
^ permalink raw reply related
* [PATCH v12 17/19] input: cyapa: add read sensors raw data debugfs interface support
From: Dudley Du @ 2014-12-03 9:30 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1417599025-21681-1-git-send-email-dudley.dulixin@gmail.com>
Add read sensors' raw data from trackpad device interface supported in cyapa
driver through debugfs raw_data interface.
Through this interface, user can read difference count map of each sensors
directly from trackpad device (some customers want). And it's useful to help
users to find out the root cause when there is performance gap happened.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/cyapa.c | 90 +++++++++++++++++++++++++++++++++++++++++++++
drivers/input/mouse/cyapa.h | 4 ++
2 files changed, 94 insertions(+)
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index d6eb3f2..09111ed 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -34,6 +34,7 @@
#define CYAPA_ADAPTER_FUNC_BOTH 3
#define CYAPA_DEBUGFS_READ_FW "read_fw"
+#define CYAPA_DEBUGFS_RAW_DATA "raw_data"
#define CYAPA_FW_NAME "cyapa.bin"
const char unique_str[] = "CYTRA";
@@ -726,6 +727,91 @@ static const struct file_operations cyapa_read_fw_fops = {
.read = cyapa_debugfs_read_fw
};
+static int cyapa_debugfs_raw_data_open(struct inode *inode, struct file *file)
+{
+ struct cyapa *cyapa = inode->i_private;
+ int error;
+
+ if (!cyapa)
+ return -ENODEV;
+
+ /* Start to be supported after Gen5 trackpad devices. */
+ if (cyapa->gen < CYAPA_GEN5)
+ return -ENOTSUPP;
+
+ error = mutex_lock_interruptible(&cyapa->debugfs_mutex);
+ if (error)
+ return error;
+
+ if (!get_device(&cyapa->client->dev)) {
+ error = -ENODEV;
+ goto out;
+ }
+
+ file->private_data = cyapa;
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ goto out;
+
+ if (cyapa->ops->read_raw_data) {
+ cyapa_enable_irq_for_cmd(cyapa);
+ error = cyapa->ops->read_raw_data(cyapa);
+ cyapa_disable_irq_for_cmd(cyapa);
+ } else {
+ error = -EPERM;
+ }
+
+ mutex_unlock(&cyapa->state_sync_lock);
+out:
+ mutex_unlock(&cyapa->debugfs_mutex);
+ return error;
+}
+
+static int cyapa_debugfs_raw_data_release(struct inode *inode,
+ struct file *file)
+{
+ struct cyapa *cyapa = file->private_data;
+ int error;
+
+ if (!cyapa)
+ return 0;
+
+ error = mutex_lock_interruptible(&cyapa->debugfs_mutex);
+ if (error)
+ return error;
+ file->private_data = NULL;
+ put_device(&cyapa->client->dev);
+ mutex_unlock(&cyapa->debugfs_mutex);
+
+ return 0;
+}
+
+static ssize_t cyapa_debugfs_read_raw_data(struct file *file,
+ char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct cyapa *cyapa = file->private_data;
+
+ if (*ppos >= cyapa->tp_raw_data_size)
+ return 0;
+
+ if (count + *ppos > cyapa->tp_raw_data_size)
+ count = cyapa->tp_raw_data_size - *ppos;
+
+ if (copy_to_user(buffer, &cyapa->tp_raw_data[*ppos], count))
+ return -EFAULT;
+
+ *ppos += count;
+ return count;
+}
+
+static const struct file_operations cyapa_read_raw_data_fops = {
+ .open = cyapa_debugfs_raw_data_open,
+ .release = cyapa_debugfs_raw_data_release,
+ .read = cyapa_debugfs_read_raw_data
+};
+
static int cyapa_debugfs_init(struct cyapa *cyapa)
{
struct device *dev = &cyapa->client->dev;
@@ -744,6 +830,10 @@ static int cyapa_debugfs_init(struct cyapa *cyapa)
debugfs_create_file(CYAPA_DEBUGFS_READ_FW, S_IRUSR, cyapa->dentry_dev,
cyapa, &cyapa_read_fw_fops);
+ if (cyapa->gen >= CYAPA_GEN5)
+ debugfs_create_file(CYAPA_DEBUGFS_RAW_DATA, S_IRUSR,
+ cyapa->dentry_dev, cyapa, &cyapa_read_raw_data_fops);
+
return 0;
}
diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h
index 8aa51af..93dfe86 100644
--- a/drivers/input/mouse/cyapa.h
+++ b/drivers/input/mouse/cyapa.h
@@ -187,6 +187,7 @@ struct cyapa_dev_ops {
struct device_attribute *, const char *, size_t);
int (*read_fw)(struct cyapa *);
+ int (*read_raw_data)(struct cyapa *);
int (*initialize)(struct cyapa *cyapa);
@@ -307,6 +308,9 @@ struct cyapa {
struct cyapa_tsg_bin_image_head fw_img_head;
u8 *fw_image;
size_t fw_image_size;
+ /* Buffer to store sensors' raw data */
+ u8 *tp_raw_data;
+ size_t tp_raw_data_size;
const struct cyapa_dev_ops *ops;
--
1.9.1
^ permalink raw reply related
* [PATCH v12 18/19] input: cyapa: add gen5 trackpad device read raw data function support
From: Dudley Du @ 2014-12-03 9:30 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1417599025-21681-1-git-send-email-dudley.dulixin@gmail.com>
Add read raw data function supported for gen5 trackpad device,
it can be used through debugfs raw_data interface.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/cyapa_gen5.c | 138 +++++++++++++++++++++++++++++++++++++++
1 file changed, 138 insertions(+)
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index f75461c..af098d4 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -2363,6 +2363,143 @@ resume_scanning:
return size;
}
+static int cyapa_gen5_read_electrodies_rx_tx(struct cyapa *cyapa)
+{
+ u8 cmd[7] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x71 };
+ u8 resp_data[7];
+ int resp_len;
+ int error;
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, 7,
+ resp_data, &resp_len,
+ 150, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x71) ||
+ !resp_data[5] || !resp_data[6])
+ return -EINVAL;
+
+ cyapa->electrodes_rx = resp_data[6];
+
+ return 0;
+}
+
+static int cyapa_gen5_read_raw_data(struct cyapa *cyapa)
+{
+ int raw_cap_mutual_max, raw_cap_mutual_min, raw_cap_mutual_ave;
+ int raw_cap_self_max, raw_cap_self_min, raw_cap_self_ave;
+ int offset;
+ int data_size, max, min, ave;
+ ktime_t time_mono;
+ int error, resume_error;
+
+ offset = 0;
+ if (!cyapa->tp_raw_data) {
+ if (cyapa->state != CYAPA_STATE_GEN5_APP ||
+ !cyapa->electrodes_x || !cyapa->electrodes_y)
+ return -EINVAL;
+
+ cyapa->tp_raw_data_size = sizeof(s32) * (cyapa->electrodes_x *
+ cyapa->electrodes_y + cyapa->electrodes_x +
+ cyapa->electrodes_y) + GEN5_RAW_DATA_HEAD_SIZE;
+ /*
+ * This buffer will be hold after used until the driver is
+ * unloaded, the purpose of it is to improve the performace
+ * to avoid frequently allocate and release the buffer.
+ */
+ cyapa->tp_raw_data = devm_kzalloc(&cyapa->client->dev,
+ cyapa->tp_raw_data_size, GFP_KERNEL);
+ if (!cyapa->tp_raw_data)
+ return -ENOMEM;
+ }
+
+ /*
+ * 1. Suspend Scanning.
+ *
+ * After suspend scanning, the raw data will not be updated,
+ * so the time of the raw data is before scanning suspended.
+ */
+ time_mono = ktime_get();
+ error = cyapa_gen5_suspend_scanning(cyapa);
+ if (error)
+ return error;
+
+ /* 2. Get the correct electrodes_rx number. */
+ if (cyapa->electrodes_rx == 0) {
+ error = cyapa_gen5_read_electrodies_rx_tx(cyapa);
+ if (error || cyapa->electrodes_rx == 0) {
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ /*
+ * Since, old firmware doesn't support the command to
+ * read the electrodies' Rx and Tx values, so using
+ * the read global idac interface to get the Rx number,
+ * this value is useful to analyze and
+ * display the raw data map in userspace.
+ */
+ data_size = 0;
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_MUTUAL_PWC_DATA,
+ &data_size, &max, &min, &ave);
+ if (error || cyapa->electrodes_rx == 0)
+ goto resume_scanning;
+ }
+ }
+
+ /* 3. Execuate panel scan. It must be executed before read data. */
+ error = cyapa_gen5_execute_panel_scan(cyapa);
+ if (error)
+ goto resume_scanning;
+
+ /* 4. Retrieve panel scan, mutual cap raw data. */
+ offset = GEN5_RAW_DATA_HEAD_SIZE;
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT,
+ cyapa->electrodes_x * cyapa->electrodes_y,
+ &raw_cap_mutual_max, &raw_cap_mutual_min,
+ &raw_cap_mutual_ave,
+ cyapa->tp_raw_data + offset);
+ if (error)
+ goto resume_scanning;
+
+ offset += sizeof(s32) * cyapa->electrodes_x * cyapa->electrodes_y;
+
+ /* 5. Retrieve panel scan, self cap raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_SELF_DIFFCOUNT,
+ cyapa->electrodes_x + cyapa->electrodes_y,
+ &raw_cap_self_max, &raw_cap_self_min,
+ &raw_cap_self_ave,
+ cyapa->tp_raw_data + offset);
+ if (error)
+ goto resume_scanning;
+
+ offset += sizeof(s32) * (cyapa->electrodes_x + cyapa->electrodes_y);
+
+resume_scanning:
+ /* 6. Resume Scanning*/
+ resume_error = cyapa_gen5_resume_scanning(cyapa);
+ if (resume_error || error)
+ return resume_error ? resume_error : error;
+
+ *((struct timeval *)&cyapa->tp_raw_data[0]) =
+ ktime_to_timeval(time_mono);
+ cyapa->tp_raw_data[16] = (u8)cyapa->electrodes_x;
+ cyapa->tp_raw_data[17] = (u8)cyapa->electrodes_y;
+ cyapa->tp_raw_data[18] = (u8)cyapa->x_origin;
+ cyapa->tp_raw_data[19] = (u8)cyapa->y_origin;
+ cyapa->tp_raw_data[20] = (u8)sizeof(s32);
+ cyapa->tp_raw_data[21] = (u8)sizeof(s32);
+ cyapa->tp_raw_data[22] = (u8)cyapa->electrodes_rx;
+ cyapa->tp_raw_data[23] = 0; /* Reserved. */
+
+ cyapa->tp_raw_data_size = offset;
+ return 0;
+}
+
static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa,
u8 *buf, int len)
{
@@ -2777,6 +2914,7 @@ const struct cyapa_dev_ops cyapa_gen5_ops = {
.calibrate_store = cyapa_gen5_do_calibrate,
.read_fw = cyapa_gen5_read_fw,
+ .read_raw_data = cyapa_gen5_read_raw_data,
.initialize = cyapa_gen5_initialize,
--
1.9.1
^ permalink raw reply related
* [PATCH v12 19/19] input: cyapa: add acpi device id supported
From: Dudley Du @ 2014-12-03 9:30 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1417599025-21681-1-git-send-email-dudley.dulixin@gmail.com>
Add acpi device tree supported.
acpi device id "CYAP0000" is for old gen3 trackpad devices.
acpi device id "CYAP0001" is for new gen5 trackpad devices.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/cyapa.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index 09111ed..75f3876 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
+#include <linux/acpi.h>
#include "cyapa.h"
@@ -1569,11 +1570,23 @@ static const struct i2c_device_id cyapa_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, cyapa_id_table);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cyapa_acpi_id[] = {
+ { "CYAP0000", 0 }, /* Gen3 trackpad with 0x67 I2C address. */
+ { "CYAP0001", 0 }, /* Gen5 trackpad with 0x24 I2C address. */
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id);
+#endif
+
static struct i2c_driver cyapa_driver = {
.driver = {
.name = "cyapa",
.owner = THIS_MODULE,
.pm = &cyapa_pm_ops,
+#ifdef CONFIG_ACPI
+ .acpi_match_table = ACPI_PTR(cyapa_acpi_id),
+#endif
},
.probe = cyapa_probe,
--
1.9.1
^ permalink raw reply related
* [PATCH v12 00/19] input: cyapa: instruction of cyapa patches
From: Dudley Du @ 2014-12-03 9:30 UTC (permalink / raw)
To: dmitry.torokhov, rydberg
Cc: Dudley Du, bleung, dso, linux-input, linux-kernel
V12 patches have below main updates compared with v10 patches:
1) Add check that when TP is detected but not operational, do not exit driver
immediately, but wait and export the update_fw interface for recovering.
2) Re-arrange the function codes, remove unnesseary protype definitions in
the header file.
V11 patches have below main updates compared with v10 patches:
1) Add add acpi device id supported for old gen3 and new gen5 trackpad devices.
2) Fix the unable to update firmware issue when cyapa_open is not called
which means the irq for firwmare update process is not enabled. This fix
by checking if the irq is enabled, if not then enable irq before start to
do firmware update.
V10 patches have below main updates compared with v9 patches:
1) Modify code to following kernel code style.
e.g.: correct to use error as return name when there is only error path,
and fix the checkpatch.sh wanting in the driver.
2) Remove cyapa_remove method and use input open and close interface to
following device resouse management infrastructure.
3) Modify cyapa_detect method to return tristate issue to make the return value
much more consistent and clear.
4) Use platform supplied functions as possible instead of driver
specific rewritten version.
V9 patches have below updates compared with v8 patches:
1) Removed all async thread stuff from the driver.
2) Split driver into 18 patches for each function change one patch.
V8 patches have below updates compared with v7 patches:
1) [PATCH v8 01/13] - Remove the async thread for device detect in
probe routine, now the device detect process is completely done within
the device probe routine.
2) [PATCH v8 01/13] - Split the irq cmd hander function to separated
function cyapa_default_irq_cmd_handler() and set it to interface
cyapa_default_ops.irq_cmd_handler.
3) [PATCH v8 06/13] - Add cyapa->gen check in cyapa_gen3_irq_cmd_handler()
to avoid miss-enter when device protocol is still in detecting.
V7 patches have below updates compared with v6 patches:
1) [PATCH v7 01/13] - Split the irq cmd hander function to separated
function cyapa_default_irq_cmd_handler() and set it to interface
cyapa_default_ops.irq_cmd_handler.
2) [PATCH v7 06/13] - Add cyapa->gen check in cyapa_gen3_irq_cmd_handler()
to avoid miss-enter when device protocol is still in detecting.
V6 patches have below updates compared with v5 patches:
1) Remove patch 14 of the lid filtering from the cyapa driver.
V5 patches have below updates compared with v4 patches:
1) Uses get_device()/put_device() instead of kobject_get()/kobject_put();
2) Fix memories freed before debugfs entries issue;
3) Make cyapa_debugs_root valid in driver module level
in module_init()/moudle_exit() ;
4) Fix i2c_transfer() may return partial transfer issues.
5) Add cyapa->removed flag to avoid detecting thread may still running
when driver module is removed.
6) Fix the meanings of some comments and return error code not clear issue.
This patch set is aimed to re-design the cyapa driver to support
old gen3 trackpad devices and new gen5 trackpad devices in one
cyapa driver, it's for easily productions support based on
customers' requirements. And add sysfs functions and interfaces
supported that required by users and customers.
Since the earlier gen3 and the latest gen5 trackpad devices using
two different chipsets, and have different protocols and interfaces,
so if supported these two type trackpad devices in two different drivers,
then it will be difficult to manage productions and later firmware updates.
e.g.: It will cause customer don't know which one trackpad device firmware
image to use and update when it has been used and integrated
in same one productions, so here we support these two trackpad
devices in same on driver.
The new design cyapa driver contains:
cyapa.c - the core of the re-design, supply interfaces and
functions to system and read trackpad devices.
cyapa.h - header file including macros and data structure definitions.
cyapa_gen3.c - functions support for gen3 trackpad devices,
cyapa_gen5.c - functions support for gen5 trackpad devices.
Beside this introduction patch, it has 18 patches listed as below.
For these patches each one is patched based on previous one.
patch 1/19: modify code to following kernel code style.
patch 2/19: add device resource management infrastructure support.
patch 3/19: re-design cyapa driver with core functions and interface
to support multi-type trackpad devices.
patch 4/19: add gen5 trackpad device basic functions supported into the
re-design cyapa driver.
patch 5/19: add power management interfaces supported for the deivce.
patch 6/19: add runtime power management interfaces supported for the device.
patch 7/19: add sysfs interfaces supported in the cyapa driver.
Including read firmware version, get production ID, read baseline,
re-calibrate trackpad baselines and do trackpad firmware update.
patch 8/19: add gen3 trackpad device's firmware update function supported.
patch 9/19: add gen3 trackpad device's read baseline function supported.
patch 10/19: add gen3 trackpad device's force re-calibrate function supported.
patch 11/19: add gen5 trackpad device's firmware update function supported.
patch 12/19: add gen5 trackpad device's read baseline function supported.
patch 13/19: add gen5 trackpad device's force re-calibrate function.
patch 14/19: add read firmware image debugfs interface supported
in the cyapa driver.
patch 15/19: add gen3 trackpad device's read firmware image function supported.
patch 16/19: add gen5 trackpad device's read firmware image function supported.
patch 17/19: add read trackpad device's sensors' raw data debugfs interface
supported in the cyapa driver.
patch 18/19: add gen5 trackpad device's read read raw function supported.
patch 19/19: add acpi device id supported.
^ permalink raw reply
* Re: [PATCH] i2c-hid / PM: Replace CONFIG_PM_RUNTIME with CONFIG_PM
From: Mika Westerberg @ 2014-12-03 9:53 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: Jiri Kosina, linux-input, Linux Kernel Mailing List,
Linux PM list
In-Reply-To: <3331107.SjqxFqQlza@vostro.rjw.lan>
On Wed, Dec 03, 2014 at 02:56:07AM +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> After commit b2b49ccbdd54 (PM: Kconfig: Set PM_RUNTIME if PM_SLEEP is
> selected) PM_RUNTIME is always set if PM is set, so #ifdef blocks
> depending on CONFIG_PM_RUNTIME may now be changed to depend on
> CONFIG_PM.
>
> Replace CONFIG_PM_RUNTIME with CONFIG_PM in drivers/hid/i2c-hid/i2c-hid.c.
>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
^ permalink raw reply
* Re: Re: [PATCH v7 1/6] mfd: AXP20x: Add bindings documentation
From: Chen-Yu Tsai @ 2014-12-03 10:05 UTC (permalink / raw)
To: Mark Rutland
Cc: Carlo Caione, lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org,
hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-sunxi
In-Reply-To: <20140630094854.GY7262@leverpostej>
Hi Mark,
I'm (hopefully) picking up the work for this series.
On Mon, Jun 30, 2014 at 5:48 PM, Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org> wrote:
> On Sun, Jun 29, 2014 at 07:23:52PM +0100, Carlo Caione wrote:
>> Bindings documentation for the AXP20x driver. In this file also
>> sub-nodes are documented.
>>
>> Signed-off-by: Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
>> Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> ---
>> Documentation/devicetree/bindings/mfd/axp20x.txt | 93 ++++++++++++++++++++++++
>> 1 file changed, 93 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/mfd/axp20x.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/axp20x.txt b/Documentation/devicetree/bindings/mfd/axp20x.txt
>> new file mode 100644
>> index 0000000..cc9e01b
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mfd/axp20x.txt
>> @@ -0,0 +1,93 @@
>> +AXP202/AXP209 device tree bindings
>> +
>> +The axp20x family current members :-
>> +axp202 (X-Powers)
>> +axp209 (X-Powers)
>> +
>> +Required properties:
>> +- compatible: "x-powers,axp202" or "x-powers,axp209"
>> +- reg: The I2C slave address for the AXP chip
>> +- interrupt-parent: The parent interrupt controller
>> +- interrupts: Interrupt specifiers for interrupt sources
>
> How many, what are they?
Now reads: SoC external interrupt / NMI connected to the PMIC's IRQ pin
>> +- interrupt-controller: axp20x has its own internal IRQs
>> +- #interrupt-cells: Should be set to 1
>> +- acin-supply: The input supply for LDO1
>> +- vin2-supply: The input supply for DCDC2
>> +- vin3-supply: The input supply for DCDC3
>> +- ldo24in-supply: The input supply for LDO2, LDO4
>> +- ldo3in-supply: The input supply for LDO3
>> +- ldo5in-supply: The input supply for LDO5
>> +
>> +- regulators: A node that houses a sub-node for each regulator. The regulators are
>> + bound using their name as listed here: dcdc2, dcdc3, ldo1, ldo2,
>> + ldo3, ldo4, ldo5. The bindings details of individual regulator
>> + device can be found in:
>> + Documentation/devicetree/bindings/regulator/regulator.txt with
>> + the exception of x-powers,dcdc-freq
>> +- x-powers,dcdc-freq: defines the work frequency of DC-DC in KHz
>> + (range: 750-1875). Default: 1.5MHz
>> +
>> +Optional properties for DCDCs:
>> +- x-powers,dcdc-workmode: 1 for PWM mode, 0 for AUTO mode
>> + Default: AUTO mode
>
> When would I want to select PWM mode, and why should this be in the DT?
Expanded description:
"""
The DCDC regulators work in a mixed PWM/PFM mode,
using PFM under light loads and switching to PWM
for heavier loads. Forcing PWM mode trades efficiency
under light loads for lower output noise. This
probably makes sense for HiFi audio related
applications that aren't battery constrained.
"""
As I'm not an electronics person, I really can't say under
what circumstances one would force the PMIC into PWM mode.
The expanded description is an educated guess based on
research on the internet about PWM and PFM.
I think it makes sense to put this in the DT. The vendor
building the board/DT is in the best position to know the
constraints and requirements of the board, and can decide
whether the trade off makes sense. As for the boards/DTs
already out there, we can just leave it in auto mode.
Regards
ChenYu
^ permalink raw reply
* Re: [PATCH 0/7] Fixes for ALPS trackstick
From: Pali Rohár @ 2014-12-03 10:59 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Hans de Goede, Yunkang Tang, Vadim Klishko, linux-input,
linux-kernel
In-Reply-To: <DD50BA4C-4E7C-4E69-9A79-52C2B577F580@gmail.com>
[-- Attachment #1: Type: Text/Plain, Size: 1901 bytes --]
On Thursday 27 November 2014 19:08:04 Dmitry Torokhov wrote:
> On November 25, 2014 3:08:31 AM PST, "Pali Rohár"
<pali.rohar@gmail.com> wrote:
> >On Thursday 20 November 2014 00:29:49 Pali Rohár wrote:
> >> On Monday 17 November 2014 08:39:14 Pali Rohár wrote:
> >> > On Friday 14 November 2014 21:59:31 Dmitry Torokhov wrote:
> >> > > Hi Pali,
> >> > >
> >> > > On Friday, November 14, 2014 08:38:19 PM Pali Rohár
wrote:
> >> > > > This patch series fix detection and identifying
> >> > > > trackstick on machines with ALPS devices. Last patch
> >> > > > split trackstick and bare PS/2 mouse packets between
> >> > > > dev2 and dev3 input devices which make sure that
> >> > > > driver will send only trackstick data to trackstick
> >> > > > input device.
> >> > >
> >> > > Thank you for splitting the change, unfortunately it is
> >> > > now quite big to apply to 3.18. Any chance you could
> >> > > try implementing what I suggested in
> >> > > http://www.spinics.net/lists/linux-input/msg34029.html
> >> > > and then we can do the more comprehensive solution in
> >> > > 3.19.
> >> > >
> >> > > Thanks.
> >> >
> >> > Hello, I think that patches 1/7 and 5/7 could do that
> >> > job. I did not tested them alone (without other
> >> > patches), but if you think that two patches are ok for
> >> > 3.18 & stable I can test them...
> >>
> >> Dmitry, ping.
> >
> >Dmitry: ping again.
>
> Hi Pali,
>
> I'm on vacation and unfortunately connection here is
> horrendous so I likely won't be able to do anything until
> after 12/03.
>
> Sorry about that.
Hi Dmitry,
I tested that two patches 1/7 and 5/7 on top of 3.18 and it fixed
name of ALPS devices. Can you send those two patches to 3.18
queue (just remove comment about speed as without other patches
duplicate detection is still called)?
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: Side effect of pressing special keys
From: Pavel Machek @ 2014-12-03 12:40 UTC (permalink / raw)
To: Pali Rohár
Cc: linux-input, platform-driver-x86, Gabriele Mazzotta, linux-kernel
In-Reply-To: <201411231441.17592@pali>
On Sun 2014-11-23 14:41:17, Pali Rohár wrote:
> Hello,
>
> pressing some keys on laptops could cause some side effects.
>
> Example scenario 1:
>
> Laptop has Fn key for enabling/disabling WIFI and when that key
> is pressed BIOS is doing two things:
>
> 1) Switch hard rfkill state of WIFI
> 2) Report that Fn key was pressed to kernel
> (either via i8042 bus or via ACPI/WMI)
We should not really report that as a "key" to userspace. We might
want to report that rfkill state changed....
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Side effect of pressing special keys
From: Pali Rohár @ 2014-12-03 12:46 UTC (permalink / raw)
To: Pavel Machek
Cc: linux-input, platform-driver-x86, Gabriele Mazzotta, linux-kernel
In-Reply-To: <20141203124042.GA504@amd>
[-- Attachment #1: Type: Text/Plain, Size: 795 bytes --]
On Wednesday 03 December 2014 13:40:42 Pavel Machek wrote:
> On Sun 2014-11-23 14:41:17, Pali Rohár wrote:
> > Hello,
> >
> > pressing some keys on laptops could cause some side effects.
> >
> > Example scenario 1:
> >
> > Laptop has Fn key for enabling/disabling WIFI and when that
> > key is pressed BIOS is doing two things:
> >
> > 1) Switch hard rfkill state of WIFI
> > 2) Report that Fn key was pressed to kernel
> >
> > (either via i8042 bus or via ACPI/WMI)
>
> We should not really report that as a "key" to userspace. We
> might want to report that rfkill state changed....
> Pavel
Ok, and what about KEY_KBDILLUMTOGGLE when bios also handle
keyboard backlight level? Should be this key filtered too?
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: Side effect of pressing special keys
From: Henrique de Moraes Holschuh @ 2014-12-03 13:12 UTC (permalink / raw)
To: Pali Rohár
Cc: Pavel Machek, linux-input, platform-driver-x86, Gabriele Mazzotta,
linux-kernel
In-Reply-To: <201412031346.13297@pali>
On Wed, 03 Dec 2014, Pali Rohár wrote:
> Ok, and what about KEY_KBDILLUMTOGGLE when bios also handle
> keyboard backlight level? Should be this key filtered too?
IME, heck yes.
If you ever make the mistake of sending to userspace something the
BIOS/kernel already reacted to, they will find a way to loop it back to you
and cause all sort of issues.
--
"One disk to rule them all, One disk to find them. One disk to bring
them all and in the darkness grind them. In the Land of Redmond
where the shadows lie." -- The Silicon Valley Tarot
Henrique Holschuh
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Side effect of pressing special keys
From: Pali Rohár @ 2014-12-03 13:24 UTC (permalink / raw)
To: Henrique de Moraes Holschuh, Gabriele Mazzotta
Cc: Pavel Machek, linux-input, platform-driver-x86, linux-kernel
In-Reply-To: <20141203131254.GB20212@khazad-dum.debian.net>
[-- Attachment #1: Type: Text/Plain, Size: 884 bytes --]
On Wednesday 03 December 2014 14:12:54 Henrique de Moraes
Holschuh wrote:
> On Wed, 03 Dec 2014, Pali Rohár wrote:
> > Ok, and what about KEY_KBDILLUMTOGGLE when bios also handle
> > keyboard backlight level? Should be this key filtered too?
>
> IME, heck yes.
>
> If you ever make the mistake of sending to userspace something
> the BIOS/kernel already reacted to, they will find a way to
> loop it back to you and cause all sort of issues.
Ok, I think same. In KDE4 I see some loop/noop operation when new
dell keyboard backlight driver is used. Key KEY_KBDILLUMTOGGLE
cause that BIOS change brightness and also KDE4 see it and change
it too...
Similar problem there is with KEY_WLAN and NetworkManager.
Gabriele, can you create patch which disable both KEY_WLAN and
KEY_KBDILLUMTOGGLE in dell-wmi.c driver?
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* [PATCH 1/4] alps: v7: Document the v7 touchpad packet protocol
From: Hans de Goede @ 2014-12-03 13:27 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, Benjamin Tissoires, Hans de Goede, stable
Add a table documenting where all the bits are in the v7 touchpad packets.
Cc: stable@vger.kernel.org # 3.17
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/input/mouse/alps.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index d125a01..aceaade 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -881,6 +881,34 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
unsigned char *pkt,
unsigned char pkt_id)
{
+ /*
+ * packet-fmt b7 b6 b5 b4 b3 b2 b1 b0
+ * Byte0 TWO & MULTI L 1 R M 1 Y0-2 Y0-1 Y0-0
+ * Byte0 NEW L 1 X1-5 1 1 Y0-2 Y0-1 Y0-0
+ * Byte1 Y0-10 Y0-9 Y0-8 Y0-7 Y0-6 Y0-5 Y0-4 Y0-3
+ * Byte2 X0-11 1 X0-10 X0-9 X0-8 X0-7 X0-6 X0-5
+ * Byte3 X1-11 1 X0-4 X0-3 1 X0-2 X0-1 X0-0
+ * Byte4 TWO X1-10 TWO X1-9 X1-8 X1-7 X1-6 X1-5 X1-4
+ * Byte4 MULTI X1-10 TWO X1-9 X1-8 X1-7 X1-6 Y1-5 1
+ * Byte4 NEW X1-10 TWO X1-9 X1-8 X1-7 X1-6 0 0
+ * Byte5 TWO & NEW Y1-10 0 Y1-9 Y1-8 Y1-7 Y1-6 Y1-5 Y1-4
+ * Byte5 MULTI Y1-10 0 Y1-9 Y1-8 Y1-7 Y1-6 F-1 F-0
+ * L: Left button
+ * R / M: Non-clickpads: Right / Middle button
+ * Clickpads: When > 2 fingers are down, and some fingers
+ * are in the button area, then the 2 coordinates reported
+ * are for fingers outside the button area and these report
+ * extra fingers being present in the right / left button
+ * area. Note these fingers are not added to the F field!
+ * so if a TWO packet is received and R = 1 then there are
+ * 3 fingers down, etc.
+ * TWO: 1: Two touches present, byte 0/4/5 are in TWO fmt
+ * 0: If byte 4 bit 0 is 1, then byte 0/4/5 are in MULTI fmt
+ * otherwise byte 0 bit 4 must be set and byte 0/4/5 are
+ * in NEW fmt
+ * F: Number of fingers - 3, 0 means 3 fingers, 1 means 4 ...
+ */
+
mt[0].x = ((pkt[2] & 0x80) << 4);
mt[0].x |= ((pkt[2] & 0x3F) << 5);
mt[0].x |= ((pkt[3] & 0x30) >> 1);
--
2.1.0
^ permalink raw reply related
* [PATCH 2/4] alps: v7: Ignore new packets
From: Hans de Goede @ 2014-12-03 13:27 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, Benjamin Tissoires, Hans de Goede, stable
In-Reply-To: <1417613268-13674-1-git-send-email-hdegoede@redhat.com>
NEW packets are send to indicate a discontinuity in the finger coordinate
reporting. Specifically a finger may have moved from slot 0 to 1 or vice versa.
INPUT_MT_TRACK takes care of this for us.
NEW packets have 3 problems:
1) They do not contain middle / right button info (on non clickpads)
this can be worked around by preserving the old button state
2) They do not contain an accurate fingercount, and they are
typically send when the number of fingers changes. We cannot use
the old finger count as that may mismatch with the amount of
touch coordinates we've available in the NEW packet
3) Their x data for the second touch is inaccurate leading to
a possible jump of the x coordinate by 16 units when the first
non NEW packet comes in
Since problems 2 & 3 cannot be worked around, just ignore them.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=86338
Cc: stable@vger.kernel.org # 3.17
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/input/mouse/alps.c | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index aceaade..6b11629 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -966,18 +966,36 @@ static int alps_decode_packet_v7(struct alps_fields *f,
return 0;
if (pkt_id == V7_PACKET_ID_UNKNOWN)
return -1;
+ /*
+ * NEW packets are send to indicate a discontinuity in the finger
+ * coordinate reporting. Specifically a finger may have moved from
+ * slot 0 to 1 or vice versa. INPUT_MT_TRACK takes care of this for
+ * us.
+ *
+ * NEW packets have 3 problems:
+ * 1) They do not contain middle / right button info (on non clickpads)
+ * this can be worked around by preserving the old button state
+ * 2) They do not contain an accurate fingercount, and they are
+ * typically send when the number of fingers changes. We cannot use
+ * the old finger count as that may mismatch with the amount of
+ * touch coordinates we've available in the NEW packet
+ * 3) Their x data for the second touch is inaccurate leading to
+ * a possible jump of the x coordinate by 16 units when the first
+ * non NEW packet comes in
+ * Since problems 2 & 3 cannot be worked around, just ignore them.
+ */
+ if (pkt_id == V7_PACKET_ID_NEW)
+ return 1;
alps_get_finger_coordinate_v7(f->mt, p, pkt_id);
- if (pkt_id == V7_PACKET_ID_TWO || pkt_id == V7_PACKET_ID_MULTI) {
- f->left = (p[0] & 0x80) >> 7;
- f->right = (p[0] & 0x20) >> 5;
- f->middle = (p[0] & 0x10) >> 4;
- }
+ f->left = (p[0] & 0x80) >> 7;
+ f->right = (p[0] & 0x20) >> 5;
+ f->middle = (p[0] & 0x10) >> 4;
if (pkt_id == V7_PACKET_ID_TWO)
f->fingers = alps_get_mt_count(f->mt);
- else if (pkt_id == V7_PACKET_ID_MULTI)
+ else /* pkt_id == V7_PACKET_ID_MULTI */
f->fingers = 3 + (p[5] & 0x03);
return 0;
--
2.1.0
^ permalink raw reply related
* [PATCH 3/4] alps: v7: Sometimes a single touch is reported in mt[1] rather then mt[0]
From: Hans de Goede @ 2014-12-03 13:27 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, Benjamin Tissoires, Hans de Goede, stable
In-Reply-To: <1417613268-13674-1-git-send-email-hdegoede@redhat.com>
The v7 proto differentiates between a primary touch (with high precision)
and a secondary touch (with lower precision). Normally when 2 fingers are
down and one is lifted the still present touch becomes the primary touch,
but some traces have shown that this does not happen always.
This commit deals with this by making alps_get_mt_count() not stop at the
first empty mt slot, and if a touch is present in mt[1] and not mt[0] moving
the data to mt[0] (for input_mt_assign_slots).
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=86338
Cc: stable@vger.kernel.org # 3.17
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/input/mouse/alps.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 6b11629..77c7afe 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -947,12 +947,14 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
static int alps_get_mt_count(struct input_mt_pos *mt)
{
- int i;
+ int i, fingers = 0;
- for (i = 0; i < MAX_TOUCHES && mt[i].x != 0 && mt[i].y != 0; i++)
- /* empty */;
+ for (i = 0; i < MAX_TOUCHES; i++) {
+ if (mt[i].x != 0 || mt[i].y != 0)
+ fingers++;
+ }
- return i;
+ return fingers;
}
static int alps_decode_packet_v7(struct alps_fields *f,
@@ -998,6 +1000,14 @@ static int alps_decode_packet_v7(struct alps_fields *f,
else /* pkt_id == V7_PACKET_ID_MULTI */
f->fingers = 3 + (p[5] & 0x03);
+ /* Sometimes a single touch is reported in mt[1] rather then mt[0] */
+ if (f->fingers == 1 && f->mt[0].x == 0 && f->mt[0].y == 0) {
+ f->mt[0].x = f->mt[1].x;
+ f->mt[0].y = f->mt[1].y;
+ f->mt[1].x = 0;
+ f->mt[1].y = 0;
+ }
+
return 0;
}
--
2.1.0
^ permalink raw reply related
* [PATCH 4/4] alps: v7: Fix finger counting for > 2 fingers on clickpads
From: Hans de Goede @ 2014-12-03 13:27 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, Benjamin Tissoires, Hans de Goede, stable
In-Reply-To: <1417613268-13674-1-git-send-email-hdegoede@redhat.com>
Protocol v7 uses the middle / right button bits on clickpads to communicate
"location" information of a 3th touch (and possible 4th) touch on clickpads.
Specifically when 3 touches are down, if one of the 3 touches is in the
left / right button area, this will get reported in the middle / right button
bits and the touchpad will still send a TWO type packet rather then a MULTI
type packet, so when this happens we must add the finger reported in the
button area to the finger count.
Likewise we must also add fingers reported this way to the finger count
when we get MULTI packets.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=86338
Cc: stable@vger.kernel.org # 3.17
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/input/mouse/alps.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 77c7afe..d88d73d 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -961,6 +961,7 @@ static int alps_decode_packet_v7(struct alps_fields *f,
unsigned char *p,
struct psmouse *psmouse)
{
+ struct alps_data *priv = psmouse->private;
unsigned char pkt_id;
pkt_id = alps_get_packet_id_v7(p);
@@ -991,15 +992,22 @@ static int alps_decode_packet_v7(struct alps_fields *f,
alps_get_finger_coordinate_v7(f->mt, p, pkt_id);
- f->left = (p[0] & 0x80) >> 7;
- f->right = (p[0] & 0x20) >> 5;
- f->middle = (p[0] & 0x10) >> 4;
-
if (pkt_id == V7_PACKET_ID_TWO)
f->fingers = alps_get_mt_count(f->mt);
else /* pkt_id == V7_PACKET_ID_MULTI */
f->fingers = 3 + (p[5] & 0x03);
+ f->left = (p[0] & 0x80) >> 7;
+ if (priv->flags & ALPS_BUTTONPAD) {
+ if (p[0] & 0x20)
+ f->fingers++;
+ if (p[0] & 0x10)
+ f->fingers++;
+ } else {
+ f->right = (p[0] & 0x20) >> 5;
+ f->middle = (p[0] & 0x10) >> 4;
+ }
+
/* Sometimes a single touch is reported in mt[1] rather then mt[0] */
if (f->fingers == 1 && f->mt[0].x == 0 && f->mt[0].y == 0) {
f->mt[0].x = f->mt[1].x;
--
2.1.0
^ permalink raw reply related
* Re: Side effect of pressing special keys
From: Gabriele Mazzotta @ 2014-12-03 13:38 UTC (permalink / raw)
To: Pali Rohár
Cc: Henrique de Moraes Holschuh, Pavel Machek, linux-input,
platform-driver-x86, linux-kernel
In-Reply-To: <201412031424.12142@pali>
On Wednesday 03 December 2014 14:24:11 Pali Rohár wrote:
> On Wednesday 03 December 2014 14:12:54 Henrique de Moraes
>
> Holschuh wrote:
> > On Wed, 03 Dec 2014, Pali Rohár wrote:
> > > Ok, and what about KEY_KBDILLUMTOGGLE when bios also handle
> > > keyboard backlight level? Should be this key filtered too?
> >
> > IME, heck yes.
> >
> > If you ever make the mistake of sending to userspace something
> > the BIOS/kernel already reacted to, they will find a way to
> > loop it back to you and cause all sort of issues.
>
> Ok, I think same. In KDE4 I see some loop/noop operation when new
> dell keyboard backlight driver is used. Key KEY_KBDILLUMTOGGLE
> cause that BIOS change brightness and also KDE4 see it and change
> it too...
>
> Similar problem there is with KEY_WLAN and NetworkManager.
>
> Gabriele, can you create patch which disable both KEY_WLAN and
> KEY_KBDILLUMTOGGLE in dell-wmi.c driver?
KEY_KBDILLUMTOGGLE is actually disabled already, but KEY_WLAN (which
I guess it should changed to KEY_RFKILL now that it exists) isn't, so
I will submit a patch. The comment above it in dell-wmi.c makes me think
that for all the systems the BIOS does everything and not only mine.
Gabriele
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Side effect of pressing special keys
From: Pali Rohár @ 2014-12-03 13:40 UTC (permalink / raw)
To: Gabriele Mazzotta
Cc: Henrique de Moraes Holschuh, Pavel Machek, linux-input,
platform-driver-x86, linux-kernel
In-Reply-To: <2102451.ffMsF9xTEG@xps13>
[-- Attachment #1: Type: Text/Plain, Size: 1520 bytes --]
On Wednesday 03 December 2014 14:38:15 Gabriele Mazzotta wrote:
> On Wednesday 03 December 2014 14:24:11 Pali Rohár wrote:
> > On Wednesday 03 December 2014 14:12:54 Henrique de Moraes
> >
> > Holschuh wrote:
> > > On Wed, 03 Dec 2014, Pali Rohár wrote:
> > > > Ok, and what about KEY_KBDILLUMTOGGLE when bios also
> > > > handle keyboard backlight level? Should be this key
> > > > filtered too?
> > >
> > > IME, heck yes.
> > >
> > > If you ever make the mistake of sending to userspace
> > > something the BIOS/kernel already reacted to, they will
> > > find a way to loop it back to you and cause all sort of
> > > issues.
> >
> > Ok, I think same. In KDE4 I see some loop/noop operation
> > when new dell keyboard backlight driver is used. Key
> > KEY_KBDILLUMTOGGLE cause that BIOS change brightness and
> > also KDE4 see it and change it too...
> >
> > Similar problem there is with KEY_WLAN and NetworkManager.
> >
> > Gabriele, can you create patch which disable both KEY_WLAN
> > and KEY_KBDILLUMTOGGLE in dell-wmi.c driver?
>
> KEY_KBDILLUMTOGGLE is actually disabled already, but KEY_WLAN
> (which I guess it should changed to KEY_RFKILL now that it
> exists) isn't, so I will submit a patch. The comment above it
> in dell-wmi.c makes me think that for all the systems the
> BIOS does everything and not only mine.
>
> Gabriele
KEY_KBDILLUMTOGGLE is not disabled for sure. I see it in log from
input-events program.
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: Incorrect Key Values in the array atakbd_keycode in atakdb.c
From: Dmitry Torokhov @ 2014-12-03 19:45 UTC (permalink / raw)
To: nick; +Cc: linux-input, linux-kernel
In-Reply-To: <547F0C47.4070104@gmail.com>
On Wed, Dec 03, 2014 at 08:12:39AM -0500, nick wrote:
> No I don't. I am was wondering why they are there still if there is no reason for them.
> Cheers Nick
I'd rather hear this statement from a person with the hardware (such as
Geert for example).
Thanks.
>
> On 2014-12-03 12:52 AM, Dmitry Torokhov wrote:
> > Hi Nick,
> >
> > On Tue, Nov 25, 2014 at 09:32:36PM -0500, nick wrote:
> >> Greetings Dmitry,
> >> I don't known the key codes for this array but when you need around to it
> >> would be very helpful, if you can send me what keys are wrong according to
> >> the FIX ME messages or are they all correct.
> >
> > Unfortunately I do not have/use Atari so I do not know if why current mappings
> > are marked with FIXMEs.
> >
> > Do you have an Atari and something is not quite working for you?
> >
> > Thanks.
> >
--
Dmitry
^ permalink raw reply
* Re: [PATCH] input/speaker: additional clicks and tones for future accessibility
From: Dmitry Torokhov @ 2014-12-03 19:58 UTC (permalink / raw)
To: Karl Dahlke; +Cc: vojtech, linux-input
In-Reply-To: <20141102001740.eklhad@comcast.net>
Hi Karl,
On Tue, Dec 02, 2014 at 12:17:40AM -0500, Karl Dahlke wrote:
> From: Karl Dahlke <eklhad@gmail.com>
>
> Add clicks, tones, and tone sequences to the pc speaker.
>
> The speaker driver can play a tone at a specified frequency,
> or the standard control G bell,
> which is a special case of TONE at 1000 hz 0.1 seconds.
> Add kd_mkpulse() to generate a soft click.
> This is introduced to support accessibility modules and adapters in the future.
> It is a means to an end.
> With this function in place, a module can easily provide soft clicks,
> i.e. audible feedback, whenever a key is depressed,
> or when that keystroke is echoed on screen.
> This allows a blind user, for example, to have rapid feedback while typing,
> even if he is, at the same time, listening to text that is already on screen.
> It is faster and more convenient than having characters echoed verbally.
> And it works all the time, even if speech or braille is not working
> for whatever reason.
>
> Also add the function kd_mknotes,
> which plays a series of tones in the background.
> Of course this can already be done with kd_mksound and timers,
> but why should everyone reinvent the wheel?
> It is better to write the function once, properly, in the kernel,
> and let modules use it thereafter.
> Again, this is a means to an end.
> Accessibility modules can generate rapid sequences of notes
> to indicate various conditions, sometimes error conditions,
> especially if speech or braille is not working.
> These notes may be the only feedback the user has to diagnose the problem.
> This may be useful to other developers in other situations as well.
>
> Finally add kd_mksteps to run something like a chromatic scale,
> from one frequency to another in specified steps.
> The half-tone scale, with a step of 6%, starting at middle C, is approximately
> kd_mksteps(260, 530, 6, 150);
I have exactly the same response as a year earlier:
"I do not think it is a good idea to add SND_PULSE as it can be easily
implemented by SND_TONE with the additional benefit that parameters of
the click can be adjusted. Also, if clicking is done elsewhere, it would
work with other speaker drivers besides pcspkr.
...
[re kd_mknotes] Can it be put into a library instead? Especially given
David's work on trying to push the VT code out of the kernel. Also, what
if you want clicks to go through sound card and not the speaker
interface?"
In other words, I'd rather have it all be done in userpsace by a daemon
that listens to all keystrokes and emits notes or clicks or something
else via whatever sound device is present on the system, be it a PC
speaker, SPARC speaker, a sound card, or maybe something else.
Thanks.
--
Dmitry
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox