b79609c798ea874c51410d196a098623a114ad85
[~emulex/for-vlad/old/compat.git] / compat / compat-2.6.36.c
1 /*
2  * Copyright 2010    Hauke Mehrtens <hauke@hauke-m.de>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * Compatibility file for Linux wireless for kernels 2.6.36.
9  */
10
11 #include <linux/compat.h>
12 #include <linux/usb.h>
13
14 #ifdef CONFIG_COMPAT_USB_URB_THREAD_FIX
15 /* Callers must hold anchor->lock */
16 static void __usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor)
17 {
18         urb->anchor = NULL;
19         list_del(&urb->anchor_list);
20         usb_put_urb(urb);
21         if (list_empty(&anchor->urb_list))
22                 wake_up(&anchor->wait);
23 }
24
25 /**
26  * usb_unlink_anchored_urbs - asynchronously cancel transfer requests en masse
27  * @anchor: anchor the requests are bound to
28  *
29  * this allows all outstanding URBs to be unlinked starting
30  * from the back of the queue. This function is asynchronous.
31  * The unlinking is just tiggered. It may happen after this
32  * function has returned.
33  *
34  * This routine should not be called by a driver after its disconnect
35  * method has returned.
36  */
37 void compat_usb_unlink_anchored_urbs(struct usb_anchor *anchor)
38 {
39         struct urb *victim;
40
41         while ((victim = usb_get_from_anchor(anchor)) != NULL) {
42                 usb_unlink_urb(victim);
43                 usb_put_urb(victim);
44         }
45 }
46 EXPORT_SYMBOL_GPL(compat_usb_unlink_anchored_urbs);
47
48 /**
49  * usb_get_from_anchor - get an anchor's oldest urb
50  * @anchor: the anchor whose urb you want
51  *
52  * this will take the oldest urb from an anchor,
53  * unanchor and return it
54  */
55 struct urb *compat_usb_get_from_anchor(struct usb_anchor *anchor)
56 {
57         struct urb *victim;
58         unsigned long flags;
59
60         spin_lock_irqsave(&anchor->lock, flags);
61         if (!list_empty(&anchor->urb_list)) {
62                 victim = list_entry(anchor->urb_list.next, struct urb,
63                                     anchor_list);
64                 usb_get_urb(victim);
65                 __usb_unanchor_urb(victim, anchor);
66         } else {
67                 victim = NULL;
68         }
69         spin_unlock_irqrestore(&anchor->lock, flags);
70
71         return victim;
72 }
73 EXPORT_SYMBOL_GPL(compat_usb_get_from_anchor);
74
75 /**
76  * usb_scuttle_anchored_urbs - unanchor all an anchor's urbs
77  * @anchor: the anchor whose urbs you want to unanchor
78  *
79  * use this to get rid of all an anchor's urbs
80  */
81 void compat_usb_scuttle_anchored_urbs(struct usb_anchor *anchor)
82 {
83         struct urb *victim;
84         unsigned long flags;
85
86         spin_lock_irqsave(&anchor->lock, flags);
87         while (!list_empty(&anchor->urb_list)) {
88                 victim = list_entry(anchor->urb_list.prev, struct urb,
89                                     anchor_list);
90                 __usb_unanchor_urb(victim, anchor);
91         }
92         spin_unlock_irqrestore(&anchor->lock, flags);
93 }
94 EXPORT_SYMBOL_GPL(compat_usb_scuttle_anchored_urbs);
95
96 #endif /* CONFIG_COMPAT_USB_URB_THREAD_FIX */
97
98 struct workqueue_struct *system_wq __read_mostly;
99 struct workqueue_struct *system_long_wq __read_mostly;
100 struct workqueue_struct *system_nrt_wq __read_mostly;
101 EXPORT_SYMBOL_GPL(system_wq);
102 EXPORT_SYMBOL_GPL(system_long_wq);
103 EXPORT_SYMBOL_GPL(system_nrt_wq);
104
105 int compat_schedule_work(struct work_struct *work)
106 {
107         return queue_work(system_wq, work);
108 }
109 EXPORT_SYMBOL_GPL(compat_schedule_work);
110
111 int compat_schedule_work_on(int cpu, struct work_struct *work)
112 {
113 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
114         return queue_work_on(cpu, system_wq, work);
115 #else
116         return queue_work(system_wq, work);
117 #endif
118 }
119 EXPORT_SYMBOL_GPL(compat_schedule_work_on);
120
121 int compat_schedule_delayed_work(struct delayed_work *dwork,
122                                  unsigned long delay)
123 {
124         return queue_delayed_work(system_wq, dwork, delay);
125 }
126 EXPORT_SYMBOL_GPL(compat_schedule_delayed_work);
127
128 int compat_schedule_delayed_work_on(int cpu,
129                                     struct delayed_work *dwork,
130                                     unsigned long delay)
131 {
132         return queue_delayed_work_on(cpu, system_wq, dwork, delay);
133 }
134 EXPORT_SYMBOL_GPL(compat_schedule_delayed_work_on);
135
136 void compat_flush_scheduled_work(void)
137 {
138         /*
139          * It is debatable which one we should prioritize first, lets
140          * go with the old kernel's one first for now (keventd_wq) and
141          * if think its reasonable later we can flip this around.
142          */
143         flush_workqueue(system_wq);
144         flush_scheduled_work();
145 }
146 EXPORT_SYMBOL_GPL(compat_flush_scheduled_work);
147
148 void compat_system_workqueue_create()
149 {
150         system_wq = alloc_workqueue("events", 0, 0);
151         system_long_wq = alloc_workqueue("events_long", 0, 0);
152         system_nrt_wq = create_singlethread_workqueue("events_nrt");
153         BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq);
154 }
155
156 void compat_system_workqueue_destroy()
157 {
158         destroy_workqueue(system_wq);
159         destroy_workqueue(system_long_wq);
160         destroy_workqueue(system_nrt_wq);
161 }