Received: by 10.223.176.46 with SMTP id f43csp1448857wra; Fri, 19 Jan 2018 11:43:05 -0800 (PST) X-Google-Smtp-Source: ACJfBoslwG4qvUSSnXgS9q9vruvqwZgtu78tL6t82zN7waQBZxFU8ATpfJBsbAT1wZcBAGtSPdFk X-Received: by 10.99.170.10 with SMTP id e10mr19495929pgf.81.1516390985020; Fri, 19 Jan 2018 11:43:05 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516390984; cv=none; d=google.com; s=arc-20160816; b=qmvxhmTgEd7zBxgcJEkPl870gmxsYOfmjNQeoTieCL8HEQty6c5g8CS9139AcG3YQK JzVnOyfJE3QN86szqTmgxZaD82AphB194w/3kI+iYnAqaE5c79vrRc/svLu7wygHciEI JyZ55rb/EVZsrlebmvbFJD+ZWcfAnKJP0G4NoyU+OGneNznNxtv5U5ASSOLxEscy62F4 XU9f7uwC0OYFogeg2gj6WCj4Jb64KBskfydx7VEmUwpEGfBQWpEPxIB3AM0cLnxqo8eU /QDgqkB8bdtAw5XEPpmI0cNa8YfGB2TDKyUShtsW25WKOBRuJd9dK+dFkAlNXM2x1LWQ MVtg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=5WQApq1rq7CW5Q3kz63MtBJ2tOQgLMREtVNXOmz0r58=; b=hhUe8jLv+YEXe/0BHyaerw5gcEYLjpjRe/SRf1mzl0ZipaR+Qrv6g1lgzDNJf8xgXE JOBxDGxTl9jLy8QwJtF+0tKkVV/0UeQGL7PwEV19QBlvZ7b7rK/miDe2xkEQ1KZeo/PV BHKDwIpaZRWxsIEq5yQYhn6yLA/ZakkrgT+BON01OFN9VjLmXYPQJqM0nrRV+V2KGrMA HxG49d4e0J0kmWlxMLa2pBHgJEWxK2l6C1x33iVQw85mwnPDsh8R7+m/UHJRNQuhnzTw cA8dH5dqRPy0t/XbOF+Vu5zEUys4aM/nb543RczT8M1Ju18WZ80ojLuyLvVgNay/2CZv Auow== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=sUHVv8SR; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id x70si8787639pgd.590.2018.01.19.11.42.50; Fri, 19 Jan 2018 11:43:04 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=sUHVv8SR; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756504AbeASTmG (ORCPT + 99 others); Fri, 19 Jan 2018 14:42:06 -0500 Received: from mail-pg0-f65.google.com ([74.125.83.65]:43838 "EHLO mail-pg0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756107AbeASTlW (ORCPT ); Fri, 19 Jan 2018 14:41:22 -0500 Received: by mail-pg0-f65.google.com with SMTP id n17so2161940pgf.10; Fri, 19 Jan 2018 11:41:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=5WQApq1rq7CW5Q3kz63MtBJ2tOQgLMREtVNXOmz0r58=; b=sUHVv8SRGzaRVPktSLmuMzKY0vUGmjGZonSmkn/mks2VWTi++/wuVKhD7tgW2t1Y73 yO+ZZtft+NiIa3yqZw4OQw2e3qHfmS2mZZvrAdzag/WO1hgRDoQknKs+gt1bT3XnYNEy B2CiG83TDk9ld5V+1T4pLnrHRDvFD94S45Pc3kf90KPjgikw56BYe/Iq41QPtkG/Bkgd K0osKJBuHEKAhtNVvG8rc84jgkkI1GamYe34Na1KTai23TlHq8VimtxroHJyzCN+YuOB cfeq63RPoWXDDMjrleQXwTk2SOSB+13Ob6NEMeOVx5rfYWF/J4RAjy8OQqELD4EcUlRn 9kmA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=5WQApq1rq7CW5Q3kz63MtBJ2tOQgLMREtVNXOmz0r58=; b=LoXusHausSZ3/zhYWMXn/qND7/z6kGT7odagqB5HamHg3frPrGxC9V7OQqxAbYWY8E tNyEQEp6/vIbo/ubKzn91Pg94Au1P6A3KRCpxRi8qT0pwjyXG9sO2wRklNBaVTLj6xg5 IpTdhLjMxuHTV3VmV9roXxGBT4bBEQNv561lpTPapKZIpmJaHWbkVHurDkSK7EeuTPXB p9Ojq/N+rKmUqbRst1Wv3fwa58atWHrfHCIqa0rvscXPnDsYZWzFLKtYlfs19unGHSXM qcRvANzg8LtYv0NJ3YQQ6wfJ003DlSoIzm3pWfZ+NZ/uUSek6Efl8cbLLTCQFihy4fhV sx0Q== X-Gm-Message-State: AKwxyteehAxNkS1+7pNhr/6AbCPUMkxKCalBblIfIhsLroVdEk4kECDW UEQGbTZUortGxkMdhIlOZNo= X-Received: by 2002:a17:902:5305:: with SMTP id b5-v6mr2139658pli.325.1516390881110; Fri, 19 Jan 2018 11:41:21 -0800 (PST) Received: from dtor-ws.mtv.corp.google.com ([2620:0:1000:1611:da80:8749:c06f:9515]) by smtp.gmail.com with ESMTPSA id p1sm18947830pgr.44.2018.01.19.11.41.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 19 Jan 2018 11:41:20 -0800 (PST) From: Dmitry Torokhov To: Benjamin Tissoires , Hans de Goede , Lyude Paul Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 6/7] Input: libps2 - support retransmission of command data Date: Fri, 19 Jan 2018 11:41:10 -0800 Message-Id: <20180119194111.185590-7-dmitry.torokhov@gmail.com> X-Mailer: git-send-email 2.16.0.rc1.238.g530d649a79-goog In-Reply-To: <20180119194111.185590-1-dmitry.torokhov@gmail.com> References: <20180119194111.185590-1-dmitry.torokhov@gmail.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The devices are allowed to respond to either command byte or command parameter with a NAK (0xfe), and the host is supposed to resend the "correct" byte. The device then will either respond with ACK or ERR (0xfc). Let's teach libps2 to handle the NAK responses properly, so that individual drivers do not need to handle them. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/libps2.c | 103 +++++++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 32 deletions(-) diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 82befae4dab04..f05c407b31f3d 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -26,35 +26,63 @@ MODULE_AUTHOR("Dmitry Torokhov "); MODULE_DESCRIPTION("PS/2 driver library"); MODULE_LICENSE("GPL"); -static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout) +static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte, + unsigned int timeout, unsigned int max_attempts) + __releases(&ps2dev->serio->lock) __acquires(&ps2dev->serio->lock) { + int attempt = 0; int error; - serio_pause_rx(ps2dev->serio); - ps2dev->nak = 1; - ps2dev->flags |= PS2_FLAG_ACK; - serio_continue_rx(ps2dev->serio); + lockdep_assert_held(&ps2dev->serio->lock); - error = serio_write(ps2dev->serio, byte); - if (error) - dev_dbg(&ps2dev->serio->dev, - "failed to write %#02x: %d\n", byte, error); - else - wait_event_timeout(ps2dev->wait, - !(ps2dev->flags & PS2_FLAG_ACK), - msecs_to_jiffies(timeout)); + do { + ps2dev->nak = 1; + ps2dev->flags |= PS2_FLAG_ACK; + + serio_continue_rx(ps2dev->serio); + + error = serio_write(ps2dev->serio, byte); + if (error) + dev_dbg(&ps2dev->serio->dev, + "failed to write %#02x: %d\n", byte, error); + else + wait_event_timeout(ps2dev->wait, + !(ps2dev->flags & PS2_FLAG_ACK), + msecs_to_jiffies(timeout)); + + serio_pause_rx(ps2dev->serio); + } while (ps2dev->nak == PS2_RET_NAK && ++attempt < max_attempts); - serio_pause_rx(ps2dev->serio); ps2dev->flags &= ~PS2_FLAG_ACK; - serio_continue_rx(ps2dev->serio); - return -ps2dev->nak; + if (!error) { + switch (ps2dev->nak) { + case 0: + break; + case PS2_RET_NAK: + error = -EAGAIN; + break; + case PS2_RET_ERR: + error = -EPROTO; + break; + default: + error = -EIO; + break; + } + } + + if (error || attempt > 1) + dev_dbg(&ps2dev->serio->dev, + "%02x - %d (%x), attempt %d\n", + byte, error, ps2dev->nak, attempt); + + return error; } /* * ps2_sendbyte() sends a byte to the device and waits for acknowledge. - * It doesn't handle retransmission, though it could - because if there - * is a need for retransmissions device has to be replaced anyway. + * It doesn't handle retransmission, the caller is expected to handle + * it when needed. * * ps2_sendbyte() can only be called from a process context. */ @@ -63,9 +91,13 @@ int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout) { int retval; - retval = ps2_do_sendbyte(ps2dev, byte, timeout); + serio_pause_rx(ps2dev->serio); + + retval = ps2_do_sendbyte(ps2dev, byte, timeout, 1); dev_dbg(&ps2dev->serio->dev, "%02x - %x\n", byte, ps2dev->nak); + serio_continue_rx(ps2dev->serio); + return retval; } EXPORT_SYMBOL(ps2_sendbyte); @@ -200,48 +232,48 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) unsigned int timeout; unsigned int send = (command >> 12) & 0xf; unsigned int receive = (command >> 8) & 0xf; - int rc = -1; + int rc; int i; u8 send_param[16]; if (receive > sizeof(ps2dev->cmdbuf)) { WARN_ON(1); - return -1; + return -EINVAL; } if (send && !param) { WARN_ON(1); - return -1; + return -EINVAL; } memcpy(send_param, param, send); serio_pause_rx(ps2dev->serio); + ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; ps2dev->cmdcnt = receive; if (receive && param) for (i = 0; i < receive; i++) ps2dev->cmdbuf[(receive - 1) - i] = param[i]; - serio_continue_rx(ps2dev->serio); /* * Some devices (Synaptics) peform the reset before * ACKing the reset command, and so it can take a long * time before the ACK arrives. */ - if (ps2_do_sendbyte(ps2dev, command & 0xff, - command == PS2_CMD_RESET_BAT ? 1000 : 200)) { - serio_pause_rx(ps2dev->serio); + rc = ps2_do_sendbyte(ps2dev, command & 0xff, + command == PS2_CMD_RESET_BAT ? 1000 : 200, 2); + if (rc) goto out_reset_flags; - } for (i = 0; i < send; i++) { - if (ps2_do_sendbyte(ps2dev, param[i], 200)) { - serio_pause_rx(ps2dev->serio); + rc = ps2_do_sendbyte(ps2dev, param[i], 200, 2); + if (rc) goto out_reset_flags; - } } + serio_continue_rx(ps2dev->serio); + /* * The reset command takes a long time to execute. */ @@ -263,8 +295,11 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) for (i = 0; i < receive; i++) param[i] = ps2dev->cmdbuf[(receive - 1) - i]; - if (ps2dev->cmdcnt && (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) + if (ps2dev->cmdcnt && + (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) { + rc = -EPROTO; goto out_reset_flags; + } rc = 0; @@ -278,7 +313,11 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) ps2dev->nak, ps2dev->flags, receive, param ?: send_param); - return rc; + /* + * ps_command() handles resends itself, so do not leak -EAGAIN + * to the callers. + */ + return rc != -EAGAIN ? rc : -EPROTO; } EXPORT_SYMBOL(__ps2_command); -- 2.16.0.rc1.238.g530d649a79-goog