From patchwork Fri Oct 7 19:39:34 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roderick Colenbrander X-Patchwork-Id: 9367429 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 2C7E7600C8 for ; Fri, 7 Oct 2016 19:40:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1A88E297EE for ; Fri, 7 Oct 2016 19:40:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0EA3829832; Fri, 7 Oct 2016 19:40:15 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 87065297EE for ; Fri, 7 Oct 2016 19:40:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755497AbcJGTkN (ORCPT ); Fri, 7 Oct 2016 15:40:13 -0400 Received: from mail-it0-f42.google.com ([209.85.214.42]:38479 "EHLO mail-it0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752666AbcJGTkN (ORCPT ); Fri, 7 Oct 2016 15:40:13 -0400 Received: by mail-it0-f42.google.com with SMTP id o19so26658363ito.1 for ; Fri, 07 Oct 2016 12:40:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gaikai-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=hz0gMGtQwe4KtOAY/zEhZG5eFxpYdDlBIFwg7vcMMFk=; b=GfU2Y2KVFIGdM3c0avegfvUhpbwRbK0BaSEjLbGCr1/y7+82UGyjJMbLc5t6t8ie49 rmFbSrOElD4I2WtqX/Q5TBoMFlXyTadTqV/E077MioobWXWHJhJNnrbKsbMc+CgEcxX0 RYYHkJo6kjduTgoTdIVJkFaP6cpWB1TIArBguyb+28+xrTCEtpoJwzoiIDNMBVUNvrB0 lFWHrJiX4Q/x/H1rosfTM+hRSpzqwpgfKHZk6lqIiwXPOBkPlIGULpw5HG6b6Al/FFTR zeeqzGgG96BT1ZqrSaPmX1ahBrYu38aqKJJk4nedsTxeaAO1RL7nvspktMjXaginJcOO VQJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=hz0gMGtQwe4KtOAY/zEhZG5eFxpYdDlBIFwg7vcMMFk=; b=WGDg6FrrH82YIuRIhvkSvjp4QDq4d4LMzffbndNfIR08YHG4em3KwK7fxsrCikoUqO lbomw3ffZn3LvJmyV4YMfFLas8FqzKerobes8Ps6iMy5Vg55GdKWmATf9bIp438UgmeL qZ+jWtMmzJs1AgCG+xQx/Y4tZnMlNYo6ojXRoHTghaXTGidGm0W9/ZKzp2klnMH5r6Pr IYgyOkIvXoTI/MygoEe6ZCepY+JUIL5Le8WoeqopvP4CuuyA0xq23fAAUysctjy4CW1O w58icIMlCReCTb96jmm2g2whIhUG2GJ8Xbl79qm3LlD/dt3XmTlYac0/qklEDEqPjVeU KTVA== X-Gm-Message-State: AA6/9Rl3g6qWR+VdfUrvAP4PfHSRPqW/Zo8poooO4/Bzrc7nIwng3mU34ucRISgvxLE7kV8r X-Received: by 10.36.245.9 with SMTP id k9mr341065ith.81.1475869212068; Fri, 07 Oct 2016 12:40:12 -0700 (PDT) Received: from konan1.dev.biz ([100.42.98.197]) by smtp.gmail.com with ESMTPSA id v7sm1735481itd.6.2016.10.07.12.40.11 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 07 Oct 2016 12:40:11 -0700 (PDT) From: Roderick Colenbrander To: linux-input@vger.kernel.org Cc: Benjamin Tissoires , Jiri Kosina , Tim Bird , Roderick Colenbrander Subject: [PATCH 1/7] HID: sony: Fix race condition in sony_probe Date: Fri, 7 Oct 2016 12:39:34 -0700 Message-Id: <1475869180-26757-2-git-send-email-roderick@gaikai.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1475869180-26757-1-git-send-email-roderick@gaikai.com> References: <1475869180-26757-1-git-send-email-roderick@gaikai.com> Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Roderick Colenbrander Early on the sony_probe function calls hid_hw_start to start the hardware. Afterwards it issues some hardware requests, initializes other functionality like Force Feedback, power classes and others. However by the time hid_hw_start returns, the device nodes have already been created, which leads to a race condition by user space applications which may detect the device prior to completion of initialization. We have observed this problem many times, this patch fixes the problem. This patch moves most of sony_probe to sony_input_configured, which is called prior to device registration. This fixes the race condition and the same approach is used in other HID drivers. Signed-off-by: Roderick Colenbrander --- drivers/hid/hid-sony.c | 117 ++++++++++++++++++++++++------------------------- 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index b0bb99a..afa8219 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1387,28 +1387,6 @@ static int sony_register_touchpad(struct hid_input *hi, int touch_count, return 0; } -static int sony_input_configured(struct hid_device *hdev, - struct hid_input *hidinput) -{ - struct sony_sc *sc = hid_get_drvdata(hdev); - int ret; - - /* - * The Dualshock 4 touchpad supports 2 touches and has a - * resolution of 1920x942 (44.86 dots/mm). - */ - if (sc->quirks & DUALSHOCK4_CONTROLLER) { - ret = sony_register_touchpad(hidinput, 2, 1920, 942); - if (ret) { - hid_err(sc->hdev, - "Unable to initialize multi-touch slots: %d\n", - ret); - return ret; - } - } - - return 0; -} /* * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller @@ -2329,45 +2307,12 @@ static inline void sony_cancel_work_sync(struct sony_sc *sc) cancel_work_sync(&sc->state_worker); } -static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) +static int sony_input_configured(struct hid_device *hdev, + struct hid_input *hidinput) { - int ret; + struct sony_sc *sc = hid_get_drvdata(hdev); int append_dev_id; - unsigned long quirks = id->driver_data; - struct sony_sc *sc; - unsigned int connect_mask = HID_CONNECT_DEFAULT; - - if (!strcmp(hdev->name, "FutureMax Dance Mat")) - quirks |= FUTUREMAX_DANCE_MAT; - - sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL); - if (sc == NULL) { - hid_err(hdev, "can't alloc sony descriptor\n"); - return -ENOMEM; - } - - spin_lock_init(&sc->lock); - - sc->quirks = quirks; - hid_set_drvdata(hdev, sc); - sc->hdev = hdev; - - ret = hid_parse(hdev); - if (ret) { - hid_err(hdev, "parse failed\n"); - return ret; - } - - if (sc->quirks & VAIO_RDESC_CONSTANT) - connect_mask |= HID_CONNECT_HIDDEV_FORCE; - else if (sc->quirks & SIXAXIS_CONTROLLER) - connect_mask |= HID_CONNECT_HIDDEV_FORCE; - - ret = hid_hw_start(hdev, connect_mask); - if (ret) { - hid_err(hdev, "hw start failed\n"); - return ret; - } + int ret; ret = sony_set_device_id(sc); if (ret < 0) { @@ -2427,6 +2372,18 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) } } + /* + * The Dualshock 4 touchpad supports 2 touches and has a + * resolution of 1920x942 (44.86 dots/mm). + */ + ret = sony_register_touchpad(hidinput, 2, 1920, 942); + if (ret) { + hid_err(sc->hdev, + "Unable to initialize multi-touch slots: %d\n", + ret); + return ret; + } + sony_init_output_report(sc, dualshock4_send_output_report); } else if (sc->quirks & MOTION_CONTROLLER) { sony_init_output_report(sc, motion_send_output_report); @@ -2482,6 +2439,48 @@ err_stop: return ret; } +static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + unsigned long quirks = id->driver_data; + struct sony_sc *sc; + unsigned int connect_mask = HID_CONNECT_DEFAULT; + + if (!strcmp(hdev->name, "FutureMax Dance Mat")) + quirks |= FUTUREMAX_DANCE_MAT; + + sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL); + if (sc == NULL) { + hid_err(hdev, "can't alloc sony descriptor\n"); + return -ENOMEM; + } + + spin_lock_init(&sc->lock); + + sc->quirks = quirks; + hid_set_drvdata(hdev, sc); + sc->hdev = hdev; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + return ret; + } + + if (sc->quirks & VAIO_RDESC_CONSTANT) + connect_mask |= HID_CONNECT_HIDDEV_FORCE; + else if (sc->quirks & SIXAXIS_CONTROLLER) + connect_mask |= HID_CONNECT_HIDDEV_FORCE; + + ret = hid_hw_start(hdev, connect_mask); + if (ret) { + hid_err(hdev, "hw start failed\n"); + return ret; + } + + return ret; +} + static void sony_remove(struct hid_device *hdev) { struct sony_sc *sc = hid_get_drvdata(hdev);