From patchwork Tue Jan 18 07:26:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 533072 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 376E2C433EF for ; Tue, 18 Jan 2022 07:26:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234285AbiARH0f (ORCPT ); Tue, 18 Jan 2022 02:26:35 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43410 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234037AbiARH0d (ORCPT ); Tue, 18 Jan 2022 02:26:33 -0500 Received: from mail-pg1-x52d.google.com (mail-pg1-x52d.google.com [IPv6:2607:f8b0:4864:20::52d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C3C7AC061574; Mon, 17 Jan 2022 23:26:33 -0800 (PST) Received: by mail-pg1-x52d.google.com with SMTP id i8so13121937pgt.13; Mon, 17 Jan 2022 23:26:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=V0/xeb/ltQYaEaF113sypfFpexckyEO/l19a8/MnbB0=; b=NfgJNWaqhS8piWDRfV9g5I3M7ApDQ2XvtoYhCRfaS+d7AR50shzyQIotLT3zdSHNBx N3Jbj6DtwpFLebXYIYvMY29+BSnqzAv5K1WFkYS8AE/J5Z4zkDCkwRVEaWTFZ4nnPW9Y Yt3t3Az3RIYB2MPvXE99lJwJ0dCIYNsUca3h5Eb+bRD+W+2AxRvYUySYSUBhR/R3PpDr dvMJ89SLo9zZxh6DU8NUyQ35MbgPBXVtIe16M+5r5YXcIjzMfMElKYRU+W3Ba0QRvBpD NschROAPDFsqWZ4tqGtiBsbFMwHoaQOq5rmookkp14cT2eb153N9M+TpBmFincp1zW47 LbIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=V0/xeb/ltQYaEaF113sypfFpexckyEO/l19a8/MnbB0=; b=68q8T2DsWXGtAwZE7rayT+kwPd8SLwY3vrWtJPsTbUObpS5AhtAcZUR07WA9KW39iC YrsEdttOAVuKyjPiPtKr7blET7xnN/gN+DoZLqNIeS+dZvJxYgRZr/DHBykV8fehgiDr T4220SHi915Fu94AjkxHJzNIKTeSmT+MQ/mg3eBHbzlPdJ0fsIMGkE7fDPHPaOBh/n3E Pxu8h72H67YnJ1xnZCNaKQA4Eox4Kqk6jJfnD9a8kstela0DdF27c2yhOyNWOUWhY4qc Pbhi5kLG+5e6WW6iKOxdzJWK/yuzANo+YJ+IBjsejI7TcLsd3lX+tmFEoPpDT+WeUUst 8goQ== X-Gm-Message-State: AOAM5313bh1omYdn4s2PsUEuNIIaoJmSsh0wT6GgAiO5xBoFlUI+4NQ4 gB3QGJYR9R4ARP13k/hqW+M= X-Google-Smtp-Source: ABdhPJySuGgE/LOdJB7H2LXfyH0/wfP+Sp291d9HnX7lvDs2GqjEHCGkHHY0/IEj6qHnoGyEjXe4UQ== X-Received: by 2002:a63:6c03:: with SMTP id h3mr21624014pgc.604.1642490793264; Mon, 17 Jan 2022 23:26:33 -0800 (PST) Received: from dtor-ws.mtv.corp.google.com ([2620:15c:202:201:bf2e:59:5029:f4c5]) by smtp.gmail.com with ESMTPSA id y18sm11079816pfl.156.2022.01.17.23.26.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jan 2022 23:26:32 -0800 (PST) From: Dmitry Torokhov To: Jiri Kosina , Benjamin Tissoires Cc: Angela Czubak , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 01/12] HID: i2c-hid: fix handling numbered reports with IDs of 15 and above Date: Mon, 17 Jan 2022 23:26:17 -0800 Message-Id: <20220118072628.1617172-2-dmitry.torokhov@gmail.com> X-Mailer: git-send-email 2.34.1.703.g22d0c6ccf7-goog In-Reply-To: <20220118072628.1617172-1-dmitry.torokhov@gmail.com> References: <20220118072628.1617172-1-dmitry.torokhov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org From: Angela Czubak Special handling of numbered reports with IDs of 15 and above is only needed when executing what HID-I2C spec is calling "Class Specific Requests", and not when simply sending output reports. Additionally, our mangling of report ID in i2c_hid_set_or_send_report() resulted in incorrect report ID being written into SET_REPORT command payload. To solve it let's move all the report ID manipulation into __i2c_hid_command() where we form the command data structure. Signed-off-by: Angela Czubak Signed-off-by: Dmitry Torokhov --- drivers/hid/i2c-hid/i2c-hid-core.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 517141138b00..bd7b0eeca3ea 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -97,6 +97,7 @@ union command { __le16 reg; __u8 reportTypeID; __u8 opcode; + __u8 reportID; } __packed c; }; @@ -232,7 +233,13 @@ static int __i2c_hid_command(struct i2c_client *client, if (length > 2) { cmd->c.opcode = command->opcode; - cmd->c.reportTypeID = reportID | reportType << 4; + if (reportID < 0x0F) { + cmd->c.reportTypeID = reportType << 4 | reportID; + } else { + cmd->c.reportTypeID = reportType << 4 | 0x0F; + cmd->c.reportID = reportID; + length++; + } } memcpy(cmd->data + length, args, args_len); @@ -293,18 +300,13 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType, u8 reportID, unsigned char *buf_recv, int data_len) { struct i2c_hid *ihid = i2c_get_clientdata(client); - u8 args[3]; + u8 args[2]; int ret; int args_len = 0; u16 readRegister = le16_to_cpu(ihid->hdesc.wDataRegister); i2c_hid_dbg(ihid, "%s\n", __func__); - if (reportID >= 0x0F) { - args[args_len++] = reportID; - reportID = 0x0F; - } - args[args_len++] = readRegister & 0xFF; args[args_len++] = readRegister >> 8; @@ -350,18 +352,12 @@ static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType, size = 2 /* size */ + (reportID ? 1 : 0) /* reportID */ + data_len /* buf */; - args_len = (reportID >= 0x0F ? 1 : 0) /* optional third byte */ + - 2 /* dataRegister */ + + args_len = 2 /* dataRegister */ + size /* args */; if (!use_data && maxOutputLength == 0) return -ENOSYS; - if (reportID >= 0x0F) { - args[index++] = reportID; - reportID = 0x0F; - } - /* * use the data register for feature reports or if the device does not * support the output register From patchwork Tue Jan 18 07:26:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 533071 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 62057C433EF for ; Tue, 18 Jan 2022 07:26:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244758AbiARH0j (ORCPT ); Tue, 18 Jan 2022 02:26:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43424 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244677AbiARH0h (ORCPT ); Tue, 18 Jan 2022 02:26:37 -0500 Received: from mail-pg1-x52c.google.com (mail-pg1-x52c.google.com [IPv6:2607:f8b0:4864:20::52c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F0C66C061574; Mon, 17 Jan 2022 23:26:36 -0800 (PST) Received: by mail-pg1-x52c.google.com with SMTP id x83so13127365pgx.4; Mon, 17 Jan 2022 23:26:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ES83obJErk0lZ4kelhdPyHXgtGt2UP7T+Eb9i5keaTM=; b=Dof1I0AksaKXl49yzZAExVWINZ4MxevKOcEeLwdD2dE/gECkf8YV+E24U/LyroD5kK pXwQz+F2yWZITKUZn0xafEOhs0MbvYnLQKOQ0XbmqyL3q9Kcvkwi63Ni1uzC0EXlEFnL qv8YECHIcW5R4rwZUV6qqsN07vvrEJUMcqzCINd+6i42zrh7Rqirr+1i3z1nOqZZ9QaW myNRdfGwzSLk/bRsYXouXgNZkxdSltiRdhpHBvCo6PgeV/WvGre8PYHy+eI2qDwSE0ao RSh24CPa3wPnsuEETTCnqBrXdcRXcAbyFx1s/ZHoVCAzOGX7dUpc99dVdl3ZfDlaJ93v fV5Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ES83obJErk0lZ4kelhdPyHXgtGt2UP7T+Eb9i5keaTM=; b=0lmI4SwNpBWQBmGMyQwi2IT2HP/bj0aSYfiGZms2ePxms6Ehc4e/OjuR24DCXgDhYr Jd6Xgn4mnMzscGzixcLVxQaE22ffp8Yr9GIyGFdIGTrWqvfPQk7dhLbNqEpUG9WEWYvv +49YgLiaAfqIHinADaWJSctey48lPMlO8f7xztsf6j5OGqWlDhGWY2JIk7w83V2UKD2C ZOxumTTTra22NT50vzjtGhAZhmss2OiKyeUdf5m25KyVgM/nzdMiFg+5AVSEQFe6s8d7 WKtniT6kRs/MBIdPb7TaSb3uXW+85U1pwrRg0dTjR4scgMZTSIn+PpB6GXR6xhq6CbCD QfwQ== X-Gm-Message-State: AOAM533E16Ppf9nJIpniwHJljJZ5kd5cglg5YZmpouajCF26i5wTDkdb YiW+sSMF6DEU16dfc+y3GwU= X-Google-Smtp-Source: ABdhPJymuOUypPqjMMF/NOLafAl1UOlyqABEc3f57QAFEh5XJVlNnxaTYWSoD+d3uKT51lpzk2IzLw== X-Received: by 2002:a65:6859:: with SMTP id q25mr18771789pgt.452.1642490796350; Mon, 17 Jan 2022 23:26:36 -0800 (PST) Received: from dtor-ws.mtv.corp.google.com ([2620:15c:202:201:bf2e:59:5029:f4c5]) by smtp.gmail.com with ESMTPSA id y18sm11079816pfl.156.2022.01.17.23.26.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jan 2022 23:26:35 -0800 (PST) From: Dmitry Torokhov To: Jiri Kosina , Benjamin Tissoires Cc: Angela Czubak , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 03/12] HID: i2c-hid: use "struct i2c_hid" as argument in most calls Date: Mon, 17 Jan 2022 23:26:19 -0800 Message-Id: <20220118072628.1617172-4-dmitry.torokhov@gmail.com> X-Mailer: git-send-email 2.34.1.703.g22d0c6ccf7-goog In-Reply-To: <20220118072628.1617172-1-dmitry.torokhov@gmail.com> References: <20220118072628.1617172-1-dmitry.torokhov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org The main object in the driver is struct i2c_hid so it makes more sense to pass it around instead of passing i2c_client and then fetching i2c_hid associated with it. Signed-off-by: Dmitry Torokhov --- drivers/hid/i2c-hid/i2c-hid-core.c | 75 ++++++++++++++---------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index b383003ff676..bae3e7a9b2e4 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -208,12 +208,12 @@ static u32 i2c_hid_lookup_quirk(const u16 idVendor, const u16 idProduct) return quirks; } -static int __i2c_hid_command(struct i2c_client *client, +static int __i2c_hid_command(struct i2c_hid *ihid, const struct i2c_hid_cmd *command, u8 reportID, u8 reportType, u8 *args, int args_len, unsigned char *buf_recv, int data_len) { - struct i2c_hid *ihid = i2c_get_clientdata(client); + struct i2c_client *client = ihid->client; union command *cmd = (union command *)ihid->cmdbuf; int ret; struct i2c_msg msg[2]; @@ -288,18 +288,17 @@ static int __i2c_hid_command(struct i2c_client *client, return ret; } -static int i2c_hid_command(struct i2c_client *client, +static int i2c_hid_command(struct i2c_hid *ihid, const struct i2c_hid_cmd *command, unsigned char *buf_recv, int data_len) { - return __i2c_hid_command(client, command, 0, 0, NULL, 0, + return __i2c_hid_command(ihid, command, 0, 0, NULL, 0, buf_recv, data_len); } -static int i2c_hid_get_report(struct i2c_client *client, u8 reportType, +static int i2c_hid_get_report(struct i2c_hid *ihid, u8 reportType, u8 reportID, unsigned char *buf_recv, int data_len) { - struct i2c_hid *ihid = i2c_get_clientdata(client); u8 args[2]; int ret; int args_len = 0; @@ -310,10 +309,10 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType, args[args_len++] = readRegister & 0xFF; args[args_len++] = readRegister >> 8; - ret = __i2c_hid_command(client, &hid_get_report_cmd, reportID, + ret = __i2c_hid_command(ihid, &hid_get_report_cmd, reportID, reportType, args, args_len, buf_recv, data_len); if (ret) { - dev_err(&client->dev, + dev_err(&ihid->client->dev, "failed to retrieve report from device.\n"); return ret; } @@ -323,17 +322,16 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType, /** * i2c_hid_set_or_send_report: forward an incoming report to the device - * @client: the i2c_client of the device + * @ihid: the i2c hid device * @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT * @reportID: the report ID * @buf: the actual data to transfer, without the report ID * @data_len: size of buf * @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report */ -static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType, +static int i2c_hid_set_or_send_report(struct i2c_hid *ihid, u8 reportType, u8 reportID, unsigned char *buf, size_t data_len, bool use_data) { - struct i2c_hid *ihid = i2c_get_clientdata(client); u8 *args = ihid->argsbuf; const struct i2c_hid_cmd *hidcmd; int ret; @@ -380,19 +378,19 @@ static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType, memcpy(&args[index], buf, data_len); - ret = __i2c_hid_command(client, hidcmd, reportID, + ret = __i2c_hid_command(ihid, hidcmd, reportID, reportType, args, args_len, NULL, 0); if (ret) { - dev_err(&client->dev, "failed to set a report to device.\n"); + dev_err(&ihid->client->dev, + "failed to set a report to device.\n"); return ret; } return data_len; } -static int i2c_hid_set_power(struct i2c_client *client, int power_state) +static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state) { - struct i2c_hid *ihid = i2c_get_clientdata(client); int ret; i2c_hid_dbg(ihid, "%s\n", __func__); @@ -404,18 +402,18 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state) */ if (power_state == I2C_HID_PWR_ON && ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) { - ret = i2c_hid_command(client, &hid_set_power_cmd, NULL, 0); + ret = i2c_hid_command(ihid, &hid_set_power_cmd, NULL, 0); /* Device was already activated */ if (!ret) goto set_pwr_exit; } - ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state, + ret = __i2c_hid_command(ihid, &hid_set_power_cmd, power_state, 0, NULL, 0, NULL, 0); - if (ret) - dev_err(&client->dev, "failed to change power setting.\n"); + dev_err(&ihid->client->dev, + "failed to change power setting.\n"); set_pwr_exit: @@ -434,9 +432,8 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state) return ret; } -static int i2c_hid_hwreset(struct i2c_client *client) +static int i2c_hid_hwreset(struct i2c_hid *ihid) { - struct i2c_hid *ihid = i2c_get_clientdata(client); int ret; i2c_hid_dbg(ihid, "%s\n", __func__); @@ -448,22 +445,22 @@ static int i2c_hid_hwreset(struct i2c_client *client) */ mutex_lock(&ihid->reset_lock); - ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); + ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); if (ret) goto out_unlock; i2c_hid_dbg(ihid, "resetting...\n"); - ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0); + ret = i2c_hid_command(ihid, &hid_reset_cmd, NULL, 0); if (ret) { - dev_err(&client->dev, "failed to reset device.\n"); - i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); + dev_err(&ihid->client->dev, "failed to reset device.\n"); + i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP); goto out_unlock; } /* At least some SIS devices need this after reset */ if (!(ihid->quirks & I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET)) - ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); + ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); out_unlock: mutex_unlock(&ihid->reset_lock); @@ -625,7 +622,7 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, /* +2 bytes to include the size of the reply in the query buffer */ ask_count = min(count + 2, (size_t)ihid->bufsize); - ret = i2c_hid_get_report(client, + ret = i2c_hid_get_report(ihid, report_type == HID_FEATURE_REPORT ? 0x03 : 0x01, report_number, ihid->rawbuf, ask_count); @@ -669,7 +666,7 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, * to i2c_hid_set_or_send_report which takes care of encoding * everything properly. */ - ret = i2c_hid_set_or_send_report(client, + ret = i2c_hid_set_or_send_report(ihid, report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, report_id, buf + 1, count - 1, use_data); @@ -724,7 +721,7 @@ static int i2c_hid_parse(struct hid_device *hid) } do { - ret = i2c_hid_hwreset(client); + ret = i2c_hid_hwreset(ihid); if (ret) msleep(1000); } while (tries-- > 0 && ret); @@ -748,7 +745,7 @@ static int i2c_hid_parse(struct hid_device *hid) i2c_hid_dbg(ihid, "asking HID report descriptor\n"); - ret = i2c_hid_command(client, &hid_report_descr_cmd, + ret = i2c_hid_command(ihid, &hid_report_descr_cmd, rdesc, rsize); if (ret) { hid_err(hid, "reading report descriptor failed\n"); @@ -868,11 +865,11 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) *i2c_hid_get_dmi_i2c_hid_desc_override(client->name); } else { i2c_hid_dbg(ihid, "Fetching the HID descriptor\n"); - ret = i2c_hid_command(client, &hid_descr_cmd, + ret = i2c_hid_command(ihid, &hid_descr_cmd, ihid->hdesc_buffer, sizeof(struct i2c_hid_desc)); if (ret) { - dev_err(&client->dev, "hid_descr_cmd failed\n"); + dev_err(&ihid->client->dev, "hid_descr_cmd failed\n"); return -ENODEV; } } @@ -882,7 +879,7 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) * bytes 2-3 -> bcdVersion (has to be 1.00) */ /* check bcdVersion == 1.0 */ if (le16_to_cpu(hdesc->bcdVersion) != 0x0100) { - dev_err(&client->dev, + dev_err(&ihid->client->dev, "unexpected HID descriptor bcdVersion (0x%04hx)\n", le16_to_cpu(hdesc->bcdVersion)); return -ENODEV; @@ -891,8 +888,8 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) /* Descriptor length should be 30 bytes as per the specification */ dsize = le16_to_cpu(hdesc->wHIDDescLength); if (dsize != sizeof(struct i2c_hid_desc)) { - dev_err(&client->dev, "weird size of HID descriptor (%u)\n", - dsize); + dev_err(&ihid->client->dev, + "weird size of HID descriptor (%u)\n", dsize); return -ENODEV; } i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, ihid->hdesc_buffer); @@ -1059,7 +1056,7 @@ void i2c_hid_core_shutdown(struct i2c_client *client) { struct i2c_hid *ihid = i2c_get_clientdata(client); - i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); + i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP); free_irq(client->irq, ihid); i2c_hid_core_shutdown_tail(ihid); @@ -1082,7 +1079,7 @@ static int i2c_hid_core_suspend(struct device *dev) } /* Save some power */ - i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); + i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP); disable_irq(client->irq); @@ -1130,9 +1127,9 @@ static int i2c_hid_core_resume(struct device *dev) * let's still reset them here. */ if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME) - ret = i2c_hid_hwreset(client); + ret = i2c_hid_hwreset(ihid); else - ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); + ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON); if (ret) return ret; From patchwork Tue Jan 18 07:26:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 533070 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D7223C433EF for ; Tue, 18 Jan 2022 07:26:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245198AbiARH0t (ORCPT ); Tue, 18 Jan 2022 02:26:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43450 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245003AbiARH0k (ORCPT ); Tue, 18 Jan 2022 02:26:40 -0500 Received: from mail-pf1-x42e.google.com (mail-pf1-x42e.google.com [IPv6:2607:f8b0:4864:20::42e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2E026C06161C; Mon, 17 Jan 2022 23:26:40 -0800 (PST) Received: by mail-pf1-x42e.google.com with SMTP id 128so12314415pfe.12; Mon, 17 Jan 2022 23:26:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=k+ph1/QN1j4IUgMje1r3voGZ5lWOAeDuTQ2adMCwVo4=; b=d9IrUOz1Qx2Ta+vK+JxM+FjX3giOOtnWxsZxAith22VZ9u1OzLfLGPxgRV2P7c8qbF Wd81PF21eA/yYvDsAOl2iUwJ8PaQIN4cJKIyXM8wjVg8sxUspJVV14GmtJrNQdNHe6by TdbZA+VGr5nGfylMiBRQE3oyHiVlRmR/pQdiiOC9feZTMj2Q9heU5WKuK2xeHOXl1yzN P98J7bN1b+KZHx+j4ldEXi+SDB1LjdAtlyRfnfLksJcZ/MIzksv+dT4fdfIWyVU9Trq0 e5wApwwDvL8CRL82d/icWLkp1qlOc8M2Pyyis+7O8T+3gAfKFhtQTv4lN9SDO0tLetUk Mp3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=k+ph1/QN1j4IUgMje1r3voGZ5lWOAeDuTQ2adMCwVo4=; b=GgE3WkadAYKySQg+8wyUfuvo6nq1dOa5f5mShUBDecHy9Vvyd/hT/Q7UsivEoIUXwH c+Jk+fSQ+s09zjxKfR6kXHFGf8RquMzuxp43ohb0NvZKXyOYq6zhEgc+ocJ1OUXMRQ1Y V1xc4NvYQ71t/IugYpg6ClSwf0ukFyF9eapbeuYInaPFqUorwinQ50h23qQJbjbmaI0i RTUIyMflTWv+6ezvhfywfA6JjrctRUnWDZ+Z0xUWJq4yFindfD1JOK4uaXIEjgAdPROm VHueUn7qGhgKTi/5ufs8ggG86Z+iD86h2vShxWAp49r3E7njReli7KMWafelCQGNqmAL p3Aw== X-Gm-Message-State: AOAM533yZYOYQovGJmdiMLSrUvPj0AyKGjFla33v5t8VDShgvLZbDHST OFiS3KlRoDwvOuMi3XKArso= X-Google-Smtp-Source: ABdhPJwoFtTgwbO/ax9ClEazGtTyGQl8RDqbAevp+ac5daYdSvOADsp/NAzsJJMADXFwHGh2ciaEDA== X-Received: by 2002:a63:3e0e:: with SMTP id l14mr21803126pga.223.1642490799442; Mon, 17 Jan 2022 23:26:39 -0800 (PST) Received: from dtor-ws.mtv.corp.google.com ([2620:15c:202:201:bf2e:59:5029:f4c5]) by smtp.gmail.com with ESMTPSA id y18sm11079816pfl.156.2022.01.17.23.26.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jan 2022 23:26:38 -0800 (PST) From: Dmitry Torokhov To: Jiri Kosina , Benjamin Tissoires Cc: Angela Czubak , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 05/12] HID: i2c-hid: explicitly code setting and sending reports Date: Mon, 17 Jan 2022 23:26:21 -0800 Message-Id: <20220118072628.1617172-6-dmitry.torokhov@gmail.com> X-Mailer: git-send-email 2.34.1.703.g22d0c6ccf7-goog In-Reply-To: <20220118072628.1617172-1-dmitry.torokhov@gmail.com> References: <20220118072628.1617172-1-dmitry.torokhov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Instead of relying on __i2c_hid_command() that tries to handle all commands and because of that is very complicated, let's define a new dumb helper i2c_hid_xfer() that actually transfers (write and read) data, and use it when sending and setting reports. By doing that we can save on number of copy operations we have to execute, and make logic of sending reports much clearer. Signed-off-by: Dmitry Torokhov --- drivers/hid/i2c-hid/i2c-hid-core.c | 269 ++++++++++++++++------------- 1 file changed, 151 insertions(+), 118 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 6c1741d9211d..c48b75bd81e0 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "../hid-ids.h" #include "i2c-hid.h" @@ -47,6 +48,15 @@ #define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(6) #define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(7) +/* Command opcodes */ +#define I2C_HID_OPCODE_RESET 0x01 +#define I2C_HID_OPCODE_GET_REPORT 0x02 +#define I2C_HID_OPCODE_SET_REPORT 0x03 +#define I2C_HID_OPCODE_GET_IDLE 0x04 +#define I2C_HID_OPCODE_SET_IDLE 0x05 +#define I2C_HID_OPCODE_GET_PROTOCOL 0x06 +#define I2C_HID_OPCODE_SET_PROTOCOL 0x07 +#define I2C_HID_OPCODE_SET_POWER 0x08 /* flags */ #define I2C_HID_STARTED 0 @@ -90,16 +100,6 @@ struct i2c_hid_cmd { unsigned int length; }; -union command { - u8 data[0]; - struct cmd { - __le16 reg; - __u8 reportTypeID; - __u8 opcode; - __u8 reportID; - } __packed c; -}; - #define I2C_HID_CMD(opcode_) \ .opcode = opcode_, .length = 4, \ .registerIndex = offsetof(struct i2c_hid_desc, wCommandRegister) @@ -115,9 +115,7 @@ static const struct i2c_hid_cmd hid_report_descr_cmd = { /* commands */ static const struct i2c_hid_cmd hid_reset_cmd = { I2C_HID_CMD(0x01) }; static const struct i2c_hid_cmd hid_get_report_cmd = { I2C_HID_CMD(0x02) }; -static const struct i2c_hid_cmd hid_set_report_cmd = { I2C_HID_CMD(0x03) }; static const struct i2c_hid_cmd hid_set_power_cmd = { I2C_HID_CMD(0x08) }; -static const struct i2c_hid_cmd hid_no_cmd = { .length = 0 }; /* * These definitions are not used here, but are defined by the spec. @@ -144,7 +142,6 @@ struct i2c_hid { u8 *inbuf; /* Input buffer */ u8 *rawbuf; /* Raw Input buffer */ u8 *cmdbuf; /* Command buffer */ - u8 *argsbuf; /* Command arguments buffer */ unsigned long flags; /* device flags */ unsigned long quirks; /* Various quirks */ @@ -206,67 +203,90 @@ static u32 i2c_hid_lookup_quirk(const u16 idVendor, const u16 idProduct) return quirks; } +static int i2c_hid_xfer(struct i2c_hid *ihid, + u8 *send_buf, int send_len, u8 *recv_buf, int recv_len) +{ + struct i2c_client *client = ihid->client; + struct i2c_msg msgs[2] = { 0 }; + int n = 0; + int ret; + + if (send_len) { + i2c_hid_dbg(ihid, "%s: cmd=%*ph\n", + __func__, send_len, send_buf); + + msgs[n].addr = client->addr; + msgs[n].flags = client->flags & I2C_M_TEN; + msgs[n].len = send_len; + msgs[n].buf = send_buf; + n++; + } + + if (recv_len) { + msgs[n].addr = client->addr; + msgs[n].flags = (client->flags & I2C_M_TEN) | I2C_M_RD; + msgs[n].len = recv_len; + msgs[n].buf = recv_buf; + n++; + + set_bit(I2C_HID_READ_PENDING, &ihid->flags); + } + + ret = i2c_transfer(client->adapter, msgs, n); + + if (recv_len) + clear_bit(I2C_HID_READ_PENDING, &ihid->flags); + + if (ret != n) + return ret < 0 ? ret : -EIO; + + return 0; +} + +static size_t i2c_hid_encode_command(u8 *buf, u8 opcode, + int report_type, int report_id) +{ + size_t length = 0; + + if (report_id < 0x0F) { + buf[length++] = report_type << 4 | report_id; + buf[length++] = opcode; + } else { + buf[length++] = report_type << 4 | 0x0F; + buf[length++] = opcode; + buf[length++] = report_id; + } + + return length; +} + static int __i2c_hid_command(struct i2c_hid *ihid, const struct i2c_hid_cmd *command, u8 reportID, u8 reportType, u8 *args, int args_len, unsigned char *buf_recv, int data_len) { - struct i2c_client *client = ihid->client; - union command *cmd = (union command *)ihid->cmdbuf; - int ret; - struct i2c_msg msg[2]; - int msg_num = 1; - int length = command->length; unsigned int registerIndex = command->registerIndex; /* special case for hid_descr_cmd */ if (command == &hid_descr_cmd) { - cmd->c.reg = ihid->wHIDDescRegister; + *(__le16 *)ihid->cmdbuf = ihid->wHIDDescRegister; } else { - cmd->data[0] = ihid->hdesc_buffer[registerIndex]; - cmd->data[1] = ihid->hdesc_buffer[registerIndex + 1]; + ihid->cmdbuf[0] = ihid->hdesc_buffer[registerIndex]; + ihid->cmdbuf[1] = ihid->hdesc_buffer[registerIndex + 1]; } if (length > 2) { - cmd->c.opcode = command->opcode; - if (reportID < 0x0F) { - cmd->c.reportTypeID = reportType << 4 | reportID; - } else { - cmd->c.reportTypeID = reportType << 4 | 0x0F; - cmd->c.reportID = reportID; - length++; - } + length = sizeof(__le16) + /* register */ + i2c_hid_encode_command(ihid->cmdbuf + sizeof(__le16), + command->opcode, + reportType, reportID); } - memcpy(cmd->data + length, args, args_len); + memcpy(ihid->cmdbuf + length, args, args_len); length += args_len; - i2c_hid_dbg(ihid, "%s: cmd=%*ph\n", __func__, length, cmd->data); - - msg[0].addr = client->addr; - msg[0].flags = client->flags & I2C_M_TEN; - msg[0].len = length; - msg[0].buf = cmd->data; - if (data_len > 0) { - msg[1].addr = client->addr; - msg[1].flags = client->flags & I2C_M_TEN; - msg[1].flags |= I2C_M_RD; - msg[1].len = data_len; - msg[1].buf = buf_recv; - msg_num = 2; - set_bit(I2C_HID_READ_PENDING, &ihid->flags); - } - - ret = i2c_transfer(client->adapter, msg, msg_num); - - if (data_len > 0) - clear_bit(I2C_HID_READ_PENDING, &ihid->flags); - - if (ret != msg_num) - return ret < 0 ? ret : -EIO; - - return 0; + return i2c_hid_xfer(ihid, ihid->cmdbuf, length, buf_recv, data_len); } static int i2c_hid_command(struct i2c_hid *ihid, @@ -301,70 +321,81 @@ static int i2c_hid_get_report(struct i2c_hid *ihid, u8 reportType, return 0; } +static size_t i2c_hid_format_report(u8 *buf, int report_id, + const u8 *data, size_t size) +{ + size_t length = sizeof(__le16); /* reserve space to store size */ + + if (report_id) + buf[length++] = report_id; + + memcpy(buf + length, data, size); + length += size; + + /* Store overall size in the beginning of the buffer */ + put_unaligned_le16(length, buf); + + return length; +} + /** * i2c_hid_set_or_send_report: forward an incoming report to the device * @ihid: the i2c hid device - * @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT - * @reportID: the report ID + * @report_type: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT + * @report_id: the report ID * @buf: the actual data to transfer, without the report ID * @data_len: size of buf - * @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report + * @do_set: true: use SET_REPORT HID command, false: send plain OUTPUT report */ -static int i2c_hid_set_or_send_report(struct i2c_hid *ihid, u8 reportType, - u8 reportID, unsigned char *buf, size_t data_len, bool use_data) +static int i2c_hid_set_or_send_report(struct i2c_hid *ihid, + u8 report_type, u8 report_id, + const u8 *buf, size_t data_len, + bool do_set) { - u8 *args = ihid->argsbuf; - const struct i2c_hid_cmd *hidcmd; - int ret; - u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister); - u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister); - u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength); - u16 size; - int args_len; - int index = 0; + size_t length = 0; + int error; i2c_hid_dbg(ihid, "%s\n", __func__); if (data_len > ihid->bufsize) return -EINVAL; - size = 2 /* size */ + - (reportID ? 1 : 0) /* reportID */ + - data_len /* buf */; - args_len = 2 /* dataRegister */ + - size /* args */; - - if (!use_data && maxOutputLength == 0) + if (!do_set && le16_to_cpu(ihid->hdesc.wMaxOutputLength) == 0) return -ENOSYS; - /* - * use the data register for feature reports or if the device does not - * support the output register - */ - if (use_data) { - args[index++] = dataRegister & 0xFF; - args[index++] = dataRegister >> 8; - hidcmd = &hid_set_report_cmd; + if (do_set) { + /* Command register goes first */ + *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister; + length += sizeof(__le16); + /* Next is SET_REPORT command */ + length += i2c_hid_encode_command(ihid->cmdbuf + length, + I2C_HID_OPCODE_SET_REPORT, + report_type, report_id); + /* + * Report data will go into the data register. Because + * command can be either 2 or 3 bytes destination for + * the data register may be not aligned. + */ + put_unaligned_le16(le16_to_cpu(ihid->hdesc.wDataRegister), + ihid->cmdbuf + length); + length += sizeof(__le16); } else { - args[index++] = outputRegister & 0xFF; - args[index++] = outputRegister >> 8; - hidcmd = &hid_no_cmd; + /* + * With simple "send report" all data goes into the output + * register. + */ + *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister; + length += sizeof(__le16); } - args[index++] = size & 0xFF; - args[index++] = size >> 8; - - if (reportID) - args[index++] = reportID; + length += i2c_hid_format_report(ihid->cmdbuf + length, + report_id, buf, data_len); - memcpy(&args[index], buf, data_len); - - ret = __i2c_hid_command(ihid, hidcmd, reportID, - reportType, args, args_len, NULL, 0); - if (ret) { + error = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0); + if (error) { dev_err(&ihid->client->dev, - "failed to set a report to device.\n"); - return ret; + "failed to set a report to device: %d\n", error); + return error; } return data_len; @@ -575,31 +606,33 @@ static void i2c_hid_free_buffers(struct i2c_hid *ihid) { kfree(ihid->inbuf); kfree(ihid->rawbuf); - kfree(ihid->argsbuf); kfree(ihid->cmdbuf); ihid->inbuf = NULL; ihid->rawbuf = NULL; ihid->cmdbuf = NULL; - ihid->argsbuf = NULL; ihid->bufsize = 0; } static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size) { - /* the worst case is computed from the set_report command with a - * reportID > 15 and the maximum report length */ - int args_len = sizeof(__u8) + /* ReportID */ - sizeof(__u8) + /* optional ReportID byte */ - sizeof(__u16) + /* data register */ - sizeof(__u16) + /* size of the report */ - report_size; /* report */ + /* + * The worst case is computed from the set_report command with a + * reportID > 15 and the maximum report length. + */ + int cmd_len = sizeof(__le16) + /* command register */ + sizeof(u8) + /* encoded report type/ID */ + sizeof(u8) + /* opcode */ + sizeof(u8) + /* optional 3rd byte report ID */ + sizeof(__le16) + /* data register */ + sizeof(__le16) + /* report data size */ + sizeof(u8) + /* report ID if numbered report */ + report_size; ihid->inbuf = kzalloc(report_size, GFP_KERNEL); ihid->rawbuf = kzalloc(report_size, GFP_KERNEL); - ihid->argsbuf = kzalloc(args_len, GFP_KERNEL); - ihid->cmdbuf = kzalloc(sizeof(union command) + args_len, GFP_KERNEL); + ihid->cmdbuf = kzalloc(cmd_len, GFP_KERNEL); - if (!ihid->inbuf || !ihid->rawbuf || !ihid->argsbuf || !ihid->cmdbuf) { + if (!ihid->inbuf || !ihid->rawbuf || !ihid->cmdbuf) { i2c_hid_free_buffers(ihid); return -ENOMEM; } @@ -659,8 +692,9 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, return count; } -static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, - size_t count, unsigned char report_type, bool use_data) +static int i2c_hid_output_raw_report(struct hid_device *hid, + const u8 *buf, size_t count, + u8 report_type, bool do_set) { struct i2c_client *client = hid->driver_data; struct i2c_hid *ihid = i2c_get_clientdata(client); @@ -681,7 +715,7 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, */ ret = i2c_hid_set_or_send_report(ihid, report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, - report_id, buf + 1, count - 1, use_data); + report_id, buf + 1, count - 1, do_set); if (ret >= 0) ret++; /* add report_id to the number of transferred bytes */ @@ -691,11 +725,10 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, return ret; } -static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf, - size_t count) +static int i2c_hid_output_report(struct hid_device *hid, u8 *buf, size_t count) { return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT, - false); + false); } static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum, From patchwork Tue Jan 18 07:26:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 533069 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2941CC433EF for ; Tue, 18 Jan 2022 07:27:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245665AbiARH13 (ORCPT ); Tue, 18 Jan 2022 02:27:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43498 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245189AbiARH0t (ORCPT ); Tue, 18 Jan 2022 02:26:49 -0500 Received: from mail-pj1-x102e.google.com (mail-pj1-x102e.google.com [IPv6:2607:f8b0:4864:20::102e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8B50FC06174E; Mon, 17 Jan 2022 23:26:43 -0800 (PST) Received: by mail-pj1-x102e.google.com with SMTP id hv15so22492997pjb.5; Mon, 17 Jan 2022 23:26:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=v5cTrYGjBflhhMN+moNPPDrBhqrz1YMurZIOtJGj4T8=; b=PnRPOQlOkC0+w2q3TwAX4p9rjPF13nnic+JiOLS5P8IioE7xRg7kDifNJFNd5SlbkQ j6dMtDwMty2mP0hn8n7tVG7AsxYnsioWbIicTCvWfJ7+VEgLgTjWC9mi6SrU8GY4mkqw 8WOVL9z6/eUBlcsEgbtA8NYreBsjnoduNm4xGaIRz9HSLa2PNOMAqf8sQwLEyELf/a0J CpgPBR8xt9HtpFbvqLXBeggS+AWdI+ZiM0bBYvz8aDrisIduD3nFtxV0d2gzn6xqdLhD Lc2Nh/rYifYppCk1Z91OpwuTIlfnkxQOHSu5DD8+Up0OQql7j9S7tLIOuz0xkiU7lQMY E6kQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=v5cTrYGjBflhhMN+moNPPDrBhqrz1YMurZIOtJGj4T8=; b=UCRI4YXQ0i3Ln1FdCUe48HQjTM8QlanY189CJxlkeccsEWmcxqUjX2pTI+3ms227SM qOi2+pTbRC0tpBz7RMVmCmLgIxCMym1BpLZPhx9EdQXpjwP8aTTJoGee8u1N5OYLkQ7p lzNhZDuU9TC/5y9c9TUqhdGwrUY5ihvaE1DJxSKnq2Owc3Dsei7XhdwrVyVqH8LD2z2R /wxrr6CdE3naBCKl2K3tiQj8u4K4aBf73t+QsX5d+0Xxxmn7Vh4DnEdt+STqDzgup8tZ EUOZHyOdKVYiRhvBorz4LyRK/L9D+p0XI/sstKQlqpObYfj0K8Pnf2DD9aVOXz0EHLrB iQqg== X-Gm-Message-State: AOAM532CqZjDoGq9S2+hV42PS/kiNAVYOPad/6ROIjZvnq3j+xKIedKX vSmWHMj6/kqqWuUj0C+6MEqxtMSch5Q= X-Google-Smtp-Source: ABdhPJyGmwVLeZUI6G30LQqbTTobWIVDhijM49SVWx7lgNZEcFLEghjxLpa0gExdKXDoVRn9AtBD+w== X-Received: by 2002:a17:902:ecc9:b0:14a:7a70:1fb8 with SMTP id a9-20020a170902ecc900b0014a7a701fb8mr25230777plh.22.1642490803026; Mon, 17 Jan 2022 23:26:43 -0800 (PST) Received: from dtor-ws.mtv.corp.google.com ([2620:15c:202:201:bf2e:59:5029:f4c5]) by smtp.gmail.com with ESMTPSA id y18sm11079816pfl.156.2022.01.17.23.26.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jan 2022 23:26:42 -0800 (PST) From: Dmitry Torokhov To: Jiri Kosina , Benjamin Tissoires Cc: Angela Czubak , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 07/12] HID: i2c-hid: create a helper for SET_POWER command Date: Mon, 17 Jan 2022 23:26:23 -0800 Message-Id: <20220118072628.1617172-8-dmitry.torokhov@gmail.com> X-Mailer: git-send-email 2.34.1.703.g22d0c6ccf7-goog In-Reply-To: <20220118072628.1617172-1-dmitry.torokhov@gmail.com> References: <20220118072628.1617172-1-dmitry.torokhov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Another case where creating a dedicated helper allows for cleaner code that shows exactly what communication happens with the device when toggling its power. Signed-off-by: Dmitry Torokhov --- drivers/hid/i2c-hid/i2c-hid-core.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index b1a2c6ad374d..da673e3f2910 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -107,7 +107,6 @@ struct i2c_hid_cmd { /* commands */ static const struct i2c_hid_cmd hid_reset_cmd = { I2C_HID_CMD(0x01) }; static const struct i2c_hid_cmd hid_get_report_cmd = { I2C_HID_CMD(0x02) }; -static const struct i2c_hid_cmd hid_set_power_cmd = { I2C_HID_CMD(0x08) }; /* * These definitions are not used here, but are defined by the spec. @@ -396,6 +395,22 @@ static int i2c_hid_set_or_send_report(struct i2c_hid *ihid, return data_len; } +static int i2c_hid_set_power_command(struct i2c_hid *ihid, int power_state) +{ + size_t length; + + /* SET_POWER uses command register */ + *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister; + length = sizeof(__le16); + + /* Now the command itself */ + length += i2c_hid_encode_command(ihid->cmdbuf + length, + I2C_HID_OPCODE_SET_POWER, + 0, power_state); + + return i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0); +} + static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state) { int ret; @@ -409,15 +424,14 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state) */ if (power_state == I2C_HID_PWR_ON && ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) { - ret = i2c_hid_command(ihid, &hid_set_power_cmd, NULL, 0); + ret = i2c_hid_set_power_command(ihid, I2C_HID_PWR_ON); /* Device was already activated */ if (!ret) goto set_pwr_exit; } - ret = __i2c_hid_command(ihid, &hid_set_power_cmd, power_state, - 0, NULL, 0, NULL, 0); + ret = i2c_hid_set_power_command(ihid, power_state); if (ret) dev_err(&ihid->client->dev, "failed to change power setting.\n"); From patchwork Tue Jan 18 07:26:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 533068 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C1324C433FE for ; Tue, 18 Jan 2022 07:27:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245107AbiARH1l (ORCPT ); Tue, 18 Jan 2022 02:27:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43558 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245410AbiARH1F (ORCPT ); Tue, 18 Jan 2022 02:27:05 -0500 Received: from mail-pg1-x536.google.com (mail-pg1-x536.google.com [IPv6:2607:f8b0:4864:20::536]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 160AEC061753; Mon, 17 Jan 2022 23:26:45 -0800 (PST) Received: by mail-pg1-x536.google.com with SMTP id t32so13125619pgm.7; Mon, 17 Jan 2022 23:26:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=C+G0JoqHk9MHyC89islo0SeNocmMaP3foPpVXqYBGEg=; b=RQ3cifQrU4BE4SCz9CJFD9YnebPR8r9bSam51P5U7Ex6EgaEWsV6J1KuB8rGvFGwiD xd8Qhyc0a7vUeJTc1xUX7fI9zG62DX4E1ZtAyD6JYvTiGk8Q0t8xvBl2q4zV1MBRPewv 5blby41KXuVFpC9u8lxnxa0GzHqeLf6qjAwJI6/RH91d65bIGyDqbeSlnNRZRVan9qYR 0SecNmy/nhJSRfsGnzFUjm9oBx2nKZl/QB14+nvH3igk0w2nhZGOkLebFO521wZdxgTl CZ9al1oVxaI3kcH50k+7RKIcBiXFFrsUoixlRG4/vgdDpRI1e2PqeWyKUSl6MxA8xkPN KuZg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=C+G0JoqHk9MHyC89islo0SeNocmMaP3foPpVXqYBGEg=; b=Cdrc5FO8rVd5iC0bY0BSw7S+sx0DEUkZYdUsjegjZujX6qUnTzwAw7oXztJfRvv/8Q bB/jf+MlK8CuMFHZ5aoJu7zlC7q5KfDVhoojN95w9m3Fnz7ynUvQ0Ue6kNkntU+DIRl7 +XKLrsGTB6PmAw8DoGTm0CRxsUzsotslwZmpp4Ka/eBttV6m/fWKSXum3oRFowmLf5A2 Fac613mzoDN6aLog9K4LDcKAmHggEFLbI71IdHkYgXHf9e8uPsEJeWNg8ZUasyzxC+UE 7q8mPfOFROe9cWjDdMTWctav/ocZubfBvxVblQJw7c1IkdxjicS4Md6D1O4fUDSsMVJg yAIg== X-Gm-Message-State: AOAM533OAOmqhxGPjhN8mNo2PH0Ufiljr9Fy8MSCtjZjFZD/K/Cupo+z T9WtBAbD7aQ0xRD/bU/J6dbn+yJrsAk= X-Google-Smtp-Source: ABdhPJx6WF+fulXii6EXo6BdGddcJf2GslDii+H89qhlP4sEBDhyL8fhvirKm3h8MtrW79Hlo4tSGQ== X-Received: by 2002:a05:6a00:1988:b0:4c3:b9cd:f09a with SMTP id d8-20020a056a00198800b004c3b9cdf09amr11725662pfl.2.1642490804460; Mon, 17 Jan 2022 23:26:44 -0800 (PST) Received: from dtor-ws.mtv.corp.google.com ([2620:15c:202:201:bf2e:59:5029:f4c5]) by smtp.gmail.com with ESMTPSA id y18sm11079816pfl.156.2022.01.17.23.26.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jan 2022 23:26:43 -0800 (PST) From: Dmitry Torokhov To: Jiri Kosina , Benjamin Tissoires Cc: Angela Czubak , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 08/12] HID: i2c-hid: convert i2c_hid_execute_reset() to use i2c_hid_xfer() Date: Mon, 17 Jan 2022 23:26:24 -0800 Message-Id: <20220118072628.1617172-9-dmitry.torokhov@gmail.com> X-Mailer: git-send-email 2.34.1.703.g22d0c6ccf7-goog In-Reply-To: <20220118072628.1617172-1-dmitry.torokhov@gmail.com> References: <20220118072628.1617172-1-dmitry.torokhov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org This will allow us to drop i2c_hid_command() wrapper and get close to removing __i2c_hid_command(). Signed-off-by: Dmitry Torokhov --- drivers/hid/i2c-hid/i2c-hid-core.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index da673e3f2910..1515fc892e61 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -105,7 +105,6 @@ struct i2c_hid_cmd { .registerIndex = offsetof(struct i2c_hid_desc, wCommandRegister) /* commands */ -static const struct i2c_hid_cmd hid_reset_cmd = { I2C_HID_CMD(0x01) }; static const struct i2c_hid_cmd hid_get_report_cmd = { I2C_HID_CMD(0x02) }; /* @@ -283,14 +282,6 @@ static int __i2c_hid_command(struct i2c_hid *ihid, return i2c_hid_xfer(ihid, ihid->cmdbuf, length, buf_recv, data_len); } -static int i2c_hid_command(struct i2c_hid *ihid, - const struct i2c_hid_cmd *command, - unsigned char *buf_recv, int data_len) -{ - return __i2c_hid_command(ihid, command, 0, 0, NULL, 0, - buf_recv, data_len); -} - static int i2c_hid_get_report(struct i2c_hid *ihid, u8 reportType, u8 reportID, unsigned char *buf_recv, int data_len) { @@ -455,13 +446,21 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state) static int i2c_hid_execute_reset(struct i2c_hid *ihid) { + size_t length = 0; int ret; i2c_hid_dbg(ihid, "resetting...\n"); + /* Prepare reset command. Command register goes first. */ + *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister; + length += sizeof(__le16); + /* Next is RESET command itself */ + length += i2c_hid_encode_command(ihid->cmdbuf + length, + I2C_HID_OPCODE_RESET, 0, 0); + set_bit(I2C_HID_RESET_PENDING, &ihid->flags); - ret = i2c_hid_command(ihid, &hid_reset_cmd, NULL, 0); + ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0); if (ret) { dev_err(&ihid->client->dev, "failed to reset device.\n"); goto out; From patchwork Tue Jan 18 07:26:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 533067 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2EFD8C4332F for ; Tue, 18 Jan 2022 07:27:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245731AbiARH1q (ORCPT ); Tue, 18 Jan 2022 02:27:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43648 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245617AbiARH12 (ORCPT ); Tue, 18 Jan 2022 02:27:28 -0500 Received: from mail-pg1-x529.google.com (mail-pg1-x529.google.com [IPv6:2607:f8b0:4864:20::529]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4BC03C06175A; Mon, 17 Jan 2022 23:26:51 -0800 (PST) Received: by mail-pg1-x529.google.com with SMTP id q75so5414056pgq.5; Mon, 17 Jan 2022 23:26:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=6FvLWa2TvyJ6Dd9BiAJ7VPRCB014iQemLHUSFzvWnWU=; b=h3iIB2y8FkG6MKnZaDBFUhMwfS62Rr7ktzTHy3yh2ICJyDJRH0rBiw7WLu3lZWGry7 uVPQYqiY02ci2moKyxdUlEHCTMXRXuRQwrsUkJLzRuAo7pN80bYoYYVN35m39oiq3SnH U2WjSqamnusgMkMAsp5rjwLBi61kv/P2KeSGYxME/lyM12zf0Fb1EgJlKOGh2wPuIrDJ 8qIwG9Np7wmBvmCj3mzZaTLYKqcbdMLo9arQQFiJgnkwnUMk+A60PafPr0vNiTp9xJmB xdQGX0T7dy6xRuKlJOItr4bmC2oWJnmAtiubM4fEv1j9+pKD32R+PKg1ZVRj4bjul5Tq TJfg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=6FvLWa2TvyJ6Dd9BiAJ7VPRCB014iQemLHUSFzvWnWU=; b=L/BuxlG+dWGiXpvzUoPYyi638kTlH0GnHZ6FYOrO7k6gqZiYSVmZvyIJKbFCszOZWf QTbmsHW4Oosbvxfyh9Z3AnIhCz0UOuxrUNPommP5VEjSkoeQOT2vBjQvTq9EEtqC8ftG XOLSw/oFuwuw+2i64hjS9yUhAENjfEDHTkSpbc/7VvskrgqSSzbsnApy7uFAI8e42zg3 sMp68ZhE5jn8ZejNI9PwdA3dL7yR4g2E/paVuaHIkcgxO48M7v669zCJKk6RMB+tTPb8 cxpuDZYMGtx7oFpFF3M66ZLsenahBadTzIW+wwo+gpcuVEGbOUjzOp8s6HNDqMM4RdDl ficQ== X-Gm-Message-State: AOAM531SSBotrpU1zT5vYZrpGyAHBVgF9dpr/DFZK0SAR6bTC1L6i3SD 4g5/0kLWbftyC+MztBbK+mc7DskrHGw= X-Google-Smtp-Source: ABdhPJztueEeTXZP+eCSDmu5GHanYJ4WiG6kPm9zlg+DjVkc4ncXIWE0B3PfTtorjbKJYarWOkoKEg== X-Received: by 2002:a63:8b4a:: with SMTP id j71mr22134690pge.430.1642490810698; Mon, 17 Jan 2022 23:26:50 -0800 (PST) Received: from dtor-ws.mtv.corp.google.com ([2620:15c:202:201:bf2e:59:5029:f4c5]) by smtp.gmail.com with ESMTPSA id y18sm11079816pfl.156.2022.01.17.23.26.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jan 2022 23:26:49 -0800 (PST) From: Dmitry Torokhov To: Jiri Kosina , Benjamin Tissoires Cc: Angela Czubak , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 12/12] HID: i2c-hid: note that I2C xfer buffers are DMA-safe Date: Mon, 17 Jan 2022 23:26:28 -0800 Message-Id: <20220118072628.1617172-13-dmitry.torokhov@gmail.com> X-Mailer: git-send-email 2.34.1.703.g22d0c6ccf7-goog In-Reply-To: <20220118072628.1617172-1-dmitry.torokhov@gmail.com> References: <20220118072628.1617172-1-dmitry.torokhov@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org All I2C communications in the driver use driver-private buffers that are DMA-safe, so mark them as such. Signed-off-by: Dmitry Torokhov --- drivers/hid/i2c-hid/i2c-hid-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index aa7c573b35bc..92dd86c42975 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -180,7 +180,7 @@ static int i2c_hid_xfer(struct i2c_hid *ihid, __func__, send_len, send_buf); msgs[n].addr = client->addr; - msgs[n].flags = client->flags & I2C_M_TEN; + msgs[n].flags = (client->flags & I2C_M_TEN) | I2C_M_DMA_SAFE; msgs[n].len = send_len; msgs[n].buf = send_buf; n++; @@ -188,7 +188,8 @@ static int i2c_hid_xfer(struct i2c_hid *ihid, if (recv_len) { msgs[n].addr = client->addr; - msgs[n].flags = (client->flags & I2C_M_TEN) | I2C_M_RD; + msgs[n].flags = (client->flags & I2C_M_TEN) | + I2C_M_RD | I2C_M_DMA_SAFE; msgs[n].len = recv_len; msgs[n].buf = recv_buf; n++;