summaryrefslogtreecommitdiffstats
path: root/meta-moblin/packages/linux/linux-moblin-2.6.31.5/linux-2.6.31-bluetooth-suspend.patch
diff options
context:
space:
mode:
authorRichard Purdie <rpurdie@linux.intel.com>2010-01-26 15:59:18 +0000
committerRichard Purdie <rpurdie@linux.intel.com>2010-01-26 15:59:18 +0000
commit684d263e75a6a7ede638afa60e35a238e24c12ba (patch)
tree5ab1d38848909494b693e31d0a29659bcaa365e4 /meta-moblin/packages/linux/linux-moblin-2.6.31.5/linux-2.6.31-bluetooth-suspend.patch
parent3a32c2c6e9d1d9823971a17c0ee8f8839bd79b1f (diff)
downloadpoky-684d263e75a6a7ede638afa60e35a238e24c12ba.tar.gz
linux-moblin: Add 2.6.31.5
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.31.5/linux-2.6.31-bluetooth-suspend.patch')
-rw-r--r--meta-moblin/packages/linux/linux-moblin-2.6.31.5/linux-2.6.31-bluetooth-suspend.patch465
1 files changed, 465 insertions, 0 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.31.5/linux-2.6.31-bluetooth-suspend.patch b/meta-moblin/packages/linux/linux-moblin-2.6.31.5/linux-2.6.31-bluetooth-suspend.patch
new file mode 100644
index 0000000000..786e1f2fcd
--- /dev/null
+++ b/meta-moblin/packages/linux/linux-moblin-2.6.31.5/linux-2.6.31-bluetooth-suspend.patch
@@ -0,0 +1,465 @@
1diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
2index e70c57e..8e36fc8 100644
3--- a/drivers/bluetooth/btusb.c
4+++ b/drivers/bluetooth/btusb.c
5@@ -35,7 +36,7 @@
6 #include <net/bluetooth/bluetooth.h>
7 #include <net/bluetooth/hci_core.h>
8
9-#define VERSION "0.5"
10+#define VERSION "0.6"
11
12 static int ignore_dga;
13 static int ignore_csr;
14@@ -145,6 +146,7 @@ static struct usb_device_id blacklist_table[] = {
15 #define BTUSB_INTR_RUNNING 0
16 #define BTUSB_BULK_RUNNING 1
17 #define BTUSB_ISOC_RUNNING 2
18+#define BTUSB_SUSPENDING 3
19
20 struct btusb_data {
21 struct hci_dev *hdev;
22@@ -157,11 +159,15 @@ struct btusb_data {
23 unsigned long flags;
24
25 struct work_struct work;
26+ struct work_struct waker;
27
28 struct usb_anchor tx_anchor;
29 struct usb_anchor intr_anchor;
30 struct usb_anchor bulk_anchor;
31 struct usb_anchor isoc_anchor;
32+ struct usb_anchor deferred;
33+ int tx_in_flight;
34+ spinlock_t txlock;
35
36 struct usb_endpoint_descriptor *intr_ep;
37 struct usb_endpoint_descriptor *bulk_tx_ep;
38@@ -174,8 +180,26 @@ struct btusb_data {
39 unsigned int sco_num;
40 int isoc_altsetting;
41 int suspend_count;
42+ int did_iso_resume:1;
43 };
44
45+static int inc_tx(struct btusb_data *data)
46+{
47+ unsigned long flags;
48+ int rv;
49+
50+ spin_lock_irqsave(&data->txlock, flags);
51+ rv = test_bit(BTUSB_SUSPENDING, &data->flags);
52+ BT_DBG("BTUSB_SUSPENDING bit = %d for intf %p in %s",
53+ rv, data->intf, __func__);
54+ if (!rv)
55+ data->tx_in_flight++;
56+ spin_unlock_irqrestore(&data->txlock, flags);
57+
58+ return rv;
59+}
60+
61+
62 static void btusb_intr_complete(struct urb *urb)
63 {
64 struct hci_dev *hdev = urb->context;
65@@ -202,6 +226,7 @@ static void btusb_intr_complete(struct urb *urb)
66 if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
67 return;
68
69+ usb_mark_last_busy(data->udev);
70 usb_anchor_urb(urb, &data->intr_anchor);
71
72 err = usb_submit_urb(urb, GFP_ATOMIC);
73@@ -327,6 +352,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
74
75 urb->transfer_flags |= URB_FREE_BUFFER;
76
77+ usb_mark_last_busy(data->udev);
78 usb_anchor_urb(urb, &data->bulk_anchor);
79
80 err = usb_submit_urb(urb, mem_flags);
81@@ -465,6 +491,33 @@ static void btusb_tx_complete(struct urb *urb)
82 {
83 struct sk_buff *skb = urb->context;
84 struct hci_dev *hdev = (struct hci_dev *) skb->dev;
85+ struct btusb_data *data = hdev->driver_data;
86+
87+ BT_DBG("%s urb %p status %d count %d", hdev->name,
88+ urb, urb->status, urb->actual_length);
89+
90+ if (!test_bit(HCI_RUNNING, &hdev->flags))
91+ goto done;
92+
93+ if (!urb->status)
94+ hdev->stat.byte_tx += urb->transfer_buffer_length;
95+ else
96+ hdev->stat.err_tx++;
97+
98+done:
99+ spin_lock(&data->txlock);
100+ data->tx_in_flight--;
101+ spin_unlock(&data->txlock);
102+
103+ kfree(urb->setup_packet);
104+
105+ kfree_skb(skb);
106+}
107+
108+static void btusb_isoc_tx_complete(struct urb *urb)
109+{
110+ struct sk_buff *skb = urb->context;
111+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
112
113 BT_DBG("%s urb %p status %d count %d", hdev->name,
114 urb, urb->status, urb->actual_length);
115@@ -490,11 +543,16 @@ static int btusb_open(struct hci_dev *hdev)
116
117 BT_DBG("%s", hdev->name);
118
119+ err = usb_autopm_get_interface(data->intf);
120+ if (err < 0)
121+ return err;
122+ data->intf->needs_remote_wakeup = 1;
123+
124 if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
125- return 0;
126+ goto out;
127
128 if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
129- return 0;
130+ goto out;
131
132 err = btusb_submit_intr_urb(hdev, GFP_KERNEL);
133 if (err < 0)
134@@ -502,6 +560,7 @@ static int btusb_open(struct hci_dev *hdev)
135
136 err = btusb_submit_bulk_urb(hdev, GFP_KERNEL);
137 if (err < 0) {
138+ BT_DBG("kill urbs %s", __func__);
139 usb_kill_anchored_urbs(&data->intr_anchor);
140 goto failed;
141 }
142@@ -509,17 +568,28 @@ static int btusb_open(struct hci_dev *hdev)
143 set_bit(BTUSB_BULK_RUNNING, &data->flags);
144 btusb_submit_bulk_urb(hdev, GFP_KERNEL);
145
146+out:
147+ usb_autopm_put_interface(data->intf);
148 return 0;
149
150 failed:
151 clear_bit(BTUSB_INTR_RUNNING, &data->flags);
152 clear_bit(HCI_RUNNING, &hdev->flags);
153+ usb_autopm_put_interface(data->intf);
154 return err;
155 }
156
157+static void btusb_stop_traffic(struct btusb_data *data)
158+{
159+ usb_kill_anchored_urbs(&data->intr_anchor);
160+ usb_kill_anchored_urbs(&data->bulk_anchor);
161+ usb_kill_anchored_urbs(&data->isoc_anchor);
162+}
163+
164 static int btusb_close(struct hci_dev *hdev)
165 {
166 struct btusb_data *data = hdev->driver_data;
167+ int err;
168
169 BT_DBG("%s", hdev->name);
170
171@@ -529,13 +599,16 @@ static int btusb_close(struct hci_dev *hdev)
172 cancel_work_sync(&data->work);
173
174 clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
175- usb_kill_anchored_urbs(&data->isoc_anchor);
176-
177 clear_bit(BTUSB_BULK_RUNNING, &data->flags);
178- usb_kill_anchored_urbs(&data->bulk_anchor);
179-
180 clear_bit(BTUSB_INTR_RUNNING, &data->flags);
181- usb_kill_anchored_urbs(&data->intr_anchor);
182+
183+ BT_DBG("kill urbs %s", __func__);
184+ btusb_stop_traffic(data);
185+ err = usb_autopm_get_interface(data->intf);
186+ if (!err) {
187+ data->intf->needs_remote_wakeup = 0;
188+ usb_autopm_put_interface(data->intf);
189+ }
190
191 return 0;
192 }
193@@ -546,6 +619,7 @@ static int btusb_flush(struct hci_dev *hdev)
194
195 BT_DBG("%s", hdev->name);
196
197+ BT_DBG("kill urbs %s", __func__);
198 usb_kill_anchored_urbs(&data->tx_anchor);
199
200 return 0;
201@@ -622,7 +696,7 @@ static int btusb_send_frame(struct sk_buff *skb)
202 urb->dev = data->udev;
203 urb->pipe = pipe;
204 urb->context = skb;
205- urb->complete = btusb_tx_complete;
206+ urb->complete = btusb_isoc_tx_complete;
207 urb->interval = data->isoc_tx_ep->bInterval;
208
209 urb->transfer_flags = URB_ISO_ASAP;
210@@ -633,12 +707,23 @@ static int btusb_send_frame(struct sk_buff *skb)
211 le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
212
213 hdev->stat.sco_tx++;
214- break;
215+ goto skip_waking;
216
217 default:
218 return -EILSEQ;
219 }
220
221+ err = inc_tx(data);
222+ if (err) {
223+
224+ usb_anchor_urb(urb, &data->deferred);
225+ schedule_work(&data->waker);
226+ err = 0;
227+ goto out;
228+ } else {
229+
230+ }
231+skip_waking:
232 usb_anchor_urb(urb, &data->tx_anchor);
233
234 err = usb_submit_urb(urb, GFP_ATOMIC);
235@@ -646,10 +731,13 @@ static int btusb_send_frame(struct sk_buff *skb)
236 BT_ERR("%s urb %p submission failed", hdev->name, urb);
237 kfree(urb->setup_packet);
238 usb_unanchor_urb(urb);
239+ } else {
240+ usb_mark_last_busy(data->udev);
241 }
242
243 usb_free_urb(urb);
244
245+out:
246 return err;
247 }
248
249@@ -721,10 +809,23 @@ static void btusb_work(struct work_struct *work)
250 {
251 struct btusb_data *data = container_of(work, struct btusb_data, work);
252 struct hci_dev *hdev = data->hdev;
253+ int err;
254
255 if (hdev->conn_hash.sco_num > 0) {
256+ if (!data->did_iso_resume) {
257+ err = usb_autopm_get_interface(data->isoc);
258+ if (!err) {
259+ data->did_iso_resume = 1;
260+ } else {
261+ clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
262+ BT_DBG("kill urbs %s", __func__);
263+ usb_kill_anchored_urbs(&data->isoc_anchor);
264+ return;
265+ }
266+ }
267 if (data->isoc_altsetting != 2) {
268 clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
269+ BT_DBG("kill urbs %s", __func__);
270 usb_kill_anchored_urbs(&data->isoc_anchor);
271
272 if (__set_isoc_interface(hdev, 2) < 0)
273@@ -739,12 +840,28 @@ static void btusb_work(struct work_struct *work)
274 }
275 } else {
276 clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
277+ BT_DBG("kill urbs %s", __func__);
278 usb_kill_anchored_urbs(&data->isoc_anchor);
279
280 __set_isoc_interface(hdev, 0);
281+ if (data->did_iso_resume) {
282+ data->did_iso_resume = 0;
283+ usb_autopm_put_interface(data->isoc);
284+ }
285 }
286 }
287
288+static void btusb_waker(struct work_struct *work)
289+{
290+ struct btusb_data *data = container_of(work, struct btusb_data, waker);
291+ int err;
292+
293+
294+ err = usb_autopm_get_interface(data->intf);
295+ if (!err)
296+ usb_autopm_put_interface(data->intf);
297+}
298+
299 static int btusb_probe(struct usb_interface *intf,
300 const struct usb_device_id *id)
301 {
302@@ -814,11 +931,14 @@ static int btusb_probe(struct usb_interface *intf,
303 spin_lock_init(&data->lock);
304
305 INIT_WORK(&data->work, btusb_work);
306+ INIT_WORK(&data->waker, btusb_waker);
307+ spin_lock_init(&data->txlock);
308
309 init_usb_anchor(&data->tx_anchor);
310 init_usb_anchor(&data->intr_anchor);
311 init_usb_anchor(&data->bulk_anchor);
312 init_usb_anchor(&data->isoc_anchor);
313+ init_usb_anchor(&data->deferred);
314
315 hdev = hci_alloc_dev();
316 if (!hdev) {
317@@ -949,39 +1069,78 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
318
319 BT_DBG("intf %p", intf);
320
321- if (data->suspend_count++)
322+ if (data->suspend_count++) {
323+ BT_DBG("data->suspend_count = %d for intf %p, returning from %s",
324+ data->suspend_count, intf, __func__);
325 return 0;
326+ }
327+ BT_DBG("data->suspend_count = %d for intf %p, continuing %s",
328+ data->suspend_count, intf, __func__);
329+
330+ spin_lock_irq(&data->txlock);
331+ if (!(interface_to_usbdev(intf)->auto_pm && data->tx_in_flight)) {
332+ BT_DBG("Setting BTUSB_SUSPENDING bit in %s for intf %p",
333+ __func__, intf);
334+ set_bit(BTUSB_SUSPENDING, &data->flags);
335+ spin_unlock_irq(&data->txlock);
336+ } else {
337+ spin_unlock_irq(&data->txlock);
338+ BT_DBG("%d URBs in flight", data->tx_in_flight);
339+ data->suspend_count--;
340+ return -EBUSY;
341+ }
342
343 cancel_work_sync(&data->work);
344
345+ BT_DBG("kill urbs %s", __func__);
346+ btusb_stop_traffic(data);
347 usb_kill_anchored_urbs(&data->tx_anchor);
348
349- usb_kill_anchored_urbs(&data->isoc_anchor);
350- usb_kill_anchored_urbs(&data->bulk_anchor);
351- usb_kill_anchored_urbs(&data->intr_anchor);
352-
353 return 0;
354 }
355
356+static void play_deferred(struct btusb_data *data)
357+{
358+ struct urb *urb;
359+ int err;
360+
361+ while ((urb = usb_get_from_anchor(&data->deferred))) {
362+ err = usb_submit_urb(urb, GFP_ATOMIC);
363+ if (err < 0)
364+ break;
365+ else
366+ data->tx_in_flight++;
367+
368+ }
369+ usb_scuttle_anchored_urbs(&data->deferred);
370+}
371+
372 static int btusb_resume(struct usb_interface *intf)
373 {
374 struct btusb_data *data = usb_get_intfdata(intf);
375 struct hci_dev *hdev = data->hdev;
376- int err;
377+ int err = 0;
378
379 BT_DBG("intf %p", intf);
380
381- if (--data->suspend_count)
382+ if (--data->suspend_count) {
383+ BT_DBG("data->suspend_count = %d for intf %p, returning from %s",
384+ data->suspend_count, intf, __func__);
385 return 0;
386+ }
387
388- if (!test_bit(HCI_RUNNING, &hdev->flags))
389- return 0;
390+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
391+ BT_DBG("HCI not running, returning from %s", __func__);
392+ goto no_io_needed;
393+ }
394
395 if (test_bit(BTUSB_INTR_RUNNING, &data->flags)) {
396 err = btusb_submit_intr_urb(hdev, GFP_NOIO);
397 if (err < 0) {
398 clear_bit(BTUSB_INTR_RUNNING, &data->flags);
399- return err;
400+ BT_DBG("Error (%d) submitting interrupt URB, returning from %s",
401+ err, __func__);
402+ goto err_out;
403 }
404 }
405
406@@ -989,9 +1148,12 @@ static int btusb_resume(struct usb_interface *intf)
407 err = btusb_submit_bulk_urb(hdev, GFP_NOIO);
408 if (err < 0) {
409 clear_bit(BTUSB_BULK_RUNNING, &data->flags);
410- return err;
411- } else
412+ BT_DBG("Error (%d) submitting bulk URB, returning from %s",
413+ err, __func__);
414+ goto err_out;
415+ } else {
416 btusb_submit_bulk_urb(hdev, GFP_NOIO);
417+ }
418 }
419
420 if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
421@@ -1001,7 +1163,24 @@ static int btusb_resume(struct usb_interface *intf)
422 btusb_submit_isoc_urb(hdev, GFP_NOIO);
423 }
424
425+ spin_lock_irq(&data->txlock);
426+ play_deferred(data);
427+ BT_DBG("Clearing BTUSB_SUSPENDING bit in %s for intf %p", __func__, intf);
428+ clear_bit(BTUSB_SUSPENDING, &data->flags);
429+ spin_unlock_irq(&data->txlock);
430+ schedule_work(&data->work);
431+
432 return 0;
433+
434+err_out:
435+ usb_scuttle_anchored_urbs(&data->deferred);
436+no_io_needed:
437+ spin_lock_irq(&data->txlock);
438+ BT_DBG("Clearing BTUSB_SUSPENDING bit in %s for intf %p", __func__, intf);
439+ clear_bit(BTUSB_SUSPENDING, &data->flags);
440+ spin_unlock_irq(&data->txlock);
441+
442+ return err;
443 }
444
445 static struct usb_driver btusb_driver = {
446@@ -1011,6 +1190,7 @@ static struct usb_driver btusb_driver = {
447 .suspend = btusb_suspend,
448 .resume = btusb_resume,
449 .id_table = btusb_table,
450+ .supports_autosuspend = 1,
451 };
452
453 static int __init btusb_init(void)
454diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
455index e70c57e..ac94f91 100644
456--- a/drivers/bluetooth/btusb.c
457+++ b/drivers/bluetooth/btusb.c
458@@ -908,6 +967,7 @@ static int btusb_probe(struct usb_interface *intf,
459 }
460
461 usb_set_intfdata(intf, data);
462+ usb_device_autosuspend_enable(data->udev);
463
464 return 0;
465 }