Skip to content

Commit 85df713

Browse files
dtorJiri Kosina
authored andcommitted
HID: i2c-hid: rework i2c_hid_get_report() to use i2c_hid_xfer()
Explicitly prepare command for i2c_hid_get_report() which makes the logic clearer and allows us to get rid of __i2c_hid_command() and related command definitions. Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Tested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent 50c5249 commit 85df713

1 file changed

Lines changed: 59 additions & 91 deletions

File tree

drivers/hid/i2c-hid/i2c-hid-core.c

Lines changed: 59 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -94,29 +94,6 @@ struct i2c_hid_desc {
9494
__le32 reserved;
9595
} __packed;
9696

97-
struct i2c_hid_cmd {
98-
unsigned int registerIndex;
99-
__u8 opcode;
100-
unsigned int length;
101-
};
102-
103-
#define I2C_HID_CMD(opcode_) \
104-
.opcode = opcode_, .length = 4, \
105-
.registerIndex = offsetof(struct i2c_hid_desc, wCommandRegister)
106-
107-
/* commands */
108-
static const struct i2c_hid_cmd hid_get_report_cmd = { I2C_HID_CMD(0x02) };
109-
110-
/*
111-
* These definitions are not used here, but are defined by the spec.
112-
* Keeping them here for documentation purposes.
113-
*
114-
* static const struct i2c_hid_cmd hid_get_idle_cmd = { I2C_HID_CMD(0x04) };
115-
* static const struct i2c_hid_cmd hid_set_idle_cmd = { I2C_HID_CMD(0x05) };
116-
* static const struct i2c_hid_cmd hid_get_protocol_cmd = { I2C_HID_CMD(0x06) };
117-
* static const struct i2c_hid_cmd hid_set_protocol_cmd = { I2C_HID_CMD(0x07) };
118-
*/
119-
12097
/* The main device structure */
12198
struct i2c_hid {
12299
struct i2c_client *client; /* i2c client */
@@ -258,52 +235,62 @@ static size_t i2c_hid_encode_command(u8 *buf, u8 opcode,
258235
return length;
259236
}
260237

261-
static int __i2c_hid_command(struct i2c_hid *ihid,
262-
const struct i2c_hid_cmd *command, u8 reportID,
263-
u8 reportType, u8 *args, int args_len,
264-
unsigned char *buf_recv, int data_len)
238+
static int i2c_hid_get_report(struct i2c_hid *ihid,
239+
u8 report_type, u8 report_id,
240+
u8 *recv_buf, size_t recv_len)
265241
{
266-
int length = command->length;
267-
unsigned int registerIndex = command->registerIndex;
268-
269-
ihid->cmdbuf[0] = ihid->hdesc_buffer[registerIndex];
270-
ihid->cmdbuf[1] = ihid->hdesc_buffer[registerIndex + 1];
242+
size_t length = 0;
243+
size_t ret_count;
244+
int error;
271245

272-
if (length > 2) {
273-
length = sizeof(__le16) + /* register */
274-
i2c_hid_encode_command(ihid->cmdbuf + sizeof(__le16),
275-
command->opcode,
276-
reportType, reportID);
277-
}
246+
i2c_hid_dbg(ihid, "%s\n", __func__);
278247

279-
memcpy(ihid->cmdbuf + length, args, args_len);
280-
length += args_len;
248+
/* Command register goes first */
249+
*(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
250+
length += sizeof(__le16);
251+
/* Next is GET_REPORT command */
252+
length += i2c_hid_encode_command(ihid->cmdbuf + length,
253+
I2C_HID_OPCODE_GET_REPORT,
254+
report_type, report_id);
255+
/*
256+
* Device will send report data through data register. Because
257+
* command can be either 2 or 3 bytes destination for the data
258+
* register may be not aligned.
259+
*/
260+
put_unaligned_le16(le16_to_cpu(ihid->hdesc.wDataRegister),
261+
ihid->cmdbuf + length);
262+
length += sizeof(__le16);
281263

282-
return i2c_hid_xfer(ihid, ihid->cmdbuf, length, buf_recv, data_len);
283-
}
264+
/*
265+
* In addition to report data device will supply data length
266+
* in the first 2 bytes of the response, so adjust .
267+
*/
268+
error = i2c_hid_xfer(ihid, ihid->cmdbuf, length,
269+
ihid->rawbuf, recv_len + sizeof(__le16));
270+
if (error) {
271+
dev_err(&ihid->client->dev,
272+
"failed to set a report to device: %d\n", error);
273+
return error;
274+
}
284275

285-
static int i2c_hid_get_report(struct i2c_hid *ihid, u8 reportType,
286-
u8 reportID, unsigned char *buf_recv, int data_len)
287-
{
288-
u8 args[2];
289-
int ret;
290-
int args_len = 0;
291-
u16 readRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
276+
/* The buffer is sufficiently aligned */
277+
ret_count = le16_to_cpup((__le16 *)ihid->rawbuf);
292278

293-
i2c_hid_dbg(ihid, "%s\n", __func__);
279+
/* Check for empty report response */
280+
if (ret_count <= sizeof(__le16))
281+
return 0;
294282

295-
args[args_len++] = readRegister & 0xFF;
296-
args[args_len++] = readRegister >> 8;
283+
recv_len = min(recv_len, ret_count - sizeof(__le16));
284+
memcpy(recv_buf, ihid->rawbuf + sizeof(__le16), recv_len);
297285

298-
ret = __i2c_hid_command(ihid, &hid_get_report_cmd, reportID,
299-
reportType, args, args_len, buf_recv, data_len);
300-
if (ret) {
286+
if (report_id && recv_len != 0 && recv_buf[0] != report_id) {
301287
dev_err(&ihid->client->dev,
302-
"failed to retrieve report from device.\n");
303-
return ret;
288+
"device returned incorrect report (%d vs %d expected)\n",
289+
recv_buf[0], report_id);
290+
return -EINVAL;
304291
}
305292

306-
return 0;
293+
return recv_len;
307294
}
308295

309296
static size_t i2c_hid_format_report(u8 *buf, int report_id,
@@ -654,13 +641,12 @@ static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size)
654641
}
655642

656643
static int i2c_hid_get_raw_report(struct hid_device *hid,
657-
unsigned char report_number, __u8 *buf, size_t count,
658-
unsigned char report_type)
644+
u8 report_type, u8 report_id,
645+
u8 *buf, size_t count)
659646
{
660647
struct i2c_client *client = hid->driver_data;
661648
struct i2c_hid *ihid = i2c_get_clientdata(client);
662-
size_t ret_count, ask_count;
663-
int ret;
649+
int ret_count;
664650

665651
if (report_type == HID_OUTPUT_REPORT)
666652
return -EINVAL;
@@ -670,42 +656,24 @@ static int i2c_hid_get_raw_report(struct hid_device *hid,
670656
* not have the report ID that the upper layers expect, so we need
671657
* to stash it the buffer ourselves and adjust the data size.
672658
*/
673-
if (!report_number) {
659+
if (!report_id) {
674660
buf[0] = 0;
675661
buf++;
676662
count--;
677663
}
678664

679-
/* +2 bytes to include the size of the reply in the query buffer */
680-
ask_count = min(count + 2, (size_t)ihid->bufsize);
681-
682-
ret = i2c_hid_get_report(ihid,
665+
ret_count = i2c_hid_get_report(ihid,
683666
report_type == HID_FEATURE_REPORT ? 0x03 : 0x01,
684-
report_number, ihid->rawbuf, ask_count);
685-
686-
if (ret < 0)
687-
return ret;
688-
689-
ret_count = ihid->rawbuf[0] | (ihid->rawbuf[1] << 8);
690-
691-
if (ret_count <= 2)
692-
return 0;
693-
694-
ret_count = min(ret_count, ask_count);
695-
696-
/* The query buffer contains the size, dropping it in the reply */
697-
count = min(count, ret_count - 2);
698-
memcpy(buf, ihid->rawbuf + 2, count);
667+
report_id, buf, count);
699668

700-
if (!report_number)
701-
count++;
669+
if (ret_count > 0 && !report_id)
670+
ret_count++;
702671

703-
return count;
672+
return ret_count;
704673
}
705674

706-
static int i2c_hid_output_raw_report(struct hid_device *hid,
707-
const u8 *buf, size_t count,
708-
u8 report_type, bool do_set)
675+
static int i2c_hid_output_raw_report(struct hid_device *hid, u8 report_type,
676+
const u8 *buf, size_t count, bool do_set)
709677
{
710678
struct i2c_client *client = hid->driver_data;
711679
struct i2c_hid *ihid = i2c_get_clientdata(client);
@@ -738,7 +706,7 @@ static int i2c_hid_output_raw_report(struct hid_device *hid,
738706

739707
static int i2c_hid_output_report(struct hid_device *hid, u8 *buf, size_t count)
740708
{
741-
return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT,
709+
return i2c_hid_output_raw_report(hid, HID_OUTPUT_REPORT, buf, count,
742710
false);
743711
}
744712

@@ -748,11 +716,11 @@ static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
748716
{
749717
switch (reqtype) {
750718
case HID_REQ_GET_REPORT:
751-
return i2c_hid_get_raw_report(hid, reportnum, buf, len, rtype);
719+
return i2c_hid_get_raw_report(hid, rtype, reportnum, buf, len);
752720
case HID_REQ_SET_REPORT:
753721
if (buf[0] != reportnum)
754722
return -EINVAL;
755-
return i2c_hid_output_raw_report(hid, buf, len, rtype, true);
723+
return i2c_hid_output_raw_report(hid, rtype, buf, len, true);
756724
default:
757725
return -EIO;
758726
}

0 commit comments

Comments
 (0)