From patchwork Thu Mar 14 14:30:07 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Woodhouse X-Patchwork-Id: 2271591 Return-Path: X-Original-To: patchwork-linux-input@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id B77053FC8A for ; Thu, 14 Mar 2013 14:30:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756037Ab3CNOaS (ORCPT ); Thu, 14 Mar 2013 10:30:18 -0400 Received: from merlin.infradead.org ([205.233.59.134]:59109 "EHLO merlin.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755923Ab3CNOaR (ORCPT ); Thu, 14 Mar 2013 10:30:17 -0400 Received: from i7.infradead.org ([2001:8b0:10b:1:225:64ff:fee8:e9df]) by merlin.infradead.org with esmtpsa (Exim 4.80.1 #2 (Red Hat Linux)) id 1UG9Ae-0001NS-BD; Thu, 14 Mar 2013 14:30:16 +0000 Message-ID: <1363271407.4853.52.camel@i7.infradead.org> Subject: [RFC/RFT] Reset bcm5974 into wellspring mode when it forgets From: David Woodhouse To: Henrik Rydberg Cc: linux-input@vger.kernel.org Date: Thu, 14 Mar 2013 14:30:07 +0000 X-Mailer: Evolution 3.6.3 (3.6.3-2.fc18) Mime-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by merlin.infradead.org See http://www.infradead.org/rpr.html Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Occasionally the trackpad in my MacBookPro 8,3 stops working, spewing 'bcm5974: bad trackpad package, length: 8' I haven't been able to reproduce this on demand, but it's annoying when it does happen. I'm *assuming* that it's somehow forgotten what mode it's supposed to be in. The fix for this on suspend/resume was to switch it back to Wellspring mode again, so let's try that... Untested, because my trackpad seems to *know* when I'm actually running a kernel with this patch, and doesn't ever misbehave. I've played with removing the *normal* mode switch in bcm5974_start_traffic() but can't get it to produce the 'bad trackpad package' message at all in that case, so the rest function doesn't get invoked. Signed-off-by: David Woodhouse diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index 2baff1b..db0b3ab 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -244,6 +244,7 @@ struct bcm5974 { struct bt_data *bt_data; /* button transferred data */ struct urb *tp_urb; /* trackpad usb request block */ u8 *tp_data; /* trackpad transferred data */ + struct work_struct reset_work; /* reset to wellspring mode */ const struct tp_finger *index[MAX_FINGERS]; /* finger index data */ struct input_mt_pos pos[MAX_FINGERS]; /* position array */ int slots[MAX_FINGERS]; /* slot assignments */ @@ -676,9 +677,14 @@ static void bcm5974_irq_trackpad(struct urb *urb) if (dev->tp_urb->actual_length == 2) goto exit; - if (report_tp_state(dev, dev->tp_urb->actual_length)) + if (report_tp_state(dev, dev->tp_urb->actual_length)) { dprintk(1, "bcm5974: bad trackpad package, length: %d\n", dev->tp_urb->actual_length); + if (dev->tp_urb->actual_length == 8) { + /* Hm. Make sure it's in wellspring mode... */ + schedule_work(&dev->reset_work); + } + } exit: error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC); @@ -815,6 +821,14 @@ static int bcm5974_resume(struct usb_interface *iface) return error; } +static void bcm5974_mode_workfn(struct work_struct *work) +{ + struct bcm5974 *dev = container_of(work, struct bcm5974, reset_work); + + dev_info(&dev->intf->dev, "Reset into wellspring mode...\n"); + bcm5974_wellspring_mode(dev, true); +} + static int bcm5974_probe(struct usb_interface *iface, const struct usb_device_id *id) { @@ -840,6 +854,7 @@ static int bcm5974_probe(struct usb_interface *iface, dev->input = input_dev; dev->cfg = *cfg; mutex_init(&dev->pm_mutex); + INIT_WORK(&dev->reset_work, bcm5974_mode_workfn); /* setup urbs */ if (cfg->tp_type == TYPE1) { @@ -936,6 +951,7 @@ static void bcm5974_disconnect(struct usb_interface *iface) dev->bt_data, dev->bt_urb->transfer_dma); usb_free_urb(dev->tp_urb); usb_free_urb(dev->bt_urb); + cancel_work_sync(&dev->reset_work); kfree(dev); }