diff options
Diffstat (limited to 'drivers/hid/hid-rmi.c')
-rw-r--r-- | drivers/hid/hid-rmi.c | 177 |
1 files changed, 174 insertions, 3 deletions
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 49d4fe4f5987..368ffdf2c0a3 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -104,6 +104,7 @@ struct rmi_data { unsigned long flags; + struct rmi_function f01; struct rmi_function f11; struct rmi_function f30; @@ -124,6 +125,7 @@ struct rmi_data { struct hid_device *hdev; unsigned long device_flags; + unsigned long firmware_id; }; #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) @@ -272,6 +274,46 @@ static inline int rmi_read(struct hid_device *hdev, u16 addr, void *buf) return rmi_read_block(hdev, addr, buf, 1); } +static int rmi_write_block(struct hid_device *hdev, u16 addr, void *buf, + const int len) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + + mutex_lock(&data->page_mutex); + + if (RMI_PAGE(addr) != data->page) { + ret = rmi_set_page(hdev, RMI_PAGE(addr)); + if (ret < 0) + goto exit; + } + + data->writeReport[0] = RMI_WRITE_REPORT_ID; + data->writeReport[1] = len; + data->writeReport[2] = addr & 0xFF; + data->writeReport[3] = (addr >> 8) & 0xFF; + memcpy(&data->writeReport[4], buf, len); + + ret = rmi_write_report(hdev, data->writeReport, + data->output_report_size); + if (ret < 0) { + dev_err(&hdev->dev, + "failed to write request output report (%d)\n", + ret); + goto exit; + } + ret = 0; + +exit: + mutex_unlock(&data->page_mutex); + return ret; +} + +static inline int rmi_write(struct hid_device *hdev, u16 addr, void *buf) +{ + return rmi_write_block(hdev, addr, buf, 1); +} + static void rmi_f11_process_touch(struct rmi_data *hdata, int slot, u8 finger_state, u8 *touch_data) { @@ -532,6 +574,9 @@ static void rmi_register_function(struct rmi_data *data, u16 page_base = page << 8; switch (pdt_entry->function_number) { + case 0x01: + f = &data->f01; + break; case 0x11: f = &data->f11; break; @@ -604,6 +649,92 @@ error_exit: return retval; } +#define RMI_DEVICE_F01_BASIC_QUERY_LEN 11 + +static int rmi_populate_f01(struct hid_device *hdev) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + u8 basic_queries[RMI_DEVICE_F01_BASIC_QUERY_LEN]; + u8 info[3]; + int ret; + bool has_query42; + bool has_lts; + bool has_sensor_id; + bool has_ds4_queries = false; + bool has_build_id_query = false; + bool has_package_id_query = false; + u16 query_offset = data->f01.query_base_addr; + u16 prod_info_addr; + u8 ds4_query_len; + + ret = rmi_read_block(hdev, query_offset, basic_queries, + RMI_DEVICE_F01_BASIC_QUERY_LEN); + if (ret) { + hid_err(hdev, "Can not read basic queries from Function 0x1.\n"); + return ret; + } + + has_lts = !!(basic_queries[0] & BIT(2)); + has_sensor_id = !!(basic_queries[1] & BIT(3)); + has_query42 = !!(basic_queries[1] & BIT(7)); + + query_offset += 11; + prod_info_addr = query_offset + 6; + query_offset += 10; + + if (has_lts) + query_offset += 20; + + if (has_sensor_id) + query_offset++; + + if (has_query42) { + ret = rmi_read(hdev, query_offset, info); + if (ret) { + hid_err(hdev, "Can not read query42.\n"); + return ret; + } + has_ds4_queries = !!(info[0] & BIT(0)); + query_offset++; + } + + if (has_ds4_queries) { + ret = rmi_read(hdev, query_offset, &ds4_query_len); + if (ret) { + hid_err(hdev, "Can not read DS4 Query length.\n"); + return ret; + } + query_offset++; + + if (ds4_query_len > 0) { + ret = rmi_read(hdev, query_offset, info); + if (ret) { + hid_err(hdev, "Can not read DS4 query.\n"); + return ret; + } + + has_package_id_query = !!(info[0] & BIT(0)); + has_build_id_query = !!(info[0] & BIT(1)); + } + } + + if (has_package_id_query) + prod_info_addr++; + + if (has_build_id_query) { + ret = rmi_read_block(hdev, prod_info_addr, info, 3); + if (ret) { + hid_err(hdev, "Can not read product info.\n"); + return ret; + } + + data->firmware_id = info[1] << 8 | info[0]; + data->firmware_id += info[2] * 65536; + } + + return 0; +} + static int rmi_populate_f11(struct hid_device *hdev) { struct rmi_data *data = hid_get_drvdata(hdev); @@ -620,6 +751,8 @@ static int rmi_populate_f11(struct hid_device *hdev) bool has_gestures; bool has_rel; bool has_data40 = false; + bool has_dribble = false; + bool has_palm_detect = false; unsigned x_size, y_size; u16 query_offset; @@ -661,6 +794,14 @@ static int rmi_populate_f11(struct hid_device *hdev) has_rel = !!(buf[0] & BIT(3)); has_gestures = !!(buf[0] & BIT(5)); + ret = rmi_read(hdev, data->f11.query_base_addr + 5, buf); + if (ret) { + hid_err(hdev, "can not get absolute data sources: %d.\n", ret); + return ret; + } + + has_dribble = !!(buf[0] & BIT(4)); + /* * At least 4 queries are guaranteed to be present in F11 * +1 for query 5 which is present since absolute events are @@ -680,6 +821,7 @@ static int rmi_populate_f11(struct hid_device *hdev) ret); return ret; } + has_palm_detect = !!(buf[0] & BIT(0)); has_query10 = !!(buf[0] & BIT(2)); query_offset += 2; /* query 7 and 8 are present */ @@ -766,17 +908,38 @@ static int rmi_populate_f11(struct hid_device *hdev) * retrieve the ctrl registers * the ctrl register has a size of 20 but a fw bug split it into 16 + 4, * and there is no way to know if the first 20 bytes are here or not. - * We use only the first 10 bytes, so get only them. + * We use only the first 12 bytes, so get only them. */ - ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 10); + ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 12); if (ret) { - hid_err(hdev, "can not read ctrl block of size 10: %d.\n", ret); + hid_err(hdev, "can not read ctrl block of size 11: %d.\n", ret); return ret; } data->max_x = buf[6] | (buf[7] << 8); data->max_y = buf[8] | (buf[9] << 8); + if (has_dribble) { + buf[0] = buf[0] & ~BIT(6); + ret = rmi_write(hdev, data->f11.control_base_addr, buf); + if (ret) { + hid_err(hdev, "can not write to control reg 0: %d.\n", + ret); + return ret; + } + } + + if (has_palm_detect) { + buf[11] = buf[11] & ~BIT(0); + ret = rmi_write(hdev, data->f11.control_base_addr + 11, + &buf[11]); + if (ret) { + hid_err(hdev, "can not write to control reg 11: %d.\n", + ret); + return ret; + } + } + return 0; } @@ -858,6 +1021,12 @@ static int rmi_populate(struct hid_device *hdev) return ret; } + ret = rmi_populate_f01(hdev); + if (ret) { + hid_err(hdev, "Error while initializing F01 (%d).\n", ret); + return ret; + } + ret = rmi_populate_f11(hdev); if (ret) { hid_err(hdev, "Error while initializing F11 (%d).\n", ret); @@ -907,6 +1076,8 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) if (ret) goto exit; + hid_info(hdev, "firmware id: %ld\n", data->firmware_id); + __set_bit(EV_ABS, input->evbit); input_set_abs_params(input, ABS_MT_POSITION_X, 1, data->max_x, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 1, data->max_y, 0, 0); |