From patchwork Sun Nov 17 18:08:25 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sven Eckelmann X-Patchwork-Id: 3194571 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: X-Original-To: patchwork-linux-input@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 67256C045B for ; Sun, 17 Nov 2013 18:08:31 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 9C9BD206DC for ; Sun, 17 Nov 2013 18:08:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id ABD65206D9 for ; Sun, 17 Nov 2013 18:08:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752012Ab3KQSI2 (ORCPT ); Sun, 17 Nov 2013 13:08:28 -0500 Received: from narfation.org ([79.140.41.39]:42089 "EHLO v3-1039.vlinux.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752006Ab3KQSI2 (ORCPT ); Sun, 17 Nov 2013 13:08:28 -0500 Received: from sven-desktop.localnet (drsd-4d05faee.pool.mediaWays.net [77.5.250.238]) by v3-1039.vlinux.de (Postfix) with ESMTPSA id A21D51100BD; Sun, 17 Nov 2013 19:08:26 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=narfation.org; s=20121; t=1384711707; bh=df/GwEsTOnadZiQSNlUMtOegD6dP5pqmIVcRNTj7LZQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wPcSBJ8JdIUB5h/cDw2wIuCSogt1HpDSkYICdId9K8mWr0Qi4ozafTDlEepboM1M7 lGfX+cONULSi5OicZt0dXvgDDDfq9AhE8Ud1eviB6UY/BnpqW/YF9X2JAQAQHcvSWS pJ2tvw3qZG8SNcOtTSQCfUFSTRGDLNIfQvrbo+U0= From: Sven Eckelmann To: David Herrmann Cc: Simon Wood , "open list:HID CORE LAYER" , Jiri Kosina , Colin Leitner Subject: Re: Re: Re: [PATCH] HID: sony: Add force feedback support for Dualshock3 USB Date: Sun, 17 Nov 2013 19:08:25 +0100 Message-ID: <2014555.nmU692BQMt@sven-desktop> User-Agent: KMail/4.11.3 (Linux/3.11-2-amd64; KDE/4.11.3; x86_64; ; ) In-Reply-To: References: <1384021557-24106-1-git-send-email-sven@narfation.org> <1567991.TNa7UhjX8Q@sven-desktop> MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Spam-Status: No, score=-5.8 required=5.0 tests=BAYES_00,DKIM_ADSP_ALL, DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_WEB, RP_MATCHES_RCVD, T_DKIM_INVALID, T_TVD_MIME_EPI,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP On Sunday 17 November 2013 17:30:51 David Herrmann wrote: > Yeah, the input-ff callbacks cannot be handled inline. You also get > deadlocks with the input-spinlock. In the wiimote driver I simply > dispatch the ff-events to a workqueue. You can have a look at > drivers/hid/hid-wiimote-modules.c. You can get some ordering-problems > then, but these can usually be ignored as they just collapse events. > > The related commit was: > > commit f50f9aabf32db7414551ffdfdccc71be5f3d6e7d > Author: David Herrmann > Date: Wed Oct 2 13:47:28 2013 +0200 > > HID: wiimote: fix FF deadlock Yes, I've played around with the linux kernel usb message api and came to the same conclusion (for now). I've only tested it with a small proof of concept patch and it didn't hang anymore with testhaptic. Maybe Simon Wood can test his devices because I am unsure whether PS3 dualshock clones will work with the interrupt or control urbs. For example the script from Simon didn't work at all for me. Kind regards, Sven diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index da551d1..d509447 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -224,6 +224,10 @@ static const unsigned int buzz_keymap[] = { struct sony_sc { unsigned long quirks; + struct work_struct rumble_worker; + struct hid_device *hdev; + __u8 left; + __u8 right; void *extra; }; @@ -614,35 +618,53 @@ static void buzz_remove(struct hid_device *hdev) drv_data->extra = NULL; } -#ifdef CONFIG_SONY_FF -static int sony_play_effect(struct input_dev *dev, void *data, - struct ff_effect *effect) +static void sony_rumble_worker(struct work_struct *work) { + struct sony_sc *sc = container_of(work, struct sony_sc, rumble_worker); unsigned char buf[] = { 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, - 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 }; - __u8 left; - __u8 right; + struct usb_interface *intf = to_usb_interface(sc->hdev->dev.parent); + struct usb_device *usbdev = interface_to_usbdev(intf); + + buf[3] = sc->right; + buf[5] = sc->left; + + if (sc->right || sc->left) + usb_interrupt_msg(usbdev, usb_sndctrlpipe(usbdev, 2), buf, + sizeof(buf), NULL, USB_CTRL_SET_TIMEOUT); + + buf[10] = 0x1e; + usb_interrupt_msg(usbdev, usb_sndctrlpipe(usbdev, 2), buf, sizeof(buf), + NULL, USB_CTRL_SET_TIMEOUT); +} + +#ifdef CONFIG_SONY_FF +static int sony_play_effect(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ struct hid_device *hid = input_get_drvdata(dev); + struct sony_sc *sc = hid_get_drvdata(hid); if (effect->type != FF_RUMBLE) return 0; - left = effect->u.rumble.strong_magnitude / 256; - right = effect->u.rumble.weak_magnitude ? 1 : 0; + sc->left = effect->u.rumble.strong_magnitude / 256; + sc->right = effect->u.rumble.weak_magnitude ? 1 : 0; - buf[3] = right; - buf[5] = left; - return hid->hid_output_raw_report(hid, buf, sizeof(buf), - HID_OUTPUT_REPORT); + schedule_work(&sc->rumble_worker); + return 0; } static int sony_init_ff(struct hid_device *hdev) @@ -650,6 +672,9 @@ static int sony_init_ff(struct hid_device *hdev) struct hid_input *hidinput = list_entry(hdev->inputs.next, struct hid_input, list); struct input_dev *input_dev = hidinput->input; + struct sony_sc *sc = hid_get_drvdata(hdev); + + INIT_WORK(&sc->rumble_worker, sony_rumble_worker); input_set_capability(input_dev, EV_FF, FF_RUMBLE); return input_ff_create_memless(input_dev, NULL, sony_play_effect); @@ -711,6 +736,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret < 0) goto err_stop; + sc->hdev = hdev; ret = sony_init_ff(hdev); if (ret < 0) goto err_stop; @@ -728,6 +754,8 @@ static void sony_remove(struct hid_device *hdev) if (sc->quirks & BUZZ_CONTROLLER) buzz_remove(hdev); + cancel_work_sync(&sc->rumble_worker); + hid_hw_stop(hdev); }