diff options
author | David Vrabel <dv02@dv02pc01.europe.root.pri> | 2008-10-10 06:47:31 -0400 |
---|---|---|
committer | David Vrabel <dv02@dv02pc01.europe.root.pri> | 2008-10-10 06:47:31 -0400 |
commit | 99ee3a6d4577e7633c66304e4aefeca5489c8d5c (patch) | |
tree | 94dbf1db8b2efb6b4fdaf6fdaa86de655c64ff1c /drivers/usb | |
parent | 3fa8749e584b55f1180411ab1b51117190bac1e5 (diff) | |
parent | edfa042c880f62848aa55b3e71e538fe383929da (diff) |
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/dvrabel/uwb into for-upstream
Diffstat (limited to 'drivers/usb')
34 files changed, 12213 insertions, 0 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index bcefbddeba50..c23a9857ee67 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig | |||
@@ -97,6 +97,8 @@ source "drivers/usb/core/Kconfig" | |||
97 | 97 | ||
98 | source "drivers/usb/mon/Kconfig" | 98 | source "drivers/usb/mon/Kconfig" |
99 | 99 | ||
100 | source "drivers/usb/wusbcore/Kconfig" | ||
101 | |||
100 | source "drivers/usb/host/Kconfig" | 102 | source "drivers/usb/host/Kconfig" |
101 | 103 | ||
102 | source "drivers/usb/musb/Kconfig" | 104 | source "drivers/usb/musb/Kconfig" |
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index a419c42e880e..8b7c419b876e 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile | |||
@@ -16,9 +16,12 @@ obj-$(CONFIG_USB_UHCI_HCD) += host/ | |||
16 | obj-$(CONFIG_USB_SL811_HCD) += host/ | 16 | obj-$(CONFIG_USB_SL811_HCD) += host/ |
17 | obj-$(CONFIG_USB_U132_HCD) += host/ | 17 | obj-$(CONFIG_USB_U132_HCD) += host/ |
18 | obj-$(CONFIG_USB_R8A66597_HCD) += host/ | 18 | obj-$(CONFIG_USB_R8A66597_HCD) += host/ |
19 | obj-$(CONFIG_USB_HWA_HCD) += host/ | ||
19 | 20 | ||
20 | obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ | 21 | obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ |
21 | 22 | ||
23 | obj-$(CONFIG_USB_WUSB) += wusbcore/ | ||
24 | |||
22 | obj-$(CONFIG_USB_ACM) += class/ | 25 | obj-$(CONFIG_USB_ACM) += class/ |
23 | obj-$(CONFIG_USB_PRINTER) += class/ | 26 | obj-$(CONFIG_USB_PRINTER) += class/ |
24 | 27 | ||
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 228797e54f9c..72fb655e6033 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
@@ -305,3 +305,31 @@ config SUPERH_ON_CHIP_R8A66597 | |||
305 | help | 305 | help |
306 | This driver enables support for the on-chip R8A66597 in the | 306 | This driver enables support for the on-chip R8A66597 in the |
307 | SH7366 and SH7723 processors. | 307 | SH7366 and SH7723 processors. |
308 | |||
309 | config USB_WHCI_HCD | ||
310 | tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)" | ||
311 | depends on EXPERIMENTAL | ||
312 | depends on PCI && USB | ||
313 | select USB_WUSB | ||
314 | select UWB_WHCI | ||
315 | help | ||
316 | A driver for PCI-based Wireless USB Host Controllers that are | ||
317 | compliant with the WHCI specification. | ||
318 | |||
319 | To compile this driver a module, choose M here: the module | ||
320 | will be called "whci-hcd". | ||
321 | |||
322 | config USB_HWA_HCD | ||
323 | tristate "Host Wire Adapter (HWA) driver (EXPERIMENTAL)" | ||
324 | depends on EXPERIMENTAL | ||
325 | depends on USB | ||
326 | select USB_WUSB | ||
327 | select UWB_HWA | ||
328 | help | ||
329 | This driver enables you to connect Wireless USB devices to | ||
330 | your system using a Host Wire Adaptor USB dongle. This is an | ||
331 | UWB Radio Controller and WUSB Host Controller connected to | ||
332 | your machine via USB (specified in WUSB1.0). | ||
333 | |||
334 | To compile this driver a module, choose M here: the module | ||
335 | will be called "hwa-hc". | ||
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index f1edda2dcfde..23be22224044 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile | |||
@@ -8,6 +8,8 @@ endif | |||
8 | 8 | ||
9 | isp1760-objs := isp1760-hcd.o isp1760-if.o | 9 | isp1760-objs := isp1760-hcd.o isp1760-if.o |
10 | 10 | ||
11 | obj-$(CONFIG_USB_WHCI_HCD) += whci/ | ||
12 | |||
11 | obj-$(CONFIG_PCI) += pci-quirks.o | 13 | obj-$(CONFIG_PCI) += pci-quirks.o |
12 | 14 | ||
13 | obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o | 15 | obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o |
@@ -19,3 +21,4 @@ obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o | |||
19 | obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o | 21 | obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o |
20 | obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o | 22 | obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o |
21 | obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o | 23 | obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o |
24 | obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o | ||
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c new file mode 100644 index 000000000000..64be4d88df11 --- /dev/null +++ b/drivers/usb/host/hwa-hc.c | |||
@@ -0,0 +1,925 @@ | |||
1 | /* | ||
2 | * Host Wire Adapter: | ||
3 | * Driver glue, HWA-specific functions, bridges to WAHC and WUSBHC | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * The HWA driver is a simple layer that forwards requests to the WAHC | ||
24 | * (Wire Adater Host Controller) or WUSBHC (Wireless USB Host | ||
25 | * Controller) layers. | ||
26 | * | ||
27 | * Host Wire Adapter is the 'WUSB 1.0 standard' name for Wireless-USB | ||
28 | * Host Controller that is connected to your system via USB (a USB | ||
29 | * dongle that implements a USB host...). There is also a Device Wired | ||
30 | * Adaptor, DWA (Wireless USB hub) that uses the same mechanism for | ||
31 | * transferring data (it is after all a USB host connected via | ||
32 | * Wireless USB), we have a common layer called Wire Adapter Host | ||
33 | * Controller that does all the hard work. The WUSBHC (Wireless USB | ||
34 | * Host Controller) is the part common to WUSB Host Controllers, the | ||
35 | * HWA and the PCI-based one, that is implemented following the WHCI | ||
36 | * spec. All these layers are implemented in ../wusbcore. | ||
37 | * | ||
38 | * The main functions are hwahc_op_urb_{en,de}queue(), that pass the | ||
39 | * job of converting a URB to a Wire Adapter | ||
40 | * | ||
41 | * Entry points: | ||
42 | * | ||
43 | * hwahc_driver_*() Driver initialization, registration and | ||
44 | * teardown. | ||
45 | * | ||
46 | * hwahc_probe() New device came up, create an instance for | ||
47 | * it [from device enumeration]. | ||
48 | * | ||
49 | * hwahc_disconnect() Remove device instance [from device | ||
50 | * enumeration]. | ||
51 | * | ||
52 | * [__]hwahc_op_*() Host-Wire-Adaptor specific functions for | ||
53 | * starting/stopping/etc (some might be made also | ||
54 | * DWA). | ||
55 | */ | ||
56 | #include <linux/kernel.h> | ||
57 | #include <linux/version.h> | ||
58 | #include <linux/init.h> | ||
59 | #include <linux/module.h> | ||
60 | #include <linux/workqueue.h> | ||
61 | #include <linux/wait.h> | ||
62 | #include <linux/completion.h> | ||
63 | #include "../wusbcore/wa-hc.h" | ||
64 | #include "../wusbcore/wusbhc.h" | ||
65 | |||
66 | #define D_LOCAL 0 | ||
67 | #include <linux/uwb/debug.h> | ||
68 | |||
69 | struct hwahc { | ||
70 | struct wusbhc wusbhc; /* has to be 1st */ | ||
71 | struct wahc wa; | ||
72 | u8 buffer[16]; /* for misc usb transactions */ | ||
73 | }; | ||
74 | |||
75 | /** | ||
76 | * FIXME should be wusbhc | ||
77 | * | ||
78 | * NOTE: we need to cache the Cluster ID because later...there is no | ||
79 | * way to get it :) | ||
80 | */ | ||
81 | static int __hwahc_set_cluster_id(struct hwahc *hwahc, u8 cluster_id) | ||
82 | { | ||
83 | int result; | ||
84 | struct wusbhc *wusbhc = &hwahc->wusbhc; | ||
85 | struct wahc *wa = &hwahc->wa; | ||
86 | struct device *dev = &wa->usb_iface->dev; | ||
87 | |||
88 | result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
89 | WUSB_REQ_SET_CLUSTER_ID, | ||
90 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
91 | cluster_id, | ||
92 | wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
93 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
94 | if (result < 0) | ||
95 | dev_err(dev, "Cannot set WUSB Cluster ID to 0x%02x: %d\n", | ||
96 | cluster_id, result); | ||
97 | else | ||
98 | wusbhc->cluster_id = cluster_id; | ||
99 | dev_info(dev, "Wireless USB Cluster ID set to 0x%02x\n", cluster_id); | ||
100 | return result; | ||
101 | } | ||
102 | |||
103 | static int __hwahc_op_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots) | ||
104 | { | ||
105 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
106 | struct wahc *wa = &hwahc->wa; | ||
107 | |||
108 | return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
109 | WUSB_REQ_SET_NUM_DNTS, | ||
110 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
111 | interval << 8 | slots, | ||
112 | wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
113 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * Reset a WUSB host controller and wait for it to complete doing it. | ||
118 | * | ||
119 | * @usb_hcd: Pointer to WUSB Host Controller instance. | ||
120 | * | ||
121 | */ | ||
122 | static int hwahc_op_reset(struct usb_hcd *usb_hcd) | ||
123 | { | ||
124 | int result; | ||
125 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
126 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
127 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
128 | |||
129 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
130 | mutex_lock(&wusbhc->mutex); | ||
131 | wa_nep_disarm(&hwahc->wa); | ||
132 | result = __wa_set_feature(&hwahc->wa, WA_RESET); | ||
133 | if (result < 0) { | ||
134 | dev_err(dev, "error commanding HC to reset: %d\n", result); | ||
135 | goto error_unlock; | ||
136 | } | ||
137 | d_printf(3, dev, "reset: waiting for device to change state\n"); | ||
138 | result = __wa_wait_status(&hwahc->wa, WA_STATUS_RESETTING, 0); | ||
139 | if (result < 0) { | ||
140 | dev_err(dev, "error waiting for HC to reset: %d\n", result); | ||
141 | goto error_unlock; | ||
142 | } | ||
143 | error_unlock: | ||
144 | mutex_unlock(&wusbhc->mutex); | ||
145 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
146 | return result; | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * FIXME: break this function up | ||
151 | */ | ||
152 | static int hwahc_op_start(struct usb_hcd *usb_hcd) | ||
153 | { | ||
154 | u8 addr; | ||
155 | int result; | ||
156 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
157 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
158 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
159 | |||
160 | /* Set up a Host Info WUSB Information Element */ | ||
161 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
162 | result = -ENOSPC; | ||
163 | mutex_lock(&wusbhc->mutex); | ||
164 | /* Start the numbering from the top so that the bottom | ||
165 | * range of the unauth addr space is used for devices, | ||
166 | * the top for HCs; use 0xfe - RC# */ | ||
167 | addr = wusb_cluster_id_get(); | ||
168 | if (addr == 0) | ||
169 | goto error_cluster_id_get; | ||
170 | result = __hwahc_set_cluster_id(hwahc, addr); | ||
171 | if (result < 0) | ||
172 | goto error_set_cluster_id; | ||
173 | |||
174 | result = wa_nep_arm(&hwahc->wa, GFP_KERNEL); | ||
175 | if (result < 0) { | ||
176 | dev_err(dev, "cannot listen to notifications: %d\n", result); | ||
177 | goto error_stop; | ||
178 | } | ||
179 | usb_hcd->uses_new_polling = 1; | ||
180 | usb_hcd->poll_rh = 1; | ||
181 | usb_hcd->state = HC_STATE_RUNNING; | ||
182 | result = 0; | ||
183 | out: | ||
184 | mutex_unlock(&wusbhc->mutex); | ||
185 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
186 | return result; | ||
187 | |||
188 | error_stop: | ||
189 | __wa_stop(&hwahc->wa); | ||
190 | error_set_cluster_id: | ||
191 | wusb_cluster_id_put(wusbhc->cluster_id); | ||
192 | error_cluster_id_get: | ||
193 | goto out; | ||
194 | |||
195 | } | ||
196 | |||
197 | /* | ||
198 | * FIXME: break this function up | ||
199 | */ | ||
200 | static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc) | ||
201 | { | ||
202 | int result; | ||
203 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
204 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
205 | |||
206 | /* Set up a Host Info WUSB Information Element */ | ||
207 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
208 | result = -ENOSPC; | ||
209 | |||
210 | result = __wa_set_feature(&hwahc->wa, WA_ENABLE); | ||
211 | if (result < 0) { | ||
212 | dev_err(dev, "error commanding HC to start: %d\n", result); | ||
213 | goto error_stop; | ||
214 | } | ||
215 | result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE); | ||
216 | if (result < 0) { | ||
217 | dev_err(dev, "error waiting for HC to start: %d\n", result); | ||
218 | goto error_stop; | ||
219 | } | ||
220 | result = 0; | ||
221 | out: | ||
222 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
223 | return result; | ||
224 | |||
225 | error_stop: | ||
226 | result = __wa_clear_feature(&hwahc->wa, WA_ENABLE); | ||
227 | goto out; | ||
228 | } | ||
229 | |||
230 | static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg) | ||
231 | { | ||
232 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
233 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
234 | dev_err(wusbhc->dev, "%s (%p [%p], 0x%lx) UNIMPLEMENTED\n", __func__, | ||
235 | usb_hcd, hwahc, *(unsigned long *) &msg); | ||
236 | return -ENOSYS; | ||
237 | } | ||
238 | |||
239 | static int hwahc_op_resume(struct usb_hcd *usb_hcd) | ||
240 | { | ||
241 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
242 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
243 | |||
244 | dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, | ||
245 | usb_hcd, hwahc); | ||
246 | return -ENOSYS; | ||
247 | } | ||
248 | |||
249 | static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc) | ||
250 | { | ||
251 | int result; | ||
252 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
253 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
254 | |||
255 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
256 | /* Nothing for now */ | ||
257 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * No need to abort pipes, as when this is called, all the children | ||
263 | * has been disconnected and that has done it [through | ||
264 | * usb_disable_interface() -> usb_disable_endpoint() -> | ||
265 | * hwahc_op_ep_disable() - >rpipe_ep_disable()]. | ||
266 | */ | ||
267 | static void hwahc_op_stop(struct usb_hcd *usb_hcd) | ||
268 | { | ||
269 | int result; | ||
270 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
271 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
272 | struct wahc *wa = &hwahc->wa; | ||
273 | struct device *dev = &wa->usb_iface->dev; | ||
274 | |||
275 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
276 | mutex_lock(&wusbhc->mutex); | ||
277 | wusbhc_stop(wusbhc); | ||
278 | wa_nep_disarm(&hwahc->wa); | ||
279 | result = __wa_stop(&hwahc->wa); | ||
280 | wusb_cluster_id_put(wusbhc->cluster_id); | ||
281 | mutex_unlock(&wusbhc->mutex); | ||
282 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
283 | return; | ||
284 | } | ||
285 | |||
286 | static int hwahc_op_get_frame_number(struct usb_hcd *usb_hcd) | ||
287 | { | ||
288 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
289 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
290 | |||
291 | dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, | ||
292 | usb_hcd, hwahc); | ||
293 | return -ENOSYS; | ||
294 | } | ||
295 | |||
296 | static int hwahc_op_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb, | ||
297 | gfp_t gfp) | ||
298 | { | ||
299 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
300 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
301 | |||
302 | return wa_urb_enqueue(&hwahc->wa, urb->ep, urb, gfp); | ||
303 | } | ||
304 | |||
305 | static int hwahc_op_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, | ||
306 | int status) | ||
307 | { | ||
308 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
309 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
310 | |||
311 | return wa_urb_dequeue(&hwahc->wa, urb); | ||
312 | } | ||
313 | |||
314 | /* | ||
315 | * Release resources allocated for an endpoint | ||
316 | * | ||
317 | * If there is an associated rpipe to this endpoint, go ahead and put it. | ||
318 | */ | ||
319 | static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd, | ||
320 | struct usb_host_endpoint *ep) | ||
321 | { | ||
322 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
323 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
324 | |||
325 | rpipe_ep_disable(&hwahc->wa, ep); | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * Set the UWB MAS allocation for the WUSB cluster | ||
330 | * | ||
331 | * @stream_index: stream to use (-1 for cancelling the allocation) | ||
332 | * @mas: mas bitmap to use | ||
333 | */ | ||
334 | static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index, | ||
335 | const struct uwb_mas_bm *mas) | ||
336 | { | ||
337 | int result; | ||
338 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
339 | struct wahc *wa = &hwahc->wa; | ||
340 | struct device *dev = &wa->usb_iface->dev; | ||
341 | u8 mas_le[UWB_NUM_MAS/8]; | ||
342 | |||
343 | /* Set the stream index */ | ||
344 | result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
345 | WUSB_REQ_SET_STREAM_IDX, | ||
346 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
347 | stream_index, | ||
348 | wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
349 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
350 | if (result < 0) { | ||
351 | dev_err(dev, "Cannot set WUSB stream index: %d\n", result); | ||
352 | goto out; | ||
353 | } | ||
354 | uwb_mas_bm_copy_le(mas_le, mas); | ||
355 | /* Set the MAS allocation */ | ||
356 | result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
357 | WUSB_REQ_SET_WUSB_MAS, | ||
358 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
359 | 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
360 | mas_le, 32, 1000 /* FIXME: arbitrary */); | ||
361 | if (result < 0) | ||
362 | dev_err(dev, "Cannot set WUSB MAS allocation: %d\n", result); | ||
363 | out: | ||
364 | return result; | ||
365 | } | ||
366 | |||
367 | /* | ||
368 | * Add an IE to the host's MMC | ||
369 | * | ||
370 | * @interval: See WUSB1.0[8.5.3.1] | ||
371 | * @repeat_cnt: See WUSB1.0[8.5.3.1] | ||
372 | * @handle: See WUSB1.0[8.5.3.1] | ||
373 | * @wuie: Pointer to the header of the WUSB IE data to add. | ||
374 | * MUST BE allocated in a kmalloc buffer (no stack or | ||
375 | * vmalloc). | ||
376 | * | ||
377 | * NOTE: the format of the WUSB IEs for MMCs are different to the | ||
378 | * normal MBOA MAC IEs (IE Id + Length in MBOA MAC vs. Length + | ||
379 | * Id in WUSB IEs). Standards...you gotta love'em. | ||
380 | */ | ||
381 | static int __hwahc_op_mmcie_add(struct wusbhc *wusbhc, u8 interval, | ||
382 | u8 repeat_cnt, u8 handle, | ||
383 | struct wuie_hdr *wuie) | ||
384 | { | ||
385 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
386 | struct wahc *wa = &hwahc->wa; | ||
387 | u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
388 | |||
389 | return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
390 | WUSB_REQ_ADD_MMC_IE, | ||
391 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
392 | interval << 8 | repeat_cnt, | ||
393 | handle << 8 | iface_no, | ||
394 | wuie, wuie->bLength, 1000 /* FIXME: arbitrary */); | ||
395 | } | ||
396 | |||
397 | /* | ||
398 | * Remove an IE to the host's MMC | ||
399 | * | ||
400 | * @handle: See WUSB1.0[8.5.3.1] | ||
401 | */ | ||
402 | static int __hwahc_op_mmcie_rm(struct wusbhc *wusbhc, u8 handle) | ||
403 | { | ||
404 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
405 | struct wahc *wa = &hwahc->wa; | ||
406 | u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
407 | return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
408 | WUSB_REQ_REMOVE_MMC_IE, | ||
409 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
410 | 0, handle << 8 | iface_no, | ||
411 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
412 | } | ||
413 | |||
414 | /* | ||
415 | * Update device information for a given fake port | ||
416 | * | ||
417 | * @port_idx: Fake port to which device is connected (wusbhc index, not | ||
418 | * USB port number). | ||
419 | */ | ||
420 | static int __hwahc_op_dev_info_set(struct wusbhc *wusbhc, | ||
421 | struct wusb_dev *wusb_dev) | ||
422 | { | ||
423 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
424 | struct wahc *wa = &hwahc->wa; | ||
425 | u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
426 | struct hwa_dev_info *dev_info; | ||
427 | int ret; | ||
428 | |||
429 | /* fill out the Device Info buffer and send it */ | ||
430 | dev_info = kzalloc(sizeof(struct hwa_dev_info), GFP_KERNEL); | ||
431 | if (!dev_info) | ||
432 | return -ENOMEM; | ||
433 | uwb_mas_bm_copy_le(dev_info->bmDeviceAvailability, | ||
434 | &wusb_dev->availability); | ||
435 | dev_info->bDeviceAddress = wusb_dev->addr; | ||
436 | |||
437 | /* | ||
438 | * If the descriptors haven't been read yet, use a default PHY | ||
439 | * rate of 53.3 Mbit/s only. The correct value will be used | ||
440 | * when this will be called again as part of the | ||
441 | * authentication process (which occurs after the descriptors | ||
442 | * have been read). | ||
443 | */ | ||
444 | if (wusb_dev->wusb_cap_descr) | ||
445 | dev_info->wPHYRates = wusb_dev->wusb_cap_descr->wPHYRates; | ||
446 | else | ||
447 | dev_info->wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53); | ||
448 | |||
449 | ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
450 | WUSB_REQ_SET_DEV_INFO, | ||
451 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
452 | 0, wusb_dev->port_idx << 8 | iface_no, | ||
453 | dev_info, sizeof(struct hwa_dev_info), | ||
454 | 1000 /* FIXME: arbitrary */); | ||
455 | kfree(dev_info); | ||
456 | return ret; | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | * Set host's idea of which encryption (and key) method to use when | ||
461 | * talking to ad evice on a given port. | ||
462 | * | ||
463 | * If key is NULL, it means disable encryption for that "virtual port" | ||
464 | * (used when we disconnect). | ||
465 | */ | ||
466 | static int __hwahc_dev_set_key(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, | ||
467 | const void *key, size_t key_size, | ||
468 | u8 key_idx) | ||
469 | { | ||
470 | int result = -ENOMEM; | ||
471 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
472 | struct wahc *wa = &hwahc->wa; | ||
473 | u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
474 | struct usb_key_descriptor *keyd; | ||
475 | size_t keyd_len; | ||
476 | |||
477 | keyd_len = sizeof(*keyd) + key_size; | ||
478 | keyd = kzalloc(keyd_len, GFP_KERNEL); | ||
479 | if (keyd == NULL) | ||
480 | return -ENOMEM; | ||
481 | |||
482 | keyd->bLength = keyd_len; | ||
483 | keyd->bDescriptorType = USB_DT_KEY; | ||
484 | keyd->tTKID[0] = (tkid >> 0) & 0xff; | ||
485 | keyd->tTKID[1] = (tkid >> 8) & 0xff; | ||
486 | keyd->tTKID[2] = (tkid >> 16) & 0xff; | ||
487 | memcpy(keyd->bKeyData, key, key_size); | ||
488 | |||
489 | result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
490 | USB_REQ_SET_DESCRIPTOR, | ||
491 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
492 | USB_DT_KEY << 8 | key_idx, | ||
493 | port_idx << 8 | iface_no, | ||
494 | keyd, keyd_len, 1000 /* FIXME: arbitrary */); | ||
495 | |||
496 | memset(keyd, 0, sizeof(*keyd)); /* clear keys etc. */ | ||
497 | kfree(keyd); | ||
498 | return result; | ||
499 | } | ||
500 | |||
501 | /* | ||
502 | * Set host's idea of which encryption (and key) method to use when | ||
503 | * talking to ad evice on a given port. | ||
504 | * | ||
505 | * If key is NULL, it means disable encryption for that "virtual port" | ||
506 | * (used when we disconnect). | ||
507 | */ | ||
508 | static int __hwahc_op_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, | ||
509 | const void *key, size_t key_size) | ||
510 | { | ||
511 | int result = -ENOMEM; | ||
512 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
513 | struct wahc *wa = &hwahc->wa; | ||
514 | u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
515 | u8 encryption_value; | ||
516 | |||
517 | /* Tell the host which key to use to talk to the device */ | ||
518 | if (key) { | ||
519 | u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_PTK, | ||
520 | WUSB_KEY_INDEX_ORIGINATOR_HOST); | ||
521 | |||
522 | result = __hwahc_dev_set_key(wusbhc, port_idx, tkid, | ||
523 | key, key_size, key_idx); | ||
524 | if (result < 0) | ||
525 | goto error_set_key; | ||
526 | encryption_value = wusbhc->ccm1_etd->bEncryptionValue; | ||
527 | } else { | ||
528 | /* FIXME: this should come from wusbhc->etd[UNSECURE].value */ | ||
529 | encryption_value = 0; | ||
530 | } | ||
531 | |||
532 | /* Set the encryption type for commmunicating with the device */ | ||
533 | result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
534 | USB_REQ_SET_ENCRYPTION, | ||
535 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
536 | encryption_value, port_idx << 8 | iface_no, | ||
537 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
538 | if (result < 0) | ||
539 | dev_err(wusbhc->dev, "Can't set host's WUSB encryption for " | ||
540 | "port index %u to %s (value %d): %d\n", port_idx, | ||
541 | wusb_et_name(wusbhc->ccm1_etd->bEncryptionType), | ||
542 | wusbhc->ccm1_etd->bEncryptionValue, result); | ||
543 | error_set_key: | ||
544 | return result; | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | * Set host's GTK key | ||
549 | */ | ||
550 | static int __hwahc_op_set_gtk(struct wusbhc *wusbhc, u32 tkid, | ||
551 | const void *key, size_t key_size) | ||
552 | { | ||
553 | u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK, | ||
554 | WUSB_KEY_INDEX_ORIGINATOR_HOST); | ||
555 | |||
556 | return __hwahc_dev_set_key(wusbhc, 0, tkid, key, key_size, key_idx); | ||
557 | } | ||
558 | |||
559 | /* | ||
560 | * Get the Wire Adapter class-specific descriptor | ||
561 | * | ||
562 | * NOTE: this descriptor comes with the big bundled configuration | ||
563 | * descriptor that includes the interfaces' and endpoints', so | ||
564 | * we just look for it in the cached copy kept by the USB stack. | ||
565 | * | ||
566 | * NOTE2: We convert LE fields to CPU order. | ||
567 | */ | ||
568 | static int wa_fill_descr(struct wahc *wa) | ||
569 | { | ||
570 | int result; | ||
571 | struct device *dev = &wa->usb_iface->dev; | ||
572 | char *itr; | ||
573 | struct usb_device *usb_dev = wa->usb_dev; | ||
574 | struct usb_descriptor_header *hdr; | ||
575 | struct usb_wa_descriptor *wa_descr; | ||
576 | size_t itr_size, actconfig_idx; | ||
577 | |||
578 | actconfig_idx = (usb_dev->actconfig - usb_dev->config) / | ||
579 | sizeof(usb_dev->config[0]); | ||
580 | itr = usb_dev->rawdescriptors[actconfig_idx]; | ||
581 | itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength); | ||
582 | while (itr_size >= sizeof(*hdr)) { | ||
583 | hdr = (struct usb_descriptor_header *) itr; | ||
584 | d_printf(3, dev, "Extra device descriptor: " | ||
585 | "type %02x/%u bytes @ %zu (%zu left)\n", | ||
586 | hdr->bDescriptorType, hdr->bLength, | ||
587 | (itr - usb_dev->rawdescriptors[actconfig_idx]), | ||
588 | itr_size); | ||
589 | if (hdr->bDescriptorType == USB_DT_WIRE_ADAPTER) | ||
590 | goto found; | ||
591 | itr += hdr->bLength; | ||
592 | itr_size -= hdr->bLength; | ||
593 | } | ||
594 | dev_err(dev, "cannot find Wire Adapter Class descriptor\n"); | ||
595 | return -ENODEV; | ||
596 | |||
597 | found: | ||
598 | result = -EINVAL; | ||
599 | if (hdr->bLength > itr_size) { /* is it available? */ | ||
600 | dev_err(dev, "incomplete Wire Adapter Class descriptor " | ||
601 | "(%zu bytes left, %u needed)\n", | ||
602 | itr_size, hdr->bLength); | ||
603 | goto error; | ||
604 | } | ||
605 | if (hdr->bLength < sizeof(*wa->wa_descr)) { | ||
606 | dev_err(dev, "short Wire Adapter Class descriptor\n"); | ||
607 | goto error; | ||
608 | } | ||
609 | wa->wa_descr = wa_descr = (struct usb_wa_descriptor *) hdr; | ||
610 | /* Make LE fields CPU order */ | ||
611 | wa_descr->bcdWAVersion = le16_to_cpu(wa_descr->bcdWAVersion); | ||
612 | wa_descr->wNumRPipes = le16_to_cpu(wa_descr->wNumRPipes); | ||
613 | wa_descr->wRPipeMaxBlock = le16_to_cpu(wa_descr->wRPipeMaxBlock); | ||
614 | if (wa_descr->bcdWAVersion > 0x0100) | ||
615 | dev_warn(dev, "Wire Adapter v%d.%d newer than groked v1.0\n", | ||
616 | wa_descr->bcdWAVersion & 0xff00 >> 8, | ||
617 | wa_descr->bcdWAVersion & 0x00ff); | ||
618 | result = 0; | ||
619 | error: | ||
620 | return result; | ||
621 | } | ||
622 | |||
623 | static struct hc_driver hwahc_hc_driver = { | ||
624 | .description = "hwa-hcd", | ||
625 | .product_desc = "Wireless USB HWA host controller", | ||
626 | .hcd_priv_size = sizeof(struct hwahc) - sizeof(struct usb_hcd), | ||
627 | .irq = NULL, /* FIXME */ | ||
628 | .flags = HCD_USB2, /* FIXME */ | ||
629 | .reset = hwahc_op_reset, | ||
630 | .start = hwahc_op_start, | ||
631 | .pci_suspend = hwahc_op_suspend, | ||
632 | .pci_resume = hwahc_op_resume, | ||
633 | .stop = hwahc_op_stop, | ||
634 | .get_frame_number = hwahc_op_get_frame_number, | ||
635 | .urb_enqueue = hwahc_op_urb_enqueue, | ||
636 | .urb_dequeue = hwahc_op_urb_dequeue, | ||
637 | .endpoint_disable = hwahc_op_endpoint_disable, | ||
638 | |||
639 | .hub_status_data = wusbhc_rh_status_data, | ||
640 | .hub_control = wusbhc_rh_control, | ||
641 | .bus_suspend = wusbhc_rh_suspend, | ||
642 | .bus_resume = wusbhc_rh_resume, | ||
643 | .start_port_reset = wusbhc_rh_start_port_reset, | ||
644 | }; | ||
645 | |||
646 | static int hwahc_security_create(struct hwahc *hwahc) | ||
647 | { | ||
648 | int result; | ||
649 | struct wusbhc *wusbhc = &hwahc->wusbhc; | ||
650 | struct usb_device *usb_dev = hwahc->wa.usb_dev; | ||
651 | struct device *dev = &usb_dev->dev; | ||
652 | struct usb_security_descriptor *secd; | ||
653 | struct usb_encryption_descriptor *etd; | ||
654 | void *itr, *top; | ||
655 | size_t itr_size, needed, bytes; | ||
656 | u8 index; | ||
657 | char buf[64]; | ||
658 | |||
659 | /* Find the host's security descriptors in the config descr bundle */ | ||
660 | index = (usb_dev->actconfig - usb_dev->config) / | ||
661 | sizeof(usb_dev->config[0]); | ||
662 | itr = usb_dev->rawdescriptors[index]; | ||
663 | itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength); | ||
664 | top = itr + itr_size; | ||
665 | result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index], | ||
666 | le16_to_cpu(usb_dev->actconfig->desc.wTotalLength), | ||
667 | USB_DT_SECURITY, (void **) &secd); | ||
668 | if (result == -1) { | ||
669 | dev_warn(dev, "BUG? WUSB host has no security descriptors\n"); | ||
670 | return 0; | ||
671 | } | ||
672 | needed = sizeof(*secd); | ||
673 | if (top - (void *)secd < needed) { | ||
674 | dev_err(dev, "BUG? Not enough data to process security " | ||
675 | "descriptor header (%zu bytes left vs %zu needed)\n", | ||
676 | top - (void *) secd, needed); | ||
677 | return 0; | ||
678 | } | ||
679 | needed = le16_to_cpu(secd->wTotalLength); | ||
680 | if (top - (void *)secd < needed) { | ||
681 | dev_err(dev, "BUG? Not enough data to process security " | ||
682 | "descriptors (%zu bytes left vs %zu needed)\n", | ||
683 | top - (void *) secd, needed); | ||
684 | return 0; | ||
685 | } | ||
686 | /* Walk over the sec descriptors and store CCM1's on wusbhc */ | ||
687 | itr = (void *) secd + sizeof(*secd); | ||
688 | top = (void *) secd + le16_to_cpu(secd->wTotalLength); | ||
689 | index = 0; | ||
690 | bytes = 0; | ||
691 | while (itr < top) { | ||
692 | etd = itr; | ||
693 | if (top - itr < sizeof(*etd)) { | ||
694 | dev_err(dev, "BUG: bad host security descriptor; " | ||
695 | "not enough data (%zu vs %zu left)\n", | ||
696 | top - itr, sizeof(*etd)); | ||
697 | break; | ||
698 | } | ||
699 | if (etd->bLength < sizeof(*etd)) { | ||
700 | dev_err(dev, "BUG: bad host encryption descriptor; " | ||
701 | "descriptor is too short " | ||
702 | "(%zu vs %zu needed)\n", | ||
703 | (size_t)etd->bLength, sizeof(*etd)); | ||
704 | break; | ||
705 | } | ||
706 | itr += etd->bLength; | ||
707 | bytes += snprintf(buf + bytes, sizeof(buf) - bytes, | ||
708 | "%s (0x%02x) ", | ||
709 | wusb_et_name(etd->bEncryptionType), | ||
710 | etd->bEncryptionValue); | ||
711 | wusbhc->ccm1_etd = etd; | ||
712 | } | ||
713 | dev_info(dev, "supported encryption types: %s\n", buf); | ||
714 | if (wusbhc->ccm1_etd == NULL) { | ||
715 | dev_err(dev, "E: host doesn't support CCM-1 crypto\n"); | ||
716 | return 0; | ||
717 | } | ||
718 | /* Pretty print what we support */ | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | static void hwahc_security_release(struct hwahc *hwahc) | ||
723 | { | ||
724 | /* nothing to do here so far... */ | ||
725 | } | ||
726 | |||
727 | static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface) | ||
728 | { | ||
729 | int result; | ||
730 | struct device *dev = &iface->dev; | ||
731 | struct wusbhc *wusbhc = &hwahc->wusbhc; | ||
732 | struct wahc *wa = &hwahc->wa; | ||
733 | struct usb_device *usb_dev = interface_to_usbdev(iface); | ||
734 | |||
735 | wa->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */ | ||
736 | wa->usb_iface = usb_get_intf(iface); | ||
737 | wusbhc->dev = dev; | ||
738 | wusbhc->uwb_rc = uwb_rc_get_by_grandpa(iface->dev.parent); | ||
739 | if (wusbhc->uwb_rc == NULL) { | ||
740 | result = -ENODEV; | ||
741 | dev_err(dev, "Cannot get associated UWB Host Controller\n"); | ||
742 | goto error_rc_get; | ||
743 | } | ||
744 | result = wa_fill_descr(wa); /* Get the device descriptor */ | ||
745 | if (result < 0) | ||
746 | goto error_fill_descriptor; | ||
747 | if (wa->wa_descr->bNumPorts > USB_MAXCHILDREN) { | ||
748 | dev_err(dev, "FIXME: USB_MAXCHILDREN too low for WUSB " | ||
749 | "adapter (%u ports)\n", wa->wa_descr->bNumPorts); | ||
750 | wusbhc->ports_max = USB_MAXCHILDREN; | ||
751 | } else { | ||
752 | wusbhc->ports_max = wa->wa_descr->bNumPorts; | ||
753 | } | ||
754 | wusbhc->mmcies_max = wa->wa_descr->bNumMMCIEs; | ||
755 | wusbhc->start = __hwahc_op_wusbhc_start; | ||
756 | wusbhc->stop = __hwahc_op_wusbhc_stop; | ||
757 | wusbhc->mmcie_add = __hwahc_op_mmcie_add; | ||
758 | wusbhc->mmcie_rm = __hwahc_op_mmcie_rm; | ||
759 | wusbhc->dev_info_set = __hwahc_op_dev_info_set; | ||
760 | wusbhc->bwa_set = __hwahc_op_bwa_set; | ||
761 | wusbhc->set_num_dnts = __hwahc_op_set_num_dnts; | ||
762 | wusbhc->set_ptk = __hwahc_op_set_ptk; | ||
763 | wusbhc->set_gtk = __hwahc_op_set_gtk; | ||
764 | result = hwahc_security_create(hwahc); | ||
765 | if (result < 0) { | ||
766 | dev_err(dev, "Can't initialize security: %d\n", result); | ||
767 | goto error_security_create; | ||
768 | } | ||
769 | wa->wusb = wusbhc; /* FIXME: ugly, need to fix */ | ||
770 | result = wusbhc_create(&hwahc->wusbhc); | ||
771 | if (result < 0) { | ||
772 | dev_err(dev, "Can't create WUSB HC structures: %d\n", result); | ||
773 | goto error_wusbhc_create; | ||
774 | } | ||
775 | result = wa_create(&hwahc->wa, iface); | ||
776 | if (result < 0) | ||
777 | goto error_wa_create; | ||
778 | return 0; | ||
779 | |||
780 | error_wa_create: | ||
781 | wusbhc_destroy(&hwahc->wusbhc); | ||
782 | error_wusbhc_create: | ||
783 | /* WA Descr fill allocs no resources */ | ||
784 | error_security_create: | ||
785 | error_fill_descriptor: | ||
786 | uwb_rc_put(wusbhc->uwb_rc); | ||
787 | error_rc_get: | ||
788 | usb_put_intf(iface); | ||
789 | usb_put_dev(usb_dev); | ||
790 | return result; | ||
791 | } | ||
792 | |||
793 | static void hwahc_destroy(struct hwahc *hwahc) | ||
794 | { | ||
795 | struct wusbhc *wusbhc = &hwahc->wusbhc; | ||
796 | |||
797 | d_fnstart(1, NULL, "(hwahc %p)\n", hwahc); | ||
798 | mutex_lock(&wusbhc->mutex); | ||
799 | __wa_destroy(&hwahc->wa); | ||
800 | wusbhc_destroy(&hwahc->wusbhc); | ||
801 | hwahc_security_release(hwahc); | ||
802 | hwahc->wusbhc.dev = NULL; | ||
803 | uwb_rc_put(wusbhc->uwb_rc); | ||
804 | usb_put_intf(hwahc->wa.usb_iface); | ||
805 | usb_put_dev(hwahc->wa.usb_dev); | ||
806 | mutex_unlock(&wusbhc->mutex); | ||
807 | d_fnend(1, NULL, "(hwahc %p) = void\n", hwahc); | ||
808 | } | ||
809 | |||
810 | static void hwahc_init(struct hwahc *hwahc) | ||
811 | { | ||
812 | wa_init(&hwahc->wa); | ||
813 | } | ||
814 | |||
815 | static int hwahc_probe(struct usb_interface *usb_iface, | ||
816 | const struct usb_device_id *id) | ||
817 | { | ||
818 | int result; | ||
819 | struct usb_hcd *usb_hcd; | ||
820 | struct wusbhc *wusbhc; | ||
821 | struct hwahc *hwahc; | ||
822 | struct device *dev = &usb_iface->dev; | ||
823 | |||
824 | d_fnstart(4, dev, "(%p, %p)\n", usb_iface, id); | ||
825 | result = -ENOMEM; | ||
826 | usb_hcd = usb_create_hcd(&hwahc_hc_driver, &usb_iface->dev, "wusb-hwa"); | ||
827 | if (usb_hcd == NULL) { | ||
828 | dev_err(dev, "unable to allocate instance\n"); | ||
829 | goto error_alloc; | ||
830 | } | ||
831 | usb_hcd->wireless = 1; | ||
832 | usb_hcd->flags |= HCD_FLAG_SAW_IRQ; | ||
833 | wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
834 | hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
835 | hwahc_init(hwahc); | ||
836 | result = hwahc_create(hwahc, usb_iface); | ||
837 | if (result < 0) { | ||
838 | dev_err(dev, "Cannot initialize internals: %d\n", result); | ||
839 | goto error_hwahc_create; | ||
840 | } | ||
841 | result = usb_add_hcd(usb_hcd, 0, 0); | ||
842 | if (result < 0) { | ||
843 | dev_err(dev, "Cannot add HCD: %d\n", result); | ||
844 | goto error_add_hcd; | ||
845 | } | ||
846 | result = wusbhc_b_create(&hwahc->wusbhc); | ||
847 | if (result < 0) { | ||
848 | dev_err(dev, "Cannot setup phase B of WUSBHC: %d\n", result); | ||
849 | goto error_wusbhc_b_create; | ||
850 | } | ||
851 | d_fnend(4, dev, "(%p, %p) = 0\n", usb_iface, id); | ||
852 | return 0; | ||
853 | |||
854 | error_wusbhc_b_create: | ||
855 | usb_remove_hcd(usb_hcd); | ||
856 | error_add_hcd: | ||
857 | hwahc_destroy(hwahc); | ||
858 | error_hwahc_create: | ||
859 | usb_put_hcd(usb_hcd); | ||
860 | error_alloc: | ||
861 | d_fnend(4, dev, "(%p, %p) = %d\n", usb_iface, id, result); | ||
862 | return result; | ||
863 | } | ||
864 | |||
865 | static void hwahc_disconnect(struct usb_interface *usb_iface) | ||
866 | { | ||
867 | struct usb_hcd *usb_hcd; | ||
868 | struct wusbhc *wusbhc; | ||
869 | struct hwahc *hwahc; | ||
870 | |||
871 | usb_hcd = usb_get_intfdata(usb_iface); | ||
872 | wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
873 | hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
874 | |||
875 | d_fnstart(1, NULL, "(hwahc %p [usb_iface %p])\n", hwahc, usb_iface); | ||
876 | wusbhc_b_destroy(&hwahc->wusbhc); | ||
877 | usb_remove_hcd(usb_hcd); | ||
878 | hwahc_destroy(hwahc); | ||
879 | usb_put_hcd(usb_hcd); | ||
880 | d_fnend(1, NULL, "(hwahc %p [usb_iface %p]) = void\n", hwahc, | ||
881 | usb_iface); | ||
882 | } | ||
883 | |||
884 | /** USB device ID's that we handle */ | ||
885 | static struct usb_device_id hwahc_id_table[] = { | ||
886 | /* FIXME: use class labels for this */ | ||
887 | { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), }, | ||
888 | {}, | ||
889 | }; | ||
890 | MODULE_DEVICE_TABLE(usb, hwahc_id_table); | ||
891 | |||
892 | static struct usb_driver hwahc_driver = { | ||
893 | .name = "hwa-hc", | ||
894 | .probe = hwahc_probe, | ||
895 | .disconnect = hwahc_disconnect, | ||
896 | .id_table = hwahc_id_table, | ||
897 | }; | ||
898 | |||
899 | static int __init hwahc_driver_init(void) | ||
900 | { | ||
901 | int result; | ||
902 | result = usb_register(&hwahc_driver); | ||
903 | if (result < 0) { | ||
904 | printk(KERN_ERR "WA-CDS: Cannot register USB driver: %d\n", | ||
905 | result); | ||
906 | goto error_usb_register; | ||
907 | } | ||
908 | return 0; | ||
909 | |||
910 | error_usb_register: | ||
911 | return result; | ||
912 | |||
913 | } | ||
914 | module_init(hwahc_driver_init); | ||
915 | |||
916 | static void __exit hwahc_driver_exit(void) | ||
917 | { | ||
918 | usb_deregister(&hwahc_driver); | ||
919 | } | ||
920 | module_exit(hwahc_driver_exit); | ||
921 | |||
922 | |||
923 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
924 | MODULE_DESCRIPTION("Host Wired Adapter USB Host Control Driver"); | ||
925 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/host/whci/Kbuild b/drivers/usb/host/whci/Kbuild new file mode 100644 index 000000000000..26a3871ea0f9 --- /dev/null +++ b/drivers/usb/host/whci/Kbuild | |||
@@ -0,0 +1,11 @@ | |||
1 | obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o | ||
2 | |||
3 | whci-hcd-y := \ | ||
4 | asl.o \ | ||
5 | hcd.o \ | ||
6 | hw.o \ | ||
7 | init.o \ | ||
8 | int.o \ | ||
9 | pzl.o \ | ||
10 | qset.o \ | ||
11 | wusb.o | ||
diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c new file mode 100644 index 000000000000..4d7078e50572 --- /dev/null +++ b/drivers/usb/host/whci/asl.c | |||
@@ -0,0 +1,367 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) asynchronous schedule management. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/uwb/umc.h> | ||
21 | #include <linux/usb.h> | ||
22 | #define D_LOCAL 0 | ||
23 | #include <linux/uwb/debug.h> | ||
24 | |||
25 | #include "../../wusbcore/wusbhc.h" | ||
26 | |||
27 | #include "whcd.h" | ||
28 | |||
29 | #if D_LOCAL >= 4 | ||
30 | static void dump_asl(struct whc *whc, const char *tag) | ||
31 | { | ||
32 | struct device *dev = &whc->umc->dev; | ||
33 | struct whc_qset *qset; | ||
34 | |||
35 | d_printf(4, dev, "ASL %s\n", tag); | ||
36 | |||
37 | list_for_each_entry(qset, &whc->async_list, list_node) { | ||
38 | dump_qset(qset, dev); | ||
39 | } | ||
40 | } | ||
41 | #else | ||
42 | static inline void dump_asl(struct whc *whc, const char *tag) | ||
43 | { | ||
44 | } | ||
45 | #endif | ||
46 | |||
47 | |||
48 | static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset, | ||
49 | struct whc_qset **next, struct whc_qset **prev) | ||
50 | { | ||
51 | struct list_head *n, *p; | ||
52 | |||
53 | BUG_ON(list_empty(&whc->async_list)); | ||
54 | |||
55 | n = qset->list_node.next; | ||
56 | if (n == &whc->async_list) | ||
57 | n = n->next; | ||
58 | p = qset->list_node.prev; | ||
59 | if (p == &whc->async_list) | ||
60 | p = p->prev; | ||
61 | |||
62 | *next = container_of(n, struct whc_qset, list_node); | ||
63 | *prev = container_of(p, struct whc_qset, list_node); | ||
64 | |||
65 | } | ||
66 | |||
67 | static void asl_qset_insert_begin(struct whc *whc, struct whc_qset *qset) | ||
68 | { | ||
69 | list_move(&qset->list_node, &whc->async_list); | ||
70 | qset->in_sw_list = true; | ||
71 | } | ||
72 | |||
73 | static void asl_qset_insert(struct whc *whc, struct whc_qset *qset) | ||
74 | { | ||
75 | struct whc_qset *next, *prev; | ||
76 | |||
77 | qset_clear(whc, qset); | ||
78 | |||
79 | /* Link into ASL. */ | ||
80 | qset_get_next_prev(whc, qset, &next, &prev); | ||
81 | whc_qset_set_link_ptr(&qset->qh.link, next->qset_dma); | ||
82 | whc_qset_set_link_ptr(&prev->qh.link, qset->qset_dma); | ||
83 | qset->in_hw_list = true; | ||
84 | } | ||
85 | |||
86 | static void asl_qset_remove(struct whc *whc, struct whc_qset *qset) | ||
87 | { | ||
88 | struct whc_qset *prev, *next; | ||
89 | |||
90 | qset_get_next_prev(whc, qset, &next, &prev); | ||
91 | |||
92 | list_move(&qset->list_node, &whc->async_removed_list); | ||
93 | qset->in_sw_list = false; | ||
94 | |||
95 | /* | ||
96 | * No more qsets in the ASL? The caller must stop the ASL as | ||
97 | * it's no longer valid. | ||
98 | */ | ||
99 | if (list_empty(&whc->async_list)) | ||
100 | return; | ||
101 | |||
102 | /* Remove from ASL. */ | ||
103 | whc_qset_set_link_ptr(&prev->qh.link, next->qset_dma); | ||
104 | qset->in_hw_list = false; | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * process_qset - process any recently inactivated or halted qTDs in a | ||
109 | * qset. | ||
110 | * | ||
111 | * After inactive qTDs are removed, new qTDs can be added if the | ||
112 | * urb queue still contains URBs. | ||
113 | * | ||
114 | * Returns any additional WUSBCMD bits for the ASL sync command (i.e., | ||
115 | * WUSBCMD_ASYNC_QSET_RM if a halted qset was removed). | ||
116 | */ | ||
117 | static uint32_t process_qset(struct whc *whc, struct whc_qset *qset) | ||
118 | { | ||
119 | enum whc_update update = 0; | ||
120 | uint32_t status = 0; | ||
121 | |||
122 | while (qset->ntds) { | ||
123 | struct whc_qtd *td; | ||
124 | int t; | ||
125 | |||
126 | t = qset->td_start; | ||
127 | td = &qset->qtd[qset->td_start]; | ||
128 | status = le32_to_cpu(td->status); | ||
129 | |||
130 | /* | ||
131 | * Nothing to do with a still active qTD. | ||
132 | */ | ||
133 | if (status & QTD_STS_ACTIVE) | ||
134 | break; | ||
135 | |||
136 | if (status & QTD_STS_HALTED) { | ||
137 | /* Ug, an error. */ | ||
138 | process_halted_qtd(whc, qset, td); | ||
139 | goto done; | ||
140 | } | ||
141 | |||
142 | /* Mmm, a completed qTD. */ | ||
143 | process_inactive_qtd(whc, qset, td); | ||
144 | } | ||
145 | |||
146 | update |= qset_add_qtds(whc, qset); | ||
147 | |||
148 | done: | ||
149 | /* | ||
150 | * Remove this qset from the ASL if requested, but only if has | ||
151 | * no qTDs. | ||
152 | */ | ||
153 | if (qset->remove && qset->ntds == 0) { | ||
154 | asl_qset_remove(whc, qset); | ||
155 | update |= WHC_UPDATE_REMOVED; | ||
156 | } | ||
157 | return update; | ||
158 | } | ||
159 | |||
160 | void asl_start(struct whc *whc) | ||
161 | { | ||
162 | struct whc_qset *qset; | ||
163 | |||
164 | qset = list_first_entry(&whc->async_list, struct whc_qset, list_node); | ||
165 | |||
166 | le_writeq(qset->qset_dma | QH_LINK_NTDS(8), whc->base + WUSBASYNCLISTADDR); | ||
167 | |||
168 | whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, WUSBCMD_ASYNC_EN); | ||
169 | whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, | ||
170 | WUSBSTS_ASYNC_SCHED, WUSBSTS_ASYNC_SCHED, | ||
171 | 1000, "start ASL"); | ||
172 | } | ||
173 | |||
174 | void asl_stop(struct whc *whc) | ||
175 | { | ||
176 | whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, 0); | ||
177 | whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, | ||
178 | WUSBSTS_ASYNC_SCHED, 0, | ||
179 | 1000, "stop ASL"); | ||
180 | } | ||
181 | |||
182 | void asl_update(struct whc *whc, uint32_t wusbcmd) | ||
183 | { | ||
184 | whc_write_wusbcmd(whc, wusbcmd, wusbcmd); | ||
185 | wait_event(whc->async_list_wq, | ||
186 | (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0); | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * scan_async_work - scan the ASL for qsets to process. | ||
191 | * | ||
192 | * Process each qset in the ASL in turn and then signal the WHC that | ||
193 | * the ASL has been updated. | ||
194 | * | ||
195 | * Then start, stop or update the asynchronous schedule as required. | ||
196 | */ | ||
197 | void scan_async_work(struct work_struct *work) | ||
198 | { | ||
199 | struct whc *whc = container_of(work, struct whc, async_work); | ||
200 | struct whc_qset *qset, *t; | ||
201 | enum whc_update update = 0; | ||
202 | |||
203 | spin_lock_irq(&whc->lock); | ||
204 | |||
205 | dump_asl(whc, "before processing"); | ||
206 | |||
207 | /* | ||
208 | * Transerve the software list backwards so new qsets can be | ||
209 | * safely inserted into the ASL without making it non-circular. | ||
210 | */ | ||
211 | list_for_each_entry_safe_reverse(qset, t, &whc->async_list, list_node) { | ||
212 | if (!qset->in_hw_list) { | ||
213 | asl_qset_insert(whc, qset); | ||
214 | update |= WHC_UPDATE_ADDED; | ||
215 | } | ||
216 | |||
217 | update |= process_qset(whc, qset); | ||
218 | } | ||
219 | |||
220 | dump_asl(whc, "after processing"); | ||
221 | |||
222 | spin_unlock_irq(&whc->lock); | ||
223 | |||
224 | if (update) { | ||
225 | uint32_t wusbcmd = WUSBCMD_ASYNC_UPDATED | WUSBCMD_ASYNC_SYNCED_DB; | ||
226 | if (update & WHC_UPDATE_REMOVED) | ||
227 | wusbcmd |= WUSBCMD_ASYNC_QSET_RM; | ||
228 | asl_update(whc, wusbcmd); | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * Now that the ASL is updated, complete the removal of any | ||
233 | * removed qsets. | ||
234 | */ | ||
235 | spin_lock(&whc->lock); | ||
236 | |||
237 | list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) { | ||
238 | qset_remove_complete(whc, qset); | ||
239 | } | ||
240 | |||
241 | spin_unlock(&whc->lock); | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * asl_urb_enqueue - queue an URB onto the asynchronous list (ASL). | ||
246 | * @whc: the WHCI host controller | ||
247 | * @urb: the URB to enqueue | ||
248 | * @mem_flags: flags for any memory allocations | ||
249 | * | ||
250 | * The qset for the endpoint is obtained and the urb queued on to it. | ||
251 | * | ||
252 | * Work is scheduled to update the hardware's view of the ASL. | ||
253 | */ | ||
254 | int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags) | ||
255 | { | ||
256 | struct whc_qset *qset; | ||
257 | int err; | ||
258 | unsigned long flags; | ||
259 | |||
260 | spin_lock_irqsave(&whc->lock, flags); | ||
261 | |||
262 | qset = get_qset(whc, urb, GFP_ATOMIC); | ||
263 | if (qset == NULL) | ||
264 | err = -ENOMEM; | ||
265 | else | ||
266 | err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); | ||
267 | if (!err) { | ||
268 | usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); | ||
269 | if (!qset->in_sw_list) | ||
270 | asl_qset_insert_begin(whc, qset); | ||
271 | } | ||
272 | |||
273 | spin_unlock_irqrestore(&whc->lock, flags); | ||
274 | |||
275 | if (!err) | ||
276 | queue_work(whc->workqueue, &whc->async_work); | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | /** | ||
282 | * asl_urb_dequeue - remove an URB (qset) from the async list. | ||
283 | * @whc: the WHCI host controller | ||
284 | * @urb: the URB to dequeue | ||
285 | * @status: the current status of the URB | ||
286 | * | ||
287 | * URBs that do yet have qTDs can simply be removed from the software | ||
288 | * queue, otherwise the qset must be removed from the ASL so the qTDs | ||
289 | * can be removed. | ||
290 | */ | ||
291 | int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status) | ||
292 | { | ||
293 | struct whc_urb *wurb = urb->hcpriv; | ||
294 | struct whc_qset *qset = wurb->qset; | ||
295 | struct whc_std *std, *t; | ||
296 | int ret; | ||
297 | unsigned long flags; | ||
298 | |||
299 | spin_lock_irqsave(&whc->lock, flags); | ||
300 | |||
301 | ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status); | ||
302 | if (ret < 0) | ||
303 | goto out; | ||
304 | |||
305 | list_for_each_entry_safe(std, t, &qset->stds, list_node) { | ||
306 | if (std->urb == urb) | ||
307 | qset_free_std(whc, std); | ||
308 | else | ||
309 | std->qtd = NULL; /* so this std is re-added when the qset is */ | ||
310 | } | ||
311 | |||
312 | asl_qset_remove(whc, qset); | ||
313 | wurb->status = status; | ||
314 | wurb->is_async = true; | ||
315 | queue_work(whc->workqueue, &wurb->dequeue_work); | ||
316 | |||
317 | out: | ||
318 | spin_unlock_irqrestore(&whc->lock, flags); | ||
319 | |||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | /** | ||
324 | * asl_qset_delete - delete a qset from the ASL | ||
325 | */ | ||
326 | void asl_qset_delete(struct whc *whc, struct whc_qset *qset) | ||
327 | { | ||
328 | qset->remove = 1; | ||
329 | queue_work(whc->workqueue, &whc->async_work); | ||
330 | qset_delete(whc, qset); | ||
331 | } | ||
332 | |||
333 | /** | ||
334 | * asl_init - initialize the asynchronous schedule list | ||
335 | * | ||
336 | * A dummy qset with no qTDs is added to the ASL to simplify removing | ||
337 | * qsets (no need to stop the ASL when the last qset is removed). | ||
338 | */ | ||
339 | int asl_init(struct whc *whc) | ||
340 | { | ||
341 | struct whc_qset *qset; | ||
342 | |||
343 | qset = qset_alloc(whc, GFP_KERNEL); | ||
344 | if (qset == NULL) | ||
345 | return -ENOMEM; | ||
346 | |||
347 | asl_qset_insert_begin(whc, qset); | ||
348 | asl_qset_insert(whc, qset); | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | /** | ||
354 | * asl_clean_up - free ASL resources | ||
355 | * | ||
356 | * The ASL is stopped and empty except for the dummy qset. | ||
357 | */ | ||
358 | void asl_clean_up(struct whc *whc) | ||
359 | { | ||
360 | struct whc_qset *qset; | ||
361 | |||
362 | if (!list_empty(&whc->async_list)) { | ||
363 | qset = list_first_entry(&whc->async_list, struct whc_qset, list_node); | ||
364 | list_del(&qset->list_node); | ||
365 | qset_free(whc, qset); | ||
366 | } | ||
367 | } | ||
diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c new file mode 100644 index 000000000000..ef3ad4dca945 --- /dev/null +++ b/drivers/usb/host/whci/hcd.c | |||
@@ -0,0 +1,339 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) driver. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/uwb/umc.h> | ||
22 | |||
23 | #include "../../wusbcore/wusbhc.h" | ||
24 | |||
25 | #include "whcd.h" | ||
26 | |||
27 | /* | ||
28 | * One time initialization. | ||
29 | * | ||
30 | * Nothing to do here. | ||
31 | */ | ||
32 | static int whc_reset(struct usb_hcd *usb_hcd) | ||
33 | { | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * Start the wireless host controller. | ||
39 | * | ||
40 | * Start device notification. | ||
41 | * | ||
42 | * Put hc into run state, set DNTS parameters. | ||
43 | */ | ||
44 | static int whc_start(struct usb_hcd *usb_hcd) | ||
45 | { | ||
46 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
47 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
48 | u8 bcid; | ||
49 | int ret; | ||
50 | |||
51 | mutex_lock(&wusbhc->mutex); | ||
52 | |||
53 | le_writel(WUSBINTR_GEN_CMD_DONE | ||
54 | | WUSBINTR_HOST_ERR | ||
55 | | WUSBINTR_ASYNC_SCHED_SYNCED | ||
56 | | WUSBINTR_DNTS_INT | ||
57 | | WUSBINTR_ERR_INT | ||
58 | | WUSBINTR_INT, | ||
59 | whc->base + WUSBINTR); | ||
60 | |||
61 | /* set cluster ID */ | ||
62 | bcid = wusb_cluster_id_get(); | ||
63 | ret = whc_set_cluster_id(whc, bcid); | ||
64 | if (ret < 0) | ||
65 | goto out; | ||
66 | wusbhc->cluster_id = bcid; | ||
67 | |||
68 | /* start HC */ | ||
69 | whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN); | ||
70 | |||
71 | usb_hcd->uses_new_polling = 1; | ||
72 | usb_hcd->poll_rh = 1; | ||
73 | usb_hcd->state = HC_STATE_RUNNING; | ||
74 | |||
75 | out: | ||
76 | mutex_unlock(&wusbhc->mutex); | ||
77 | return ret; | ||
78 | } | ||
79 | |||
80 | |||
81 | /* | ||
82 | * Stop the wireless host controller. | ||
83 | * | ||
84 | * Stop device notification. | ||
85 | * | ||
86 | * Wait for pending transfer to stop? Put hc into stop state? | ||
87 | */ | ||
88 | static void whc_stop(struct usb_hcd *usb_hcd) | ||
89 | { | ||
90 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
91 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
92 | |||
93 | mutex_lock(&wusbhc->mutex); | ||
94 | |||
95 | wusbhc_stop(wusbhc); | ||
96 | |||
97 | /* stop HC */ | ||
98 | le_writel(0, whc->base + WUSBINTR); | ||
99 | whc_write_wusbcmd(whc, WUSBCMD_RUN, 0); | ||
100 | whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, | ||
101 | WUSBSTS_HCHALTED, WUSBSTS_HCHALTED, | ||
102 | 100, "HC to halt"); | ||
103 | |||
104 | wusb_cluster_id_put(wusbhc->cluster_id); | ||
105 | |||
106 | mutex_unlock(&wusbhc->mutex); | ||
107 | } | ||
108 | |||
109 | static int whc_get_frame_number(struct usb_hcd *usb_hcd) | ||
110 | { | ||
111 | /* Frame numbers are not applicable to WUSB. */ | ||
112 | return -ENOSYS; | ||
113 | } | ||
114 | |||
115 | |||
116 | /* | ||
117 | * Queue an URB to the ASL or PZL | ||
118 | */ | ||
119 | static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb, | ||
120 | gfp_t mem_flags) | ||
121 | { | ||
122 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
123 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
124 | int ret; | ||
125 | |||
126 | switch (usb_pipetype(urb->pipe)) { | ||
127 | case PIPE_INTERRUPT: | ||
128 | ret = pzl_urb_enqueue(whc, urb, mem_flags); | ||
129 | break; | ||
130 | case PIPE_ISOCHRONOUS: | ||
131 | dev_err(&whc->umc->dev, "isochronous transfers unsupported\n"); | ||
132 | ret = -ENOTSUPP; | ||
133 | break; | ||
134 | case PIPE_CONTROL: | ||
135 | case PIPE_BULK: | ||
136 | default: | ||
137 | ret = asl_urb_enqueue(whc, urb, mem_flags); | ||
138 | break; | ||
139 | }; | ||
140 | |||
141 | return ret; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Remove a queued URB from the ASL or PZL. | ||
146 | */ | ||
147 | static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status) | ||
148 | { | ||
149 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
150 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
151 | int ret; | ||
152 | |||
153 | switch (usb_pipetype(urb->pipe)) { | ||
154 | case PIPE_INTERRUPT: | ||
155 | ret = pzl_urb_dequeue(whc, urb, status); | ||
156 | break; | ||
157 | case PIPE_ISOCHRONOUS: | ||
158 | ret = -ENOTSUPP; | ||
159 | break; | ||
160 | case PIPE_CONTROL: | ||
161 | case PIPE_BULK: | ||
162 | default: | ||
163 | ret = asl_urb_dequeue(whc, urb, status); | ||
164 | break; | ||
165 | }; | ||
166 | |||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * Wait for all URBs to the endpoint to be completed, then delete the | ||
172 | * qset. | ||
173 | */ | ||
174 | static void whc_endpoint_disable(struct usb_hcd *usb_hcd, | ||
175 | struct usb_host_endpoint *ep) | ||
176 | { | ||
177 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
178 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
179 | struct whc_qset *qset; | ||
180 | |||
181 | qset = ep->hcpriv; | ||
182 | if (qset) { | ||
183 | ep->hcpriv = NULL; | ||
184 | if (usb_endpoint_xfer_bulk(&ep->desc) | ||
185 | || usb_endpoint_xfer_control(&ep->desc)) | ||
186 | asl_qset_delete(whc, qset); | ||
187 | else | ||
188 | pzl_qset_delete(whc, qset); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | static struct hc_driver whc_hc_driver = { | ||
193 | .description = "whci-hcd", | ||
194 | .product_desc = "Wireless host controller", | ||
195 | .hcd_priv_size = sizeof(struct whc) - sizeof(struct usb_hcd), | ||
196 | .irq = whc_int_handler, | ||
197 | .flags = HCD_USB2, | ||
198 | |||
199 | .reset = whc_reset, | ||
200 | .start = whc_start, | ||
201 | .stop = whc_stop, | ||
202 | .get_frame_number = whc_get_frame_number, | ||
203 | .urb_enqueue = whc_urb_enqueue, | ||
204 | .urb_dequeue = whc_urb_dequeue, | ||
205 | .endpoint_disable = whc_endpoint_disable, | ||
206 | |||
207 | .hub_status_data = wusbhc_rh_status_data, | ||
208 | .hub_control = wusbhc_rh_control, | ||
209 | .bus_suspend = wusbhc_rh_suspend, | ||
210 | .bus_resume = wusbhc_rh_resume, | ||
211 | .start_port_reset = wusbhc_rh_start_port_reset, | ||
212 | }; | ||
213 | |||
214 | static int whc_probe(struct umc_dev *umc) | ||
215 | { | ||
216 | int ret = -ENOMEM; | ||
217 | struct usb_hcd *usb_hcd; | ||
218 | struct wusbhc *wusbhc = NULL; | ||
219 | struct whc *whc = NULL; | ||
220 | struct device *dev = &umc->dev; | ||
221 | |||
222 | usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci"); | ||
223 | if (usb_hcd == NULL) { | ||
224 | dev_err(dev, "unable to create hcd\n"); | ||
225 | goto error; | ||
226 | } | ||
227 | |||
228 | usb_hcd->wireless = 1; | ||
229 | |||
230 | wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
231 | whc = wusbhc_to_whc(wusbhc); | ||
232 | whc->umc = umc; | ||
233 | |||
234 | ret = whc_init(whc); | ||
235 | if (ret) | ||
236 | goto error; | ||
237 | |||
238 | wusbhc->dev = dev; | ||
239 | wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent); | ||
240 | if (!wusbhc->uwb_rc) { | ||
241 | ret = -ENODEV; | ||
242 | dev_err(dev, "cannot get radio controller\n"); | ||
243 | goto error; | ||
244 | } | ||
245 | |||
246 | if (whc->n_devices > USB_MAXCHILDREN) { | ||
247 | dev_warn(dev, "USB_MAXCHILDREN too low for WUSB adapter (%u ports)\n", | ||
248 | whc->n_devices); | ||
249 | wusbhc->ports_max = USB_MAXCHILDREN; | ||
250 | } else | ||
251 | wusbhc->ports_max = whc->n_devices; | ||
252 | wusbhc->mmcies_max = whc->n_mmc_ies; | ||
253 | wusbhc->start = whc_wusbhc_start; | ||
254 | wusbhc->stop = whc_wusbhc_stop; | ||
255 | wusbhc->mmcie_add = whc_mmcie_add; | ||
256 | wusbhc->mmcie_rm = whc_mmcie_rm; | ||
257 | wusbhc->dev_info_set = whc_dev_info_set; | ||
258 | wusbhc->bwa_set = whc_bwa_set; | ||
259 | wusbhc->set_num_dnts = whc_set_num_dnts; | ||
260 | wusbhc->set_ptk = whc_set_ptk; | ||
261 | wusbhc->set_gtk = whc_set_gtk; | ||
262 | |||
263 | ret = wusbhc_create(wusbhc); | ||
264 | if (ret) | ||
265 | goto error_wusbhc_create; | ||
266 | |||
267 | ret = usb_add_hcd(usb_hcd, whc->umc->irq, IRQF_SHARED); | ||
268 | if (ret) { | ||
269 | dev_err(dev, "cannot add HCD: %d\n", ret); | ||
270 | goto error_usb_add_hcd; | ||
271 | } | ||
272 | |||
273 | ret = wusbhc_b_create(wusbhc); | ||
274 | if (ret) { | ||
275 | dev_err(dev, "WUSBHC phase B setup failed: %d\n", ret); | ||
276 | goto error_wusbhc_b_create; | ||
277 | } | ||
278 | |||
279 | return 0; | ||
280 | |||
281 | error_wusbhc_b_create: | ||
282 | usb_remove_hcd(usb_hcd); | ||
283 | error_usb_add_hcd: | ||
284 | wusbhc_destroy(wusbhc); | ||
285 | error_wusbhc_create: | ||
286 | uwb_rc_put(wusbhc->uwb_rc); | ||
287 | error: | ||
288 | whc_clean_up(whc); | ||
289 | if (usb_hcd) | ||
290 | usb_put_hcd(usb_hcd); | ||
291 | return ret; | ||
292 | } | ||
293 | |||
294 | |||
295 | static void whc_remove(struct umc_dev *umc) | ||
296 | { | ||
297 | struct usb_hcd *usb_hcd = dev_get_drvdata(&umc->dev); | ||
298 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
299 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
300 | |||
301 | if (usb_hcd) { | ||
302 | wusbhc_b_destroy(wusbhc); | ||
303 | usb_remove_hcd(usb_hcd); | ||
304 | wusbhc_destroy(wusbhc); | ||
305 | uwb_rc_put(wusbhc->uwb_rc); | ||
306 | whc_clean_up(whc); | ||
307 | usb_put_hcd(usb_hcd); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | static struct umc_driver whci_hc_driver = { | ||
312 | .name = "whci-hcd", | ||
313 | .cap_id = UMC_CAP_ID_WHCI_WUSB_HC, | ||
314 | .probe = whc_probe, | ||
315 | .remove = whc_remove, | ||
316 | }; | ||
317 | |||
318 | static int __init whci_hc_driver_init(void) | ||
319 | { | ||
320 | return umc_driver_register(&whci_hc_driver); | ||
321 | } | ||
322 | module_init(whci_hc_driver_init); | ||
323 | |||
324 | static void __exit whci_hc_driver_exit(void) | ||
325 | { | ||
326 | umc_driver_unregister(&whci_hc_driver); | ||
327 | } | ||
328 | module_exit(whci_hc_driver_exit); | ||
329 | |||
330 | /* PCI device ID's that we handle (so it gets loaded) */ | ||
331 | static struct pci_device_id whci_hcd_id_table[] = { | ||
332 | { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) }, | ||
333 | { /* empty last entry */ } | ||
334 | }; | ||
335 | MODULE_DEVICE_TABLE(pci, whci_hcd_id_table); | ||
336 | |||
337 | MODULE_DESCRIPTION("WHCI Wireless USB host controller driver"); | ||
338 | MODULE_AUTHOR("Cambridge Silicon Radio Ltd."); | ||
339 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/host/whci/hw.c b/drivers/usb/host/whci/hw.c new file mode 100644 index 000000000000..ac86e59c1225 --- /dev/null +++ b/drivers/usb/host/whci/hw.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) hardware access helpers. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/uwb/umc.h> | ||
21 | |||
22 | #include "../../wusbcore/wusbhc.h" | ||
23 | |||
24 | #include "whcd.h" | ||
25 | |||
26 | void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val) | ||
27 | { | ||
28 | unsigned long flags; | ||
29 | u32 cmd; | ||
30 | |||
31 | spin_lock_irqsave(&whc->lock, flags); | ||
32 | |||
33 | cmd = le_readl(whc->base + WUSBCMD); | ||
34 | cmd = (cmd & ~mask) | val; | ||
35 | le_writel(cmd, whc->base + WUSBCMD); | ||
36 | |||
37 | spin_unlock_irqrestore(&whc->lock, flags); | ||
38 | } | ||
39 | |||
40 | /** | ||
41 | * whc_do_gencmd - start a generic command via the WUSBGENCMDSTS register | ||
42 | * @whc: the WHCI HC | ||
43 | * @cmd: command to start. | ||
44 | * @params: parameters for the command (the WUSBGENCMDPARAMS register value). | ||
45 | * @addr: pointer to any data for the command (may be NULL). | ||
46 | * @len: length of the data (if any). | ||
47 | */ | ||
48 | int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len) | ||
49 | { | ||
50 | unsigned long flags; | ||
51 | dma_addr_t dma_addr; | ||
52 | int t; | ||
53 | |||
54 | mutex_lock(&whc->mutex); | ||
55 | |||
56 | /* Wait for previous command to complete. */ | ||
57 | t = wait_event_timeout(whc->cmd_wq, | ||
58 | (le_readl(whc->base + WUSBGENCMDSTS) & WUSBGENCMDSTS_ACTIVE) == 0, | ||
59 | WHC_GENCMD_TIMEOUT_MS); | ||
60 | if (t == 0) { | ||
61 | dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n", | ||
62 | le_readl(whc->base + WUSBGENCMDSTS), | ||
63 | le_readl(whc->base + WUSBGENCMDPARAMS)); | ||
64 | return -ETIMEDOUT; | ||
65 | } | ||
66 | |||
67 | if (addr) { | ||
68 | memcpy(whc->gen_cmd_buf, addr, len); | ||
69 | dma_addr = whc->gen_cmd_buf_dma; | ||
70 | } else | ||
71 | dma_addr = 0; | ||
72 | |||
73 | /* Poke registers to start cmd. */ | ||
74 | spin_lock_irqsave(&whc->lock, flags); | ||
75 | |||
76 | le_writel(params, whc->base + WUSBGENCMDPARAMS); | ||
77 | le_writeq(dma_addr, whc->base + WUSBGENADDR); | ||
78 | |||
79 | le_writel(WUSBGENCMDSTS_ACTIVE | WUSBGENCMDSTS_IOC | cmd, | ||
80 | whc->base + WUSBGENCMDSTS); | ||
81 | |||
82 | spin_unlock_irqrestore(&whc->lock, flags); | ||
83 | |||
84 | mutex_unlock(&whc->mutex); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
diff --git a/drivers/usb/host/whci/init.c b/drivers/usb/host/whci/init.c new file mode 100644 index 000000000000..34a783cb0133 --- /dev/null +++ b/drivers/usb/host/whci/init.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) initialization. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/uwb/umc.h> | ||
21 | |||
22 | #include "../../wusbcore/wusbhc.h" | ||
23 | |||
24 | #include "whcd.h" | ||
25 | |||
26 | /* | ||
27 | * Reset the host controller. | ||
28 | */ | ||
29 | static void whc_hw_reset(struct whc *whc) | ||
30 | { | ||
31 | le_writel(WUSBCMD_WHCRESET, whc->base + WUSBCMD); | ||
32 | whci_wait_for(&whc->umc->dev, whc->base + WUSBCMD, WUSBCMD_WHCRESET, 0, | ||
33 | 100, "reset"); | ||
34 | } | ||
35 | |||
36 | static void whc_hw_init_di_buf(struct whc *whc) | ||
37 | { | ||
38 | int d; | ||
39 | |||
40 | /* Disable all entries in the Device Information buffer. */ | ||
41 | for (d = 0; d < whc->n_devices; d++) | ||
42 | whc->di_buf[d].addr_sec_info = WHC_DI_DISABLE; | ||
43 | |||
44 | le_writeq(whc->di_buf_dma, whc->base + WUSBDEVICEINFOADDR); | ||
45 | } | ||
46 | |||
47 | static void whc_hw_init_dn_buf(struct whc *whc) | ||
48 | { | ||
49 | /* Clear the Device Notification buffer to ensure the V (valid) | ||
50 | * bits are clear. */ | ||
51 | memset(whc->dn_buf, 0, 4096); | ||
52 | |||
53 | le_writeq(whc->dn_buf_dma, whc->base + WUSBDNTSBUFADDR); | ||
54 | } | ||
55 | |||
56 | int whc_init(struct whc *whc) | ||
57 | { | ||
58 | u32 whcsparams; | ||
59 | int ret, i; | ||
60 | resource_size_t start, len; | ||
61 | |||
62 | spin_lock_init(&whc->lock); | ||
63 | mutex_init(&whc->mutex); | ||
64 | init_waitqueue_head(&whc->cmd_wq); | ||
65 | init_waitqueue_head(&whc->async_list_wq); | ||
66 | init_waitqueue_head(&whc->periodic_list_wq); | ||
67 | whc->workqueue = create_singlethread_workqueue(dev_name(&whc->umc->dev)); | ||
68 | if (whc->workqueue == NULL) { | ||
69 | ret = -ENOMEM; | ||
70 | goto error; | ||
71 | } | ||
72 | INIT_WORK(&whc->dn_work, whc_dn_work); | ||
73 | |||
74 | INIT_WORK(&whc->async_work, scan_async_work); | ||
75 | INIT_LIST_HEAD(&whc->async_list); | ||
76 | INIT_LIST_HEAD(&whc->async_removed_list); | ||
77 | |||
78 | INIT_WORK(&whc->periodic_work, scan_periodic_work); | ||
79 | for (i = 0; i < 5; i++) | ||
80 | INIT_LIST_HEAD(&whc->periodic_list[i]); | ||
81 | INIT_LIST_HEAD(&whc->periodic_removed_list); | ||
82 | |||
83 | /* Map HC registers. */ | ||
84 | start = whc->umc->resource.start; | ||
85 | len = whc->umc->resource.end - start + 1; | ||
86 | if (!request_mem_region(start, len, "whci-hc")) { | ||
87 | dev_err(&whc->umc->dev, "can't request HC region\n"); | ||
88 | ret = -EBUSY; | ||
89 | goto error; | ||
90 | } | ||
91 | whc->base_phys = start; | ||
92 | whc->base = ioremap(start, len); | ||
93 | if (!whc->base) { | ||
94 | dev_err(&whc->umc->dev, "ioremap\n"); | ||
95 | ret = -ENOMEM; | ||
96 | goto error; | ||
97 | } | ||
98 | |||
99 | whc_hw_reset(whc); | ||
100 | |||
101 | /* Read maximum number of devices, keys and MMC IEs. */ | ||
102 | whcsparams = le_readl(whc->base + WHCSPARAMS); | ||
103 | whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams); | ||
104 | whc->n_keys = WHCSPARAMS_TO_N_KEYS(whcsparams); | ||
105 | whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams); | ||
106 | |||
107 | dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n", | ||
108 | whc->n_devices, whc->n_keys, whc->n_mmc_ies); | ||
109 | |||
110 | whc->qset_pool = dma_pool_create("qset", &whc->umc->dev, | ||
111 | sizeof(struct whc_qset), 64, 0); | ||
112 | if (whc->qset_pool == NULL) { | ||
113 | ret = -ENOMEM; | ||
114 | goto error; | ||
115 | } | ||
116 | |||
117 | ret = asl_init(whc); | ||
118 | if (ret < 0) | ||
119 | goto error; | ||
120 | ret = pzl_init(whc); | ||
121 | if (ret < 0) | ||
122 | goto error; | ||
123 | |||
124 | /* Allocate and initialize a buffer for generic commands, the | ||
125 | Device Information buffer, and the Device Notification | ||
126 | buffer. */ | ||
127 | |||
128 | whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN, | ||
129 | &whc->gen_cmd_buf_dma, GFP_KERNEL); | ||
130 | if (whc->gen_cmd_buf == NULL) { | ||
131 | ret = -ENOMEM; | ||
132 | goto error; | ||
133 | } | ||
134 | |||
135 | whc->dn_buf = dma_alloc_coherent(&whc->umc->dev, | ||
136 | sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES, | ||
137 | &whc->dn_buf_dma, GFP_KERNEL); | ||
138 | if (!whc->dn_buf) { | ||
139 | ret = -ENOMEM; | ||
140 | goto error; | ||
141 | } | ||
142 | whc_hw_init_dn_buf(whc); | ||
143 | |||
144 | whc->di_buf = dma_alloc_coherent(&whc->umc->dev, | ||
145 | sizeof(struct di_buf_entry) * whc->n_devices, | ||
146 | &whc->di_buf_dma, GFP_KERNEL); | ||
147 | if (!whc->di_buf) { | ||
148 | ret = -ENOMEM; | ||
149 | goto error; | ||
150 | } | ||
151 | whc_hw_init_di_buf(whc); | ||
152 | |||
153 | return 0; | ||
154 | |||
155 | error: | ||
156 | whc_clean_up(whc); | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | void whc_clean_up(struct whc *whc) | ||
161 | { | ||
162 | resource_size_t len; | ||
163 | |||
164 | if (whc->di_buf) | ||
165 | dma_free_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices, | ||
166 | whc->di_buf, whc->di_buf_dma); | ||
167 | if (whc->dn_buf) | ||
168 | dma_free_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES, | ||
169 | whc->dn_buf, whc->dn_buf_dma); | ||
170 | if (whc->gen_cmd_buf) | ||
171 | dma_free_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN, | ||
172 | whc->gen_cmd_buf, whc->gen_cmd_buf_dma); | ||
173 | |||
174 | pzl_clean_up(whc); | ||
175 | asl_clean_up(whc); | ||
176 | |||
177 | if (whc->qset_pool) | ||
178 | dma_pool_destroy(whc->qset_pool); | ||
179 | |||
180 | len = whc->umc->resource.end - whc->umc->resource.start + 1; | ||
181 | if (whc->base) | ||
182 | iounmap(whc->base); | ||
183 | if (whc->base_phys) | ||
184 | release_mem_region(whc->base_phys, len); | ||
185 | |||
186 | if (whc->workqueue) | ||
187 | destroy_workqueue(whc->workqueue); | ||
188 | } | ||
diff --git a/drivers/usb/host/whci/int.c b/drivers/usb/host/whci/int.c new file mode 100644 index 000000000000..fce01174aa9b --- /dev/null +++ b/drivers/usb/host/whci/int.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) interrupt handling. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/uwb/umc.h> | ||
22 | |||
23 | #include "../../wusbcore/wusbhc.h" | ||
24 | |||
25 | #include "whcd.h" | ||
26 | |||
27 | static void transfer_done(struct whc *whc) | ||
28 | { | ||
29 | queue_work(whc->workqueue, &whc->async_work); | ||
30 | queue_work(whc->workqueue, &whc->periodic_work); | ||
31 | } | ||
32 | |||
33 | irqreturn_t whc_int_handler(struct usb_hcd *hcd) | ||
34 | { | ||
35 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(hcd); | ||
36 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
37 | u32 sts; | ||
38 | |||
39 | sts = le_readl(whc->base + WUSBSTS); | ||
40 | if (!(sts & WUSBSTS_INT_MASK)) | ||
41 | return IRQ_NONE; | ||
42 | le_writel(sts & WUSBSTS_INT_MASK, whc->base + WUSBSTS); | ||
43 | |||
44 | if (sts & WUSBSTS_GEN_CMD_DONE) | ||
45 | wake_up(&whc->cmd_wq); | ||
46 | |||
47 | if (sts & WUSBSTS_HOST_ERR) | ||
48 | dev_err(&whc->umc->dev, "FIXME: host system error\n"); | ||
49 | |||
50 | if (sts & WUSBSTS_ASYNC_SCHED_SYNCED) | ||
51 | wake_up(&whc->async_list_wq); | ||
52 | |||
53 | if (sts & WUSBSTS_PERIODIC_SCHED_SYNCED) | ||
54 | wake_up(&whc->periodic_list_wq); | ||
55 | |||
56 | if (sts & WUSBSTS_DNTS_INT) | ||
57 | queue_work(whc->workqueue, &whc->dn_work); | ||
58 | |||
59 | /* | ||
60 | * A transfer completed (see [WHCI] section 4.7.1.2 for when | ||
61 | * this occurs). | ||
62 | */ | ||
63 | if (sts & (WUSBSTS_INT | WUSBSTS_ERR_INT)) | ||
64 | transfer_done(whc); | ||
65 | |||
66 | return IRQ_HANDLED; | ||
67 | } | ||
68 | |||
69 | static int process_dn_buf(struct whc *whc) | ||
70 | { | ||
71 | struct wusbhc *wusbhc = &whc->wusbhc; | ||
72 | struct dn_buf_entry *dn; | ||
73 | int processed = 0; | ||
74 | |||
75 | for (dn = whc->dn_buf; dn < whc->dn_buf + WHC_N_DN_ENTRIES; dn++) { | ||
76 | if (dn->status & WHC_DN_STATUS_VALID) { | ||
77 | wusbhc_handle_dn(wusbhc, dn->src_addr, | ||
78 | (struct wusb_dn_hdr *)dn->dn_data, | ||
79 | dn->msg_size); | ||
80 | dn->status &= ~WHC_DN_STATUS_VALID; | ||
81 | processed++; | ||
82 | } | ||
83 | } | ||
84 | return processed; | ||
85 | } | ||
86 | |||
87 | void whc_dn_work(struct work_struct *work) | ||
88 | { | ||
89 | struct whc *whc = container_of(work, struct whc, dn_work); | ||
90 | int processed; | ||
91 | |||
92 | do { | ||
93 | processed = process_dn_buf(whc); | ||
94 | } while (processed); | ||
95 | } | ||
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c new file mode 100644 index 000000000000..8d62df0c330b --- /dev/null +++ b/drivers/usb/host/whci/pzl.c | |||
@@ -0,0 +1,398 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) periodic schedule management. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/uwb/umc.h> | ||
21 | #include <linux/usb.h> | ||
22 | #define D_LOCAL 0 | ||
23 | #include <linux/uwb/debug.h> | ||
24 | |||
25 | #include "../../wusbcore/wusbhc.h" | ||
26 | |||
27 | #include "whcd.h" | ||
28 | |||
29 | #if D_LOCAL >= 4 | ||
30 | static void dump_pzl(struct whc *whc, const char *tag) | ||
31 | { | ||
32 | struct device *dev = &whc->umc->dev; | ||
33 | struct whc_qset *qset; | ||
34 | int period = 0; | ||
35 | |||
36 | d_printf(4, dev, "PZL %s\n", tag); | ||
37 | |||
38 | for (period = 0; period < 5; period++) { | ||
39 | d_printf(4, dev, "Period %d\n", period); | ||
40 | list_for_each_entry(qset, &whc->periodic_list[period], list_node) { | ||
41 | dump_qset(qset, dev); | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | #else | ||
46 | static inline void dump_pzl(struct whc *whc, const char *tag) | ||
47 | { | ||
48 | } | ||
49 | #endif | ||
50 | |||
51 | static void update_pzl_pointers(struct whc *whc, int period, u64 addr) | ||
52 | { | ||
53 | switch (period) { | ||
54 | case 0: | ||
55 | whc_qset_set_link_ptr(&whc->pz_list[0], addr); | ||
56 | whc_qset_set_link_ptr(&whc->pz_list[2], addr); | ||
57 | whc_qset_set_link_ptr(&whc->pz_list[4], addr); | ||
58 | whc_qset_set_link_ptr(&whc->pz_list[6], addr); | ||
59 | whc_qset_set_link_ptr(&whc->pz_list[8], addr); | ||
60 | whc_qset_set_link_ptr(&whc->pz_list[10], addr); | ||
61 | whc_qset_set_link_ptr(&whc->pz_list[12], addr); | ||
62 | whc_qset_set_link_ptr(&whc->pz_list[14], addr); | ||
63 | break; | ||
64 | case 1: | ||
65 | whc_qset_set_link_ptr(&whc->pz_list[1], addr); | ||
66 | whc_qset_set_link_ptr(&whc->pz_list[5], addr); | ||
67 | whc_qset_set_link_ptr(&whc->pz_list[9], addr); | ||
68 | whc_qset_set_link_ptr(&whc->pz_list[13], addr); | ||
69 | break; | ||
70 | case 2: | ||
71 | whc_qset_set_link_ptr(&whc->pz_list[3], addr); | ||
72 | whc_qset_set_link_ptr(&whc->pz_list[11], addr); | ||
73 | break; | ||
74 | case 3: | ||
75 | whc_qset_set_link_ptr(&whc->pz_list[7], addr); | ||
76 | break; | ||
77 | case 4: | ||
78 | whc_qset_set_link_ptr(&whc->pz_list[15], addr); | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Return the 'period' to use for this qset. The minimum interval for | ||
85 | * the endpoint is used so whatever urbs are submitted the device is | ||
86 | * polled often enough. | ||
87 | */ | ||
88 | static int qset_get_period(struct whc *whc, struct whc_qset *qset) | ||
89 | { | ||
90 | uint8_t bInterval = qset->ep->desc.bInterval; | ||
91 | |||
92 | if (bInterval < 6) | ||
93 | bInterval = 6; | ||
94 | if (bInterval > 10) | ||
95 | bInterval = 10; | ||
96 | return bInterval - 6; | ||
97 | } | ||
98 | |||
99 | static void qset_insert_in_sw_list(struct whc *whc, struct whc_qset *qset) | ||
100 | { | ||
101 | int period; | ||
102 | |||
103 | period = qset_get_period(whc, qset); | ||
104 | |||
105 | qset_clear(whc, qset); | ||
106 | list_move(&qset->list_node, &whc->periodic_list[period]); | ||
107 | qset->in_sw_list = true; | ||
108 | } | ||
109 | |||
110 | static void pzl_qset_remove(struct whc *whc, struct whc_qset *qset) | ||
111 | { | ||
112 | list_move(&qset->list_node, &whc->periodic_removed_list); | ||
113 | qset->in_hw_list = false; | ||
114 | qset->in_sw_list = false; | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * pzl_process_qset - process any recently inactivated or halted qTDs | ||
119 | * in a qset. | ||
120 | * | ||
121 | * After inactive qTDs are removed, new qTDs can be added if the | ||
122 | * urb queue still contains URBs. | ||
123 | * | ||
124 | * Returns the schedule updates required. | ||
125 | */ | ||
126 | static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset) | ||
127 | { | ||
128 | enum whc_update update = 0; | ||
129 | uint32_t status = 0; | ||
130 | |||
131 | while (qset->ntds) { | ||
132 | struct whc_qtd *td; | ||
133 | int t; | ||
134 | |||
135 | t = qset->td_start; | ||
136 | td = &qset->qtd[qset->td_start]; | ||
137 | status = le32_to_cpu(td->status); | ||
138 | |||
139 | /* | ||
140 | * Nothing to do with a still active qTD. | ||
141 | */ | ||
142 | if (status & QTD_STS_ACTIVE) | ||
143 | break; | ||
144 | |||
145 | if (status & QTD_STS_HALTED) { | ||
146 | /* Ug, an error. */ | ||
147 | process_halted_qtd(whc, qset, td); | ||
148 | goto done; | ||
149 | } | ||
150 | |||
151 | /* Mmm, a completed qTD. */ | ||
152 | process_inactive_qtd(whc, qset, td); | ||
153 | } | ||
154 | |||
155 | update |= qset_add_qtds(whc, qset); | ||
156 | |||
157 | done: | ||
158 | /* | ||
159 | * If there are no qTDs in this qset, remove it from the PZL. | ||
160 | */ | ||
161 | if (qset->remove && qset->ntds == 0) { | ||
162 | pzl_qset_remove(whc, qset); | ||
163 | update |= WHC_UPDATE_REMOVED; | ||
164 | } | ||
165 | |||
166 | return update; | ||
167 | } | ||
168 | |||
169 | /** | ||
170 | * pzl_start - start the periodic schedule | ||
171 | * @whc: the WHCI host controller | ||
172 | * | ||
173 | * The PZL must be valid (e.g., all entries in the list should have | ||
174 | * the T bit set). | ||
175 | */ | ||
176 | void pzl_start(struct whc *whc) | ||
177 | { | ||
178 | le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE); | ||
179 | |||
180 | whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, WUSBCMD_PERIODIC_EN); | ||
181 | whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, | ||
182 | WUSBSTS_PERIODIC_SCHED, WUSBSTS_PERIODIC_SCHED, | ||
183 | 1000, "start PZL"); | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * pzl_stop - stop the periodic schedule | ||
188 | * @whc: the WHCI host controller | ||
189 | */ | ||
190 | void pzl_stop(struct whc *whc) | ||
191 | { | ||
192 | whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, 0); | ||
193 | whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, | ||
194 | WUSBSTS_PERIODIC_SCHED, 0, | ||
195 | 1000, "stop PZL"); | ||
196 | } | ||
197 | |||
198 | void pzl_update(struct whc *whc, uint32_t wusbcmd) | ||
199 | { | ||
200 | whc_write_wusbcmd(whc, wusbcmd, wusbcmd); | ||
201 | wait_event(whc->periodic_list_wq, | ||
202 | (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0); | ||
203 | } | ||
204 | |||
205 | static void update_pzl_hw_view(struct whc *whc) | ||
206 | { | ||
207 | struct whc_qset *qset, *t; | ||
208 | int period; | ||
209 | u64 tmp_qh = 0; | ||
210 | |||
211 | for (period = 0; period < 5; period++) { | ||
212 | list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) { | ||
213 | whc_qset_set_link_ptr(&qset->qh.link, tmp_qh); | ||
214 | tmp_qh = qset->qset_dma; | ||
215 | qset->in_hw_list = true; | ||
216 | } | ||
217 | update_pzl_pointers(whc, period, tmp_qh); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | /** | ||
222 | * scan_periodic_work - scan the PZL for qsets to process. | ||
223 | * | ||
224 | * Process each qset in the PZL in turn and then signal the WHC that | ||
225 | * the PZL has been updated. | ||
226 | * | ||
227 | * Then start, stop or update the periodic schedule as required. | ||
228 | */ | ||
229 | void scan_periodic_work(struct work_struct *work) | ||
230 | { | ||
231 | struct whc *whc = container_of(work, struct whc, periodic_work); | ||
232 | struct whc_qset *qset, *t; | ||
233 | enum whc_update update = 0; | ||
234 | int period; | ||
235 | |||
236 | spin_lock_irq(&whc->lock); | ||
237 | |||
238 | dump_pzl(whc, "before processing"); | ||
239 | |||
240 | for (period = 4; period >= 0; period--) { | ||
241 | list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) { | ||
242 | if (!qset->in_hw_list) | ||
243 | update |= WHC_UPDATE_ADDED; | ||
244 | update |= pzl_process_qset(whc, qset); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED)) | ||
249 | update_pzl_hw_view(whc); | ||
250 | |||
251 | dump_pzl(whc, "after processing"); | ||
252 | |||
253 | spin_unlock_irq(&whc->lock); | ||
254 | |||
255 | if (update) { | ||
256 | uint32_t wusbcmd = WUSBCMD_PERIODIC_UPDATED | WUSBCMD_PERIODIC_SYNCED_DB; | ||
257 | if (update & WHC_UPDATE_REMOVED) | ||
258 | wusbcmd |= WUSBCMD_PERIODIC_QSET_RM; | ||
259 | pzl_update(whc, wusbcmd); | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * Now that the PZL is updated, complete the removal of any | ||
264 | * removed qsets. | ||
265 | */ | ||
266 | spin_lock(&whc->lock); | ||
267 | |||
268 | list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) { | ||
269 | qset_remove_complete(whc, qset); | ||
270 | } | ||
271 | |||
272 | spin_unlock(&whc->lock); | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * pzl_urb_enqueue - queue an URB onto the periodic list (PZL) | ||
277 | * @whc: the WHCI host controller | ||
278 | * @urb: the URB to enqueue | ||
279 | * @mem_flags: flags for any memory allocations | ||
280 | * | ||
281 | * The qset for the endpoint is obtained and the urb queued on to it. | ||
282 | * | ||
283 | * Work is scheduled to update the hardware's view of the PZL. | ||
284 | */ | ||
285 | int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags) | ||
286 | { | ||
287 | struct whc_qset *qset; | ||
288 | int err; | ||
289 | unsigned long flags; | ||
290 | |||
291 | spin_lock_irqsave(&whc->lock, flags); | ||
292 | |||
293 | qset = get_qset(whc, urb, GFP_ATOMIC); | ||
294 | if (qset == NULL) | ||
295 | err = -ENOMEM; | ||
296 | else | ||
297 | err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); | ||
298 | if (!err) { | ||
299 | usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); | ||
300 | if (!qset->in_sw_list) | ||
301 | qset_insert_in_sw_list(whc, qset); | ||
302 | } | ||
303 | |||
304 | spin_unlock_irqrestore(&whc->lock, flags); | ||
305 | |||
306 | if (!err) | ||
307 | queue_work(whc->workqueue, &whc->periodic_work); | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | /** | ||
313 | * pzl_urb_dequeue - remove an URB (qset) from the periodic list | ||
314 | * @whc: the WHCI host controller | ||
315 | * @urb: the URB to dequeue | ||
316 | * @status: the current status of the URB | ||
317 | * | ||
318 | * URBs that do yet have qTDs can simply be removed from the software | ||
319 | * queue, otherwise the qset must be removed so the qTDs can be safely | ||
320 | * removed. | ||
321 | */ | ||
322 | int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status) | ||
323 | { | ||
324 | struct whc_urb *wurb = urb->hcpriv; | ||
325 | struct whc_qset *qset = wurb->qset; | ||
326 | struct whc_std *std, *t; | ||
327 | int ret; | ||
328 | unsigned long flags; | ||
329 | |||
330 | spin_lock_irqsave(&whc->lock, flags); | ||
331 | |||
332 | ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status); | ||
333 | if (ret < 0) | ||
334 | goto out; | ||
335 | |||
336 | list_for_each_entry_safe(std, t, &qset->stds, list_node) { | ||
337 | if (std->urb == urb) | ||
338 | qset_free_std(whc, std); | ||
339 | else | ||
340 | std->qtd = NULL; /* so this std is re-added when the qset is */ | ||
341 | } | ||
342 | |||
343 | pzl_qset_remove(whc, qset); | ||
344 | wurb->status = status; | ||
345 | wurb->is_async = false; | ||
346 | queue_work(whc->workqueue, &wurb->dequeue_work); | ||
347 | |||
348 | out: | ||
349 | spin_unlock_irqrestore(&whc->lock, flags); | ||
350 | |||
351 | return ret; | ||
352 | } | ||
353 | |||
354 | /** | ||
355 | * pzl_qset_delete - delete a qset from the PZL | ||
356 | */ | ||
357 | void pzl_qset_delete(struct whc *whc, struct whc_qset *qset) | ||
358 | { | ||
359 | qset->remove = 1; | ||
360 | queue_work(whc->workqueue, &whc->periodic_work); | ||
361 | qset_delete(whc, qset); | ||
362 | } | ||
363 | |||
364 | |||
365 | /** | ||
366 | * pzl_init - initialize the periodic zone list | ||
367 | * @whc: the WHCI host controller | ||
368 | */ | ||
369 | int pzl_init(struct whc *whc) | ||
370 | { | ||
371 | int i; | ||
372 | |||
373 | whc->pz_list = dma_alloc_coherent(&whc->umc->dev, sizeof(u64) * 16, | ||
374 | &whc->pz_list_dma, GFP_KERNEL); | ||
375 | if (whc->pz_list == NULL) | ||
376 | return -ENOMEM; | ||
377 | |||
378 | /* Set T bit on all elements in PZL. */ | ||
379 | for (i = 0; i < 16; i++) | ||
380 | whc->pz_list[i] = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T); | ||
381 | |||
382 | le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE); | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | /** | ||
388 | * pzl_clean_up - free PZL resources | ||
389 | * @whc: the WHCI host controller | ||
390 | * | ||
391 | * The PZL is stopped and empty. | ||
392 | */ | ||
393 | void pzl_clean_up(struct whc *whc) | ||
394 | { | ||
395 | if (whc->pz_list) | ||
396 | dma_free_coherent(&whc->umc->dev, sizeof(u64) * 16, whc->pz_list, | ||
397 | whc->pz_list_dma); | ||
398 | } | ||
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c new file mode 100644 index 000000000000..0420037d2e18 --- /dev/null +++ b/drivers/usb/host/whci/qset.c | |||
@@ -0,0 +1,567 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) qset management. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/uwb/umc.h> | ||
21 | #include <linux/usb.h> | ||
22 | |||
23 | #include "../../wusbcore/wusbhc.h" | ||
24 | |||
25 | #include "whcd.h" | ||
26 | |||
27 | void dump_qset(struct whc_qset *qset, struct device *dev) | ||
28 | { | ||
29 | struct whc_std *std; | ||
30 | struct urb *urb = NULL; | ||
31 | int i; | ||
32 | |||
33 | dev_dbg(dev, "qset %08x\n", (u32)qset->qset_dma); | ||
34 | dev_dbg(dev, " -> %08x\n", (u32)qset->qh.link); | ||
35 | dev_dbg(dev, " info: %08x %08x %08x\n", | ||
36 | qset->qh.info1, qset->qh.info2, qset->qh.info3); | ||
37 | dev_dbg(dev, " sts: %04x errs: %d\n", qset->qh.status, qset->qh.err_count); | ||
38 | dev_dbg(dev, " TD: sts: %08x opts: %08x\n", | ||
39 | qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options); | ||
40 | |||
41 | for (i = 0; i < WHCI_QSET_TD_MAX; i++) { | ||
42 | dev_dbg(dev, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n", | ||
43 | i == qset->td_start ? 'S' : ' ', | ||
44 | i == qset->td_end ? 'E' : ' ', | ||
45 | i, qset->qtd[i].status, qset->qtd[i].options, | ||
46 | (u32)qset->qtd[i].page_list_ptr); | ||
47 | } | ||
48 | dev_dbg(dev, " ntds: %d\n", qset->ntds); | ||
49 | list_for_each_entry(std, &qset->stds, list_node) { | ||
50 | if (urb != std->urb) { | ||
51 | urb = std->urb; | ||
52 | dev_dbg(dev, " urb %p transferred: %d bytes\n", urb, | ||
53 | urb->actual_length); | ||
54 | } | ||
55 | if (std->qtd) | ||
56 | dev_dbg(dev, " sTD[%td]: %zu bytes @ %08x\n", | ||
57 | std->qtd - &qset->qtd[0], | ||
58 | std->len, std->num_pointers ? | ||
59 | (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); | ||
60 | else | ||
61 | dev_dbg(dev, " sTD[-]: %zd bytes @ %08x\n", | ||
62 | std->len, std->num_pointers ? | ||
63 | (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags) | ||
68 | { | ||
69 | struct whc_qset *qset; | ||
70 | dma_addr_t dma; | ||
71 | |||
72 | qset = dma_pool_alloc(whc->qset_pool, mem_flags, &dma); | ||
73 | if (qset == NULL) | ||
74 | return NULL; | ||
75 | memset(qset, 0, sizeof(struct whc_qset)); | ||
76 | |||
77 | qset->qset_dma = dma; | ||
78 | qset->whc = whc; | ||
79 | |||
80 | INIT_LIST_HEAD(&qset->list_node); | ||
81 | INIT_LIST_HEAD(&qset->stds); | ||
82 | |||
83 | return qset; | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * qset_fill_qh - fill the static endpoint state in a qset's QHead | ||
88 | * @qset: the qset whose QH needs initializing with static endpoint | ||
89 | * state | ||
90 | * @urb: an urb for a transfer to this endpoint | ||
91 | */ | ||
92 | static void qset_fill_qh(struct whc_qset *qset, struct urb *urb) | ||
93 | { | ||
94 | struct usb_device *usb_dev = urb->dev; | ||
95 | struct usb_wireless_ep_comp_descriptor *epcd; | ||
96 | bool is_out; | ||
97 | |||
98 | is_out = usb_pipeout(urb->pipe); | ||
99 | |||
100 | epcd = (struct usb_wireless_ep_comp_descriptor *)qset->ep->extra; | ||
101 | |||
102 | if (epcd) { | ||
103 | qset->max_seq = epcd->bMaxSequence; | ||
104 | qset->max_burst = epcd->bMaxBurst; | ||
105 | } else { | ||
106 | qset->max_seq = 2; | ||
107 | qset->max_burst = 1; | ||
108 | } | ||
109 | |||
110 | qset->qh.info1 = cpu_to_le32( | ||
111 | QH_INFO1_EP(usb_pipeendpoint(urb->pipe)) | ||
112 | | (is_out ? QH_INFO1_DIR_OUT : QH_INFO1_DIR_IN) | ||
113 | | usb_pipe_to_qh_type(urb->pipe) | ||
114 | | QH_INFO1_DEV_INFO_IDX(wusb_port_no_to_idx(usb_dev->portnum)) | ||
115 | | QH_INFO1_MAX_PKT_LEN(usb_maxpacket(urb->dev, urb->pipe, is_out)) | ||
116 | ); | ||
117 | qset->qh.info2 = cpu_to_le32( | ||
118 | QH_INFO2_BURST(qset->max_burst) | ||
119 | | QH_INFO2_DBP(0) | ||
120 | | QH_INFO2_MAX_COUNT(3) | ||
121 | | QH_INFO2_MAX_RETRY(3) | ||
122 | | QH_INFO2_MAX_SEQ(qset->max_seq - 1) | ||
123 | ); | ||
124 | /* FIXME: where can we obtain these Tx parameters from? Why | ||
125 | * doesn't the chip know what Tx power to use? It knows the Rx | ||
126 | * strength and can presumably guess the Tx power required | ||
127 | * from that? */ | ||
128 | qset->qh.info3 = cpu_to_le32( | ||
129 | QH_INFO3_TX_RATE_53_3 | ||
130 | | QH_INFO3_TX_PWR(0) /* 0 == max power */ | ||
131 | ); | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * qset_clear - clear fields in a qset so it may be reinserted into a | ||
136 | * schedule | ||
137 | */ | ||
138 | void qset_clear(struct whc *whc, struct whc_qset *qset) | ||
139 | { | ||
140 | qset->td_start = qset->td_end = qset->ntds = 0; | ||
141 | qset->remove = 0; | ||
142 | |||
143 | qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); | ||
144 | qset->qh.status = cpu_to_le16(QH_STATUS_ICUR(qset->td_start)); | ||
145 | qset->qh.err_count = 0; | ||
146 | qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); | ||
147 | qset->qh.scratch[0] = 0; | ||
148 | qset->qh.scratch[1] = 0; | ||
149 | qset->qh.scratch[2] = 0; | ||
150 | |||
151 | memset(&qset->qh.overlay, 0, sizeof(qset->qh.overlay)); | ||
152 | |||
153 | init_completion(&qset->remove_complete); | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * get_qset - get the qset for an async endpoint | ||
158 | * | ||
159 | * A new qset is created if one does not already exist. | ||
160 | */ | ||
161 | struct whc_qset *get_qset(struct whc *whc, struct urb *urb, | ||
162 | gfp_t mem_flags) | ||
163 | { | ||
164 | struct whc_qset *qset; | ||
165 | |||
166 | qset = urb->ep->hcpriv; | ||
167 | if (qset == NULL) { | ||
168 | qset = qset_alloc(whc, mem_flags); | ||
169 | if (qset == NULL) | ||
170 | return NULL; | ||
171 | |||
172 | qset->ep = urb->ep; | ||
173 | urb->ep->hcpriv = qset; | ||
174 | qset_fill_qh(qset, urb); | ||
175 | } | ||
176 | return qset; | ||
177 | } | ||
178 | |||
179 | void qset_remove_complete(struct whc *whc, struct whc_qset *qset) | ||
180 | { | ||
181 | list_del_init(&qset->list_node); | ||
182 | complete(&qset->remove_complete); | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * qset_add_qtds - add qTDs for an URB to a qset | ||
187 | * | ||
188 | * Returns true if the list (ASL/PZL) must be updated because (for a | ||
189 | * WHCI 0.95 controller) an activated qTD was pointed to be iCur. | ||
190 | */ | ||
191 | enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset) | ||
192 | { | ||
193 | struct whc_std *std; | ||
194 | enum whc_update update = 0; | ||
195 | |||
196 | list_for_each_entry(std, &qset->stds, list_node) { | ||
197 | struct whc_qtd *qtd; | ||
198 | uint32_t status; | ||
199 | |||
200 | if (qset->ntds >= WHCI_QSET_TD_MAX | ||
201 | || (qset->pause_after_urb && std->urb != qset->pause_after_urb)) | ||
202 | break; | ||
203 | |||
204 | if (std->qtd) | ||
205 | continue; /* already has a qTD */ | ||
206 | |||
207 | qtd = std->qtd = &qset->qtd[qset->td_end]; | ||
208 | |||
209 | /* Fill in setup bytes for control transfers. */ | ||
210 | if (usb_pipecontrol(std->urb->pipe)) | ||
211 | memcpy(qtd->setup, std->urb->setup_packet, 8); | ||
212 | |||
213 | status = QTD_STS_ACTIVE | QTD_STS_LEN(std->len); | ||
214 | |||
215 | if (whc_std_last(std) && usb_pipeout(std->urb->pipe)) | ||
216 | status |= QTD_STS_LAST_PKT; | ||
217 | |||
218 | /* | ||
219 | * For an IN transfer the iAlt field should be set so | ||
220 | * the h/w will automatically advance to the next | ||
221 | * transfer. However, if there are 8 or more TDs | ||
222 | * remaining in this transfer then iAlt cannot be set | ||
223 | * as it could point to somewhere in this transfer. | ||
224 | */ | ||
225 | if (std->ntds_remaining < WHCI_QSET_TD_MAX) { | ||
226 | int ialt; | ||
227 | ialt = (qset->td_end + std->ntds_remaining) % WHCI_QSET_TD_MAX; | ||
228 | status |= QTD_STS_IALT(ialt); | ||
229 | } else if (usb_pipein(std->urb->pipe)) | ||
230 | qset->pause_after_urb = std->urb; | ||
231 | |||
232 | if (std->num_pointers) | ||
233 | qtd->options = cpu_to_le32(QTD_OPT_IOC); | ||
234 | else | ||
235 | qtd->options = cpu_to_le32(QTD_OPT_IOC | QTD_OPT_SMALL); | ||
236 | qtd->page_list_ptr = cpu_to_le64(std->dma_addr); | ||
237 | |||
238 | qtd->status = cpu_to_le32(status); | ||
239 | |||
240 | if (QH_STATUS_TO_ICUR(qset->qh.status) == qset->td_end) | ||
241 | update = WHC_UPDATE_UPDATED; | ||
242 | |||
243 | if (++qset->td_end >= WHCI_QSET_TD_MAX) | ||
244 | qset->td_end = 0; | ||
245 | qset->ntds++; | ||
246 | } | ||
247 | |||
248 | return update; | ||
249 | } | ||
250 | |||
251 | /** | ||
252 | * qset_remove_qtd - remove the first qTD from a qset. | ||
253 | * | ||
254 | * The qTD might be still active (if it's part of a IN URB that | ||
255 | * resulted in a short read) so ensure it's deactivated. | ||
256 | */ | ||
257 | static void qset_remove_qtd(struct whc *whc, struct whc_qset *qset) | ||
258 | { | ||
259 | qset->qtd[qset->td_start].status = 0; | ||
260 | |||
261 | if (++qset->td_start >= WHCI_QSET_TD_MAX) | ||
262 | qset->td_start = 0; | ||
263 | qset->ntds--; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * qset_free_std - remove an sTD and free it. | ||
268 | * @whc: the WHCI host controller | ||
269 | * @std: the sTD to remove and free. | ||
270 | */ | ||
271 | void qset_free_std(struct whc *whc, struct whc_std *std) | ||
272 | { | ||
273 | list_del(&std->list_node); | ||
274 | if (std->num_pointers) { | ||
275 | dma_unmap_single(whc->wusbhc.dev, std->dma_addr, | ||
276 | std->num_pointers * sizeof(struct whc_page_list_entry), | ||
277 | DMA_TO_DEVICE); | ||
278 | kfree(std->pl_virt); | ||
279 | } | ||
280 | |||
281 | kfree(std); | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * qset_remove_qtds - remove an URB's qTDs (and sTDs). | ||
286 | */ | ||
287 | static void qset_remove_qtds(struct whc *whc, struct whc_qset *qset, | ||
288 | struct urb *urb) | ||
289 | { | ||
290 | struct whc_std *std, *t; | ||
291 | |||
292 | list_for_each_entry_safe(std, t, &qset->stds, list_node) { | ||
293 | if (std->urb != urb) | ||
294 | break; | ||
295 | if (std->qtd != NULL) | ||
296 | qset_remove_qtd(whc, qset); | ||
297 | qset_free_std(whc, std); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | /** | ||
302 | * qset_free_stds - free any remaining sTDs for an URB. | ||
303 | */ | ||
304 | static void qset_free_stds(struct whc_qset *qset, struct urb *urb) | ||
305 | { | ||
306 | struct whc_std *std, *t; | ||
307 | |||
308 | list_for_each_entry_safe(std, t, &qset->stds, list_node) { | ||
309 | if (std->urb == urb) | ||
310 | qset_free_std(qset->whc, std); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_flags) | ||
315 | { | ||
316 | dma_addr_t dma_addr = std->dma_addr; | ||
317 | dma_addr_t sp, ep; | ||
318 | size_t std_len = std->len; | ||
319 | size_t pl_len; | ||
320 | int p; | ||
321 | |||
322 | sp = ALIGN(dma_addr, WHCI_PAGE_SIZE); | ||
323 | ep = dma_addr + std_len; | ||
324 | std->num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE); | ||
325 | |||
326 | pl_len = std->num_pointers * sizeof(struct whc_page_list_entry); | ||
327 | std->pl_virt = kmalloc(pl_len, mem_flags); | ||
328 | if (std->pl_virt == NULL) | ||
329 | return -ENOMEM; | ||
330 | std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE); | ||
331 | |||
332 | for (p = 0; p < std->num_pointers; p++) { | ||
333 | std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr); | ||
334 | dma_addr = ALIGN(dma_addr + WHCI_PAGE_SIZE, WHCI_PAGE_SIZE); | ||
335 | } | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * urb_dequeue_work - executes asl/pzl update and gives back the urb to the system. | ||
342 | */ | ||
343 | static void urb_dequeue_work(struct work_struct *work) | ||
344 | { | ||
345 | struct whc_urb *wurb = container_of(work, struct whc_urb, dequeue_work); | ||
346 | struct whc_qset *qset = wurb->qset; | ||
347 | struct whc *whc = qset->whc; | ||
348 | unsigned long flags; | ||
349 | |||
350 | if (wurb->is_async == true) | ||
351 | asl_update(whc, WUSBCMD_ASYNC_UPDATED | ||
352 | | WUSBCMD_ASYNC_SYNCED_DB | ||
353 | | WUSBCMD_ASYNC_QSET_RM); | ||
354 | else | ||
355 | pzl_update(whc, WUSBCMD_PERIODIC_UPDATED | ||
356 | | WUSBCMD_PERIODIC_SYNCED_DB | ||
357 | | WUSBCMD_PERIODIC_QSET_RM); | ||
358 | |||
359 | spin_lock_irqsave(&whc->lock, flags); | ||
360 | qset_remove_urb(whc, qset, wurb->urb, wurb->status); | ||
361 | spin_unlock_irqrestore(&whc->lock, flags); | ||
362 | } | ||
363 | |||
364 | /** | ||
365 | * qset_add_urb - add an urb to the qset's queue. | ||
366 | * | ||
367 | * The URB is chopped into sTDs, one for each qTD that will required. | ||
368 | * At least one qTD (and sTD) is required even if the transfer has no | ||
369 | * data (e.g., for some control transfers). | ||
370 | */ | ||
371 | int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb, | ||
372 | gfp_t mem_flags) | ||
373 | { | ||
374 | struct whc_urb *wurb; | ||
375 | int remaining = urb->transfer_buffer_length; | ||
376 | u64 transfer_dma = urb->transfer_dma; | ||
377 | int ntds_remaining; | ||
378 | |||
379 | ntds_remaining = DIV_ROUND_UP(remaining, QTD_MAX_XFER_SIZE); | ||
380 | if (ntds_remaining == 0) | ||
381 | ntds_remaining = 1; | ||
382 | |||
383 | wurb = kzalloc(sizeof(struct whc_urb), mem_flags); | ||
384 | if (wurb == NULL) | ||
385 | goto err_no_mem; | ||
386 | urb->hcpriv = wurb; | ||
387 | wurb->qset = qset; | ||
388 | wurb->urb = urb; | ||
389 | INIT_WORK(&wurb->dequeue_work, urb_dequeue_work); | ||
390 | |||
391 | while (ntds_remaining) { | ||
392 | struct whc_std *std; | ||
393 | size_t std_len; | ||
394 | |||
395 | std = kmalloc(sizeof(struct whc_std), mem_flags); | ||
396 | if (std == NULL) | ||
397 | goto err_no_mem; | ||
398 | |||
399 | std_len = remaining; | ||
400 | if (std_len > QTD_MAX_XFER_SIZE) | ||
401 | std_len = QTD_MAX_XFER_SIZE; | ||
402 | |||
403 | std->urb = urb; | ||
404 | std->dma_addr = transfer_dma; | ||
405 | std->len = std_len; | ||
406 | std->ntds_remaining = ntds_remaining; | ||
407 | std->qtd = NULL; | ||
408 | |||
409 | INIT_LIST_HEAD(&std->list_node); | ||
410 | list_add_tail(&std->list_node, &qset->stds); | ||
411 | |||
412 | if (std_len > WHCI_PAGE_SIZE) { | ||
413 | if (qset_fill_page_list(whc, std, mem_flags) < 0) | ||
414 | goto err_no_mem; | ||
415 | } else | ||
416 | std->num_pointers = 0; | ||
417 | |||
418 | ntds_remaining--; | ||
419 | remaining -= std_len; | ||
420 | transfer_dma += std_len; | ||
421 | } | ||
422 | |||
423 | return 0; | ||
424 | |||
425 | err_no_mem: | ||
426 | qset_free_stds(qset, urb); | ||
427 | return -ENOMEM; | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * qset_remove_urb - remove an URB from the urb queue. | ||
432 | * | ||
433 | * The URB is returned to the USB subsystem. | ||
434 | */ | ||
435 | void qset_remove_urb(struct whc *whc, struct whc_qset *qset, | ||
436 | struct urb *urb, int status) | ||
437 | { | ||
438 | struct wusbhc *wusbhc = &whc->wusbhc; | ||
439 | struct whc_urb *wurb = urb->hcpriv; | ||
440 | |||
441 | usb_hcd_unlink_urb_from_ep(&wusbhc->usb_hcd, urb); | ||
442 | /* Drop the lock as urb->complete() may enqueue another urb. */ | ||
443 | spin_unlock(&whc->lock); | ||
444 | wusbhc_giveback_urb(wusbhc, urb, status); | ||
445 | spin_lock(&whc->lock); | ||
446 | |||
447 | kfree(wurb); | ||
448 | } | ||
449 | |||
450 | /** | ||
451 | * get_urb_status_from_qtd - get the completed urb status from qTD status | ||
452 | * @urb: completed urb | ||
453 | * @status: qTD status | ||
454 | */ | ||
455 | static int get_urb_status_from_qtd(struct urb *urb, u32 status) | ||
456 | { | ||
457 | if (status & QTD_STS_HALTED) { | ||
458 | if (status & QTD_STS_DBE) | ||
459 | return usb_pipein(urb->pipe) ? -ENOSR : -ECOMM; | ||
460 | else if (status & QTD_STS_BABBLE) | ||
461 | return -EOVERFLOW; | ||
462 | else if (status & QTD_STS_RCE) | ||
463 | return -ETIME; | ||
464 | return -EPIPE; | ||
465 | } | ||
466 | if (usb_pipein(urb->pipe) | ||
467 | && (urb->transfer_flags & URB_SHORT_NOT_OK) | ||
468 | && urb->actual_length < urb->transfer_buffer_length) | ||
469 | return -EREMOTEIO; | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | /** | ||
474 | * process_inactive_qtd - process an inactive (but not halted) qTD. | ||
475 | * | ||
476 | * Update the urb with the transfer bytes from the qTD, if the urb is | ||
477 | * completely transfered or (in the case of an IN only) the LPF is | ||
478 | * set, then the transfer is complete and the urb should be returned | ||
479 | * to the system. | ||
480 | */ | ||
481 | void process_inactive_qtd(struct whc *whc, struct whc_qset *qset, | ||
482 | struct whc_qtd *qtd) | ||
483 | { | ||
484 | struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node); | ||
485 | struct urb *urb = std->urb; | ||
486 | uint32_t status; | ||
487 | bool complete; | ||
488 | |||
489 | status = le32_to_cpu(qtd->status); | ||
490 | |||
491 | urb->actual_length += std->len - QTD_STS_TO_LEN(status); | ||
492 | |||
493 | if (usb_pipein(urb->pipe) && (status & QTD_STS_LAST_PKT)) | ||
494 | complete = true; | ||
495 | else | ||
496 | complete = whc_std_last(std); | ||
497 | |||
498 | qset_remove_qtd(whc, qset); | ||
499 | qset_free_std(whc, std); | ||
500 | |||
501 | /* | ||
502 | * Transfers for this URB are complete? Then return it to the | ||
503 | * USB subsystem. | ||
504 | */ | ||
505 | if (complete) { | ||
506 | qset_remove_qtds(whc, qset, urb); | ||
507 | qset_remove_urb(whc, qset, urb, get_urb_status_from_qtd(urb, status)); | ||
508 | |||
509 | /* | ||
510 | * If iAlt isn't valid then the hardware didn't | ||
511 | * advance iCur. Adjust the start and end pointers to | ||
512 | * match iCur. | ||
513 | */ | ||
514 | if (!(status & QTD_STS_IALT_VALID)) | ||
515 | qset->td_start = qset->td_end | ||
516 | = QH_STATUS_TO_ICUR(le16_to_cpu(qset->qh.status)); | ||
517 | qset->pause_after_urb = NULL; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | /** | ||
522 | * process_halted_qtd - process a qset with a halted qtd | ||
523 | * | ||
524 | * Remove all the qTDs for the failed URB and return the failed URB to | ||
525 | * the USB subsystem. Then remove all other qTDs so the qset can be | ||
526 | * removed. | ||
527 | * | ||
528 | * FIXME: this is the point where rate adaptation can be done. If a | ||
529 | * transfer failed because it exceeded the maximum number of retries | ||
530 | * then it could be reactivated with a slower rate without having to | ||
531 | * remove the qset. | ||
532 | */ | ||
533 | void process_halted_qtd(struct whc *whc, struct whc_qset *qset, | ||
534 | struct whc_qtd *qtd) | ||
535 | { | ||
536 | struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node); | ||
537 | struct urb *urb = std->urb; | ||
538 | int urb_status; | ||
539 | |||
540 | urb_status = get_urb_status_from_qtd(urb, le32_to_cpu(qtd->status)); | ||
541 | |||
542 | qset_remove_qtds(whc, qset, urb); | ||
543 | qset_remove_urb(whc, qset, urb, urb_status); | ||
544 | |||
545 | list_for_each_entry(std, &qset->stds, list_node) { | ||
546 | if (qset->ntds == 0) | ||
547 | break; | ||
548 | qset_remove_qtd(whc, qset); | ||
549 | std->qtd = NULL; | ||
550 | } | ||
551 | |||
552 | qset->remove = 1; | ||
553 | } | ||
554 | |||
555 | void qset_free(struct whc *whc, struct whc_qset *qset) | ||
556 | { | ||
557 | dma_pool_free(whc->qset_pool, qset, qset->qset_dma); | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * qset_delete - wait for a qset to be unused, then free it. | ||
562 | */ | ||
563 | void qset_delete(struct whc *whc, struct whc_qset *qset) | ||
564 | { | ||
565 | wait_for_completion(&qset->remove_complete); | ||
566 | qset_free(whc, qset); | ||
567 | } | ||
diff --git a/drivers/usb/host/whci/whcd.h b/drivers/usb/host/whci/whcd.h new file mode 100644 index 000000000000..1d2a53bd39fd --- /dev/null +++ b/drivers/usb/host/whci/whcd.h | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) private header. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA. | ||
19 | */ | ||
20 | #ifndef __WHCD_H | ||
21 | #define __WHCD_H | ||
22 | |||
23 | #include <linux/uwb/whci.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | |||
26 | #include "whci-hc.h" | ||
27 | |||
28 | /* Generic command timeout. */ | ||
29 | #define WHC_GENCMD_TIMEOUT_MS 100 | ||
30 | |||
31 | |||
32 | struct whc { | ||
33 | struct wusbhc wusbhc; | ||
34 | struct umc_dev *umc; | ||
35 | |||
36 | resource_size_t base_phys; | ||
37 | void __iomem *base; | ||
38 | int irq; | ||
39 | |||
40 | u8 n_devices; | ||
41 | u8 n_keys; | ||
42 | u8 n_mmc_ies; | ||
43 | |||
44 | u64 *pz_list; | ||
45 | struct dn_buf_entry *dn_buf; | ||
46 | struct di_buf_entry *di_buf; | ||
47 | dma_addr_t pz_list_dma; | ||
48 | dma_addr_t dn_buf_dma; | ||
49 | dma_addr_t di_buf_dma; | ||
50 | |||
51 | spinlock_t lock; | ||
52 | struct mutex mutex; | ||
53 | |||
54 | void * gen_cmd_buf; | ||
55 | dma_addr_t gen_cmd_buf_dma; | ||
56 | wait_queue_head_t cmd_wq; | ||
57 | |||
58 | struct workqueue_struct *workqueue; | ||
59 | struct work_struct dn_work; | ||
60 | |||
61 | struct dma_pool *qset_pool; | ||
62 | |||
63 | struct list_head async_list; | ||
64 | struct list_head async_removed_list; | ||
65 | wait_queue_head_t async_list_wq; | ||
66 | struct work_struct async_work; | ||
67 | |||
68 | struct list_head periodic_list[5]; | ||
69 | struct list_head periodic_removed_list; | ||
70 | wait_queue_head_t periodic_list_wq; | ||
71 | struct work_struct periodic_work; | ||
72 | }; | ||
73 | |||
74 | #define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc)) | ||
75 | |||
76 | /** | ||
77 | * struct whc_std - a software TD. | ||
78 | * @urb: the URB this sTD is for. | ||
79 | * @offset: start of the URB's data for this TD. | ||
80 | * @len: the length of data in the associated TD. | ||
81 | * @ntds_remaining: number of TDs (starting from this one) in this transfer. | ||
82 | * | ||
83 | * Queued URBs may require more TDs than are available in a qset so we | ||
84 | * use a list of these "software TDs" (sTDs) to hold per-TD data. | ||
85 | */ | ||
86 | struct whc_std { | ||
87 | struct urb *urb; | ||
88 | size_t len; | ||
89 | int ntds_remaining; | ||
90 | struct whc_qtd *qtd; | ||
91 | |||
92 | struct list_head list_node; | ||
93 | int num_pointers; | ||
94 | dma_addr_t dma_addr; | ||
95 | struct whc_page_list_entry *pl_virt; | ||
96 | }; | ||
97 | |||
98 | /** | ||
99 | * struct whc_urb - per URB host controller structure. | ||
100 | * @urb: the URB this struct is for. | ||
101 | * @qset: the qset associated to the URB. | ||
102 | * @dequeue_work: the work to remove the URB when dequeued. | ||
103 | * @is_async: the URB belongs to async sheduler or not. | ||
104 | * @status: the status to be returned when calling wusbhc_giveback_urb. | ||
105 | */ | ||
106 | struct whc_urb { | ||
107 | struct urb *urb; | ||
108 | struct whc_qset *qset; | ||
109 | struct work_struct dequeue_work; | ||
110 | bool is_async; | ||
111 | int status; | ||
112 | }; | ||
113 | |||
114 | /** | ||
115 | * whc_std_last - is this sTD the URB's last? | ||
116 | * @std: the sTD to check. | ||
117 | */ | ||
118 | static inline bool whc_std_last(struct whc_std *std) | ||
119 | { | ||
120 | return std->ntds_remaining <= 1; | ||
121 | } | ||
122 | |||
123 | enum whc_update { | ||
124 | WHC_UPDATE_ADDED = 0x01, | ||
125 | WHC_UPDATE_REMOVED = 0x02, | ||
126 | WHC_UPDATE_UPDATED = 0x04, | ||
127 | }; | ||
128 | |||
129 | /* init.c */ | ||
130 | int whc_init(struct whc *whc); | ||
131 | void whc_clean_up(struct whc *whc); | ||
132 | |||
133 | /* hw.c */ | ||
134 | void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val); | ||
135 | int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len); | ||
136 | |||
137 | /* wusb.c */ | ||
138 | int whc_wusbhc_start(struct wusbhc *wusbhc); | ||
139 | void whc_wusbhc_stop(struct wusbhc *wusbhc); | ||
140 | int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, | ||
141 | u8 handle, struct wuie_hdr *wuie); | ||
142 | int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle); | ||
143 | int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm); | ||
144 | int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev); | ||
145 | int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots); | ||
146 | int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, | ||
147 | const void *ptk, size_t key_size); | ||
148 | int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid, | ||
149 | const void *gtk, size_t key_size); | ||
150 | int whc_set_cluster_id(struct whc *whc, u8 bcid); | ||
151 | |||
152 | /* int.c */ | ||
153 | irqreturn_t whc_int_handler(struct usb_hcd *hcd); | ||
154 | void whc_dn_work(struct work_struct *work); | ||
155 | |||
156 | /* asl.c */ | ||
157 | void asl_start(struct whc *whc); | ||
158 | void asl_stop(struct whc *whc); | ||
159 | int asl_init(struct whc *whc); | ||
160 | void asl_clean_up(struct whc *whc); | ||
161 | int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags); | ||
162 | int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status); | ||
163 | void asl_qset_delete(struct whc *whc, struct whc_qset *qset); | ||
164 | void scan_async_work(struct work_struct *work); | ||
165 | |||
166 | /* pzl.c */ | ||
167 | int pzl_init(struct whc *whc); | ||
168 | void pzl_clean_up(struct whc *whc); | ||
169 | void pzl_start(struct whc *whc); | ||
170 | void pzl_stop(struct whc *whc); | ||
171 | int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags); | ||
172 | int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status); | ||
173 | void pzl_qset_delete(struct whc *whc, struct whc_qset *qset); | ||
174 | void scan_periodic_work(struct work_struct *work); | ||
175 | |||
176 | /* qset.c */ | ||
177 | struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags); | ||
178 | void qset_free(struct whc *whc, struct whc_qset *qset); | ||
179 | struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags); | ||
180 | void qset_delete(struct whc *whc, struct whc_qset *qset); | ||
181 | void qset_clear(struct whc *whc, struct whc_qset *qset); | ||
182 | int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb, | ||
183 | gfp_t mem_flags); | ||
184 | void qset_free_std(struct whc *whc, struct whc_std *std); | ||
185 | void qset_remove_urb(struct whc *whc, struct whc_qset *qset, | ||
186 | struct urb *urb, int status); | ||
187 | void process_halted_qtd(struct whc *whc, struct whc_qset *qset, | ||
188 | struct whc_qtd *qtd); | ||
189 | void process_inactive_qtd(struct whc *whc, struct whc_qset *qset, | ||
190 | struct whc_qtd *qtd); | ||
191 | enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset); | ||
192 | void qset_remove_complete(struct whc *whc, struct whc_qset *qset); | ||
193 | void dump_qset(struct whc_qset *qset, struct device *dev); | ||
194 | void pzl_update(struct whc *whc, uint32_t wusbcmd); | ||
195 | void asl_update(struct whc *whc, uint32_t wusbcmd); | ||
196 | |||
197 | #endif /* #ifndef __WHCD_H */ | ||
diff --git a/drivers/usb/host/whci/whci-hc.h b/drivers/usb/host/whci/whci-hc.h new file mode 100644 index 000000000000..bff1eb7a35cf --- /dev/null +++ b/drivers/usb/host/whci/whci-hc.h | |||
@@ -0,0 +1,416 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) data structures. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA. | ||
19 | */ | ||
20 | #ifndef _WHCI_WHCI_HC_H | ||
21 | #define _WHCI_WHCI_HC_H | ||
22 | |||
23 | #include <linux/list.h> | ||
24 | |||
25 | /** | ||
26 | * WHCI_PAGE_SIZE - page size use by WHCI | ||
27 | * | ||
28 | * WHCI assumes that host system uses pages of 4096 octets. | ||
29 | */ | ||
30 | #define WHCI_PAGE_SIZE 4096 | ||
31 | |||
32 | |||
33 | /** | ||
34 | * QTD_MAX_TXFER_SIZE - max number of bytes to transfer with a single | ||
35 | * qtd. | ||
36 | * | ||
37 | * This is 2^20 - 1. | ||
38 | */ | ||
39 | #define QTD_MAX_XFER_SIZE 1048575 | ||
40 | |||
41 | |||
42 | /** | ||
43 | * struct whc_qtd - Queue Element Transfer Descriptors (qTD) | ||
44 | * | ||
45 | * This describes the data for a bulk, control or interrupt transfer. | ||
46 | * | ||
47 | * [WHCI] section 3.2.4 | ||
48 | */ | ||
49 | struct whc_qtd { | ||
50 | __le32 status; /*< remaining transfer len and transfer status */ | ||
51 | __le32 options; | ||
52 | __le64 page_list_ptr; /*< physical pointer to data buffer page list*/ | ||
53 | __u8 setup[8]; /*< setup data for control transfers */ | ||
54 | } __attribute__((packed)); | ||
55 | |||
56 | #define QTD_STS_ACTIVE (1 << 31) /* enable execution of transaction */ | ||
57 | #define QTD_STS_HALTED (1 << 30) /* transfer halted */ | ||
58 | #define QTD_STS_DBE (1 << 29) /* data buffer error */ | ||
59 | #define QTD_STS_BABBLE (1 << 28) /* babble detected */ | ||
60 | #define QTD_STS_RCE (1 << 27) /* retry count exceeded */ | ||
61 | #define QTD_STS_LAST_PKT (1 << 26) /* set Last Packet Flag in WUSB header */ | ||
62 | #define QTD_STS_INACTIVE (1 << 25) /* queue set is marked inactive */ | ||
63 | #define QTD_STS_IALT_VALID (1 << 23) /* iAlt field is valid */ | ||
64 | #define QTD_STS_IALT(i) (QTD_STS_IALT_VALID | ((i) << 20)) /* iAlt field */ | ||
65 | #define QTD_STS_LEN(l) ((l) << 0) /* transfer length */ | ||
66 | #define QTD_STS_TO_LEN(s) ((s) & 0x000fffff) | ||
67 | |||
68 | #define QTD_OPT_IOC (1 << 1) /* page_list_ptr points to buffer directly */ | ||
69 | #define QTD_OPT_SMALL (1 << 0) /* interrupt on complete */ | ||
70 | |||
71 | /** | ||
72 | * struct whc_itd - Isochronous Queue Element Transfer Descriptors (iTD) | ||
73 | * | ||
74 | * This describes the data and other parameters for an isochronous | ||
75 | * transfer. | ||
76 | * | ||
77 | * [WHCI] section 3.2.5 | ||
78 | */ | ||
79 | struct whc_itd { | ||
80 | __le16 presentation_time; /*< presentation time for OUT transfers */ | ||
81 | __u8 num_segments; /*< number of data segments in segment list */ | ||
82 | __u8 status; /*< command execution status */ | ||
83 | __le32 options; /*< misc transfer options */ | ||
84 | __le64 page_list_ptr; /*< physical pointer to data buffer page list */ | ||
85 | __le64 seg_list_ptr; /*< physical pointer to segment list */ | ||
86 | } __attribute__((packed)); | ||
87 | |||
88 | #define ITD_STS_ACTIVE (1 << 7) /* enable execution of transaction */ | ||
89 | #define ITD_STS_DBE (1 << 5) /* data buffer error */ | ||
90 | #define ITD_STS_BABBLE (1 << 4) /* babble detected */ | ||
91 | #define ITD_STS_INACTIVE (1 << 1) /* queue set is marked inactive */ | ||
92 | |||
93 | #define ITD_OPT_IOC (1 << 1) /* interrupt on complete */ | ||
94 | #define ITD_OPT_SMALL (1 << 0) /* page_list_ptr points to buffer directly */ | ||
95 | |||
96 | /** | ||
97 | * Page list entry. | ||
98 | * | ||
99 | * A TD's page list must contain sufficient page list entries for the | ||
100 | * total data length in the TD. | ||
101 | * | ||
102 | * [WHCI] section 3.2.4.3 | ||
103 | */ | ||
104 | struct whc_page_list_entry { | ||
105 | __le64 buf_ptr; /*< physical pointer to buffer */ | ||
106 | } __attribute__((packed)); | ||
107 | |||
108 | /** | ||
109 | * struct whc_seg_list_entry - Segment list entry. | ||
110 | * | ||
111 | * Describes a portion of the data buffer described in the containing | ||
112 | * qTD's page list. | ||
113 | * | ||
114 | * seg_ptr = qtd->page_list_ptr[qtd->seg_list_ptr[seg].idx].buf_ptr | ||
115 | * + qtd->seg_list_ptr[seg].offset; | ||
116 | * | ||
117 | * Segments can't cross page boundries. | ||
118 | * | ||
119 | * [WHCI] section 3.2.5.5 | ||
120 | */ | ||
121 | struct whc_seg_list_entry { | ||
122 | __le16 len; /*< segment length */ | ||
123 | __u8 idx; /*< index into page list */ | ||
124 | __u8 status; /*< segment status */ | ||
125 | __le16 offset; /*< 12 bit offset into page */ | ||
126 | } __attribute__((packed)); | ||
127 | |||
128 | /** | ||
129 | * struct whc_qhead - endpoint and status information for a qset. | ||
130 | * | ||
131 | * [WHCI] section 3.2.6 | ||
132 | */ | ||
133 | struct whc_qhead { | ||
134 | __le64 link; /*< next qset in list */ | ||
135 | __le32 info1; | ||
136 | __le32 info2; | ||
137 | __le32 info3; | ||
138 | __le16 status; | ||
139 | __le16 err_count; /*< transaction error count */ | ||
140 | __le32 cur_window; | ||
141 | __le32 scratch[3]; /*< h/w scratch area */ | ||
142 | union { | ||
143 | struct whc_qtd qtd; | ||
144 | struct whc_itd itd; | ||
145 | } overlay; | ||
146 | } __attribute__((packed)); | ||
147 | |||
148 | #define QH_LINK_PTR_MASK (~0x03Full) | ||
149 | #define QH_LINK_PTR(ptr) ((ptr) & QH_LINK_PTR_MASK) | ||
150 | #define QH_LINK_IQS (1 << 4) /* isochronous queue set */ | ||
151 | #define QH_LINK_NTDS(n) (((n) - 1) << 1) /* number of TDs in queue set */ | ||
152 | #define QH_LINK_T (1 << 0) /* last queue set in periodic schedule list */ | ||
153 | |||
154 | #define QH_INFO1_EP(e) ((e) << 0) /* endpoint number */ | ||
155 | #define QH_INFO1_DIR_IN (1 << 4) /* IN transfer */ | ||
156 | #define QH_INFO1_DIR_OUT (0 << 4) /* OUT transfer */ | ||
157 | #define QH_INFO1_TR_TYPE_CTRL (0x0 << 5) /* control transfer */ | ||
158 | #define QH_INFO1_TR_TYPE_ISOC (0x1 << 5) /* isochronous transfer */ | ||
159 | #define QH_INFO1_TR_TYPE_BULK (0x2 << 5) /* bulk transfer */ | ||
160 | #define QH_INFO1_TR_TYPE_INT (0x3 << 5) /* interrupt */ | ||
161 | #define QH_INFO1_TR_TYPE_LP_INT (0x7 << 5) /* low power interrupt */ | ||
162 | #define QH_INFO1_DEV_INFO_IDX(i) ((i) << 8) /* index into device info buffer */ | ||
163 | #define QH_INFO1_SET_INACTIVE (1 << 15) /* set inactive after transfer */ | ||
164 | #define QH_INFO1_MAX_PKT_LEN(l) ((l) << 16) /* maximum packet length */ | ||
165 | |||
166 | #define QH_INFO2_BURST(b) ((b) << 0) /* maximum burst length */ | ||
167 | #define QH_INFO2_DBP(p) ((p) << 5) /* data burst policy (see [WUSB] table 5-7) */ | ||
168 | #define QH_INFO2_MAX_COUNT(c) ((c) << 8) /* max isoc/int pkts per zone */ | ||
169 | #define QH_INFO2_RQS (1 << 15) /* reactivate queue set */ | ||
170 | #define QH_INFO2_MAX_RETRY(r) ((r) << 16) /* maximum transaction retries */ | ||
171 | #define QH_INFO2_MAX_SEQ(s) ((s) << 20) /* maximum sequence number */ | ||
172 | #define QH_INFO3_MAX_DELAY(d) ((d) << 0) /* maximum stream delay in 125 us units (isoc only) */ | ||
173 | #define QH_INFO3_INTERVAL(i) ((i) << 16) /* segment interval in 125 us units (isoc only) */ | ||
174 | |||
175 | #define QH_INFO3_TX_RATE_53_3 (0 << 24) | ||
176 | #define QH_INFO3_TX_RATE_80 (1 << 24) | ||
177 | #define QH_INFO3_TX_RATE_106_7 (2 << 24) | ||
178 | #define QH_INFO3_TX_RATE_160 (3 << 24) | ||
179 | #define QH_INFO3_TX_RATE_200 (4 << 24) | ||
180 | #define QH_INFO3_TX_RATE_320 (5 << 24) | ||
181 | #define QH_INFO3_TX_RATE_400 (6 << 24) | ||
182 | #define QH_INFO3_TX_RATE_480 (7 << 24) | ||
183 | #define QH_INFO3_TX_PWR(p) ((p) << 29) /* transmit power (see [WUSB] section 5.2.1.2) */ | ||
184 | |||
185 | #define QH_STATUS_FLOW_CTRL (1 << 15) | ||
186 | #define QH_STATUS_ICUR(i) ((i) << 5) | ||
187 | #define QH_STATUS_TO_ICUR(s) (((s) >> 5) & 0x7) | ||
188 | |||
189 | /** | ||
190 | * usb_pipe_to_qh_type - USB core pipe type to QH transfer type | ||
191 | * | ||
192 | * Returns the QH type field for a USB core pipe type. | ||
193 | */ | ||
194 | static inline unsigned usb_pipe_to_qh_type(unsigned pipe) | ||
195 | { | ||
196 | static const unsigned type[] = { | ||
197 | [PIPE_ISOCHRONOUS] = QH_INFO1_TR_TYPE_ISOC, | ||
198 | [PIPE_INTERRUPT] = QH_INFO1_TR_TYPE_INT, | ||
199 | [PIPE_CONTROL] = QH_INFO1_TR_TYPE_CTRL, | ||
200 | [PIPE_BULK] = QH_INFO1_TR_TYPE_BULK, | ||
201 | }; | ||
202 | return type[usb_pipetype(pipe)]; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * Maxiumum number of TDs in a qset. | ||
207 | */ | ||
208 | #define WHCI_QSET_TD_MAX 8 | ||
209 | |||
210 | /** | ||
211 | * struct whc_qset - WUSB data transfers to a specific endpoint | ||
212 | * @qh: the QHead of this qset | ||
213 | * @qtd: up to 8 qTDs (for qsets for control, bulk and interrupt | ||
214 | * transfers) | ||
215 | * @itd: up to 8 iTDs (for qsets for isochronous transfers) | ||
216 | * @qset_dma: DMA address for this qset | ||
217 | * @whc: WHCI HC this qset is for | ||
218 | * @ep: endpoint | ||
219 | * @stds: list of sTDs queued to this qset | ||
220 | * @ntds: number of qTDs queued (not necessarily the same as nTDs | ||
221 | * field in the QH) | ||
222 | * @td_start: index of the first qTD in the list | ||
223 | * @td_end: index of next free qTD in the list (provided | ||
224 | * ntds < WHCI_QSET_TD_MAX) | ||
225 | * | ||
226 | * Queue Sets (qsets) are added to the asynchronous schedule list | ||
227 | * (ASL) or the periodic zone list (PZL). | ||
228 | * | ||
229 | * qsets may contain up to 8 TDs (either qTDs or iTDs as appropriate). | ||
230 | * Each TD may refer to at most 1 MiB of data. If a single transfer | ||
231 | * has > 8MiB of data, TDs can be reused as they are completed since | ||
232 | * the TD list is used as a circular buffer. Similarly, several | ||
233 | * (smaller) transfers may be queued in a qset. | ||
234 | * | ||
235 | * WHCI controllers may cache portions of the qsets in the ASL and | ||
236 | * PZL, requiring the WHCD to inform the WHC that the lists have been | ||
237 | * updated (fields changed or qsets inserted or removed). For safe | ||
238 | * insertion and removal of qsets from the lists the schedule must be | ||
239 | * stopped to avoid races in updating the QH link pointers. | ||
240 | * | ||
241 | * Since the HC is free to execute qsets in any order, all transfers | ||
242 | * to an endpoint should use the same qset to ensure transfers are | ||
243 | * executed in the order they're submitted. | ||
244 | * | ||
245 | * [WHCI] section 3.2.3 | ||
246 | */ | ||
247 | struct whc_qset { | ||
248 | struct whc_qhead qh; | ||
249 | union { | ||
250 | struct whc_qtd qtd[WHCI_QSET_TD_MAX]; | ||
251 | struct whc_itd itd[WHCI_QSET_TD_MAX]; | ||
252 | }; | ||
253 | |||
254 | /* private data for WHCD */ | ||
255 | dma_addr_t qset_dma; | ||
256 | struct whc *whc; | ||
257 | struct usb_host_endpoint *ep; | ||
258 | struct list_head stds; | ||
259 | int ntds; | ||
260 | int td_start; | ||
261 | int td_end; | ||
262 | struct list_head list_node; | ||
263 | unsigned in_sw_list:1; | ||
264 | unsigned in_hw_list:1; | ||
265 | unsigned remove:1; | ||
266 | struct urb *pause_after_urb; | ||
267 | struct completion remove_complete; | ||
268 | int max_burst; | ||
269 | int max_seq; | ||
270 | }; | ||
271 | |||
272 | static inline void whc_qset_set_link_ptr(u64 *ptr, u64 target) | ||
273 | { | ||
274 | if (target) | ||
275 | *ptr = (*ptr & ~(QH_LINK_PTR_MASK | QH_LINK_T)) | QH_LINK_PTR(target); | ||
276 | else | ||
277 | *ptr = QH_LINK_T; | ||
278 | } | ||
279 | |||
280 | /** | ||
281 | * struct di_buf_entry - Device Information (DI) buffer entry. | ||
282 | * | ||
283 | * There's one of these per connected device. | ||
284 | */ | ||
285 | struct di_buf_entry { | ||
286 | __le32 availability_info[8]; /*< MAS availability information, one MAS per bit */ | ||
287 | __le32 addr_sec_info; /*< addressing and security info */ | ||
288 | __le32 reserved[7]; | ||
289 | } __attribute__((packed)); | ||
290 | |||
291 | #define WHC_DI_SECURE (1 << 31) | ||
292 | #define WHC_DI_DISABLE (1 << 30) | ||
293 | #define WHC_DI_KEY_IDX(k) ((k) << 8) | ||
294 | #define WHC_DI_KEY_IDX_MASK 0x0000ff00 | ||
295 | #define WHC_DI_DEV_ADDR(a) ((a) << 0) | ||
296 | #define WHC_DI_DEV_ADDR_MASK 0x000000ff | ||
297 | |||
298 | /** | ||
299 | * struct dn_buf_entry - Device Notification (DN) buffer entry. | ||
300 | * | ||
301 | * [WHCI] section 3.2.8 | ||
302 | */ | ||
303 | struct dn_buf_entry { | ||
304 | __u8 msg_size; /*< number of octets of valid DN data */ | ||
305 | __u8 reserved1; | ||
306 | __u8 src_addr; /*< source address */ | ||
307 | __u8 status; /*< buffer entry status */ | ||
308 | __le32 tkid; /*< TKID for source device, valid if secure bit is set */ | ||
309 | __u8 dn_data[56]; /*< up to 56 octets of DN data */ | ||
310 | } __attribute__((packed)); | ||
311 | |||
312 | #define WHC_DN_STATUS_VALID (1 << 7) /* buffer entry is valid */ | ||
313 | #define WHC_DN_STATUS_SECURE (1 << 6) /* notification received using secure frame */ | ||
314 | |||
315 | #define WHC_N_DN_ENTRIES (4096 / sizeof(struct dn_buf_entry)) | ||
316 | |||
317 | /* The Add MMC IE WUSB Generic Command may take up to 256 bytes of | ||
318 | data. [WHCI] section 2.4.7. */ | ||
319 | #define WHC_GEN_CMD_DATA_LEN 256 | ||
320 | |||
321 | /* | ||
322 | * HC registers. | ||
323 | * | ||
324 | * [WHCI] section 2.4 | ||
325 | */ | ||
326 | |||
327 | #define WHCIVERSION 0x00 | ||
328 | |||
329 | #define WHCSPARAMS 0x04 | ||
330 | # define WHCSPARAMS_TO_N_MMC_IES(p) (((p) >> 16) & 0xff) | ||
331 | # define WHCSPARAMS_TO_N_KEYS(p) (((p) >> 8) & 0xff) | ||
332 | # define WHCSPARAMS_TO_N_DEVICES(p) (((p) >> 0) & 0x7f) | ||
333 | |||
334 | #define WUSBCMD 0x08 | ||
335 | # define WUSBCMD_BCID(b) ((b) << 16) | ||
336 | # define WUSBCMD_BCID_MASK (0xff << 16) | ||
337 | # define WUSBCMD_ASYNC_QSET_RM (1 << 12) | ||
338 | # define WUSBCMD_PERIODIC_QSET_RM (1 << 11) | ||
339 | # define WUSBCMD_WUSBSI(s) ((s) << 8) | ||
340 | # define WUSBCMD_WUSBSI_MASK (0x7 << 8) | ||
341 | # define WUSBCMD_ASYNC_SYNCED_DB (1 << 7) | ||
342 | # define WUSBCMD_PERIODIC_SYNCED_DB (1 << 6) | ||
343 | # define WUSBCMD_ASYNC_UPDATED (1 << 5) | ||
344 | # define WUSBCMD_PERIODIC_UPDATED (1 << 4) | ||
345 | # define WUSBCMD_ASYNC_EN (1 << 3) | ||
346 | # define WUSBCMD_PERIODIC_EN (1 << 2) | ||
347 | # define WUSBCMD_WHCRESET (1 << 1) | ||
348 | # define WUSBCMD_RUN (1 << 0) | ||
349 | |||
350 | #define WUSBSTS 0x0c | ||
351 | # define WUSBSTS_ASYNC_SCHED (1 << 15) | ||
352 | # define WUSBSTS_PERIODIC_SCHED (1 << 14) | ||
353 | # define WUSBSTS_DNTS_SCHED (1 << 13) | ||
354 | # define WUSBSTS_HCHALTED (1 << 12) | ||
355 | # define WUSBSTS_GEN_CMD_DONE (1 << 9) | ||
356 | # define WUSBSTS_CHAN_TIME_ROLLOVER (1 << 8) | ||
357 | # define WUSBSTS_DNTS_OVERFLOW (1 << 7) | ||
358 | # define WUSBSTS_BPST_ADJUSTMENT_CHANGED (1 << 6) | ||
359 | # define WUSBSTS_HOST_ERR (1 << 5) | ||
360 | # define WUSBSTS_ASYNC_SCHED_SYNCED (1 << 4) | ||
361 | # define WUSBSTS_PERIODIC_SCHED_SYNCED (1 << 3) | ||
362 | # define WUSBSTS_DNTS_INT (1 << 2) | ||
363 | # define WUSBSTS_ERR_INT (1 << 1) | ||
364 | # define WUSBSTS_INT (1 << 0) | ||
365 | # define WUSBSTS_INT_MASK 0x3ff | ||
366 | |||
367 | #define WUSBINTR 0x10 | ||
368 | # define WUSBINTR_GEN_CMD_DONE (1 << 9) | ||
369 | # define WUSBINTR_CHAN_TIME_ROLLOVER (1 << 8) | ||
370 | # define WUSBINTR_DNTS_OVERFLOW (1 << 7) | ||
371 | # define WUSBINTR_BPST_ADJUSTMENT_CHANGED (1 << 6) | ||
372 | # define WUSBINTR_HOST_ERR (1 << 5) | ||
373 | # define WUSBINTR_ASYNC_SCHED_SYNCED (1 << 4) | ||
374 | # define WUSBINTR_PERIODIC_SCHED_SYNCED (1 << 3) | ||
375 | # define WUSBINTR_DNTS_INT (1 << 2) | ||
376 | # define WUSBINTR_ERR_INT (1 << 1) | ||
377 | # define WUSBINTR_INT (1 << 0) | ||
378 | # define WUSBINTR_ALL 0x3ff | ||
379 | |||
380 | #define WUSBGENCMDSTS 0x14 | ||
381 | # define WUSBGENCMDSTS_ACTIVE (1 << 31) | ||
382 | # define WUSBGENCMDSTS_ERROR (1 << 24) | ||
383 | # define WUSBGENCMDSTS_IOC (1 << 23) | ||
384 | # define WUSBGENCMDSTS_MMCIE_ADD 0x01 | ||
385 | # define WUSBGENCMDSTS_MMCIE_RM 0x02 | ||
386 | # define WUSBGENCMDSTS_SET_MAS 0x03 | ||
387 | # define WUSBGENCMDSTS_CHAN_STOP 0x04 | ||
388 | # define WUSBGENCMDSTS_RWP_EN 0x05 | ||
389 | |||
390 | #define WUSBGENCMDPARAMS 0x18 | ||
391 | #define WUSBGENADDR 0x20 | ||
392 | #define WUSBASYNCLISTADDR 0x28 | ||
393 | #define WUSBDNTSBUFADDR 0x30 | ||
394 | #define WUSBDEVICEINFOADDR 0x38 | ||
395 | |||
396 | #define WUSBSETSECKEYCMD 0x40 | ||
397 | # define WUSBSETSECKEYCMD_SET (1 << 31) | ||
398 | # define WUSBSETSECKEYCMD_ERASE (1 << 30) | ||
399 | # define WUSBSETSECKEYCMD_GTK (1 << 8) | ||
400 | # define WUSBSETSECKEYCMD_IDX(i) ((i) << 0) | ||
401 | |||
402 | #define WUSBTKID 0x44 | ||
403 | #define WUSBSECKEY 0x48 | ||
404 | #define WUSBPERIODICLISTBASE 0x58 | ||
405 | #define WUSBMASINDEX 0x60 | ||
406 | |||
407 | #define WUSBDNTSCTRL 0x64 | ||
408 | # define WUSBDNTSCTRL_ACTIVE (1 << 31) | ||
409 | # define WUSBDNTSCTRL_INTERVAL(i) ((i) << 8) | ||
410 | # define WUSBDNTSCTRL_SLOTS(s) ((s) << 0) | ||
411 | |||
412 | #define WUSBTIME 0x68 | ||
413 | #define WUSBBPST 0x6c | ||
414 | #define WUSBDIBUPDATED 0x70 | ||
415 | |||
416 | #endif /* #ifndef _WHCI_WHCI_HC_H */ | ||
diff --git a/drivers/usb/host/whci/wusb.c b/drivers/usb/host/whci/wusb.c new file mode 100644 index 000000000000..66e4ddcd961d --- /dev/null +++ b/drivers/usb/host/whci/wusb.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) WUSB operations. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/uwb/umc.h> | ||
22 | #define D_LOCAL 1 | ||
23 | #include <linux/uwb/debug.h> | ||
24 | |||
25 | #include "../../wusbcore/wusbhc.h" | ||
26 | |||
27 | #include "whcd.h" | ||
28 | |||
29 | #if D_LOCAL >= 1 | ||
30 | static void dump_di(struct whc *whc, int idx) | ||
31 | { | ||
32 | struct di_buf_entry *di = &whc->di_buf[idx]; | ||
33 | struct device *dev = &whc->umc->dev; | ||
34 | char buf[128]; | ||
35 | |||
36 | bitmap_scnprintf(buf, sizeof(buf), (unsigned long *)di->availability_info, UWB_NUM_MAS); | ||
37 | |||
38 | d_printf(1, dev, "DI[%d]\n", idx); | ||
39 | d_printf(1, dev, " availability: %s\n", buf); | ||
40 | d_printf(1, dev, " %c%c key idx: %d dev addr: %d\n", | ||
41 | (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ', | ||
42 | (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ', | ||
43 | (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8, | ||
44 | (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK)); | ||
45 | } | ||
46 | #else | ||
47 | static inline void dump_di(struct whc *whc, int idx) | ||
48 | { | ||
49 | } | ||
50 | #endif | ||
51 | |||
52 | static int whc_update_di(struct whc *whc, int idx) | ||
53 | { | ||
54 | int offset = idx / 32; | ||
55 | u32 bit = 1 << (idx % 32); | ||
56 | |||
57 | dump_di(whc, idx); | ||
58 | |||
59 | le_writel(bit, whc->base + WUSBDIBUPDATED + offset); | ||
60 | |||
61 | return whci_wait_for(&whc->umc->dev, | ||
62 | whc->base + WUSBDIBUPDATED + offset, bit, 0, | ||
63 | 100, "DI update"); | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * WHCI starts and stops MMCs based on there being a valid GTK so | ||
68 | * these need only start/stop the asynchronous and periodic schedules. | ||
69 | */ | ||
70 | |||
71 | int whc_wusbhc_start(struct wusbhc *wusbhc) | ||
72 | { | ||
73 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
74 | |||
75 | asl_start(whc); | ||
76 | pzl_start(whc); | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | void whc_wusbhc_stop(struct wusbhc *wusbhc) | ||
82 | { | ||
83 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
84 | |||
85 | pzl_stop(whc); | ||
86 | asl_stop(whc); | ||
87 | } | ||
88 | |||
89 | int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, | ||
90 | u8 handle, struct wuie_hdr *wuie) | ||
91 | { | ||
92 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
93 | u32 params; | ||
94 | |||
95 | params = (interval << 24) | ||
96 | | (repeat_cnt << 16) | ||
97 | | (wuie->bLength << 8) | ||
98 | | handle; | ||
99 | |||
100 | return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_ADD, params, wuie, wuie->bLength); | ||
101 | } | ||
102 | |||
103 | int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle) | ||
104 | { | ||
105 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
106 | u32 params; | ||
107 | |||
108 | params = handle; | ||
109 | |||
110 | return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_RM, params, NULL, 0); | ||
111 | } | ||
112 | |||
113 | int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm) | ||
114 | { | ||
115 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
116 | |||
117 | if (stream_index >= 0) | ||
118 | whc_write_wusbcmd(whc, WUSBCMD_WUSBSI_MASK, WUSBCMD_WUSBSI(stream_index)); | ||
119 | |||
120 | return whc_do_gencmd(whc, WUSBGENCMDSTS_SET_MAS, 0, (void *)mas_bm, sizeof(*mas_bm)); | ||
121 | } | ||
122 | |||
123 | int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
124 | { | ||
125 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
126 | int idx = wusb_dev->port_idx; | ||
127 | struct di_buf_entry *di = &whc->di_buf[idx]; | ||
128 | int ret; | ||
129 | |||
130 | mutex_lock(&whc->mutex); | ||
131 | |||
132 | uwb_mas_bm_copy_le(di->availability_info, &wusb_dev->availability); | ||
133 | di->addr_sec_info &= ~(WHC_DI_DISABLE | WHC_DI_DEV_ADDR_MASK); | ||
134 | di->addr_sec_info |= WHC_DI_DEV_ADDR(wusb_dev->addr); | ||
135 | |||
136 | ret = whc_update_di(whc, idx); | ||
137 | |||
138 | mutex_unlock(&whc->mutex); | ||
139 | |||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * Set the number of Device Notification Time Slots (DNTS) and enable | ||
145 | * device notifications. | ||
146 | */ | ||
147 | int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots) | ||
148 | { | ||
149 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
150 | u32 dntsctrl; | ||
151 | |||
152 | dntsctrl = WUSBDNTSCTRL_ACTIVE | ||
153 | | WUSBDNTSCTRL_INTERVAL(interval) | ||
154 | | WUSBDNTSCTRL_SLOTS(slots); | ||
155 | |||
156 | le_writel(dntsctrl, whc->base + WUSBDNTSCTRL); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int whc_set_key(struct whc *whc, u8 key_index, uint32_t tkid, | ||
162 | const void *key, size_t key_size, bool is_gtk) | ||
163 | { | ||
164 | uint32_t setkeycmd; | ||
165 | uint32_t seckey[4]; | ||
166 | int i; | ||
167 | int ret; | ||
168 | |||
169 | memcpy(seckey, key, key_size); | ||
170 | setkeycmd = WUSBSETSECKEYCMD_SET | WUSBSETSECKEYCMD_IDX(key_index); | ||
171 | if (is_gtk) | ||
172 | setkeycmd |= WUSBSETSECKEYCMD_GTK; | ||
173 | |||
174 | le_writel(tkid, whc->base + WUSBTKID); | ||
175 | for (i = 0; i < 4; i++) | ||
176 | le_writel(seckey[i], whc->base + WUSBSECKEY + 4*i); | ||
177 | le_writel(setkeycmd, whc->base + WUSBSETSECKEYCMD); | ||
178 | |||
179 | ret = whci_wait_for(&whc->umc->dev, whc->base + WUSBSETSECKEYCMD, | ||
180 | WUSBSETSECKEYCMD_SET, 0, 100, "set key"); | ||
181 | |||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * whc_set_ptk - set the PTK to use for a device. | ||
187 | * | ||
188 | * The index into the key table for this PTK is the same as the | ||
189 | * device's port index. | ||
190 | */ | ||
191 | int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, | ||
192 | const void *ptk, size_t key_size) | ||
193 | { | ||
194 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
195 | struct di_buf_entry *di = &whc->di_buf[port_idx]; | ||
196 | int ret; | ||
197 | |||
198 | mutex_lock(&whc->mutex); | ||
199 | |||
200 | if (ptk) { | ||
201 | ret = whc_set_key(whc, port_idx, tkid, ptk, key_size, false); | ||
202 | if (ret) | ||
203 | goto out; | ||
204 | |||
205 | di->addr_sec_info &= ~WHC_DI_KEY_IDX_MASK; | ||
206 | di->addr_sec_info |= WHC_DI_SECURE | WHC_DI_KEY_IDX(port_idx); | ||
207 | } else | ||
208 | di->addr_sec_info &= ~WHC_DI_SECURE; | ||
209 | |||
210 | ret = whc_update_di(whc, port_idx); | ||
211 | out: | ||
212 | mutex_unlock(&whc->mutex); | ||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * whc_set_gtk - set the GTK for subsequent broadcast packets | ||
218 | * | ||
219 | * The GTK is stored in the last entry in the key table (the previous | ||
220 | * N_DEVICES entries are for the per-device PTKs). | ||
221 | */ | ||
222 | int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid, | ||
223 | const void *gtk, size_t key_size) | ||
224 | { | ||
225 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
226 | int ret; | ||
227 | |||
228 | mutex_lock(&whc->mutex); | ||
229 | |||
230 | ret = whc_set_key(whc, whc->n_devices, tkid, gtk, key_size, true); | ||
231 | |||
232 | mutex_unlock(&whc->mutex); | ||
233 | |||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | int whc_set_cluster_id(struct whc *whc, u8 bcid) | ||
238 | { | ||
239 | whc_write_wusbcmd(whc, WUSBCMD_BCID_MASK, WUSBCMD_BCID(bcid)); | ||
240 | return 0; | ||
241 | } | ||
diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig new file mode 100644 index 000000000000..eb09a0a14a80 --- /dev/null +++ b/drivers/usb/wusbcore/Kconfig | |||
@@ -0,0 +1,41 @@ | |||
1 | # | ||
2 | # Wireless USB Core configuration | ||
3 | # | ||
4 | config USB_WUSB | ||
5 | tristate "Enable Wireless USB extensions (EXPERIMENTAL)" | ||
6 | depends on EXPERIMENTAL | ||
7 | depends on USB | ||
8 | select UWB | ||
9 | select CRYPTO | ||
10 | select CRYPTO_BLKCIPHER | ||
11 | select CRYPTO_CBC | ||
12 | select CRYPTO_MANAGER | ||
13 | select CRYPTO_AES | ||
14 | help | ||
15 | Enable the host-side support for Wireless USB. | ||
16 | |||
17 | To compile this support select Y (built in). It is safe to | ||
18 | select even if you don't have the hardware. | ||
19 | |||
20 | config USB_WUSB_CBAF | ||
21 | tristate "Support WUSB Cable Based Association (CBA)" | ||
22 | depends on USB | ||
23 | help | ||
24 | Some WUSB devices support Cable Based Association. It's used to | ||
25 | enable the secure communication between the host and the | ||
26 | device. | ||
27 | |||
28 | Enable this option if your WUSB device must to be connected | ||
29 | via wired USB before establishing a wireless link. | ||
30 | |||
31 | It is safe to select even if you don't have a compatible | ||
32 | hardware. | ||
33 | |||
34 | config USB_WUSB_CBAF_DEBUG | ||
35 | bool "Enable CBA debug messages" | ||
36 | depends on USB_WUSB_CBAF | ||
37 | help | ||
38 | Say Y here if you want the CBA to produce a bunch of debug messages | ||
39 | to the system log. Select this if you are having a problem with | ||
40 | CBA support and want to see more of what is going on. | ||
41 | |||
diff --git a/drivers/usb/wusbcore/Makefile b/drivers/usb/wusbcore/Makefile new file mode 100644 index 000000000000..75f1ade66258 --- /dev/null +++ b/drivers/usb/wusbcore/Makefile | |||
@@ -0,0 +1,26 @@ | |||
1 | obj-$(CONFIG_USB_WUSB) += wusbcore.o | ||
2 | obj-$(CONFIG_USB_HWA_HCD) += wusb-wa.o | ||
3 | obj-$(CONFIG_USB_WUSB_CBAF) += wusb-cbaf.o | ||
4 | |||
5 | |||
6 | wusbcore-objs := \ | ||
7 | crypto.o \ | ||
8 | devconnect.o \ | ||
9 | dev-sysfs.o \ | ||
10 | mmc.o \ | ||
11 | pal.o \ | ||
12 | rh.o \ | ||
13 | reservation.o \ | ||
14 | security.o \ | ||
15 | wusbhc.o | ||
16 | |||
17 | wusb-cbaf-objs := cbaf.o | ||
18 | |||
19 | wusb-wa-objs := wa-hc.o \ | ||
20 | wa-nep.o \ | ||
21 | wa-rpipe.o \ | ||
22 | wa-xfer.o | ||
23 | |||
24 | ifeq ($(CONFIG_USB_WUSB_CBAF_DEBUG),y) | ||
25 | EXTRA_CFLAGS += -DDEBUG | ||
26 | endif | ||
diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c new file mode 100644 index 000000000000..ab4788d1785a --- /dev/null +++ b/drivers/usb/wusbcore/cbaf.c | |||
@@ -0,0 +1,673 @@ | |||
1 | /* | ||
2 | * Wireless USB - Cable Based Association | ||
3 | * | ||
4 | * | ||
5 | * Copyright (C) 2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * WUSB devices have to be paired (associated in WUSB lingo) so | ||
25 | * that they can connect to the system. | ||
26 | * | ||
27 | * One way of pairing is using CBA-Cable Based Association. First | ||
28 | * time you plug the device with a cable, association is done between | ||
29 | * host and device and subsequent times, you can connect wirelessly | ||
30 | * without having to associate again. That's the idea. | ||
31 | * | ||
32 | * This driver does nothing Earth shattering. It just provides an | ||
33 | * interface to chat with the wire-connected device so we can get a | ||
34 | * CDID (device ID) that might have been previously associated to a | ||
35 | * CHID (host ID) and to set up a new <CHID,CDID,CK> triplet | ||
36 | * (connection context), with the CK being the secret, or connection | ||
37 | * key. This is the pairing data. | ||
38 | * | ||
39 | * When a device with the CBA capability connects, the probe routine | ||
40 | * just creates a bunch of sysfs files that a user space enumeration | ||
41 | * manager uses to allow it to connect wirelessly to the system or not. | ||
42 | * | ||
43 | * The process goes like this: | ||
44 | * | ||
45 | * 1. Device plugs, cbaf is loaded, notifications happen. | ||
46 | * | ||
47 | * 2. The connection manager (CM) sees a device with CBAF capability | ||
48 | * (the wusb_chid etc. files in /sys/devices/blah/OURDEVICE). | ||
49 | * | ||
50 | * 3. The CM writes the host name, supported band groups, and the CHID | ||
51 | * (host ID) into the wusb_host_name, wusb_host_band_groups and | ||
52 | * wusb_chid files. These get sent to the device and the CDID (if | ||
53 | * any) for this host is requested. | ||
54 | * | ||
55 | * 4. The CM can verify that the device's supported band groups | ||
56 | * (wusb_device_band_groups) are compatible with the host. | ||
57 | * | ||
58 | * 5. The CM reads the wusb_cdid file. | ||
59 | * | ||
60 | * 6. The CM looks up its database | ||
61 | * | ||
62 | * 6.1 If it has a matching CHID,CDID entry, the device has been | ||
63 | * authorized before (paired) and nothing further needs to be | ||
64 | * done. | ||
65 | * | ||
66 | * 6.2 If the CDID is zero (or the CM doesn't find a matching CDID in | ||
67 | * its database), the device is assumed to be not known. The CM | ||
68 | * may associate the host with device by: writing a randomly | ||
69 | * generated CDID to wusb_cdid and then a random CK to wusb_ck | ||
70 | * (this uploads the new CC to the device). | ||
71 | * | ||
72 | * CMD may choose to prompt the user before associating with a new | ||
73 | * device. | ||
74 | * | ||
75 | * 7. Device is unplugged. | ||
76 | * | ||
77 | * When the device tries to connect wirelessly, it will present its | ||
78 | * CDID to the WUSB host controller. The CM will query the | ||
79 | * database. If the CHID/CDID pair found, it will (with a 4-way | ||
80 | * handshake) challenge the device to demonstrate it has the CK secret | ||
81 | * key (from our database) without actually exchanging it. Once | ||
82 | * satisfied, crypto keys are derived from the CK, the device is | ||
83 | * connected and all communication is encrypted. | ||
84 | * | ||
85 | * References: | ||
86 | * [WUSB-AM] Association Models Supplement to the Certified Wireless | ||
87 | * Universal Serial Bus Specification, version 1.0. | ||
88 | */ | ||
89 | #include <linux/module.h> | ||
90 | #include <linux/ctype.h> | ||
91 | #include <linux/version.h> | ||
92 | #include <linux/usb.h> | ||
93 | #include <linux/interrupt.h> | ||
94 | #include <linux/delay.h> | ||
95 | #include <linux/random.h> | ||
96 | #include <linux/mutex.h> | ||
97 | #include <linux/uwb.h> | ||
98 | #include <linux/usb/wusb.h> | ||
99 | #include <linux/usb/association.h> | ||
100 | |||
101 | #define CBA_NAME_LEN 0x40 /* [WUSB-AM] table 4-7 */ | ||
102 | |||
103 | /* An instance of a Cable-Based-Association-Framework device */ | ||
104 | struct cbaf { | ||
105 | struct usb_device *usb_dev; | ||
106 | struct usb_interface *usb_iface; | ||
107 | void *buffer; | ||
108 | size_t buffer_size; | ||
109 | |||
110 | struct wusb_ckhdid chid; | ||
111 | char host_name[CBA_NAME_LEN]; | ||
112 | u16 host_band_groups; | ||
113 | |||
114 | struct wusb_ckhdid cdid; | ||
115 | char device_name[CBA_NAME_LEN]; | ||
116 | u16 device_band_groups; | ||
117 | |||
118 | struct wusb_ckhdid ck; | ||
119 | }; | ||
120 | |||
121 | /* | ||
122 | * Verify that a CBAF USB-interface has what we need | ||
123 | * | ||
124 | * According to [WUSB-AM], CBA devices should provide at least two | ||
125 | * interfaces: | ||
126 | * - RETRIEVE_HOST_INFO | ||
127 | * - ASSOCIATE | ||
128 | * | ||
129 | * If the device doesn't provide these interfaces, we do not know how | ||
130 | * to deal with it. | ||
131 | */ | ||
132 | static int cbaf_check(struct cbaf *cbaf) | ||
133 | { | ||
134 | int result; | ||
135 | struct device *dev = &cbaf->usb_iface->dev; | ||
136 | struct wusb_cbaf_assoc_info *assoc_info; | ||
137 | struct wusb_cbaf_assoc_request *assoc_request; | ||
138 | size_t assoc_size; | ||
139 | void *itr, *top; | ||
140 | int ar_rhi = 0, ar_assoc = 0; | ||
141 | |||
142 | result = usb_control_msg( | ||
143 | cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0), | ||
144 | CBAF_REQ_GET_ASSOCIATION_INFORMATION, | ||
145 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
146 | 0, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
147 | cbaf->buffer, cbaf->buffer_size, 1000 /* FIXME: arbitrary */); | ||
148 | if (result < 0) { | ||
149 | dev_err(dev, "Cannot get available association types: %d\n", | ||
150 | result); | ||
151 | return result; | ||
152 | } | ||
153 | |||
154 | assoc_info = cbaf->buffer; | ||
155 | if (result < sizeof(*assoc_info)) { | ||
156 | dev_err(dev, "Not enough data to decode association info " | ||
157 | "header (%zu vs %zu bytes required)\n", | ||
158 | (size_t)result, sizeof(*assoc_info)); | ||
159 | return result; | ||
160 | } | ||
161 | |||
162 | assoc_size = le16_to_cpu(assoc_info->Length); | ||
163 | if (result < assoc_size) { | ||
164 | dev_err(dev, "Not enough data to decode association info " | ||
165 | "(%zu vs %zu bytes required)\n", | ||
166 | (size_t)assoc_size, sizeof(*assoc_info)); | ||
167 | return result; | ||
168 | } | ||
169 | /* | ||
170 | * From now on, we just verify, but won't error out unless we | ||
171 | * don't find the AR_TYPE_WUSB_{RETRIEVE_HOST_INFO,ASSOCIATE} | ||
172 | * types. | ||
173 | */ | ||
174 | itr = cbaf->buffer + sizeof(*assoc_info); | ||
175 | top = cbaf->buffer + assoc_size; | ||
176 | dev_dbg(dev, "Found %u association requests (%zu bytes)\n", | ||
177 | assoc_info->NumAssociationRequests, assoc_size); | ||
178 | |||
179 | while (itr < top) { | ||
180 | u16 ar_type, ar_subtype; | ||
181 | u32 ar_size; | ||
182 | const char *ar_name; | ||
183 | |||
184 | assoc_request = itr; | ||
185 | |||
186 | if (top - itr < sizeof(*assoc_request)) { | ||
187 | dev_err(dev, "Not enough data to decode associaton " | ||
188 | "request (%zu vs %zu bytes needed)\n", | ||
189 | top - itr, sizeof(*assoc_request)); | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | ar_type = le16_to_cpu(assoc_request->AssociationTypeId); | ||
194 | ar_subtype = le16_to_cpu(assoc_request->AssociationSubTypeId); | ||
195 | ar_size = le32_to_cpu(assoc_request->AssociationTypeInfoSize); | ||
196 | ar_name = "unknown"; | ||
197 | |||
198 | switch (ar_type) { | ||
199 | case AR_TYPE_WUSB: | ||
200 | /* Verify we have what is mandated by [WUSB-AM]. */ | ||
201 | switch (ar_subtype) { | ||
202 | case AR_TYPE_WUSB_RETRIEVE_HOST_INFO: | ||
203 | ar_name = "RETRIEVE_HOST_INFO"; | ||
204 | ar_rhi = 1; | ||
205 | break; | ||
206 | case AR_TYPE_WUSB_ASSOCIATE: | ||
207 | /* send assoc data */ | ||
208 | ar_name = "ASSOCIATE"; | ||
209 | ar_assoc = 1; | ||
210 | break; | ||
211 | }; | ||
212 | break; | ||
213 | }; | ||
214 | |||
215 | dev_dbg(dev, "Association request #%02u: 0x%04x/%04x " | ||
216 | "(%zu bytes): %s\n", | ||
217 | assoc_request->AssociationDataIndex, ar_type, | ||
218 | ar_subtype, (size_t)ar_size, ar_name); | ||
219 | |||
220 | itr += sizeof(*assoc_request); | ||
221 | } | ||
222 | |||
223 | if (!ar_rhi) { | ||
224 | dev_err(dev, "Missing RETRIEVE_HOST_INFO association " | ||
225 | "request\n"); | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | if (!ar_assoc) { | ||
229 | dev_err(dev, "Missing ASSOCIATE association request\n"); | ||
230 | return -EINVAL; | ||
231 | } | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static const struct wusb_cbaf_host_info cbaf_host_info_defaults = { | ||
237 | .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId, | ||
238 | .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB), | ||
239 | .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId, | ||
240 | .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_RETRIEVE_HOST_INFO), | ||
241 | .CHID_hdr = WUSB_AR_CHID, | ||
242 | .LangID_hdr = WUSB_AR_LangID, | ||
243 | .HostFriendlyName_hdr = WUSB_AR_HostFriendlyName, | ||
244 | }; | ||
245 | |||
246 | /* Send WUSB host information (CHID and name) to a CBAF device */ | ||
247 | static int cbaf_send_host_info(struct cbaf *cbaf) | ||
248 | { | ||
249 | struct wusb_cbaf_host_info *hi; | ||
250 | size_t name_len; | ||
251 | size_t hi_size; | ||
252 | |||
253 | hi = cbaf->buffer; | ||
254 | memset(hi, 0, sizeof(*hi)); | ||
255 | *hi = cbaf_host_info_defaults; | ||
256 | hi->CHID = cbaf->chid; | ||
257 | hi->LangID = 0; /* FIXME: I guess... */ | ||
258 | strlcpy(hi->HostFriendlyName, cbaf->host_name, CBA_NAME_LEN); | ||
259 | name_len = strlen(cbaf->host_name); | ||
260 | hi->HostFriendlyName_hdr.len = cpu_to_le16(name_len); | ||
261 | hi_size = sizeof(*hi) + name_len; | ||
262 | |||
263 | return usb_control_msg(cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0), | ||
264 | CBAF_REQ_SET_ASSOCIATION_RESPONSE, | ||
265 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
266 | 0x0101, | ||
267 | cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
268 | hi, hi_size, 1000 /* FIXME: arbitrary */); | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * Get device's information (CDID) associated to CHID | ||
273 | * | ||
274 | * The device will return it's information (CDID, name, bandgroups) | ||
275 | * associated to the CHID we have set before, or 0 CDID and default | ||
276 | * name and bandgroup if no CHID set or unknown. | ||
277 | */ | ||
278 | static int cbaf_cdid_get(struct cbaf *cbaf) | ||
279 | { | ||
280 | int result; | ||
281 | struct device *dev = &cbaf->usb_iface->dev; | ||
282 | struct wusb_cbaf_device_info *di; | ||
283 | size_t needed; | ||
284 | |||
285 | di = cbaf->buffer; | ||
286 | result = usb_control_msg( | ||
287 | cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0), | ||
288 | CBAF_REQ_GET_ASSOCIATION_REQUEST, | ||
289 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
290 | 0x0200, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
291 | di, cbaf->buffer_size, 1000 /* FIXME: arbitrary */); | ||
292 | if (result < 0) { | ||
293 | dev_err(dev, "Cannot request device information: %d\n", result); | ||
294 | return result; | ||
295 | } | ||
296 | |||
297 | needed = result < sizeof(*di) ? sizeof(*di) : le32_to_cpu(di->Length); | ||
298 | if (result < needed) { | ||
299 | dev_err(dev, "Not enough data in DEVICE_INFO reply (%zu vs " | ||
300 | "%zu bytes needed)\n", (size_t)result, needed); | ||
301 | return result; | ||
302 | } | ||
303 | |||
304 | strlcpy(cbaf->device_name, di->DeviceFriendlyName, CBA_NAME_LEN); | ||
305 | cbaf->cdid = di->CDID; | ||
306 | cbaf->device_band_groups = le16_to_cpu(di->BandGroups); | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static ssize_t cbaf_wusb_chid_show(struct device *dev, | ||
312 | struct device_attribute *attr, | ||
313 | char *buf) | ||
314 | { | ||
315 | struct usb_interface *iface = to_usb_interface(dev); | ||
316 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
317 | char pr_chid[WUSB_CKHDID_STRSIZE]; | ||
318 | |||
319 | ckhdid_printf(pr_chid, sizeof(pr_chid), &cbaf->chid); | ||
320 | return scnprintf(buf, PAGE_SIZE, "%s\n", pr_chid); | ||
321 | } | ||
322 | |||
323 | static ssize_t cbaf_wusb_chid_store(struct device *dev, | ||
324 | struct device_attribute *attr, | ||
325 | const char *buf, size_t size) | ||
326 | { | ||
327 | ssize_t result; | ||
328 | struct usb_interface *iface = to_usb_interface(dev); | ||
329 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
330 | |||
331 | result = sscanf(buf, | ||
332 | "%02hhx %02hhx %02hhx %02hhx " | ||
333 | "%02hhx %02hhx %02hhx %02hhx " | ||
334 | "%02hhx %02hhx %02hhx %02hhx " | ||
335 | "%02hhx %02hhx %02hhx %02hhx", | ||
336 | &cbaf->chid.data[0] , &cbaf->chid.data[1], | ||
337 | &cbaf->chid.data[2] , &cbaf->chid.data[3], | ||
338 | &cbaf->chid.data[4] , &cbaf->chid.data[5], | ||
339 | &cbaf->chid.data[6] , &cbaf->chid.data[7], | ||
340 | &cbaf->chid.data[8] , &cbaf->chid.data[9], | ||
341 | &cbaf->chid.data[10], &cbaf->chid.data[11], | ||
342 | &cbaf->chid.data[12], &cbaf->chid.data[13], | ||
343 | &cbaf->chid.data[14], &cbaf->chid.data[15]); | ||
344 | |||
345 | if (result != 16) | ||
346 | return -EINVAL; | ||
347 | |||
348 | result = cbaf_send_host_info(cbaf); | ||
349 | if (result < 0) | ||
350 | return result; | ||
351 | result = cbaf_cdid_get(cbaf); | ||
352 | if (result < 0) | ||
353 | return -result; | ||
354 | return size; | ||
355 | } | ||
356 | static DEVICE_ATTR(wusb_chid, 0600, cbaf_wusb_chid_show, cbaf_wusb_chid_store); | ||
357 | |||
358 | static ssize_t cbaf_wusb_host_name_show(struct device *dev, | ||
359 | struct device_attribute *attr, | ||
360 | char *buf) | ||
361 | { | ||
362 | struct usb_interface *iface = to_usb_interface(dev); | ||
363 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
364 | |||
365 | return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->host_name); | ||
366 | } | ||
367 | |||
368 | static ssize_t cbaf_wusb_host_name_store(struct device *dev, | ||
369 | struct device_attribute *attr, | ||
370 | const char *buf, size_t size) | ||
371 | { | ||
372 | ssize_t result; | ||
373 | struct usb_interface *iface = to_usb_interface(dev); | ||
374 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
375 | |||
376 | result = sscanf(buf, "%63s", cbaf->host_name); | ||
377 | if (result != 1) | ||
378 | return -EINVAL; | ||
379 | |||
380 | return size; | ||
381 | } | ||
382 | static DEVICE_ATTR(wusb_host_name, 0600, cbaf_wusb_host_name_show, | ||
383 | cbaf_wusb_host_name_store); | ||
384 | |||
385 | static ssize_t cbaf_wusb_host_band_groups_show(struct device *dev, | ||
386 | struct device_attribute *attr, | ||
387 | char *buf) | ||
388 | { | ||
389 | struct usb_interface *iface = to_usb_interface(dev); | ||
390 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
391 | |||
392 | return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->host_band_groups); | ||
393 | } | ||
394 | |||
395 | static ssize_t cbaf_wusb_host_band_groups_store(struct device *dev, | ||
396 | struct device_attribute *attr, | ||
397 | const char *buf, size_t size) | ||
398 | { | ||
399 | ssize_t result; | ||
400 | struct usb_interface *iface = to_usb_interface(dev); | ||
401 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
402 | u16 band_groups = 0; | ||
403 | |||
404 | result = sscanf(buf, "%04hx", &band_groups); | ||
405 | if (result != 1) | ||
406 | return -EINVAL; | ||
407 | |||
408 | cbaf->host_band_groups = band_groups; | ||
409 | |||
410 | return size; | ||
411 | } | ||
412 | |||
413 | static DEVICE_ATTR(wusb_host_band_groups, 0600, | ||
414 | cbaf_wusb_host_band_groups_show, | ||
415 | cbaf_wusb_host_band_groups_store); | ||
416 | |||
417 | static const struct wusb_cbaf_device_info cbaf_device_info_defaults = { | ||
418 | .Length_hdr = WUSB_AR_Length, | ||
419 | .CDID_hdr = WUSB_AR_CDID, | ||
420 | .BandGroups_hdr = WUSB_AR_BandGroups, | ||
421 | .LangID_hdr = WUSB_AR_LangID, | ||
422 | .DeviceFriendlyName_hdr = WUSB_AR_DeviceFriendlyName, | ||
423 | }; | ||
424 | |||
425 | static ssize_t cbaf_wusb_cdid_show(struct device *dev, | ||
426 | struct device_attribute *attr, char *buf) | ||
427 | { | ||
428 | struct usb_interface *iface = to_usb_interface(dev); | ||
429 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
430 | char pr_cdid[WUSB_CKHDID_STRSIZE]; | ||
431 | |||
432 | ckhdid_printf(pr_cdid, sizeof(pr_cdid), &cbaf->cdid); | ||
433 | return scnprintf(buf, PAGE_SIZE, "%s\n", pr_cdid); | ||
434 | } | ||
435 | |||
436 | static ssize_t cbaf_wusb_cdid_store(struct device *dev, | ||
437 | struct device_attribute *attr, | ||
438 | const char *buf, size_t size) | ||
439 | { | ||
440 | ssize_t result; | ||
441 | struct usb_interface *iface = to_usb_interface(dev); | ||
442 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
443 | struct wusb_ckhdid cdid; | ||
444 | |||
445 | result = sscanf(buf, | ||
446 | "%02hhx %02hhx %02hhx %02hhx " | ||
447 | "%02hhx %02hhx %02hhx %02hhx " | ||
448 | "%02hhx %02hhx %02hhx %02hhx " | ||
449 | "%02hhx %02hhx %02hhx %02hhx", | ||
450 | &cdid.data[0] , &cdid.data[1], | ||
451 | &cdid.data[2] , &cdid.data[3], | ||
452 | &cdid.data[4] , &cdid.data[5], | ||
453 | &cdid.data[6] , &cdid.data[7], | ||
454 | &cdid.data[8] , &cdid.data[9], | ||
455 | &cdid.data[10], &cdid.data[11], | ||
456 | &cdid.data[12], &cdid.data[13], | ||
457 | &cdid.data[14], &cdid.data[15]); | ||
458 | if (result != 16) | ||
459 | return -EINVAL; | ||
460 | |||
461 | cbaf->cdid = cdid; | ||
462 | |||
463 | return size; | ||
464 | } | ||
465 | static DEVICE_ATTR(wusb_cdid, 0600, cbaf_wusb_cdid_show, cbaf_wusb_cdid_store); | ||
466 | |||
467 | static ssize_t cbaf_wusb_device_band_groups_show(struct device *dev, | ||
468 | struct device_attribute *attr, | ||
469 | char *buf) | ||
470 | { | ||
471 | struct usb_interface *iface = to_usb_interface(dev); | ||
472 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
473 | |||
474 | return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->device_band_groups); | ||
475 | } | ||
476 | |||
477 | static DEVICE_ATTR(wusb_device_band_groups, 0600, | ||
478 | cbaf_wusb_device_band_groups_show, | ||
479 | NULL); | ||
480 | |||
481 | static ssize_t cbaf_wusb_device_name_show(struct device *dev, | ||
482 | struct device_attribute *attr, | ||
483 | char *buf) | ||
484 | { | ||
485 | struct usb_interface *iface = to_usb_interface(dev); | ||
486 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
487 | |||
488 | return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->device_name); | ||
489 | } | ||
490 | static DEVICE_ATTR(wusb_device_name, 0600, cbaf_wusb_device_name_show, NULL); | ||
491 | |||
492 | static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults = { | ||
493 | .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId, | ||
494 | .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB), | ||
495 | .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId, | ||
496 | .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE), | ||
497 | .Length_hdr = WUSB_AR_Length, | ||
498 | .Length = cpu_to_le32(sizeof(struct wusb_cbaf_cc_data)), | ||
499 | .ConnectionContext_hdr = WUSB_AR_ConnectionContext, | ||
500 | .BandGroups_hdr = WUSB_AR_BandGroups, | ||
501 | }; | ||
502 | |||
503 | static const struct wusb_cbaf_cc_data_fail cbaf_cc_data_fail_defaults = { | ||
504 | .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId, | ||
505 | .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId, | ||
506 | .Length_hdr = WUSB_AR_Length, | ||
507 | .AssociationStatus_hdr = WUSB_AR_AssociationStatus, | ||
508 | }; | ||
509 | |||
510 | /* | ||
511 | * Send a new CC to the device. | ||
512 | */ | ||
513 | static int cbaf_cc_upload(struct cbaf *cbaf) | ||
514 | { | ||
515 | int result; | ||
516 | struct device *dev = &cbaf->usb_iface->dev; | ||
517 | struct wusb_cbaf_cc_data *ccd; | ||
518 | char pr_cdid[WUSB_CKHDID_STRSIZE]; | ||
519 | |||
520 | ccd = cbaf->buffer; | ||
521 | *ccd = cbaf_cc_data_defaults; | ||
522 | ccd->CHID = cbaf->chid; | ||
523 | ccd->CDID = cbaf->cdid; | ||
524 | ccd->CK = cbaf->ck; | ||
525 | ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups); | ||
526 | |||
527 | dev_dbg(dev, "Trying to upload CC:\n"); | ||
528 | ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CHID); | ||
529 | dev_dbg(dev, " CHID %s\n", pr_cdid); | ||
530 | ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CDID); | ||
531 | dev_dbg(dev, " CDID %s\n", pr_cdid); | ||
532 | dev_dbg(dev, " Bandgroups 0x%04x\n", cbaf->host_band_groups); | ||
533 | |||
534 | result = usb_control_msg( | ||
535 | cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0), | ||
536 | CBAF_REQ_SET_ASSOCIATION_RESPONSE, | ||
537 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
538 | 0x0201, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
539 | ccd, sizeof(*ccd), 1000 /* FIXME: arbitrary */); | ||
540 | |||
541 | return result; | ||
542 | } | ||
543 | |||
544 | static ssize_t cbaf_wusb_ck_store(struct device *dev, | ||
545 | struct device_attribute *attr, | ||
546 | const char *buf, size_t size) | ||
547 | { | ||
548 | ssize_t result; | ||
549 | struct usb_interface *iface = to_usb_interface(dev); | ||
550 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
551 | |||
552 | result = sscanf(buf, | ||
553 | "%02hhx %02hhx %02hhx %02hhx " | ||
554 | "%02hhx %02hhx %02hhx %02hhx " | ||
555 | "%02hhx %02hhx %02hhx %02hhx " | ||
556 | "%02hhx %02hhx %02hhx %02hhx", | ||
557 | &cbaf->ck.data[0] , &cbaf->ck.data[1], | ||
558 | &cbaf->ck.data[2] , &cbaf->ck.data[3], | ||
559 | &cbaf->ck.data[4] , &cbaf->ck.data[5], | ||
560 | &cbaf->ck.data[6] , &cbaf->ck.data[7], | ||
561 | &cbaf->ck.data[8] , &cbaf->ck.data[9], | ||
562 | &cbaf->ck.data[10], &cbaf->ck.data[11], | ||
563 | &cbaf->ck.data[12], &cbaf->ck.data[13], | ||
564 | &cbaf->ck.data[14], &cbaf->ck.data[15]); | ||
565 | if (result != 16) | ||
566 | return -EINVAL; | ||
567 | |||
568 | result = cbaf_cc_upload(cbaf); | ||
569 | if (result < 0) | ||
570 | return result; | ||
571 | |||
572 | return size; | ||
573 | } | ||
574 | static DEVICE_ATTR(wusb_ck, 0600, NULL, cbaf_wusb_ck_store); | ||
575 | |||
576 | static struct attribute *cbaf_dev_attrs[] = { | ||
577 | &dev_attr_wusb_host_name.attr, | ||
578 | &dev_attr_wusb_host_band_groups.attr, | ||
579 | &dev_attr_wusb_chid.attr, | ||
580 | &dev_attr_wusb_cdid.attr, | ||
581 | &dev_attr_wusb_device_name.attr, | ||
582 | &dev_attr_wusb_device_band_groups.attr, | ||
583 | &dev_attr_wusb_ck.attr, | ||
584 | NULL, | ||
585 | }; | ||
586 | |||
587 | static struct attribute_group cbaf_dev_attr_group = { | ||
588 | .name = NULL, /* we want them in the same directory */ | ||
589 | .attrs = cbaf_dev_attrs, | ||
590 | }; | ||
591 | |||
592 | static int cbaf_probe(struct usb_interface *iface, | ||
593 | const struct usb_device_id *id) | ||
594 | { | ||
595 | struct cbaf *cbaf; | ||
596 | struct device *dev = &iface->dev; | ||
597 | int result = -ENOMEM; | ||
598 | |||
599 | cbaf = kzalloc(sizeof(*cbaf), GFP_KERNEL); | ||
600 | if (cbaf == NULL) | ||
601 | goto error_kzalloc; | ||
602 | cbaf->buffer = kmalloc(512, GFP_KERNEL); | ||
603 | if (cbaf->buffer == NULL) | ||
604 | goto error_kmalloc_buffer; | ||
605 | |||
606 | cbaf->buffer_size = 512; | ||
607 | cbaf->usb_dev = usb_get_dev(interface_to_usbdev(iface)); | ||
608 | cbaf->usb_iface = usb_get_intf(iface); | ||
609 | result = cbaf_check(cbaf); | ||
610 | if (result < 0) { | ||
611 | dev_err(dev, "This device is not WUSB-CBAF compliant" | ||
612 | "and is not supported yet.\n"); | ||
613 | goto error_check; | ||
614 | } | ||
615 | |||
616 | result = sysfs_create_group(&dev->kobj, &cbaf_dev_attr_group); | ||
617 | if (result < 0) { | ||
618 | dev_err(dev, "Can't register sysfs attr group: %d\n", result); | ||
619 | goto error_create_group; | ||
620 | } | ||
621 | usb_set_intfdata(iface, cbaf); | ||
622 | return 0; | ||
623 | |||
624 | error_create_group: | ||
625 | error_check: | ||
626 | kfree(cbaf->buffer); | ||
627 | error_kmalloc_buffer: | ||
628 | kfree(cbaf); | ||
629 | error_kzalloc: | ||
630 | return result; | ||
631 | } | ||
632 | |||
633 | static void cbaf_disconnect(struct usb_interface *iface) | ||
634 | { | ||
635 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
636 | struct device *dev = &iface->dev; | ||
637 | sysfs_remove_group(&dev->kobj, &cbaf_dev_attr_group); | ||
638 | usb_set_intfdata(iface, NULL); | ||
639 | usb_put_intf(iface); | ||
640 | kfree(cbaf->buffer); | ||
641 | /* paranoia: clean up crypto keys */ | ||
642 | memset(cbaf, 0, sizeof(*cbaf)); | ||
643 | kfree(cbaf); | ||
644 | } | ||
645 | |||
646 | static struct usb_device_id cbaf_id_table[] = { | ||
647 | { USB_INTERFACE_INFO(0xef, 0x03, 0x01), }, | ||
648 | { }, | ||
649 | }; | ||
650 | MODULE_DEVICE_TABLE(usb, cbaf_id_table); | ||
651 | |||
652 | static struct usb_driver cbaf_driver = { | ||
653 | .name = "wusb-cbaf", | ||
654 | .id_table = cbaf_id_table, | ||
655 | .probe = cbaf_probe, | ||
656 | .disconnect = cbaf_disconnect, | ||
657 | }; | ||
658 | |||
659 | static int __init cbaf_driver_init(void) | ||
660 | { | ||
661 | return usb_register(&cbaf_driver); | ||
662 | } | ||
663 | module_init(cbaf_driver_init); | ||
664 | |||
665 | static void __exit cbaf_driver_exit(void) | ||
666 | { | ||
667 | usb_deregister(&cbaf_driver); | ||
668 | } | ||
669 | module_exit(cbaf_driver_exit); | ||
670 | |||
671 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
672 | MODULE_DESCRIPTION("Wireless USB Cable Based Association"); | ||
673 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c new file mode 100644 index 000000000000..c36c4389baae --- /dev/null +++ b/drivers/usb/wusbcore/crypto.c | |||
@@ -0,0 +1,538 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * AES-128 CCM Encryption | ||
4 | * | ||
5 | * Copyright (C) 2007 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * We don't do any encryption here; we use the Linux Kernel's AES-128 | ||
24 | * crypto modules to construct keys and payload blocks in a way | ||
25 | * defined by WUSB1.0[6]. Check the erratas, as typos are are patched | ||
26 | * there. | ||
27 | * | ||
28 | * Thanks a zillion to John Keys for his help and clarifications over | ||
29 | * the designed-by-a-committee text. | ||
30 | * | ||
31 | * So the idea is that there is this basic Pseudo-Random-Function | ||
32 | * defined in WUSB1.0[6.5] which is the core of everything. It works | ||
33 | * by tweaking some blocks, AES crypting them and then xoring | ||
34 | * something else with them (this seems to be called CBC(AES) -- can | ||
35 | * you tell I know jack about crypto?). So we just funnel it into the | ||
36 | * Linux Crypto API. | ||
37 | * | ||
38 | * We leave a crypto test module so we can verify that vectors match, | ||
39 | * every now and then. | ||
40 | * | ||
41 | * Block size: 16 bytes -- AES seems to do things in 'block sizes'. I | ||
42 | * am learning a lot... | ||
43 | * | ||
44 | * Conveniently, some data structures that need to be | ||
45 | * funneled through AES are...16 bytes in size! | ||
46 | */ | ||
47 | |||
48 | #include <linux/crypto.h> | ||
49 | #include <linux/module.h> | ||
50 | #include <linux/err.h> | ||
51 | #include <linux/uwb.h> | ||
52 | #include <linux/usb/wusb.h> | ||
53 | #include <linux/scatterlist.h> | ||
54 | #define D_LOCAL 0 | ||
55 | #include <linux/uwb/debug.h> | ||
56 | |||
57 | |||
58 | /* | ||
59 | * Block of data, as understood by AES-CCM | ||
60 | * | ||
61 | * The code assumes this structure is nothing but a 16 byte array | ||
62 | * (packed in a struct to avoid common mess ups that I usually do with | ||
63 | * arrays and enforcing type checking). | ||
64 | */ | ||
65 | struct aes_ccm_block { | ||
66 | u8 data[16]; | ||
67 | } __attribute__((packed)); | ||
68 | |||
69 | /* | ||
70 | * Counter-mode Blocks (WUSB1.0[6.4]) | ||
71 | * | ||
72 | * According to CCM (or so it seems), for the purpose of calculating | ||
73 | * the MIC, the message is broken in N counter-mode blocks, B0, B1, | ||
74 | * ... BN. | ||
75 | * | ||
76 | * B0 contains flags, the CCM nonce and l(m). | ||
77 | * | ||
78 | * B1 contains l(a), the MAC header, the encryption offset and padding. | ||
79 | * | ||
80 | * If EO is nonzero, additional blocks are built from payload bytes | ||
81 | * until EO is exahusted (FIXME: padding to 16 bytes, I guess). The | ||
82 | * padding is not xmitted. | ||
83 | */ | ||
84 | |||
85 | /* WUSB1.0[T6.4] */ | ||
86 | struct aes_ccm_b0 { | ||
87 | u8 flags; /* 0x59, per CCM spec */ | ||
88 | struct aes_ccm_nonce ccm_nonce; | ||
89 | __be16 lm; | ||
90 | } __attribute__((packed)); | ||
91 | |||
92 | /* WUSB1.0[T6.5] */ | ||
93 | struct aes_ccm_b1 { | ||
94 | __be16 la; | ||
95 | u8 mac_header[10]; | ||
96 | __le16 eo; | ||
97 | u8 security_reserved; /* This is always zero */ | ||
98 | u8 padding; /* 0 */ | ||
99 | } __attribute__((packed)); | ||
100 | |||
101 | /* | ||
102 | * Encryption Blocks (WUSB1.0[6.4.4]) | ||
103 | * | ||
104 | * CCM uses Ax blocks to generate a keystream with which the MIC and | ||
105 | * the message's payload are encoded. A0 always encrypts/decrypts the | ||
106 | * MIC. Ax (x>0) are used for the sucesive payload blocks. | ||
107 | * | ||
108 | * The x is the counter, and is increased for each block. | ||
109 | */ | ||
110 | struct aes_ccm_a { | ||
111 | u8 flags; /* 0x01, per CCM spec */ | ||
112 | struct aes_ccm_nonce ccm_nonce; | ||
113 | __be16 counter; /* Value of x */ | ||
114 | } __attribute__((packed)); | ||
115 | |||
116 | static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2, | ||
117 | size_t size) | ||
118 | { | ||
119 | u8 *bo = _bo; | ||
120 | const u8 *bi1 = _bi1, *bi2 = _bi2; | ||
121 | size_t itr; | ||
122 | for (itr = 0; itr < size; itr++) | ||
123 | bo[itr] = bi1[itr] ^ bi2[itr]; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * CC-MAC function WUSB1.0[6.5] | ||
128 | * | ||
129 | * Take a data string and produce the encrypted CBC Counter-mode MIC | ||
130 | * | ||
131 | * Note the names for most function arguments are made to (more or | ||
132 | * less) match those used in the pseudo-function definition given in | ||
133 | * WUSB1.0[6.5]. | ||
134 | * | ||
135 | * @tfm_cbc: CBC(AES) blkcipher handle (initialized) | ||
136 | * | ||
137 | * @tfm_aes: AES cipher handle (initialized) | ||
138 | * | ||
139 | * @mic: buffer for placing the computed MIC (Message Integrity | ||
140 | * Code). This is exactly 8 bytes, and we expect the buffer to | ||
141 | * be at least eight bytes in length. | ||
142 | * | ||
143 | * @key: 128 bit symmetric key | ||
144 | * | ||
145 | * @n: CCM nonce | ||
146 | * | ||
147 | * @a: ASCII string, 14 bytes long (I guess zero padded if needed; | ||
148 | * we use exactly 14 bytes). | ||
149 | * | ||
150 | * @b: data stream to be processed; cannot be a global or const local | ||
151 | * (will confuse the scatterlists) | ||
152 | * | ||
153 | * @blen: size of b... | ||
154 | * | ||
155 | * Still not very clear how this is done, but looks like this: we | ||
156 | * create block B0 (as WUSB1.0[6.5] says), then we AES-crypt it with | ||
157 | * @key. We bytewise xor B0 with B1 (1) and AES-crypt that. Then we | ||
158 | * take the payload and divide it in blocks (16 bytes), xor them with | ||
159 | * the previous crypto result (16 bytes) and crypt it, repeat the next | ||
160 | * block with the output of the previous one, rinse wash (I guess this | ||
161 | * is what AES CBC mode means...but I truly have no idea). So we use | ||
162 | * the CBC(AES) blkcipher, that does precisely that. The IV (Initial | ||
163 | * Vector) is 16 bytes and is set to zero, so | ||
164 | * | ||
165 | * See rfc3610. Linux crypto has a CBC implementation, but the | ||
166 | * documentation is scarce, to say the least, and the example code is | ||
167 | * so intricated that is difficult to understand how things work. Most | ||
168 | * of this is guess work -- bite me. | ||
169 | * | ||
170 | * (1) Created as 6.5 says, again, using as l(a) 'Blen + 14', and | ||
171 | * using the 14 bytes of @a to fill up | ||
172 | * b1.{mac_header,e0,security_reserved,padding}. | ||
173 | * | ||
174 | * NOTE: The definiton of l(a) in WUSB1.0[6.5] vs the definition of | ||
175 | * l(m) is orthogonal, they bear no relationship, so it is not | ||
176 | * in conflict with the parameter's relation that | ||
177 | * WUSB1.0[6.4.2]) defines. | ||
178 | * | ||
179 | * NOTE: WUSB1.0[A.1]: Host Nonce is missing a nibble? (1e); fixed in | ||
180 | * first errata released on 2005/07. | ||
181 | * | ||
182 | * NOTE: we need to clean IV to zero at each invocation to make sure | ||
183 | * we start with a fresh empty Initial Vector, so that the CBC | ||
184 | * works ok. | ||
185 | * | ||
186 | * NOTE: blen is not aligned to a block size, we'll pad zeros, that's | ||
187 | * what sg[4] is for. Maybe there is a smarter way to do this. | ||
188 | */ | ||
189 | static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc, | ||
190 | struct crypto_cipher *tfm_aes, void *mic, | ||
191 | const struct aes_ccm_nonce *n, | ||
192 | const struct aes_ccm_label *a, const void *b, | ||
193 | size_t blen) | ||
194 | { | ||
195 | int result = 0; | ||
196 | struct blkcipher_desc desc; | ||
197 | struct aes_ccm_b0 b0; | ||
198 | struct aes_ccm_b1 b1; | ||
199 | struct aes_ccm_a ax; | ||
200 | struct scatterlist sg[4], sg_dst; | ||
201 | void *iv, *dst_buf; | ||
202 | size_t ivsize, dst_size; | ||
203 | const u8 bzero[16] = { 0 }; | ||
204 | size_t zero_padding; | ||
205 | |||
206 | d_fnstart(3, NULL, "(tfm_cbc %p, tfm_aes %p, mic %p, " | ||
207 | "n %p, a %p, b %p, blen %zu)\n", | ||
208 | tfm_cbc, tfm_aes, mic, n, a, b, blen); | ||
209 | /* | ||
210 | * These checks should be compile time optimized out | ||
211 | * ensure @a fills b1's mac_header and following fields | ||
212 | */ | ||
213 | WARN_ON(sizeof(*a) != sizeof(b1) - sizeof(b1.la)); | ||
214 | WARN_ON(sizeof(b0) != sizeof(struct aes_ccm_block)); | ||
215 | WARN_ON(sizeof(b1) != sizeof(struct aes_ccm_block)); | ||
216 | WARN_ON(sizeof(ax) != sizeof(struct aes_ccm_block)); | ||
217 | |||
218 | result = -ENOMEM; | ||
219 | zero_padding = sizeof(struct aes_ccm_block) | ||
220 | - blen % sizeof(struct aes_ccm_block); | ||
221 | zero_padding = blen % sizeof(struct aes_ccm_block); | ||
222 | if (zero_padding) | ||
223 | zero_padding = sizeof(struct aes_ccm_block) - zero_padding; | ||
224 | dst_size = blen + sizeof(b0) + sizeof(b1) + zero_padding; | ||
225 | dst_buf = kzalloc(dst_size, GFP_KERNEL); | ||
226 | if (dst_buf == NULL) { | ||
227 | printk(KERN_ERR "E: can't alloc destination buffer\n"); | ||
228 | goto error_dst_buf; | ||
229 | } | ||
230 | |||
231 | iv = crypto_blkcipher_crt(tfm_cbc)->iv; | ||
232 | ivsize = crypto_blkcipher_ivsize(tfm_cbc); | ||
233 | memset(iv, 0, ivsize); | ||
234 | |||
235 | /* Setup B0 */ | ||
236 | b0.flags = 0x59; /* Format B0 */ | ||
237 | b0.ccm_nonce = *n; | ||
238 | b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */ | ||
239 | |||
240 | /* Setup B1 | ||
241 | * | ||
242 | * The WUSB spec is anything but clear! WUSB1.0[6.5] | ||
243 | * says that to initialize B1 from A with 'l(a) = blen + | ||
244 | * 14'--after clarification, it means to use A's contents | ||
245 | * for MAC Header, EO, sec reserved and padding. | ||
246 | */ | ||
247 | b1.la = cpu_to_be16(blen + 14); | ||
248 | memcpy(&b1.mac_header, a, sizeof(*a)); | ||
249 | |||
250 | d_printf(4, NULL, "I: B0 (%zu bytes)\n", sizeof(b0)); | ||
251 | d_dump(4, NULL, &b0, sizeof(b0)); | ||
252 | d_printf(4, NULL, "I: B1 (%zu bytes)\n", sizeof(b1)); | ||
253 | d_dump(4, NULL, &b1, sizeof(b1)); | ||
254 | d_printf(4, NULL, "I: B (%zu bytes)\n", blen); | ||
255 | d_dump(4, NULL, b, blen); | ||
256 | d_printf(4, NULL, "I: B 0-padding (%zu bytes)\n", zero_padding); | ||
257 | d_printf(4, NULL, "D: IV before crypto (%zu)\n", ivsize); | ||
258 | d_dump(4, NULL, iv, ivsize); | ||
259 | |||
260 | sg_init_table(sg, ARRAY_SIZE(sg)); | ||
261 | sg_set_buf(&sg[0], &b0, sizeof(b0)); | ||
262 | sg_set_buf(&sg[1], &b1, sizeof(b1)); | ||
263 | sg_set_buf(&sg[2], b, blen); | ||
264 | /* 0 if well behaved :) */ | ||
265 | sg_set_buf(&sg[3], bzero, zero_padding); | ||
266 | sg_init_one(&sg_dst, dst_buf, dst_size); | ||
267 | |||
268 | desc.tfm = tfm_cbc; | ||
269 | desc.flags = 0; | ||
270 | result = crypto_blkcipher_encrypt(&desc, &sg_dst, sg, dst_size); | ||
271 | if (result < 0) { | ||
272 | printk(KERN_ERR "E: can't compute CBC-MAC tag (MIC): %d\n", | ||
273 | result); | ||
274 | goto error_cbc_crypt; | ||
275 | } | ||
276 | d_printf(4, NULL, "D: MIC tag\n"); | ||
277 | d_dump(4, NULL, iv, ivsize); | ||
278 | |||
279 | /* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5] | ||
280 | * The procedure is to AES crypt the A0 block and XOR the MIC | ||
281 | * Tag agains it; we only do the first 8 bytes and place it | ||
282 | * directly in the destination buffer. | ||
283 | * | ||
284 | * POS Crypto API: size is assumed to be AES's block size. | ||
285 | * Thanks for documenting it -- tip taken from airo.c | ||
286 | */ | ||
287 | ax.flags = 0x01; /* as per WUSB 1.0 spec */ | ||
288 | ax.ccm_nonce = *n; | ||
289 | ax.counter = 0; | ||
290 | crypto_cipher_encrypt_one(tfm_aes, (void *)&ax, (void *)&ax); | ||
291 | bytewise_xor(mic, &ax, iv, 8); | ||
292 | d_printf(4, NULL, "D: CTR[MIC]\n"); | ||
293 | d_dump(4, NULL, &ax, 8); | ||
294 | d_printf(4, NULL, "D: CCM-MIC tag\n"); | ||
295 | d_dump(4, NULL, mic, 8); | ||
296 | result = 8; | ||
297 | error_cbc_crypt: | ||
298 | kfree(dst_buf); | ||
299 | error_dst_buf: | ||
300 | d_fnend(3, NULL, "(tfm_cbc %p, tfm_aes %p, mic %p, " | ||
301 | "n %p, a %p, b %p, blen %zu)\n", | ||
302 | tfm_cbc, tfm_aes, mic, n, a, b, blen); | ||
303 | return result; | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * WUSB Pseudo Random Function (WUSB1.0[6.5]) | ||
308 | * | ||
309 | * @b: buffer to the source data; cannot be a global or const local | ||
310 | * (will confuse the scatterlists) | ||
311 | */ | ||
312 | ssize_t wusb_prf(void *out, size_t out_size, | ||
313 | const u8 key[16], const struct aes_ccm_nonce *_n, | ||
314 | const struct aes_ccm_label *a, | ||
315 | const void *b, size_t blen, size_t len) | ||
316 | { | ||
317 | ssize_t result, bytes = 0, bitr; | ||
318 | struct aes_ccm_nonce n = *_n; | ||
319 | struct crypto_blkcipher *tfm_cbc; | ||
320 | struct crypto_cipher *tfm_aes; | ||
321 | u64 sfn = 0; | ||
322 | __le64 sfn_le; | ||
323 | |||
324 | d_fnstart(3, NULL, "(out %p, out_size %zu, key %p, _n %p, " | ||
325 | "a %p, b %p, blen %zu, len %zu)\n", out, out_size, | ||
326 | key, _n, a, b, blen, len); | ||
327 | |||
328 | tfm_cbc = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); | ||
329 | if (IS_ERR(tfm_cbc)) { | ||
330 | result = PTR_ERR(tfm_cbc); | ||
331 | printk(KERN_ERR "E: can't load CBC(AES): %d\n", (int)result); | ||
332 | goto error_alloc_cbc; | ||
333 | } | ||
334 | result = crypto_blkcipher_setkey(tfm_cbc, key, 16); | ||
335 | if (result < 0) { | ||
336 | printk(KERN_ERR "E: can't set CBC key: %d\n", (int)result); | ||
337 | goto error_setkey_cbc; | ||
338 | } | ||
339 | |||
340 | tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); | ||
341 | if (IS_ERR(tfm_aes)) { | ||
342 | result = PTR_ERR(tfm_aes); | ||
343 | printk(KERN_ERR "E: can't load AES: %d\n", (int)result); | ||
344 | goto error_alloc_aes; | ||
345 | } | ||
346 | result = crypto_cipher_setkey(tfm_aes, key, 16); | ||
347 | if (result < 0) { | ||
348 | printk(KERN_ERR "E: can't set AES key: %d\n", (int)result); | ||
349 | goto error_setkey_aes; | ||
350 | } | ||
351 | |||
352 | for (bitr = 0; bitr < (len + 63) / 64; bitr++) { | ||
353 | sfn_le = cpu_to_le64(sfn++); | ||
354 | memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */ | ||
355 | result = wusb_ccm_mac(tfm_cbc, tfm_aes, out + bytes, | ||
356 | &n, a, b, blen); | ||
357 | if (result < 0) | ||
358 | goto error_ccm_mac; | ||
359 | bytes += result; | ||
360 | } | ||
361 | result = bytes; | ||
362 | error_ccm_mac: | ||
363 | error_setkey_aes: | ||
364 | crypto_free_cipher(tfm_aes); | ||
365 | error_alloc_aes: | ||
366 | error_setkey_cbc: | ||
367 | crypto_free_blkcipher(tfm_cbc); | ||
368 | error_alloc_cbc: | ||
369 | d_fnend(3, NULL, "(out %p, out_size %zu, key %p, _n %p, " | ||
370 | "a %p, b %p, blen %zu, len %zu) = %d\n", out, out_size, | ||
371 | key, _n, a, b, blen, len, (int)bytes); | ||
372 | return result; | ||
373 | } | ||
374 | |||
375 | /* WUSB1.0[A.2] test vectors */ | ||
376 | static const u8 stv_hsmic_key[16] = { | ||
377 | 0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d, | ||
378 | 0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f | ||
379 | }; | ||
380 | |||
381 | static const struct aes_ccm_nonce stv_hsmic_n = { | ||
382 | .sfn = { 0 }, | ||
383 | .tkid = { 0x76, 0x98, 0x01, }, | ||
384 | .dest_addr = { .data = { 0xbe, 0x00 } }, | ||
385 | .src_addr = { .data = { 0x76, 0x98 } }, | ||
386 | }; | ||
387 | |||
388 | /* | ||
389 | * Out-of-band MIC Generation verification code | ||
390 | * | ||
391 | */ | ||
392 | static int wusb_oob_mic_verify(void) | ||
393 | { | ||
394 | int result; | ||
395 | u8 mic[8]; | ||
396 | /* WUSB1.0[A.2] test vectors | ||
397 | * | ||
398 | * Need to keep it in the local stack as GCC 4.1.3something | ||
399 | * messes up and generates noise. | ||
400 | */ | ||
401 | struct usb_handshake stv_hsmic_hs = { | ||
402 | .bMessageNumber = 2, | ||
403 | .bStatus = 00, | ||
404 | .tTKID = { 0x76, 0x98, 0x01 }, | ||
405 | .bReserved = 00, | ||
406 | .CDID = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, | ||
407 | 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, | ||
408 | 0x3c, 0x3d, 0x3e, 0x3f }, | ||
409 | .nonce = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, | ||
410 | 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, | ||
411 | 0x2c, 0x2d, 0x2e, 0x2f }, | ||
412 | .MIC = { 0x75, 0x6a, 0x97, 0x51, 0x0c, 0x8c, | ||
413 | 0x14, 0x7b } , | ||
414 | }; | ||
415 | size_t hs_size; | ||
416 | |||
417 | result = wusb_oob_mic(mic, stv_hsmic_key, &stv_hsmic_n, &stv_hsmic_hs); | ||
418 | if (result < 0) | ||
419 | printk(KERN_ERR "E: WUSB OOB MIC test: failed: %d\n", result); | ||
420 | else if (memcmp(stv_hsmic_hs.MIC, mic, sizeof(mic))) { | ||
421 | printk(KERN_ERR "E: OOB MIC test: " | ||
422 | "mismatch between MIC result and WUSB1.0[A2]\n"); | ||
423 | hs_size = sizeof(stv_hsmic_hs) - sizeof(stv_hsmic_hs.MIC); | ||
424 | printk(KERN_ERR "E: Handshake2 in: (%zu bytes)\n", hs_size); | ||
425 | dump_bytes(NULL, &stv_hsmic_hs, hs_size); | ||
426 | printk(KERN_ERR "E: CCM Nonce in: (%zu bytes)\n", | ||
427 | sizeof(stv_hsmic_n)); | ||
428 | dump_bytes(NULL, &stv_hsmic_n, sizeof(stv_hsmic_n)); | ||
429 | printk(KERN_ERR "E: MIC out:\n"); | ||
430 | dump_bytes(NULL, mic, sizeof(mic)); | ||
431 | printk(KERN_ERR "E: MIC out (from WUSB1.0[A.2]):\n"); | ||
432 | dump_bytes(NULL, stv_hsmic_hs.MIC, sizeof(stv_hsmic_hs.MIC)); | ||
433 | result = -EINVAL; | ||
434 | } else | ||
435 | result = 0; | ||
436 | return result; | ||
437 | } | ||
438 | |||
439 | /* | ||
440 | * Test vectors for Key derivation | ||
441 | * | ||
442 | * These come from WUSB1.0[6.5.1], the vectors in WUSB1.0[A.1] | ||
443 | * (errata corrected in 2005/07). | ||
444 | */ | ||
445 | static const u8 stv_key_a1[16] __attribute__ ((__aligned__(4))) = { | ||
446 | 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, | ||
447 | 0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f | ||
448 | }; | ||
449 | |||
450 | static const struct aes_ccm_nonce stv_keydvt_n_a1 = { | ||
451 | .sfn = { 0 }, | ||
452 | .tkid = { 0x76, 0x98, 0x01, }, | ||
453 | .dest_addr = { .data = { 0xbe, 0x00 } }, | ||
454 | .src_addr = { .data = { 0x76, 0x98 } }, | ||
455 | }; | ||
456 | |||
457 | static const struct wusb_keydvt_out stv_keydvt_out_a1 = { | ||
458 | .kck = { | ||
459 | 0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d, | ||
460 | 0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f | ||
461 | }, | ||
462 | .ptk = { | ||
463 | 0xc8, 0x70, 0x62, 0x82, 0xb6, 0x7c, 0xe9, 0x06, | ||
464 | 0x7b, 0xc5, 0x25, 0x69, 0xf2, 0x36, 0x61, 0x2d | ||
465 | } | ||
466 | }; | ||
467 | |||
468 | /* | ||
469 | * Performa a test to make sure we match the vectors defined in | ||
470 | * WUSB1.0[A.1](Errata2006/12) | ||
471 | */ | ||
472 | static int wusb_key_derive_verify(void) | ||
473 | { | ||
474 | int result = 0; | ||
475 | struct wusb_keydvt_out keydvt_out; | ||
476 | /* These come from WUSB1.0[A.1] + 2006/12 errata | ||
477 | * NOTE: can't make this const or global -- somehow it seems | ||
478 | * the scatterlists for crypto get confused and we get | ||
479 | * bad data. There is no doc on this... */ | ||
480 | struct wusb_keydvt_in stv_keydvt_in_a1 = { | ||
481 | .hnonce = { | ||
482 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | ||
483 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f | ||
484 | }, | ||
485 | .dnonce = { | ||
486 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | ||
487 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f | ||
488 | } | ||
489 | }; | ||
490 | |||
491 | result = wusb_key_derive(&keydvt_out, stv_key_a1, &stv_keydvt_n_a1, | ||
492 | &stv_keydvt_in_a1); | ||
493 | if (result < 0) | ||
494 | printk(KERN_ERR "E: WUSB key derivation test: " | ||
495 | "derivation failed: %d\n", result); | ||
496 | if (memcmp(&stv_keydvt_out_a1, &keydvt_out, sizeof(keydvt_out))) { | ||
497 | printk(KERN_ERR "E: WUSB key derivation test: " | ||
498 | "mismatch between key derivation result " | ||
499 | "and WUSB1.0[A1] Errata 2006/12\n"); | ||
500 | printk(KERN_ERR "E: keydvt in: key (%zu bytes)\n", | ||
501 | sizeof(stv_key_a1)); | ||
502 | dump_bytes(NULL, stv_key_a1, sizeof(stv_key_a1)); | ||
503 | printk(KERN_ERR "E: keydvt in: nonce (%zu bytes)\n", | ||
504 | sizeof(stv_keydvt_n_a1)); | ||
505 | dump_bytes(NULL, &stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1)); | ||
506 | printk(KERN_ERR "E: keydvt in: hnonce & dnonce (%zu bytes)\n", | ||
507 | sizeof(stv_keydvt_in_a1)); | ||
508 | dump_bytes(NULL, &stv_keydvt_in_a1, sizeof(stv_keydvt_in_a1)); | ||
509 | printk(KERN_ERR "E: keydvt out: KCK\n"); | ||
510 | dump_bytes(NULL, &keydvt_out.kck, sizeof(keydvt_out.kck)); | ||
511 | printk(KERN_ERR "E: keydvt out: PTK\n"); | ||
512 | dump_bytes(NULL, &keydvt_out.ptk, sizeof(keydvt_out.ptk)); | ||
513 | result = -EINVAL; | ||
514 | } else | ||
515 | result = 0; | ||
516 | return result; | ||
517 | } | ||
518 | |||
519 | /* | ||
520 | * Initialize crypto system | ||
521 | * | ||
522 | * FIXME: we do nothing now, other than verifying. Later on we'll | ||
523 | * cache the encryption stuff, so that's why we have a separate init. | ||
524 | */ | ||
525 | int wusb_crypto_init(void) | ||
526 | { | ||
527 | int result; | ||
528 | |||
529 | result = wusb_key_derive_verify(); | ||
530 | if (result < 0) | ||
531 | return result; | ||
532 | return wusb_oob_mic_verify(); | ||
533 | } | ||
534 | |||
535 | void wusb_crypto_exit(void) | ||
536 | { | ||
537 | /* FIXME: free cached crypto transforms */ | ||
538 | } | ||
diff --git a/drivers/usb/wusbcore/dev-sysfs.c b/drivers/usb/wusbcore/dev-sysfs.c new file mode 100644 index 000000000000..7897a19652e5 --- /dev/null +++ b/drivers/usb/wusbcore/dev-sysfs.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * WUSB devices | ||
3 | * sysfs bindings | ||
4 | * | ||
5 | * Copyright (C) 2007 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * Get them out of the way... | ||
24 | */ | ||
25 | |||
26 | #include <linux/jiffies.h> | ||
27 | #include <linux/ctype.h> | ||
28 | #include <linux/workqueue.h> | ||
29 | #include "wusbhc.h" | ||
30 | |||
31 | #undef D_LOCAL | ||
32 | #define D_LOCAL 4 | ||
33 | #include <linux/uwb/debug.h> | ||
34 | |||
35 | static ssize_t wusb_disconnect_store(struct device *dev, | ||
36 | struct device_attribute *attr, | ||
37 | const char *buf, size_t size) | ||
38 | { | ||
39 | struct usb_device *usb_dev; | ||
40 | struct wusbhc *wusbhc; | ||
41 | unsigned command; | ||
42 | u8 port_idx; | ||
43 | |||
44 | if (sscanf(buf, "%u", &command) != 1) | ||
45 | return -EINVAL; | ||
46 | if (command == 0) | ||
47 | return size; | ||
48 | usb_dev = to_usb_device(dev); | ||
49 | wusbhc = wusbhc_get_by_usb_dev(usb_dev); | ||
50 | if (wusbhc == NULL) | ||
51 | return -ENODEV; | ||
52 | |||
53 | mutex_lock(&wusbhc->mutex); | ||
54 | port_idx = wusb_port_no_to_idx(usb_dev->portnum); | ||
55 | __wusbhc_dev_disable(wusbhc, port_idx); | ||
56 | mutex_unlock(&wusbhc->mutex); | ||
57 | wusbhc_put(wusbhc); | ||
58 | return size; | ||
59 | } | ||
60 | static DEVICE_ATTR(wusb_disconnect, 0200, NULL, wusb_disconnect_store); | ||
61 | |||
62 | static ssize_t wusb_cdid_show(struct device *dev, | ||
63 | struct device_attribute *attr, char *buf) | ||
64 | { | ||
65 | ssize_t result; | ||
66 | struct wusb_dev *wusb_dev; | ||
67 | |||
68 | wusb_dev = wusb_dev_get_by_usb_dev(to_usb_device(dev)); | ||
69 | if (wusb_dev == NULL) | ||
70 | return -ENODEV; | ||
71 | result = ckhdid_printf(buf, PAGE_SIZE, &wusb_dev->cdid); | ||
72 | strcat(buf, "\n"); | ||
73 | wusb_dev_put(wusb_dev); | ||
74 | return result + 1; | ||
75 | } | ||
76 | static DEVICE_ATTR(wusb_cdid, 0444, wusb_cdid_show, NULL); | ||
77 | |||
78 | static ssize_t wusb_ck_store(struct device *dev, | ||
79 | struct device_attribute *attr, | ||
80 | const char *buf, size_t size) | ||
81 | { | ||
82 | int result; | ||
83 | struct usb_device *usb_dev; | ||
84 | struct wusbhc *wusbhc; | ||
85 | struct wusb_ckhdid ck; | ||
86 | |||
87 | result = sscanf(buf, | ||
88 | "%02hhx %02hhx %02hhx %02hhx " | ||
89 | "%02hhx %02hhx %02hhx %02hhx " | ||
90 | "%02hhx %02hhx %02hhx %02hhx " | ||
91 | "%02hhx %02hhx %02hhx %02hhx\n", | ||
92 | &ck.data[0] , &ck.data[1], | ||
93 | &ck.data[2] , &ck.data[3], | ||
94 | &ck.data[4] , &ck.data[5], | ||
95 | &ck.data[6] , &ck.data[7], | ||
96 | &ck.data[8] , &ck.data[9], | ||
97 | &ck.data[10], &ck.data[11], | ||
98 | &ck.data[12], &ck.data[13], | ||
99 | &ck.data[14], &ck.data[15]); | ||
100 | if (result != 16) | ||
101 | return -EINVAL; | ||
102 | |||
103 | usb_dev = to_usb_device(dev); | ||
104 | wusbhc = wusbhc_get_by_usb_dev(usb_dev); | ||
105 | if (wusbhc == NULL) | ||
106 | return -ENODEV; | ||
107 | result = wusb_dev_4way_handshake(wusbhc, usb_dev->wusb_dev, &ck); | ||
108 | memset(&ck, 0, sizeof(ck)); | ||
109 | wusbhc_put(wusbhc); | ||
110 | return result < 0 ? result : size; | ||
111 | } | ||
112 | static DEVICE_ATTR(wusb_ck, 0200, NULL, wusb_ck_store); | ||
113 | |||
114 | static struct attribute *wusb_dev_attrs[] = { | ||
115 | &dev_attr_wusb_disconnect.attr, | ||
116 | &dev_attr_wusb_cdid.attr, | ||
117 | &dev_attr_wusb_ck.attr, | ||
118 | NULL, | ||
119 | }; | ||
120 | |||
121 | static struct attribute_group wusb_dev_attr_group = { | ||
122 | .name = NULL, /* we want them in the same directory */ | ||
123 | .attrs = wusb_dev_attrs, | ||
124 | }; | ||
125 | |||
126 | int wusb_dev_sysfs_add(struct wusbhc *wusbhc, struct usb_device *usb_dev, | ||
127 | struct wusb_dev *wusb_dev) | ||
128 | { | ||
129 | int result = sysfs_create_group(&usb_dev->dev.kobj, | ||
130 | &wusb_dev_attr_group); | ||
131 | struct device *dev = &usb_dev->dev; | ||
132 | if (result < 0) | ||
133 | dev_err(dev, "Cannot register WUSB-dev attributes: %d\n", | ||
134 | result); | ||
135 | return result; | ||
136 | } | ||
137 | |||
138 | void wusb_dev_sysfs_rm(struct wusb_dev *wusb_dev) | ||
139 | { | ||
140 | struct usb_device *usb_dev = wusb_dev->usb_dev; | ||
141 | if (usb_dev) | ||
142 | sysfs_remove_group(&usb_dev->dev.kobj, &wusb_dev_attr_group); | ||
143 | } | ||
diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c new file mode 100644 index 000000000000..30d7020e1c50 --- /dev/null +++ b/drivers/usb/wusbcore/devconnect.c | |||
@@ -0,0 +1,1314 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8]) | ||
3 | * Device Connect handling | ||
4 | * | ||
5 | * Copyright (C) 2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * FIXME: this file needs to be broken up, it's grown too big | ||
25 | * | ||
26 | * | ||
27 | * WUSB1.0[7.1, 7.5.1, ] | ||
28 | * | ||
29 | * WUSB device connection is kind of messy. Some background: | ||
30 | * | ||
31 | * When a device wants to connect it scans the UWB radio channels | ||
32 | * looking for a WUSB Channel; a WUSB channel is defined by MMCs | ||
33 | * (Micro Managed Commands or something like that) [see | ||
34 | * Design-overview for more on this] . | ||
35 | * | ||
36 | * So, device scans the radio, finds MMCs and thus a host and checks | ||
37 | * when the next DNTS is. It sends a Device Notification Connect | ||
38 | * (DN_Connect); the host picks it up (through nep.c and notif.c, ends | ||
39 | * up in wusb_devconnect_ack(), which creates a wusb_dev structure in | ||
40 | * wusbhc->port[port_number].wusb_dev), assigns an unauth address | ||
41 | * to the device (this means from 0x80 to 0xfe) and sends, in the MMC | ||
42 | * a Connect Ack Information Element (ConnAck IE). | ||
43 | * | ||
44 | * So now the device now has a WUSB address. From now on, we use | ||
45 | * that to talk to it in the RPipes. | ||
46 | * | ||
47 | * ASSUMPTIONS: | ||
48 | * | ||
49 | * - We use the the as device address the port number where it is | ||
50 | * connected (port 0 doesn't exist). For unauth, it is 128 + that. | ||
51 | * | ||
52 | * ROADMAP: | ||
53 | * | ||
54 | * This file contains the logic for doing that--entry points: | ||
55 | * | ||
56 | * wusb_devconnect_ack() Ack a device until _acked() called. | ||
57 | * Called by notif.c:wusb_handle_dn_connect() | ||
58 | * when a DN_Connect is received. | ||
59 | * | ||
60 | * wusbhc_devconnect_auth() Called by rh.c:wusbhc_rh_port_reset() when | ||
61 | * doing the device connect sequence. | ||
62 | * | ||
63 | * wusb_devconnect_acked() Ack done, release resources. | ||
64 | * | ||
65 | * wusb_handle_dn_alive() Called by notif.c:wusb_handle_dn() | ||
66 | * for processing a DN_Alive pong from a device. | ||
67 | * | ||
68 | * wusb_handle_dn_disconnect()Called by notif.c:wusb_handle_dn() to | ||
69 | * process a disconenct request from a | ||
70 | * device. | ||
71 | * | ||
72 | * wusb_dev_reset() Called by rh.c:wusbhc_rh_port_reset() when | ||
73 | * resetting a device. | ||
74 | * | ||
75 | * __wusb_dev_disable() Called by rh.c:wusbhc_rh_clear_port_feat() when | ||
76 | * disabling a port. | ||
77 | * | ||
78 | * wusb_devconnect_create() Called when creating the host by | ||
79 | * lc.c:wusbhc_create(). | ||
80 | * | ||
81 | * wusb_devconnect_destroy() Cleanup called removing the host. Called | ||
82 | * by lc.c:wusbhc_destroy(). | ||
83 | * | ||
84 | * Each Wireless USB host maintains a list of DN_Connect requests | ||
85 | * (actually we maintain a list of pending Connect Acks, the | ||
86 | * wusbhc->ca_list). | ||
87 | * | ||
88 | * LIFE CYCLE OF port->wusb_dev | ||
89 | * | ||
90 | * Before the @wusbhc structure put()s the reference it owns for | ||
91 | * port->wusb_dev [and clean the wusb_dev pointer], it needs to | ||
92 | * lock @wusbhc->mutex. | ||
93 | */ | ||
94 | |||
95 | #include <linux/jiffies.h> | ||
96 | #include <linux/ctype.h> | ||
97 | #include <linux/workqueue.h> | ||
98 | #include "wusbhc.h" | ||
99 | |||
100 | #undef D_LOCAL | ||
101 | #define D_LOCAL 1 | ||
102 | #include <linux/uwb/debug.h> | ||
103 | |||
104 | static void wusbhc_devconnect_acked_work(struct work_struct *work); | ||
105 | |||
106 | static void wusb_dev_free(struct wusb_dev *wusb_dev) | ||
107 | { | ||
108 | if (wusb_dev) { | ||
109 | kfree(wusb_dev->set_gtk_req); | ||
110 | usb_free_urb(wusb_dev->set_gtk_urb); | ||
111 | kfree(wusb_dev); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc) | ||
116 | { | ||
117 | struct wusb_dev *wusb_dev; | ||
118 | struct urb *urb; | ||
119 | struct usb_ctrlrequest *req; | ||
120 | |||
121 | wusb_dev = kzalloc(sizeof(*wusb_dev), GFP_KERNEL); | ||
122 | if (wusb_dev == NULL) | ||
123 | goto err; | ||
124 | |||
125 | wusb_dev->wusbhc = wusbhc; | ||
126 | |||
127 | INIT_WORK(&wusb_dev->devconnect_acked_work, wusbhc_devconnect_acked_work); | ||
128 | |||
129 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
130 | if (urb == NULL) | ||
131 | goto err; | ||
132 | |||
133 | req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); | ||
134 | if (req == NULL) | ||
135 | goto err; | ||
136 | |||
137 | req->bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; | ||
138 | req->bRequest = USB_REQ_SET_DESCRIPTOR; | ||
139 | req->wValue = cpu_to_le16(USB_DT_KEY << 8 | wusbhc->gtk_index); | ||
140 | req->wIndex = 0; | ||
141 | req->wLength = cpu_to_le16(wusbhc->gtk.descr.bLength); | ||
142 | |||
143 | wusb_dev->set_gtk_urb = urb; | ||
144 | wusb_dev->set_gtk_req = req; | ||
145 | |||
146 | return wusb_dev; | ||
147 | err: | ||
148 | wusb_dev_free(wusb_dev); | ||
149 | return NULL; | ||
150 | } | ||
151 | |||
152 | |||
153 | /* | ||
154 | * Using the Connect-Ack list, fill out the @wusbhc Connect-Ack WUSB IE | ||
155 | * properly so that it can be added to the MMC. | ||
156 | * | ||
157 | * We just get the @wusbhc->ca_list and fill out the first four ones or | ||
158 | * less (per-spec WUSB1.0[7.5, before T7-38). If the ConnectAck WUSB | ||
159 | * IE is not allocated, we alloc it. | ||
160 | * | ||
161 | * @wusbhc->mutex must be taken | ||
162 | */ | ||
163 | static void wusbhc_fill_cack_ie(struct wusbhc *wusbhc) | ||
164 | { | ||
165 | unsigned cnt; | ||
166 | struct wusb_dev *dev_itr; | ||
167 | struct wuie_connect_ack *cack_ie; | ||
168 | |||
169 | cack_ie = &wusbhc->cack_ie; | ||
170 | cnt = 0; | ||
171 | list_for_each_entry(dev_itr, &wusbhc->cack_list, cack_node) { | ||
172 | cack_ie->blk[cnt].CDID = dev_itr->cdid; | ||
173 | cack_ie->blk[cnt].bDeviceAddress = dev_itr->addr; | ||
174 | if (++cnt >= WUIE_ELT_MAX) | ||
175 | break; | ||
176 | } | ||
177 | cack_ie->hdr.bLength = sizeof(cack_ie->hdr) | ||
178 | + cnt * sizeof(cack_ie->blk[0]); | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * Register a new device that wants to connect | ||
183 | * | ||
184 | * A new device wants to connect, so we add it to the Connect-Ack | ||
185 | * list. We give it an address in the unauthorized range (bit 8 set); | ||
186 | * user space will have to drive authorization further on. | ||
187 | * | ||
188 | * @dev_addr: address to use for the device (which is also the port | ||
189 | * number). | ||
190 | * | ||
191 | * @wusbhc->mutex must be taken | ||
192 | */ | ||
193 | static struct wusb_dev *wusbhc_cack_add(struct wusbhc *wusbhc, | ||
194 | struct wusb_dn_connect *dnc, | ||
195 | const char *pr_cdid, u8 port_idx) | ||
196 | { | ||
197 | struct device *dev = wusbhc->dev; | ||
198 | struct wusb_dev *wusb_dev; | ||
199 | int new_connection = wusb_dn_connect_new_connection(dnc); | ||
200 | u8 dev_addr; | ||
201 | int result; | ||
202 | |||
203 | d_fnstart(3, dev, "(wusbhc %p port_idx %d)\n", wusbhc, port_idx); | ||
204 | /* Is it registered already? */ | ||
205 | list_for_each_entry(wusb_dev, &wusbhc->cack_list, cack_node) | ||
206 | if (!memcmp(&wusb_dev->cdid, &dnc->CDID, | ||
207 | sizeof(wusb_dev->cdid))) | ||
208 | return wusb_dev; | ||
209 | /* We don't have it, create an entry, register it */ | ||
210 | wusb_dev = wusb_dev_alloc(wusbhc); | ||
211 | if (wusb_dev == NULL) { | ||
212 | if (printk_ratelimit()) | ||
213 | dev_err(dev, "DN CONNECT: no memory to process %s's %s " | ||
214 | "request\n", pr_cdid, | ||
215 | new_connection ? "connect" : "reconnect"); | ||
216 | return NULL; | ||
217 | } | ||
218 | wusb_dev_init(wusb_dev); | ||
219 | wusb_dev->cdid = dnc->CDID; | ||
220 | wusb_dev->port_idx = port_idx; | ||
221 | |||
222 | /* | ||
223 | * Devices are always available within the cluster reservation | ||
224 | * and since the hardware will take the intersection of the | ||
225 | * per-device availability and the cluster reservation, the | ||
226 | * per-device availability can simply be set to always | ||
227 | * available. | ||
228 | */ | ||
229 | bitmap_fill(wusb_dev->availability.bm, UWB_NUM_MAS); | ||
230 | |||
231 | /* FIXME: handle reconnects instead of assuming connects are | ||
232 | always new. */ | ||
233 | if (1 && new_connection == 0) | ||
234 | new_connection = 1; | ||
235 | if (new_connection) { | ||
236 | dev_addr = (port_idx + 2) | WUSB_DEV_ADDR_UNAUTH; | ||
237 | |||
238 | dev_info(dev, "Connecting new WUSB device to address %u, " | ||
239 | "port %u\n", dev_addr, port_idx); | ||
240 | |||
241 | result = wusb_set_dev_addr(wusbhc, wusb_dev, dev_addr); | ||
242 | if (result < 0) | ||
243 | return NULL; | ||
244 | } | ||
245 | wusb_dev->entry_ts = jiffies; | ||
246 | list_add_tail(&wusb_dev->cack_node, &wusbhc->cack_list); | ||
247 | wusbhc->cack_count++; | ||
248 | wusbhc_fill_cack_ie(wusbhc); | ||
249 | d_fnend(3, dev, "(wusbhc %p port_idx %d)\n", wusbhc, port_idx); | ||
250 | return wusb_dev; | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * Remove a Connect-Ack context entry from the HCs view | ||
255 | * | ||
256 | * @wusbhc->mutex must be taken | ||
257 | */ | ||
258 | static void wusbhc_cack_rm(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
259 | { | ||
260 | struct device *dev = wusbhc->dev; | ||
261 | d_fnstart(3, dev, "(wusbhc %p wusb_dev %p)\n", wusbhc, wusb_dev); | ||
262 | list_del_init(&wusb_dev->cack_node); | ||
263 | wusbhc->cack_count--; | ||
264 | wusbhc_fill_cack_ie(wusbhc); | ||
265 | d_fnend(3, dev, "(wusbhc %p wusb_dev %p) = void\n", wusbhc, wusb_dev); | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * @wusbhc->mutex must be taken */ | ||
270 | static | ||
271 | void wusbhc_devconnect_acked(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
272 | { | ||
273 | struct device *dev = wusbhc->dev; | ||
274 | d_fnstart(3, dev, "(wusbhc %p wusb_dev %p)\n", wusbhc, wusb_dev); | ||
275 | wusbhc_cack_rm(wusbhc, wusb_dev); | ||
276 | if (wusbhc->cack_count) | ||
277 | wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr); | ||
278 | else | ||
279 | wusbhc_mmcie_rm(wusbhc, &wusbhc->cack_ie.hdr); | ||
280 | d_fnend(3, dev, "(wusbhc %p wusb_dev %p) = void\n", wusbhc, wusb_dev); | ||
281 | } | ||
282 | |||
283 | static void wusbhc_devconnect_acked_work(struct work_struct *work) | ||
284 | { | ||
285 | struct wusb_dev *wusb_dev = container_of(work, struct wusb_dev, | ||
286 | devconnect_acked_work); | ||
287 | struct wusbhc *wusbhc = wusb_dev->wusbhc; | ||
288 | |||
289 | mutex_lock(&wusbhc->mutex); | ||
290 | wusbhc_devconnect_acked(wusbhc, wusb_dev); | ||
291 | mutex_unlock(&wusbhc->mutex); | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Ack a device for connection | ||
296 | * | ||
297 | * FIXME: docs | ||
298 | * | ||
299 | * @pr_cdid: Printable CDID...hex Use @dnc->cdid for the real deal. | ||
300 | * | ||
301 | * So we get the connect ack IE (may have been allocated already), | ||
302 | * find an empty connect block, an empty virtual port, create an | ||
303 | * address with it (see below), make it an unauth addr [bit 7 set] and | ||
304 | * set the MMC. | ||
305 | * | ||
306 | * Addresses: because WUSB hosts have no downstream hubs, we can do a | ||
307 | * 1:1 mapping between 'port number' and device | ||
308 | * address. This simplifies many things, as during this | ||
309 | * initial connect phase the USB stack has no knoledge of | ||
310 | * the device and hasn't assigned an address yet--we know | ||
311 | * USB's choose_address() will use the same euristics we | ||
312 | * use here, so we can assume which address will be assigned. | ||
313 | * | ||
314 | * USB stack always assigns address 1 to the root hub, so | ||
315 | * to the port number we add 2 (thus virtual port #0 is | ||
316 | * addr #2). | ||
317 | * | ||
318 | * @wusbhc shall be referenced | ||
319 | */ | ||
320 | static | ||
321 | void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc, | ||
322 | const char *pr_cdid) | ||
323 | { | ||
324 | int result; | ||
325 | struct device *dev = wusbhc->dev; | ||
326 | struct wusb_dev *wusb_dev; | ||
327 | struct wusb_port *port; | ||
328 | unsigned idx, devnum; | ||
329 | |||
330 | d_fnstart(3, dev, "(%p, %p, %s)\n", wusbhc, dnc, pr_cdid); | ||
331 | mutex_lock(&wusbhc->mutex); | ||
332 | |||
333 | /* Check we are not handling it already */ | ||
334 | for (idx = 0; idx < wusbhc->ports_max; idx++) { | ||
335 | port = wusb_port_by_idx(wusbhc, idx); | ||
336 | if (port->wusb_dev | ||
337 | && !memcmp(&dnc->CDID, &port->wusb_dev->cdid, | ||
338 | sizeof(dnc->CDID))) { | ||
339 | if (printk_ratelimit()) | ||
340 | dev_err(dev, "Already handling dev %s " | ||
341 | " (it might be slow)\n", pr_cdid); | ||
342 | goto error_unlock; | ||
343 | } | ||
344 | } | ||
345 | /* Look up those fake ports we have for a free one */ | ||
346 | for (idx = 0; idx < wusbhc->ports_max; idx++) { | ||
347 | port = wusb_port_by_idx(wusbhc, idx); | ||
348 | if ((port->status & USB_PORT_STAT_POWER) | ||
349 | && !(port->status & USB_PORT_STAT_CONNECTION)) | ||
350 | break; | ||
351 | } | ||
352 | if (idx >= wusbhc->ports_max) { | ||
353 | dev_err(dev, "Host controller can't connect more devices " | ||
354 | "(%u already connected); device %s rejected\n", | ||
355 | wusbhc->ports_max, pr_cdid); | ||
356 | /* NOTE: we could send a WUIE_Disconnect here, but we haven't | ||
357 | * event acked, so the device will eventually timeout the | ||
358 | * connection, right? */ | ||
359 | goto error_unlock; | ||
360 | } | ||
361 | |||
362 | devnum = idx + 2; | ||
363 | |||
364 | /* Make sure we are using no crypto on that "virtual port" */ | ||
365 | wusbhc->set_ptk(wusbhc, idx, 0, NULL, 0); | ||
366 | |||
367 | /* Grab a filled in Connect-Ack context, fill out the | ||
368 | * Connect-Ack Wireless USB IE, set the MMC */ | ||
369 | wusb_dev = wusbhc_cack_add(wusbhc, dnc, pr_cdid, idx); | ||
370 | if (wusb_dev == NULL) | ||
371 | goto error_unlock; | ||
372 | result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr); | ||
373 | if (result < 0) | ||
374 | goto error_unlock; | ||
375 | /* Give the device at least 2ms (WUSB1.0[7.5.1p3]), let's do | ||
376 | * three for a good measure */ | ||
377 | msleep(3); | ||
378 | port->wusb_dev = wusb_dev; | ||
379 | port->status |= USB_PORT_STAT_CONNECTION; | ||
380 | port->change |= USB_PORT_STAT_C_CONNECTION; | ||
381 | port->reset_count = 0; | ||
382 | /* Now the port status changed to connected; khubd will | ||
383 | * pick the change up and try to reset the port to bring it to | ||
384 | * the enabled state--so this process returns up to the stack | ||
385 | * and it calls back into wusbhc_rh_port_reset() who will call | ||
386 | * devconnect_auth(). | ||
387 | */ | ||
388 | error_unlock: | ||
389 | mutex_unlock(&wusbhc->mutex); | ||
390 | d_fnend(3, dev, "(%p, %p, %s) = void\n", wusbhc, dnc, pr_cdid); | ||
391 | return; | ||
392 | |||
393 | } | ||
394 | |||
395 | /* | ||
396 | * Disconnect a Wireless USB device from its fake port | ||
397 | * | ||
398 | * Marks the port as disconnected so that khubd can pick up the change | ||
399 | * and drops our knowledge about the device. | ||
400 | * | ||
401 | * Assumes there is a device connected | ||
402 | * | ||
403 | * @port_index: zero based port number | ||
404 | * | ||
405 | * NOTE: @wusbhc->mutex is locked | ||
406 | * | ||
407 | * WARNING: From here it is not very safe to access anything hanging off | ||
408 | * wusb_dev | ||
409 | */ | ||
410 | static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc, | ||
411 | struct wusb_port *port) | ||
412 | { | ||
413 | struct device *dev = wusbhc->dev; | ||
414 | struct wusb_dev *wusb_dev = port->wusb_dev; | ||
415 | |||
416 | d_fnstart(3, dev, "(wusbhc %p, port %p)\n", wusbhc, port); | ||
417 | port->status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | ||
418 | | USB_PORT_STAT_SUSPEND | USB_PORT_STAT_RESET | ||
419 | | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); | ||
420 | port->change |= USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE; | ||
421 | if (wusb_dev) { | ||
422 | if (!list_empty(&wusb_dev->cack_node)) | ||
423 | list_del_init(&wusb_dev->cack_node); | ||
424 | /* For the one in cack_add() */ | ||
425 | wusb_dev_put(wusb_dev); | ||
426 | } | ||
427 | port->wusb_dev = NULL; | ||
428 | /* don't reset the reset_count to zero or wusbhc_rh_port_reset will get | ||
429 | * confused! We only reset to zero when we connect a new device. | ||
430 | */ | ||
431 | |||
432 | /* After a device disconnects, change the GTK (see [WUSB] | ||
433 | * section 6.2.11.2). */ | ||
434 | wusbhc_gtk_rekey(wusbhc); | ||
435 | |||
436 | d_fnend(3, dev, "(wusbhc %p, port %p) = void\n", wusbhc, port); | ||
437 | /* The Wireless USB part has forgotten about the device already; now | ||
438 | * khubd's timer will pick up the disconnection and remove the USB | ||
439 | * device from the system | ||
440 | */ | ||
441 | } | ||
442 | |||
443 | /* | ||
444 | * Authenticate a device into the WUSB Cluster | ||
445 | * | ||
446 | * Called from the Root Hub code (rh.c:wusbhc_rh_port_reset()) when | ||
447 | * asking for a reset on a port that is not enabled (ie: first connect | ||
448 | * on the port). | ||
449 | * | ||
450 | * Performs the 4way handshake to allow the device to comunicate w/ the | ||
451 | * WUSB Cluster securely; once done, issue a request to the device for | ||
452 | * it to change to address 0. | ||
453 | * | ||
454 | * This mimics the reset step of Wired USB that once resetting a | ||
455 | * device, leaves the port in enabled state and the dev with the | ||
456 | * default address (0). | ||
457 | * | ||
458 | * WUSB1.0[7.1.2] | ||
459 | * | ||
460 | * @port_idx: port where the change happened--This is the index into | ||
461 | * the wusbhc port array, not the USB port number. | ||
462 | */ | ||
463 | int wusbhc_devconnect_auth(struct wusbhc *wusbhc, u8 port_idx) | ||
464 | { | ||
465 | struct device *dev = wusbhc->dev; | ||
466 | struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx); | ||
467 | |||
468 | d_fnstart(3, dev, "(%p, %u)\n", wusbhc, port_idx); | ||
469 | port->status &= ~USB_PORT_STAT_RESET; | ||
470 | port->status |= USB_PORT_STAT_ENABLE; | ||
471 | port->change |= USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_ENABLE; | ||
472 | d_fnend(3, dev, "(%p, %u) = 0\n", wusbhc, port_idx); | ||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | /* | ||
477 | * Refresh the list of keep alives to emit in the MMC | ||
478 | * | ||
479 | * Some devices don't respond to keep alives unless they've been | ||
480 | * authenticated, so skip unauthenticated devices. | ||
481 | * | ||
482 | * We only publish the first four devices that have a coming timeout | ||
483 | * condition. Then when we are done processing those, we go for the | ||
484 | * next ones. We ignore the ones that have timed out already (they'll | ||
485 | * be purged). | ||
486 | * | ||
487 | * This might cause the first devices to timeout the last devices in | ||
488 | * the port array...FIXME: come up with a better algorithm? | ||
489 | * | ||
490 | * Note we can't do much about MMC's ops errors; we hope next refresh | ||
491 | * will kind of handle it. | ||
492 | * | ||
493 | * NOTE: @wusbhc->mutex is locked | ||
494 | */ | ||
495 | static void __wusbhc_keep_alive(struct wusbhc *wusbhc) | ||
496 | { | ||
497 | int result; | ||
498 | struct device *dev = wusbhc->dev; | ||
499 | unsigned cnt; | ||
500 | struct wusb_dev *wusb_dev; | ||
501 | struct wusb_port *wusb_port; | ||
502 | struct wuie_keep_alive *ie = &wusbhc->keep_alive_ie; | ||
503 | unsigned keep_alives, old_keep_alives; | ||
504 | |||
505 | d_fnstart(5, dev, "(wusbhc %p)\n", wusbhc); | ||
506 | old_keep_alives = ie->hdr.bLength - sizeof(ie->hdr); | ||
507 | keep_alives = 0; | ||
508 | for (cnt = 0; | ||
509 | keep_alives <= WUIE_ELT_MAX && cnt < wusbhc->ports_max; | ||
510 | cnt++) { | ||
511 | unsigned tt = msecs_to_jiffies(wusbhc->trust_timeout); | ||
512 | |||
513 | wusb_port = wusb_port_by_idx(wusbhc, cnt); | ||
514 | wusb_dev = wusb_port->wusb_dev; | ||
515 | |||
516 | if (wusb_dev == NULL) | ||
517 | continue; | ||
518 | if (wusb_dev->usb_dev == NULL || !wusb_dev->usb_dev->authenticated) | ||
519 | continue; | ||
520 | |||
521 | if (time_after(jiffies, wusb_dev->entry_ts + tt)) { | ||
522 | dev_err(dev, "KEEPALIVE: device %u timed out\n", | ||
523 | wusb_dev->addr); | ||
524 | __wusbhc_dev_disconnect(wusbhc, wusb_port); | ||
525 | } else if (time_after(jiffies, wusb_dev->entry_ts + tt/2)) { | ||
526 | /* Approaching timeout cut out, need to refresh */ | ||
527 | ie->bDeviceAddress[keep_alives++] = wusb_dev->addr; | ||
528 | } | ||
529 | } | ||
530 | if (keep_alives & 0x1) /* pad to even number ([WUSB] section 7.5.9) */ | ||
531 | ie->bDeviceAddress[keep_alives++] = 0x7f; | ||
532 | ie->hdr.bLength = sizeof(ie->hdr) + | ||
533 | keep_alives*sizeof(ie->bDeviceAddress[0]); | ||
534 | if (keep_alives > 0) { | ||
535 | result = wusbhc_mmcie_set(wusbhc, 10, 5, &ie->hdr); | ||
536 | if (result < 0 && printk_ratelimit()) | ||
537 | dev_err(dev, "KEEPALIVE: can't set MMC: %d\n", result); | ||
538 | } else if (old_keep_alives != 0) | ||
539 | wusbhc_mmcie_rm(wusbhc, &ie->hdr); | ||
540 | d_fnend(5, dev, "(wusbhc %p) = void\n", wusbhc); | ||
541 | } | ||
542 | |||
543 | /* | ||
544 | * Do a run through all devices checking for timeouts | ||
545 | */ | ||
546 | static void wusbhc_keep_alive_run(struct work_struct *ws) | ||
547 | { | ||
548 | struct delayed_work *dw = | ||
549 | container_of(ws, struct delayed_work, work); | ||
550 | struct wusbhc *wusbhc = | ||
551 | container_of(dw, struct wusbhc, keep_alive_timer); | ||
552 | |||
553 | d_fnstart(5, wusbhc->dev, "(wusbhc %p)\n", wusbhc); | ||
554 | if (wusbhc->active) { | ||
555 | mutex_lock(&wusbhc->mutex); | ||
556 | __wusbhc_keep_alive(wusbhc); | ||
557 | mutex_unlock(&wusbhc->mutex); | ||
558 | queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, | ||
559 | (wusbhc->trust_timeout * CONFIG_HZ)/1000/2); | ||
560 | } | ||
561 | d_fnend(5, wusbhc->dev, "(wusbhc %p) = void\n", wusbhc); | ||
562 | return; | ||
563 | } | ||
564 | |||
565 | /* | ||
566 | * Find the wusb_dev from its device address. | ||
567 | * | ||
568 | * The device can be found directly from the address (see | ||
569 | * wusb_cack_add() for where the device address is set to port_idx | ||
570 | * +2), except when the address is zero. | ||
571 | */ | ||
572 | static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr) | ||
573 | { | ||
574 | int p; | ||
575 | |||
576 | if (addr == 0xff) /* unconnected */ | ||
577 | return NULL; | ||
578 | |||
579 | if (addr > 0) { | ||
580 | int port = (addr & ~0x80) - 2; | ||
581 | if (port < 0 || port >= wusbhc->ports_max) | ||
582 | return NULL; | ||
583 | return wusb_port_by_idx(wusbhc, port)->wusb_dev; | ||
584 | } | ||
585 | |||
586 | /* Look for the device with address 0. */ | ||
587 | for (p = 0; p < wusbhc->ports_max; p++) { | ||
588 | struct wusb_dev *wusb_dev = wusb_port_by_idx(wusbhc, p)->wusb_dev; | ||
589 | if (wusb_dev && wusb_dev->addr == addr) | ||
590 | return wusb_dev; | ||
591 | } | ||
592 | return NULL; | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | * Handle a DN_Alive notification (WUSB1.0[7.6.1]) | ||
597 | * | ||
598 | * This just updates the device activity timestamp and then refreshes | ||
599 | * the keep alive IE. | ||
600 | * | ||
601 | * @wusbhc shall be referenced and unlocked | ||
602 | */ | ||
603 | static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
604 | { | ||
605 | struct device *dev = wusbhc->dev; | ||
606 | |||
607 | d_printf(2, dev, "DN ALIVE: device 0x%02x pong\n", wusb_dev->addr); | ||
608 | |||
609 | mutex_lock(&wusbhc->mutex); | ||
610 | wusb_dev->entry_ts = jiffies; | ||
611 | __wusbhc_keep_alive(wusbhc); | ||
612 | mutex_unlock(&wusbhc->mutex); | ||
613 | } | ||
614 | |||
615 | /* | ||
616 | * Handle a DN_Connect notification (WUSB1.0[7.6.1]) | ||
617 | * | ||
618 | * @wusbhc | ||
619 | * @pkt_hdr | ||
620 | * @size: Size of the buffer where the notification resides; if the | ||
621 | * notification data suggests there should be more data than | ||
622 | * available, an error will be signaled and the whole buffer | ||
623 | * consumed. | ||
624 | * | ||
625 | * @wusbhc->mutex shall be held | ||
626 | */ | ||
627 | static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc, | ||
628 | struct wusb_dn_hdr *dn_hdr, | ||
629 | size_t size) | ||
630 | { | ||
631 | struct device *dev = wusbhc->dev; | ||
632 | struct wusb_dn_connect *dnc; | ||
633 | char pr_cdid[WUSB_CKHDID_STRSIZE]; | ||
634 | static const char *beacon_behaviour[] = { | ||
635 | "reserved", | ||
636 | "self-beacon", | ||
637 | "directed-beacon", | ||
638 | "no-beacon" | ||
639 | }; | ||
640 | |||
641 | d_fnstart(3, dev, "(%p, %p, %zu)\n", wusbhc, dn_hdr, size); | ||
642 | if (size < sizeof(*dnc)) { | ||
643 | dev_err(dev, "DN CONNECT: short notification (%zu < %zu)\n", | ||
644 | size, sizeof(*dnc)); | ||
645 | goto out; | ||
646 | } | ||
647 | |||
648 | dnc = container_of(dn_hdr, struct wusb_dn_connect, hdr); | ||
649 | ckhdid_printf(pr_cdid, sizeof(pr_cdid), &dnc->CDID); | ||
650 | dev_info(dev, "DN CONNECT: device %s @ %x (%s) wants to %s\n", | ||
651 | pr_cdid, | ||
652 | wusb_dn_connect_prev_dev_addr(dnc), | ||
653 | beacon_behaviour[wusb_dn_connect_beacon_behavior(dnc)], | ||
654 | wusb_dn_connect_new_connection(dnc) ? "connect" : "reconnect"); | ||
655 | /* ACK the connect */ | ||
656 | wusbhc_devconnect_ack(wusbhc, dnc, pr_cdid); | ||
657 | out: | ||
658 | d_fnend(3, dev, "(%p, %p, %zu) = void\n", | ||
659 | wusbhc, dn_hdr, size); | ||
660 | return; | ||
661 | } | ||
662 | |||
663 | /* | ||
664 | * Handle a DN_Disconnect notification (WUSB1.0[7.6.1]) | ||
665 | * | ||
666 | * Device is going down -- do the disconnect. | ||
667 | * | ||
668 | * @wusbhc shall be referenced and unlocked | ||
669 | */ | ||
670 | static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
671 | { | ||
672 | struct device *dev = wusbhc->dev; | ||
673 | |||
674 | dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n", wusb_dev->addr); | ||
675 | |||
676 | mutex_lock(&wusbhc->mutex); | ||
677 | __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, wusb_dev->port_idx)); | ||
678 | mutex_unlock(&wusbhc->mutex); | ||
679 | } | ||
680 | |||
681 | /* | ||
682 | * Reset a WUSB device on a HWA | ||
683 | * | ||
684 | * @wusbhc | ||
685 | * @port_idx Index of the port where the device is | ||
686 | * | ||
687 | * In Wireless USB, a reset is more or less equivalent to a full | ||
688 | * disconnect; so we just do a full disconnect and send the device a | ||
689 | * Device Reset IE (WUSB1.0[7.5.11]) giving it a few millisecs (6 MMCs). | ||
690 | * | ||
691 | * @wusbhc should be refcounted and unlocked | ||
692 | */ | ||
693 | int wusbhc_dev_reset(struct wusbhc *wusbhc, u8 port_idx) | ||
694 | { | ||
695 | int result; | ||
696 | struct device *dev = wusbhc->dev; | ||
697 | struct wusb_dev *wusb_dev; | ||
698 | struct wuie_reset *ie; | ||
699 | |||
700 | d_fnstart(3, dev, "(%p, %u)\n", wusbhc, port_idx); | ||
701 | mutex_lock(&wusbhc->mutex); | ||
702 | result = 0; | ||
703 | wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev; | ||
704 | if (wusb_dev == NULL) { | ||
705 | /* reset no device? ignore */ | ||
706 | dev_dbg(dev, "RESET: no device at port %u, ignoring\n", | ||
707 | port_idx); | ||
708 | goto error_unlock; | ||
709 | } | ||
710 | result = -ENOMEM; | ||
711 | ie = kzalloc(sizeof(*ie), GFP_KERNEL); | ||
712 | if (ie == NULL) | ||
713 | goto error_unlock; | ||
714 | ie->hdr.bLength = sizeof(ie->hdr) + sizeof(ie->CDID); | ||
715 | ie->hdr.bIEIdentifier = WUIE_ID_RESET_DEVICE; | ||
716 | ie->CDID = wusb_dev->cdid; | ||
717 | result = wusbhc_mmcie_set(wusbhc, 0xff, 6, &ie->hdr); | ||
718 | if (result < 0) { | ||
719 | dev_err(dev, "RESET: cant's set MMC: %d\n", result); | ||
720 | goto error_kfree; | ||
721 | } | ||
722 | __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx)); | ||
723 | |||
724 | /* 120ms, hopefully 6 MMCs (FIXME) */ | ||
725 | msleep(120); | ||
726 | wusbhc_mmcie_rm(wusbhc, &ie->hdr); | ||
727 | error_kfree: | ||
728 | kfree(ie); | ||
729 | error_unlock: | ||
730 | mutex_unlock(&wusbhc->mutex); | ||
731 | d_fnend(3, dev, "(%p, %u) = %d\n", wusbhc, port_idx, result); | ||
732 | return result; | ||
733 | } | ||
734 | |||
735 | /* | ||
736 | * Handle a Device Notification coming a host | ||
737 | * | ||
738 | * The Device Notification comes from a host (HWA, DWA or WHCI) | ||
739 | * wrapped in a set of headers. Somebody else has peeled off those | ||
740 | * headers for us and we just get one Device Notifications. | ||
741 | * | ||
742 | * Invalid DNs (e.g., too short) are discarded. | ||
743 | * | ||
744 | * @wusbhc shall be referenced | ||
745 | * | ||
746 | * FIXMES: | ||
747 | * - implement priorities as in WUSB1.0[Table 7-55]? | ||
748 | */ | ||
749 | void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr, | ||
750 | struct wusb_dn_hdr *dn_hdr, size_t size) | ||
751 | { | ||
752 | struct device *dev = wusbhc->dev; | ||
753 | struct wusb_dev *wusb_dev; | ||
754 | |||
755 | d_fnstart(3, dev, "(%p, %p)\n", wusbhc, dn_hdr); | ||
756 | |||
757 | if (size < sizeof(struct wusb_dn_hdr)) { | ||
758 | dev_err(dev, "DN data shorter than DN header (%d < %d)\n", | ||
759 | (int)size, (int)sizeof(struct wusb_dn_hdr)); | ||
760 | goto out; | ||
761 | } | ||
762 | |||
763 | wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr); | ||
764 | if (wusb_dev == NULL && dn_hdr->bType != WUSB_DN_CONNECT) { | ||
765 | dev_dbg(dev, "ignoring DN %d from unconnected device %02x\n", | ||
766 | dn_hdr->bType, srcaddr); | ||
767 | goto out; | ||
768 | } | ||
769 | |||
770 | switch (dn_hdr->bType) { | ||
771 | case WUSB_DN_CONNECT: | ||
772 | wusbhc_handle_dn_connect(wusbhc, dn_hdr, size); | ||
773 | break; | ||
774 | case WUSB_DN_ALIVE: | ||
775 | wusbhc_handle_dn_alive(wusbhc, wusb_dev); | ||
776 | break; | ||
777 | case WUSB_DN_DISCONNECT: | ||
778 | wusbhc_handle_dn_disconnect(wusbhc, wusb_dev); | ||
779 | break; | ||
780 | case WUSB_DN_MASAVAILCHANGED: | ||
781 | case WUSB_DN_RWAKE: | ||
782 | case WUSB_DN_SLEEP: | ||
783 | /* FIXME: handle these DNs. */ | ||
784 | break; | ||
785 | case WUSB_DN_EPRDY: | ||
786 | /* The hardware handles these. */ | ||
787 | break; | ||
788 | default: | ||
789 | dev_warn(dev, "unknown DN %u (%d octets) from %u\n", | ||
790 | dn_hdr->bType, (int)size, srcaddr); | ||
791 | } | ||
792 | out: | ||
793 | d_fnend(3, dev, "(%p, %p) = void\n", wusbhc, dn_hdr); | ||
794 | return; | ||
795 | } | ||
796 | EXPORT_SYMBOL_GPL(wusbhc_handle_dn); | ||
797 | |||
798 | /* | ||
799 | * Disconnect a WUSB device from a the cluster | ||
800 | * | ||
801 | * @wusbhc | ||
802 | * @port Fake port where the device is (wusbhc index, not USB port number). | ||
803 | * | ||
804 | * In Wireless USB, a disconnect is basically telling the device he is | ||
805 | * being disconnected and forgetting about him. | ||
806 | * | ||
807 | * We send the device a Device Disconnect IE (WUSB1.0[7.5.11]) for 100 | ||
808 | * ms and then keep going. | ||
809 | * | ||
810 | * We don't do much in case of error; we always pretend we disabled | ||
811 | * the port and disconnected the device. If physically the request | ||
812 | * didn't get there (many things can fail in the way there), the stack | ||
813 | * will reject the device's communication attempts. | ||
814 | * | ||
815 | * @wusbhc should be refcounted and locked | ||
816 | */ | ||
817 | void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port_idx) | ||
818 | { | ||
819 | int result; | ||
820 | struct device *dev = wusbhc->dev; | ||
821 | struct wusb_dev *wusb_dev; | ||
822 | struct wuie_disconnect *ie; | ||
823 | |||
824 | d_fnstart(3, dev, "(%p, %u)\n", wusbhc, port_idx); | ||
825 | result = 0; | ||
826 | wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev; | ||
827 | if (wusb_dev == NULL) { | ||
828 | /* reset no device? ignore */ | ||
829 | dev_dbg(dev, "DISCONNECT: no device at port %u, ignoring\n", | ||
830 | port_idx); | ||
831 | goto error; | ||
832 | } | ||
833 | __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx)); | ||
834 | |||
835 | result = -ENOMEM; | ||
836 | ie = kzalloc(sizeof(*ie), GFP_KERNEL); | ||
837 | if (ie == NULL) | ||
838 | goto error; | ||
839 | ie->hdr.bLength = sizeof(*ie); | ||
840 | ie->hdr.bIEIdentifier = WUIE_ID_DEVICE_DISCONNECT; | ||
841 | ie->bDeviceAddress = wusb_dev->addr; | ||
842 | result = wusbhc_mmcie_set(wusbhc, 0, 0, &ie->hdr); | ||
843 | if (result < 0) { | ||
844 | dev_err(dev, "DISCONNECT: can't set MMC: %d\n", result); | ||
845 | goto error_kfree; | ||
846 | } | ||
847 | |||
848 | /* 120ms, hopefully 6 MMCs */ | ||
849 | msleep(100); | ||
850 | wusbhc_mmcie_rm(wusbhc, &ie->hdr); | ||
851 | error_kfree: | ||
852 | kfree(ie); | ||
853 | error: | ||
854 | d_fnend(3, dev, "(%p, %u) = %d\n", wusbhc, port_idx, result); | ||
855 | return; | ||
856 | } | ||
857 | |||
858 | static void wusb_cap_descr_printf(const unsigned level, struct device *dev, | ||
859 | const struct usb_wireless_cap_descriptor *wcd) | ||
860 | { | ||
861 | d_printf(level, dev, | ||
862 | "WUSB Capability Descriptor\n" | ||
863 | " bDevCapabilityType 0x%02x\n" | ||
864 | " bmAttributes 0x%02x\n" | ||
865 | " wPhyRates 0x%04x\n" | ||
866 | " bmTFITXPowerInfo 0x%02x\n" | ||
867 | " bmFFITXPowerInfo 0x%02x\n" | ||
868 | " bmBandGroup 0x%04x\n" | ||
869 | " bReserved 0x%02x\n", | ||
870 | wcd->bDevCapabilityType, | ||
871 | wcd->bmAttributes, | ||
872 | le16_to_cpu(wcd->wPHYRates), | ||
873 | wcd->bmTFITXPowerInfo, | ||
874 | wcd->bmFFITXPowerInfo, | ||
875 | wcd->bmBandGroup, | ||
876 | wcd->bReserved); | ||
877 | } | ||
878 | |||
879 | /* | ||
880 | * Walk over the BOS descriptor, verify and grok it | ||
881 | * | ||
882 | * @usb_dev: referenced | ||
883 | * @wusb_dev: referenced and unlocked | ||
884 | * | ||
885 | * The BOS descriptor is defined at WUSB1.0[7.4.1], and it defines a | ||
886 | * "flexible" way to wrap all kinds of descriptors inside an standard | ||
887 | * descriptor (wonder why they didn't use normal descriptors, | ||
888 | * btw). Not like they lack code. | ||
889 | * | ||
890 | * At the end we go to look for the WUSB Device Capabilities | ||
891 | * (WUSB1.0[7.4.1.1]) that is wrapped in a device capability descriptor | ||
892 | * that is part of the BOS descriptor set. That tells us what does the | ||
893 | * device support (dual role, beacon type, UWB PHY rates). | ||
894 | */ | ||
895 | static int wusb_dev_bos_grok(struct usb_device *usb_dev, | ||
896 | struct wusb_dev *wusb_dev, | ||
897 | struct usb_bos_descriptor *bos, size_t desc_size) | ||
898 | { | ||
899 | ssize_t result; | ||
900 | struct device *dev = &usb_dev->dev; | ||
901 | void *itr, *top; | ||
902 | |||
903 | /* Walk over BOS capabilities, verify them */ | ||
904 | itr = (void *)bos + sizeof(*bos); | ||
905 | top = itr + desc_size - sizeof(*bos); | ||
906 | while (itr < top) { | ||
907 | struct usb_dev_cap_header *cap_hdr = itr; | ||
908 | size_t cap_size; | ||
909 | u8 cap_type; | ||
910 | if (top - itr < sizeof(*cap_hdr)) { | ||
911 | dev_err(dev, "Device BUG? premature end of BOS header " | ||
912 | "data [offset 0x%02x]: only %zu bytes left\n", | ||
913 | (int)(itr - (void *)bos), top - itr); | ||
914 | result = -ENOSPC; | ||
915 | goto error_bad_cap; | ||
916 | } | ||
917 | cap_size = cap_hdr->bLength; | ||
918 | cap_type = cap_hdr->bDevCapabilityType; | ||
919 | d_printf(4, dev, "BOS Capability: 0x%02x (%zu bytes)\n", | ||
920 | cap_type, cap_size); | ||
921 | if (cap_size == 0) | ||
922 | break; | ||
923 | if (cap_size > top - itr) { | ||
924 | dev_err(dev, "Device BUG? premature end of BOS data " | ||
925 | "[offset 0x%02x cap %02x %zu bytes]: " | ||
926 | "only %zu bytes left\n", | ||
927 | (int)(itr - (void *)bos), | ||
928 | cap_type, cap_size, top - itr); | ||
929 | result = -EBADF; | ||
930 | goto error_bad_cap; | ||
931 | } | ||
932 | d_dump(3, dev, itr, cap_size); | ||
933 | switch (cap_type) { | ||
934 | case USB_CAP_TYPE_WIRELESS_USB: | ||
935 | if (cap_size != sizeof(*wusb_dev->wusb_cap_descr)) | ||
936 | dev_err(dev, "Device BUG? WUSB Capability " | ||
937 | "descriptor is %zu bytes vs %zu " | ||
938 | "needed\n", cap_size, | ||
939 | sizeof(*wusb_dev->wusb_cap_descr)); | ||
940 | else { | ||
941 | wusb_dev->wusb_cap_descr = itr; | ||
942 | wusb_cap_descr_printf(3, dev, itr); | ||
943 | } | ||
944 | break; | ||
945 | default: | ||
946 | dev_err(dev, "BUG? Unknown BOS capability 0x%02x " | ||
947 | "(%zu bytes) at offset 0x%02x\n", cap_type, | ||
948 | cap_size, (int)(itr - (void *)bos)); | ||
949 | } | ||
950 | itr += cap_size; | ||
951 | } | ||
952 | result = 0; | ||
953 | error_bad_cap: | ||
954 | return result; | ||
955 | } | ||
956 | |||
957 | /* | ||
958 | * Add information from the BOS descriptors to the device | ||
959 | * | ||
960 | * @usb_dev: referenced | ||
961 | * @wusb_dev: referenced and unlocked | ||
962 | * | ||
963 | * So what we do is we alloc a space for the BOS descriptor of 64 | ||
964 | * bytes; read the first four bytes which include the wTotalLength | ||
965 | * field (WUSB1.0[T7-26]) and if it fits in those 64 bytes, read the | ||
966 | * whole thing. If not we realloc to that size. | ||
967 | * | ||
968 | * Then we call the groking function, that will fill up | ||
969 | * wusb_dev->wusb_cap_descr, which is what we'll need later on. | ||
970 | */ | ||
971 | static int wusb_dev_bos_add(struct usb_device *usb_dev, | ||
972 | struct wusb_dev *wusb_dev) | ||
973 | { | ||
974 | ssize_t result; | ||
975 | struct device *dev = &usb_dev->dev; | ||
976 | struct usb_bos_descriptor *bos; | ||
977 | size_t alloc_size = 32, desc_size = 4; | ||
978 | |||
979 | bos = kmalloc(alloc_size, GFP_KERNEL); | ||
980 | if (bos == NULL) | ||
981 | return -ENOMEM; | ||
982 | result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size); | ||
983 | if (result < 4) { | ||
984 | dev_err(dev, "Can't get BOS descriptor or too short: %zd\n", | ||
985 | result); | ||
986 | goto error_get_descriptor; | ||
987 | } | ||
988 | desc_size = le16_to_cpu(bos->wTotalLength); | ||
989 | if (desc_size >= alloc_size) { | ||
990 | kfree(bos); | ||
991 | alloc_size = desc_size; | ||
992 | bos = kmalloc(alloc_size, GFP_KERNEL); | ||
993 | if (bos == NULL) | ||
994 | return -ENOMEM; | ||
995 | } | ||
996 | result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size); | ||
997 | if (result < 0 || result != desc_size) { | ||
998 | dev_err(dev, "Can't get BOS descriptor or too short (need " | ||
999 | "%zu bytes): %zd\n", desc_size, result); | ||
1000 | goto error_get_descriptor; | ||
1001 | } | ||
1002 | if (result < sizeof(*bos) | ||
1003 | || le16_to_cpu(bos->wTotalLength) != desc_size) { | ||
1004 | dev_err(dev, "Can't get BOS descriptor or too short (need " | ||
1005 | "%zu bytes): %zd\n", desc_size, result); | ||
1006 | goto error_get_descriptor; | ||
1007 | } | ||
1008 | d_printf(2, dev, "Got BOS descriptor %zd bytes, %u capabilities\n", | ||
1009 | result, bos->bNumDeviceCaps); | ||
1010 | d_dump(2, dev, bos, result); | ||
1011 | result = wusb_dev_bos_grok(usb_dev, wusb_dev, bos, result); | ||
1012 | if (result < 0) | ||
1013 | goto error_bad_bos; | ||
1014 | wusb_dev->bos = bos; | ||
1015 | return 0; | ||
1016 | |||
1017 | error_bad_bos: | ||
1018 | error_get_descriptor: | ||
1019 | kfree(bos); | ||
1020 | wusb_dev->wusb_cap_descr = NULL; | ||
1021 | return result; | ||
1022 | } | ||
1023 | |||
1024 | static void wusb_dev_bos_rm(struct wusb_dev *wusb_dev) | ||
1025 | { | ||
1026 | kfree(wusb_dev->bos); | ||
1027 | wusb_dev->wusb_cap_descr = NULL; | ||
1028 | }; | ||
1029 | |||
1030 | static struct usb_wireless_cap_descriptor wusb_cap_descr_default = { | ||
1031 | .bLength = sizeof(wusb_cap_descr_default), | ||
1032 | .bDescriptorType = USB_DT_DEVICE_CAPABILITY, | ||
1033 | .bDevCapabilityType = USB_CAP_TYPE_WIRELESS_USB, | ||
1034 | |||
1035 | .bmAttributes = USB_WIRELESS_BEACON_NONE, | ||
1036 | .wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53), | ||
1037 | .bmTFITXPowerInfo = 0, | ||
1038 | .bmFFITXPowerInfo = 0, | ||
1039 | .bmBandGroup = cpu_to_le16(0x0001), /* WUSB1.0[7.4.1] bottom */ | ||
1040 | .bReserved = 0 | ||
1041 | }; | ||
1042 | |||
1043 | /* | ||
1044 | * USB stack's device addition Notifier Callback | ||
1045 | * | ||
1046 | * Called from drivers/usb/core/hub.c when a new device is added; we | ||
1047 | * use this hook to perform certain WUSB specific setup work on the | ||
1048 | * new device. As well, it is the first time we can connect the | ||
1049 | * wusb_dev and the usb_dev. So we note it down in wusb_dev and take a | ||
1050 | * reference that we'll drop. | ||
1051 | * | ||
1052 | * First we need to determine if the device is a WUSB device (else we | ||
1053 | * ignore it). For that we use the speed setting (USB_SPEED_VARIABLE) | ||
1054 | * [FIXME: maybe we'd need something more definitive]. If so, we track | ||
1055 | * it's usb_busd and from there, the WUSB HC. | ||
1056 | * | ||
1057 | * Because all WUSB HCs are contained in a 'struct wusbhc', voila, we | ||
1058 | * get the wusbhc for the device. | ||
1059 | * | ||
1060 | * We have a reference on @usb_dev (as we are called at the end of its | ||
1061 | * enumeration). | ||
1062 | * | ||
1063 | * NOTE: @usb_dev locked | ||
1064 | */ | ||
1065 | static void wusb_dev_add_ncb(struct usb_device *usb_dev) | ||
1066 | { | ||
1067 | int result = 0; | ||
1068 | struct wusb_dev *wusb_dev; | ||
1069 | struct wusbhc *wusbhc; | ||
1070 | struct device *dev = &usb_dev->dev; | ||
1071 | u8 port_idx; | ||
1072 | |||
1073 | if (usb_dev->wusb == 0 || usb_dev->devnum == 1) | ||
1074 | return; /* skip non wusb and wusb RHs */ | ||
1075 | |||
1076 | d_fnstart(3, dev, "(usb_dev %p)\n", usb_dev); | ||
1077 | |||
1078 | wusbhc = wusbhc_get_by_usb_dev(usb_dev); | ||
1079 | if (wusbhc == NULL) | ||
1080 | goto error_nodev; | ||
1081 | mutex_lock(&wusbhc->mutex); | ||
1082 | wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev); | ||
1083 | port_idx = wusb_port_no_to_idx(usb_dev->portnum); | ||
1084 | mutex_unlock(&wusbhc->mutex); | ||
1085 | if (wusb_dev == NULL) | ||
1086 | goto error_nodev; | ||
1087 | wusb_dev->usb_dev = usb_get_dev(usb_dev); | ||
1088 | usb_dev->wusb_dev = wusb_dev_get(wusb_dev); | ||
1089 | result = wusb_dev_sec_add(wusbhc, usb_dev, wusb_dev); | ||
1090 | if (result < 0) { | ||
1091 | dev_err(dev, "Cannot enable security: %d\n", result); | ||
1092 | goto error_sec_add; | ||
1093 | } | ||
1094 | /* Now query the device for it's BOS and attach it to wusb_dev */ | ||
1095 | result = wusb_dev_bos_add(usb_dev, wusb_dev); | ||
1096 | if (result < 0) { | ||
1097 | dev_err(dev, "Cannot get BOS descriptors: %d\n", result); | ||
1098 | goto error_bos_add; | ||
1099 | } | ||
1100 | result = wusb_dev_sysfs_add(wusbhc, usb_dev, wusb_dev); | ||
1101 | if (result < 0) | ||
1102 | goto error_add_sysfs; | ||
1103 | out: | ||
1104 | wusb_dev_put(wusb_dev); | ||
1105 | wusbhc_put(wusbhc); | ||
1106 | error_nodev: | ||
1107 | d_fnend(3, dev, "(usb_dev %p) = void\n", usb_dev); | ||
1108 | return; | ||
1109 | |||
1110 | wusb_dev_sysfs_rm(wusb_dev); | ||
1111 | error_add_sysfs: | ||
1112 | wusb_dev_bos_rm(wusb_dev); | ||
1113 | error_bos_add: | ||
1114 | wusb_dev_sec_rm(wusb_dev); | ||
1115 | error_sec_add: | ||
1116 | mutex_lock(&wusbhc->mutex); | ||
1117 | __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx)); | ||
1118 | mutex_unlock(&wusbhc->mutex); | ||
1119 | goto out; | ||
1120 | } | ||
1121 | |||
1122 | /* | ||
1123 | * Undo all the steps done at connection by the notifier callback | ||
1124 | * | ||
1125 | * NOTE: @usb_dev locked | ||
1126 | */ | ||
1127 | static void wusb_dev_rm_ncb(struct usb_device *usb_dev) | ||
1128 | { | ||
1129 | struct wusb_dev *wusb_dev = usb_dev->wusb_dev; | ||
1130 | |||
1131 | if (usb_dev->wusb == 0 || usb_dev->devnum == 1) | ||
1132 | return; /* skip non wusb and wusb RHs */ | ||
1133 | |||
1134 | wusb_dev_sysfs_rm(wusb_dev); | ||
1135 | wusb_dev_bos_rm(wusb_dev); | ||
1136 | wusb_dev_sec_rm(wusb_dev); | ||
1137 | wusb_dev->usb_dev = NULL; | ||
1138 | usb_dev->wusb_dev = NULL; | ||
1139 | wusb_dev_put(wusb_dev); | ||
1140 | usb_put_dev(usb_dev); | ||
1141 | } | ||
1142 | |||
1143 | /* | ||
1144 | * Handle notifications from the USB stack (notifier call back) | ||
1145 | * | ||
1146 | * This is called when the USB stack does a | ||
1147 | * usb_{bus,device}_{add,remove}() so we can do WUSB specific | ||
1148 | * handling. It is called with [for the case of | ||
1149 | * USB_DEVICE_{ADD,REMOVE} with the usb_dev locked. | ||
1150 | */ | ||
1151 | int wusb_usb_ncb(struct notifier_block *nb, unsigned long val, | ||
1152 | void *priv) | ||
1153 | { | ||
1154 | int result = NOTIFY_OK; | ||
1155 | |||
1156 | switch (val) { | ||
1157 | case USB_DEVICE_ADD: | ||
1158 | wusb_dev_add_ncb(priv); | ||
1159 | break; | ||
1160 | case USB_DEVICE_REMOVE: | ||
1161 | wusb_dev_rm_ncb(priv); | ||
1162 | break; | ||
1163 | case USB_BUS_ADD: | ||
1164 | /* ignore (for now) */ | ||
1165 | case USB_BUS_REMOVE: | ||
1166 | break; | ||
1167 | default: | ||
1168 | WARN_ON(1); | ||
1169 | result = NOTIFY_BAD; | ||
1170 | }; | ||
1171 | return result; | ||
1172 | } | ||
1173 | |||
1174 | /* | ||
1175 | * Return a referenced wusb_dev given a @wusbhc and @usb_dev | ||
1176 | */ | ||
1177 | struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *wusbhc, | ||
1178 | struct usb_device *usb_dev) | ||
1179 | { | ||
1180 | struct wusb_dev *wusb_dev; | ||
1181 | u8 port_idx; | ||
1182 | |||
1183 | port_idx = wusb_port_no_to_idx(usb_dev->portnum); | ||
1184 | BUG_ON(port_idx > wusbhc->ports_max); | ||
1185 | wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev; | ||
1186 | if (wusb_dev != NULL) /* ops, device is gone */ | ||
1187 | wusb_dev_get(wusb_dev); | ||
1188 | return wusb_dev; | ||
1189 | } | ||
1190 | EXPORT_SYMBOL_GPL(__wusb_dev_get_by_usb_dev); | ||
1191 | |||
1192 | void wusb_dev_destroy(struct kref *_wusb_dev) | ||
1193 | { | ||
1194 | struct wusb_dev *wusb_dev | ||
1195 | = container_of(_wusb_dev, struct wusb_dev, refcnt); | ||
1196 | list_del_init(&wusb_dev->cack_node); | ||
1197 | wusb_dev_free(wusb_dev); | ||
1198 | d_fnend(1, NULL, "%s (wusb_dev %p) = void\n", __func__, wusb_dev); | ||
1199 | } | ||
1200 | EXPORT_SYMBOL_GPL(wusb_dev_destroy); | ||
1201 | |||
1202 | /* | ||
1203 | * Create all the device connect handling infrastructure | ||
1204 | * | ||
1205 | * This is basically the device info array, Connect Acknowledgement | ||
1206 | * (cack) lists, keep-alive timers (and delayed work thread). | ||
1207 | */ | ||
1208 | int wusbhc_devconnect_create(struct wusbhc *wusbhc) | ||
1209 | { | ||
1210 | d_fnstart(3, wusbhc->dev, "(wusbhc %p)\n", wusbhc); | ||
1211 | |||
1212 | wusbhc->keep_alive_ie.hdr.bIEIdentifier = WUIE_ID_KEEP_ALIVE; | ||
1213 | wusbhc->keep_alive_ie.hdr.bLength = sizeof(wusbhc->keep_alive_ie.hdr); | ||
1214 | INIT_DELAYED_WORK(&wusbhc->keep_alive_timer, wusbhc_keep_alive_run); | ||
1215 | |||
1216 | wusbhc->cack_ie.hdr.bIEIdentifier = WUIE_ID_CONNECTACK; | ||
1217 | wusbhc->cack_ie.hdr.bLength = sizeof(wusbhc->cack_ie.hdr); | ||
1218 | INIT_LIST_HEAD(&wusbhc->cack_list); | ||
1219 | |||
1220 | d_fnend(3, wusbhc->dev, "(wusbhc %p) = void\n", wusbhc); | ||
1221 | return 0; | ||
1222 | } | ||
1223 | |||
1224 | /* | ||
1225 | * Release all resources taken by the devconnect stuff | ||
1226 | */ | ||
1227 | void wusbhc_devconnect_destroy(struct wusbhc *wusbhc) | ||
1228 | { | ||
1229 | d_fnstart(3, wusbhc->dev, "(wusbhc %p)\n", wusbhc); | ||
1230 | d_fnend(3, wusbhc->dev, "(wusbhc %p) = void\n", wusbhc); | ||
1231 | } | ||
1232 | |||
1233 | /* | ||
1234 | * wusbhc_devconnect_start - start accepting device connections | ||
1235 | * @wusbhc: the WUSB HC | ||
1236 | * | ||
1237 | * Sets the Host Info IE to accept all new connections. | ||
1238 | * | ||
1239 | * FIXME: This also enables the keep alives but this is not necessary | ||
1240 | * until there are connected and authenticated devices. | ||
1241 | */ | ||
1242 | int wusbhc_devconnect_start(struct wusbhc *wusbhc, | ||
1243 | const struct wusb_ckhdid *chid) | ||
1244 | { | ||
1245 | struct device *dev = wusbhc->dev; | ||
1246 | struct wuie_host_info *hi; | ||
1247 | int result; | ||
1248 | |||
1249 | hi = kzalloc(sizeof(*hi), GFP_KERNEL); | ||
1250 | if (hi == NULL) | ||
1251 | return -ENOMEM; | ||
1252 | |||
1253 | hi->hdr.bLength = sizeof(*hi); | ||
1254 | hi->hdr.bIEIdentifier = WUIE_ID_HOST_INFO; | ||
1255 | hi->attributes = cpu_to_le16((wusbhc->rsv->stream << 3) | WUIE_HI_CAP_ALL); | ||
1256 | hi->CHID = *chid; | ||
1257 | result = wusbhc_mmcie_set(wusbhc, 0, 0, &hi->hdr); | ||
1258 | if (result < 0) { | ||
1259 | dev_err(dev, "Cannot add Host Info MMCIE: %d\n", result); | ||
1260 | goto error_mmcie_set; | ||
1261 | } | ||
1262 | wusbhc->wuie_host_info = hi; | ||
1263 | |||
1264 | queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, | ||
1265 | (wusbhc->trust_timeout*CONFIG_HZ)/1000/2); | ||
1266 | |||
1267 | return 0; | ||
1268 | |||
1269 | error_mmcie_set: | ||
1270 | kfree(hi); | ||
1271 | return result; | ||
1272 | } | ||
1273 | |||
1274 | /* | ||
1275 | * wusbhc_devconnect_stop - stop managing connected devices | ||
1276 | * @wusbhc: the WUSB HC | ||
1277 | * | ||
1278 | * Removes the Host Info IE and stops the keep alives. | ||
1279 | * | ||
1280 | * FIXME: should this disconnect all devices? | ||
1281 | */ | ||
1282 | void wusbhc_devconnect_stop(struct wusbhc *wusbhc) | ||
1283 | { | ||
1284 | cancel_delayed_work_sync(&wusbhc->keep_alive_timer); | ||
1285 | WARN_ON(!list_empty(&wusbhc->cack_list)); | ||
1286 | |||
1287 | wusbhc_mmcie_rm(wusbhc, &wusbhc->wuie_host_info->hdr); | ||
1288 | kfree(wusbhc->wuie_host_info); | ||
1289 | wusbhc->wuie_host_info = NULL; | ||
1290 | } | ||
1291 | |||
1292 | /* | ||
1293 | * wusb_set_dev_addr - set the WUSB device address used by the host | ||
1294 | * @wusbhc: the WUSB HC the device is connect to | ||
1295 | * @wusb_dev: the WUSB device | ||
1296 | * @addr: new device address | ||
1297 | */ | ||
1298 | int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, u8 addr) | ||
1299 | { | ||
1300 | int result; | ||
1301 | |||
1302 | wusb_dev->addr = addr; | ||
1303 | result = wusbhc->dev_info_set(wusbhc, wusb_dev); | ||
1304 | if (result < 0) | ||
1305 | dev_err(wusbhc->dev, "device %d: failed to set device " | ||
1306 | "address\n", wusb_dev->port_idx); | ||
1307 | else | ||
1308 | dev_info(wusbhc->dev, "device %d: %s addr %u\n", | ||
1309 | wusb_dev->port_idx, | ||
1310 | (addr & WUSB_DEV_ADDR_UNAUTH) ? "unauth" : "auth", | ||
1311 | wusb_dev->addr); | ||
1312 | |||
1313 | return result; | ||
1314 | } | ||
diff --git a/drivers/usb/wusbcore/mmc.c b/drivers/usb/wusbcore/mmc.c new file mode 100644 index 000000000000..e5390b77aaaa --- /dev/null +++ b/drivers/usb/wusbcore/mmc.c | |||
@@ -0,0 +1,329 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8]) | ||
3 | * MMC (Microscheduled Management Command) handling | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * WUIEs and MMC IEs...well, they are almost the same at the end. MMC | ||
24 | * IEs are Wireless USB IEs that go into the MMC period...[what is | ||
25 | * that? look in Design-overview.txt]. | ||
26 | * | ||
27 | * | ||
28 | * This is a simple subsystem to keep track of which IEs are being | ||
29 | * sent by the host in the MMC period. | ||
30 | * | ||
31 | * For each WUIE we ask to send, we keep it in an array, so we can | ||
32 | * request its removal later, or replace the content. They are tracked | ||
33 | * by pointer, so be sure to use the same pointer if you want to | ||
34 | * remove it or update the contents. | ||
35 | * | ||
36 | * FIXME: | ||
37 | * - add timers that autoremove intervalled IEs? | ||
38 | */ | ||
39 | #include <linux/usb/wusb.h> | ||
40 | #include "wusbhc.h" | ||
41 | |||
42 | /* Initialize the MMCIEs handling mechanism */ | ||
43 | int wusbhc_mmcie_create(struct wusbhc *wusbhc) | ||
44 | { | ||
45 | u8 mmcies = wusbhc->mmcies_max; | ||
46 | wusbhc->mmcie = kzalloc(mmcies * sizeof(wusbhc->mmcie[0]), GFP_KERNEL); | ||
47 | if (wusbhc->mmcie == NULL) | ||
48 | return -ENOMEM; | ||
49 | mutex_init(&wusbhc->mmcie_mutex); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | /* Release resources used by the MMCIEs handling mechanism */ | ||
54 | void wusbhc_mmcie_destroy(struct wusbhc *wusbhc) | ||
55 | { | ||
56 | kfree(wusbhc->mmcie); | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Add or replace an MMC Wireless USB IE. | ||
61 | * | ||
62 | * @interval: See WUSB1.0[8.5.3.1] | ||
63 | * @repeat_cnt: See WUSB1.0[8.5.3.1] | ||
64 | * @handle: See WUSB1.0[8.5.3.1] | ||
65 | * @wuie: Pointer to the header of the WUSB IE data to add. | ||
66 | * MUST BE allocated in a kmalloc buffer (no stack or | ||
67 | * vmalloc). | ||
68 | * THE CALLER ALWAYS OWNS THE POINTER (we don't free it | ||
69 | * on remove, we just forget about it). | ||
70 | * @returns: 0 if ok, < 0 errno code on error. | ||
71 | * | ||
72 | * Goes over the *whole* @wusbhc->mmcie array looking for (a) the | ||
73 | * first free spot and (b) if @wuie is already in the array (aka: | ||
74 | * transmitted in the MMCs) the spot were it is. | ||
75 | * | ||
76 | * If present, we "overwrite it" (update). | ||
77 | * | ||
78 | * | ||
79 | * NOTE: Need special ordering rules -- see below WUSB1.0 Table 7-38. | ||
80 | * The host uses the handle as the 'sort' index. We | ||
81 | * allocate the last one always for the WUIE_ID_HOST_INFO, and | ||
82 | * the rest, first come first serve in inverse order. | ||
83 | * | ||
84 | * Host software must make sure that it adds the other IEs in | ||
85 | * the right order... the host hardware is responsible for | ||
86 | * placing the WCTA IEs in the right place with the other IEs | ||
87 | * set by host software. | ||
88 | * | ||
89 | * NOTE: we can access wusbhc->wa_descr without locking because it is | ||
90 | * read only. | ||
91 | */ | ||
92 | int wusbhc_mmcie_set(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, | ||
93 | struct wuie_hdr *wuie) | ||
94 | { | ||
95 | int result = -ENOBUFS; | ||
96 | struct device *dev = wusbhc->dev; | ||
97 | unsigned handle, itr; | ||
98 | |||
99 | /* Search a handle, taking into account the ordering */ | ||
100 | mutex_lock(&wusbhc->mmcie_mutex); | ||
101 | switch (wuie->bIEIdentifier) { | ||
102 | case WUIE_ID_HOST_INFO: | ||
103 | /* Always last */ | ||
104 | handle = wusbhc->mmcies_max - 1; | ||
105 | break; | ||
106 | case WUIE_ID_ISOCH_DISCARD: | ||
107 | dev_err(wusbhc->dev, "Special ordering case for WUIE ID 0x%x " | ||
108 | "unimplemented\n", wuie->bIEIdentifier); | ||
109 | result = -ENOSYS; | ||
110 | goto error_unlock; | ||
111 | default: | ||
112 | /* search for it or find the last empty slot */ | ||
113 | handle = ~0; | ||
114 | for (itr = 0; itr < wusbhc->mmcies_max - 1; itr++) { | ||
115 | if (wusbhc->mmcie[itr] == wuie) { | ||
116 | handle = itr; | ||
117 | break; | ||
118 | } | ||
119 | if (wusbhc->mmcie[itr] == NULL) | ||
120 | handle = itr; | ||
121 | } | ||
122 | if (handle == ~0) { | ||
123 | if (printk_ratelimit()) | ||
124 | dev_err(dev, "MMC handle space exhausted\n"); | ||
125 | goto error_unlock; | ||
126 | } | ||
127 | } | ||
128 | result = (wusbhc->mmcie_add)(wusbhc, interval, repeat_cnt, handle, | ||
129 | wuie); | ||
130 | if (result >= 0) | ||
131 | wusbhc->mmcie[handle] = wuie; | ||
132 | error_unlock: | ||
133 | mutex_unlock(&wusbhc->mmcie_mutex); | ||
134 | return result; | ||
135 | } | ||
136 | EXPORT_SYMBOL_GPL(wusbhc_mmcie_set); | ||
137 | |||
138 | /* | ||
139 | * Remove an MMC IE previously added with wusbhc_mmcie_set() | ||
140 | * | ||
141 | * @wuie Pointer used to add the WUIE | ||
142 | */ | ||
143 | void wusbhc_mmcie_rm(struct wusbhc *wusbhc, struct wuie_hdr *wuie) | ||
144 | { | ||
145 | int result; | ||
146 | struct device *dev = wusbhc->dev; | ||
147 | unsigned handle, itr; | ||
148 | |||
149 | mutex_lock(&wusbhc->mmcie_mutex); | ||
150 | for (itr = 0; itr < wusbhc->mmcies_max; itr++) | ||
151 | if (wusbhc->mmcie[itr] == wuie) { | ||
152 | handle = itr; | ||
153 | goto found; | ||
154 | } | ||
155 | mutex_unlock(&wusbhc->mmcie_mutex); | ||
156 | return; | ||
157 | |||
158 | found: | ||
159 | result = (wusbhc->mmcie_rm)(wusbhc, handle); | ||
160 | if (result == 0) | ||
161 | wusbhc->mmcie[itr] = NULL; | ||
162 | else if (printk_ratelimit()) | ||
163 | dev_err(dev, "MMC: Failed to remove IE %p (0x%02x)\n", | ||
164 | wuie, wuie->bIEIdentifier); | ||
165 | mutex_unlock(&wusbhc->mmcie_mutex); | ||
166 | return; | ||
167 | } | ||
168 | EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm); | ||
169 | |||
170 | /* | ||
171 | * wusbhc_start - start transmitting MMCs and accepting connections | ||
172 | * @wusbhc: the HC to start | ||
173 | * @chid: the CHID to use for this host | ||
174 | * | ||
175 | * Establishes a cluster reservation, enables device connections, and | ||
176 | * starts MMCs with appropriate DNTS parameters. | ||
177 | */ | ||
178 | int wusbhc_start(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid) | ||
179 | { | ||
180 | int result; | ||
181 | struct device *dev = wusbhc->dev; | ||
182 | |||
183 | WARN_ON(wusbhc->wuie_host_info != NULL); | ||
184 | |||
185 | result = wusbhc_rsv_establish(wusbhc); | ||
186 | if (result < 0) { | ||
187 | dev_err(dev, "cannot establish cluster reservation: %d\n", | ||
188 | result); | ||
189 | goto error_rsv_establish; | ||
190 | } | ||
191 | |||
192 | result = wusbhc_devconnect_start(wusbhc, chid); | ||
193 | if (result < 0) { | ||
194 | dev_err(dev, "error enabling device connections: %d\n", result); | ||
195 | goto error_devconnect_start; | ||
196 | } | ||
197 | |||
198 | result = wusbhc_sec_start(wusbhc); | ||
199 | if (result < 0) { | ||
200 | dev_err(dev, "error starting security in the HC: %d\n", result); | ||
201 | goto error_sec_start; | ||
202 | } | ||
203 | /* FIXME: the choice of the DNTS parameters is somewhat | ||
204 | * arbitrary */ | ||
205 | result = wusbhc->set_num_dnts(wusbhc, 0, 15); | ||
206 | if (result < 0) { | ||
207 | dev_err(dev, "Cannot set DNTS parameters: %d\n", result); | ||
208 | goto error_set_num_dnts; | ||
209 | } | ||
210 | result = wusbhc->start(wusbhc); | ||
211 | if (result < 0) { | ||
212 | dev_err(dev, "error starting wusbch: %d\n", result); | ||
213 | goto error_wusbhc_start; | ||
214 | } | ||
215 | wusbhc->active = 1; | ||
216 | return 0; | ||
217 | |||
218 | error_wusbhc_start: | ||
219 | wusbhc_sec_stop(wusbhc); | ||
220 | error_set_num_dnts: | ||
221 | error_sec_start: | ||
222 | wusbhc_devconnect_stop(wusbhc); | ||
223 | error_devconnect_start: | ||
224 | wusbhc_rsv_terminate(wusbhc); | ||
225 | error_rsv_establish: | ||
226 | return result; | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * Disconnect all from the WUSB Channel | ||
231 | * | ||
232 | * Send a Host Disconnect IE in the MMC, wait, don't send it any more | ||
233 | */ | ||
234 | static int __wusbhc_host_disconnect_ie(struct wusbhc *wusbhc) | ||
235 | { | ||
236 | int result = -ENOMEM; | ||
237 | struct wuie_host_disconnect *host_disconnect_ie; | ||
238 | might_sleep(); | ||
239 | host_disconnect_ie = kmalloc(sizeof(*host_disconnect_ie), GFP_KERNEL); | ||
240 | if (host_disconnect_ie == NULL) | ||
241 | goto error_alloc; | ||
242 | host_disconnect_ie->hdr.bLength = sizeof(*host_disconnect_ie); | ||
243 | host_disconnect_ie->hdr.bIEIdentifier = WUIE_ID_HOST_DISCONNECT; | ||
244 | result = wusbhc_mmcie_set(wusbhc, 0, 0, &host_disconnect_ie->hdr); | ||
245 | if (result < 0) | ||
246 | goto error_mmcie_set; | ||
247 | |||
248 | /* WUSB1.0[8.5.3.1 & 7.5.2] */ | ||
249 | msleep(100); | ||
250 | wusbhc_mmcie_rm(wusbhc, &host_disconnect_ie->hdr); | ||
251 | error_mmcie_set: | ||
252 | kfree(host_disconnect_ie); | ||
253 | error_alloc: | ||
254 | return result; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * wusbhc_stop - stop transmitting MMCs | ||
259 | * @wusbhc: the HC to stop | ||
260 | * | ||
261 | * Send a Host Disconnect IE, wait, remove all the MMCs (stop sending MMCs). | ||
262 | * | ||
263 | * If we can't allocate a Host Stop IE, screw it, we don't notify the | ||
264 | * devices we are disconnecting... | ||
265 | */ | ||
266 | void wusbhc_stop(struct wusbhc *wusbhc) | ||
267 | { | ||
268 | if (wusbhc->active) { | ||
269 | wusbhc->active = 0; | ||
270 | wusbhc->stop(wusbhc); | ||
271 | wusbhc_sec_stop(wusbhc); | ||
272 | __wusbhc_host_disconnect_ie(wusbhc); | ||
273 | wusbhc_devconnect_stop(wusbhc); | ||
274 | wusbhc_rsv_terminate(wusbhc); | ||
275 | } | ||
276 | } | ||
277 | EXPORT_SYMBOL_GPL(wusbhc_stop); | ||
278 | |||
279 | /* | ||
280 | * Change the CHID in a WUSB Channel | ||
281 | * | ||
282 | * If it is just a new CHID, send a Host Disconnect IE and then change | ||
283 | * the CHID IE. | ||
284 | */ | ||
285 | static int __wusbhc_chid_change(struct wusbhc *wusbhc, | ||
286 | const struct wusb_ckhdid *chid) | ||
287 | { | ||
288 | int result = -ENOSYS; | ||
289 | struct device *dev = wusbhc->dev; | ||
290 | dev_err(dev, "%s() not implemented yet\n", __func__); | ||
291 | return result; | ||
292 | |||
293 | BUG_ON(wusbhc->wuie_host_info == NULL); | ||
294 | __wusbhc_host_disconnect_ie(wusbhc); | ||
295 | wusbhc->wuie_host_info->CHID = *chid; | ||
296 | result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->wuie_host_info->hdr); | ||
297 | if (result < 0) | ||
298 | dev_err(dev, "Can't update Host Info WUSB IE: %d\n", result); | ||
299 | return result; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * Set/reset/update a new CHID | ||
304 | * | ||
305 | * Depending on the previous state of the MMCs, start, stop or change | ||
306 | * the sent MMC. This effectively switches the host controller on and | ||
307 | * off (radio wise). | ||
308 | */ | ||
309 | int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid) | ||
310 | { | ||
311 | int result = 0; | ||
312 | |||
313 | if (memcmp(chid, &wusb_ckhdid_zero, sizeof(chid)) == 0) | ||
314 | chid = NULL; | ||
315 | |||
316 | mutex_lock(&wusbhc->mutex); | ||
317 | if (wusbhc->active) { | ||
318 | if (chid) | ||
319 | result = __wusbhc_chid_change(wusbhc, chid); | ||
320 | else | ||
321 | wusbhc_stop(wusbhc); | ||
322 | } else { | ||
323 | if (chid) | ||
324 | wusbhc_start(wusbhc, chid); | ||
325 | } | ||
326 | mutex_unlock(&wusbhc->mutex); | ||
327 | return result; | ||
328 | } | ||
329 | EXPORT_SYMBOL_GPL(wusbhc_chid_set); | ||
diff --git a/drivers/usb/wusbcore/pal.c b/drivers/usb/wusbcore/pal.c new file mode 100644 index 000000000000..7cc51e9905cf --- /dev/null +++ b/drivers/usb/wusbcore/pal.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Wireless USB Host Controller | ||
3 | * UWB Protocol Adaptation Layer (PAL) glue. | ||
4 | * | ||
5 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | #include "wusbhc.h" | ||
20 | |||
21 | /** | ||
22 | * wusbhc_pal_register - register the WUSB HC as a UWB PAL | ||
23 | * @wusbhc: the WUSB HC | ||
24 | */ | ||
25 | int wusbhc_pal_register(struct wusbhc *wusbhc) | ||
26 | { | ||
27 | uwb_pal_init(&wusbhc->pal); | ||
28 | |||
29 | wusbhc->pal.name = "wusbhc"; | ||
30 | wusbhc->pal.device = wusbhc->usb_hcd.self.controller; | ||
31 | |||
32 | return uwb_pal_register(wusbhc->uwb_rc, &wusbhc->pal); | ||
33 | } | ||
34 | |||
35 | /** | ||
36 | * wusbhc_pal_register - unregister the WUSB HC as a UWB PAL | ||
37 | * @wusbhc: the WUSB HC | ||
38 | */ | ||
39 | void wusbhc_pal_unregister(struct wusbhc *wusbhc) | ||
40 | { | ||
41 | uwb_pal_unregister(wusbhc->uwb_rc, &wusbhc->pal); | ||
42 | } | ||
diff --git a/drivers/usb/wusbcore/reservation.c b/drivers/usb/wusbcore/reservation.c new file mode 100644 index 000000000000..fc63e77ded2d --- /dev/null +++ b/drivers/usb/wusbcore/reservation.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * WUSB cluster reservation management | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/uwb.h> | ||
20 | |||
21 | #include "wusbhc.h" | ||
22 | |||
23 | /* | ||
24 | * WUSB cluster reservations are multicast reservations with the | ||
25 | * broadcast cluster ID (BCID) as the target DevAddr. | ||
26 | * | ||
27 | * FIXME: consider adjusting the reservation depending on what devices | ||
28 | * are attached. | ||
29 | */ | ||
30 | |||
31 | static int wusbhc_bwa_set(struct wusbhc *wusbhc, u8 stream, | ||
32 | const struct uwb_mas_bm *mas) | ||
33 | { | ||
34 | if (mas == NULL) | ||
35 | mas = &uwb_mas_bm_zero; | ||
36 | return wusbhc->bwa_set(wusbhc, stream, mas); | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * wusbhc_rsv_complete_cb - WUSB HC reservation complete callback | ||
41 | * @rsv: the reservation | ||
42 | * | ||
43 | * Either set or clear the HC's view of the reservation. | ||
44 | * | ||
45 | * FIXME: when a reservation is denied the HC should be stopped. | ||
46 | */ | ||
47 | static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv) | ||
48 | { | ||
49 | struct wusbhc *wusbhc = rsv->pal_priv; | ||
50 | struct device *dev = wusbhc->dev; | ||
51 | char buf[72]; | ||
52 | |||
53 | switch (rsv->state) { | ||
54 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
55 | bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS); | ||
56 | dev_dbg(dev, "established reservation: %s\n", buf); | ||
57 | wusbhc_bwa_set(wusbhc, rsv->stream, &rsv->mas); | ||
58 | break; | ||
59 | case UWB_RSV_STATE_NONE: | ||
60 | dev_dbg(dev, "removed reservation\n"); | ||
61 | wusbhc_bwa_set(wusbhc, 0, NULL); | ||
62 | wusbhc->rsv = NULL; | ||
63 | break; | ||
64 | default: | ||
65 | dev_dbg(dev, "unexpected reservation state: %d\n", rsv->state); | ||
66 | break; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | |||
71 | /** | ||
72 | * wusbhc_rsv_establish - establish a reservation for the cluster | ||
73 | * @wusbhc: the WUSB HC requesting a bandwith reservation | ||
74 | */ | ||
75 | int wusbhc_rsv_establish(struct wusbhc *wusbhc) | ||
76 | { | ||
77 | struct uwb_rc *rc = wusbhc->uwb_rc; | ||
78 | struct uwb_rsv *rsv; | ||
79 | struct uwb_dev_addr bcid; | ||
80 | int ret; | ||
81 | |||
82 | rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc); | ||
83 | if (rsv == NULL) | ||
84 | return -ENOMEM; | ||
85 | |||
86 | bcid.data[0] = wusbhc->cluster_id; | ||
87 | bcid.data[1] = 0; | ||
88 | |||
89 | rsv->owner = &rc->uwb_dev; | ||
90 | rsv->target.type = UWB_RSV_TARGET_DEVADDR; | ||
91 | rsv->target.devaddr = bcid; | ||
92 | rsv->type = UWB_DRP_TYPE_PRIVATE; | ||
93 | rsv->max_mas = 256; | ||
94 | rsv->min_mas = 16; /* one MAS per zone? */ | ||
95 | rsv->sparsity = 16; /* at least one MAS in each zone? */ | ||
96 | rsv->is_multicast = true; | ||
97 | |||
98 | ret = uwb_rsv_establish(rsv); | ||
99 | if (ret == 0) | ||
100 | wusbhc->rsv = rsv; | ||
101 | else | ||
102 | uwb_rsv_destroy(rsv); | ||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | |||
107 | /** | ||
108 | * wusbhc_rsv_terminate - terminate any cluster reservation | ||
109 | * @wusbhc: the WUSB host whose reservation is to be terminated | ||
110 | */ | ||
111 | void wusbhc_rsv_terminate(struct wusbhc *wusbhc) | ||
112 | { | ||
113 | if (wusbhc->rsv) | ||
114 | uwb_rsv_terminate(wusbhc->rsv); | ||
115 | } | ||
diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c new file mode 100644 index 000000000000..267a64325106 --- /dev/null +++ b/drivers/usb/wusbcore/rh.c | |||
@@ -0,0 +1,477 @@ | |||
1 | /* | ||
2 | * Wireless USB Host Controller | ||
3 | * Root Hub operations | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Intel Corporation | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * We fake a root hub that has fake ports (as many as simultaneous | ||
25 | * devices the Wireless USB Host Controller can deal with). For each | ||
26 | * port we keep an state in @wusbhc->port[index] identical to the one | ||
27 | * specified in the USB2.0[ch11] spec and some extra device | ||
28 | * information that complements the one in 'struct usb_device' (as | ||
29 | * this lacs a hcpriv pointer). | ||
30 | * | ||
31 | * Note this is common to WHCI and HWA host controllers. | ||
32 | * | ||
33 | * Through here we enable most of the state changes that the USB stack | ||
34 | * will use to connect or disconnect devices. We need to do some | ||
35 | * forced adaptation of Wireless USB device states vs. wired: | ||
36 | * | ||
37 | * USB: WUSB: | ||
38 | * | ||
39 | * Port Powered-off port slot n/a | ||
40 | * Powered-on port slot available | ||
41 | * Disconnected port slot available | ||
42 | * Connected port slot assigned device | ||
43 | * device sent DN_Connect | ||
44 | * device was authenticated | ||
45 | * Enabled device is authenticated, transitioned | ||
46 | * from unauth -> auth -> default address | ||
47 | * -> enabled | ||
48 | * Reset disconnect | ||
49 | * Disable disconnect | ||
50 | * | ||
51 | * This maps the standard USB port states with the WUSB device states | ||
52 | * so we can fake ports without having to modify the USB stack. | ||
53 | * | ||
54 | * FIXME: this process will change in the future | ||
55 | * | ||
56 | * | ||
57 | * ENTRY POINTS | ||
58 | * | ||
59 | * Our entry points into here are, as in hcd.c, the USB stack root hub | ||
60 | * ops defined in the usb_hcd struct: | ||
61 | * | ||
62 | * wusbhc_rh_status_data() Provide hub and port status data bitmap | ||
63 | * | ||
64 | * wusbhc_rh_control() Execution of all the major requests | ||
65 | * you can do to a hub (Set|Clear | ||
66 | * features, get descriptors, status, etc). | ||
67 | * | ||
68 | * wusbhc_rh_[suspend|resume]() That | ||
69 | * | ||
70 | * wusbhc_rh_start_port_reset() ??? unimplemented | ||
71 | */ | ||
72 | #include "wusbhc.h" | ||
73 | |||
74 | #define D_LOCAL 0 | ||
75 | #include <linux/uwb/debug.h> | ||
76 | |||
77 | /* | ||
78 | * Reset a fake port | ||
79 | * | ||
80 | * This can be called to reset a port from any other state or to reset | ||
81 | * it when connecting. In Wireless USB they are different; when doing | ||
82 | * a new connect that involves going over the authentication. When | ||
83 | * just reseting, its a different story. | ||
84 | * | ||
85 | * The Linux USB stack resets a port twice before it considers it | ||
86 | * enabled, so we have to detect and ignore that. | ||
87 | * | ||
88 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
89 | * | ||
90 | * Supposedly we are the only thread accesing @wusbhc->port; in any | ||
91 | * case, maybe we should move the mutex locking from | ||
92 | * wusbhc_devconnect_auth() to here. | ||
93 | * | ||
94 | * @port_idx refers to the wusbhc's port index, not the USB port number | ||
95 | */ | ||
96 | static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx) | ||
97 | { | ||
98 | int result = 0; | ||
99 | struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx); | ||
100 | |||
101 | d_fnstart(3, wusbhc->dev, "(wusbhc %p port_idx %u)\n", | ||
102 | wusbhc, port_idx); | ||
103 | if (port->reset_count == 0) { | ||
104 | wusbhc_devconnect_auth(wusbhc, port_idx); | ||
105 | port->reset_count++; | ||
106 | } else if (port->reset_count == 1) | ||
107 | /* see header */ | ||
108 | d_printf(2, wusbhc->dev, "Ignoring second reset on port_idx " | ||
109 | "%u\n", port_idx); | ||
110 | else | ||
111 | result = wusbhc_dev_reset(wusbhc, port_idx); | ||
112 | d_fnend(3, wusbhc->dev, "(wusbhc %p port_idx %u) = %d\n", | ||
113 | wusbhc, port_idx, result); | ||
114 | return result; | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * Return the hub change status bitmap | ||
119 | * | ||
120 | * The bits in the change status bitmap are cleared when a | ||
121 | * ClearPortFeature request is issued (USB2.0[11.12.3,11.12.4]. | ||
122 | * | ||
123 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
124 | * | ||
125 | * WARNING!! This gets called from atomic context; we cannot get the | ||
126 | * mutex--the only race condition we can find is some bit | ||
127 | * changing just after we copy it, which shouldn't be too | ||
128 | * big of a problem [and we can't make it an spinlock | ||
129 | * because other parts need to take it and sleep] . | ||
130 | * | ||
131 | * @usb_hcd is refcounted, so it won't dissapear under us | ||
132 | * and before killing a host, the polling of the root hub | ||
133 | * would be stopped anyway. | ||
134 | */ | ||
135 | int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf) | ||
136 | { | ||
137 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
138 | size_t cnt, size; | ||
139 | unsigned long *buf = (unsigned long *) _buf; | ||
140 | |||
141 | d_fnstart(1, wusbhc->dev, "(wusbhc %p)\n", wusbhc); | ||
142 | /* WE DON'T LOCK, see comment */ | ||
143 | size = wusbhc->ports_max + 1 /* hub bit */; | ||
144 | size = (size + 8 - 1) / 8; /* round to bytes */ | ||
145 | for (cnt = 0; cnt < wusbhc->ports_max; cnt++) | ||
146 | if (wusb_port_by_idx(wusbhc, cnt)->change) | ||
147 | set_bit(cnt + 1, buf); | ||
148 | else | ||
149 | clear_bit(cnt + 1, buf); | ||
150 | d_fnend(1, wusbhc->dev, "(wusbhc %p) %u, buffer:\n", wusbhc, (int)size); | ||
151 | d_dump(1, wusbhc->dev, _buf, size); | ||
152 | return size; | ||
153 | } | ||
154 | EXPORT_SYMBOL_GPL(wusbhc_rh_status_data); | ||
155 | |||
156 | /* | ||
157 | * Return the hub's desciptor | ||
158 | * | ||
159 | * NOTE: almost cut and paste from ehci-hub.c | ||
160 | * | ||
161 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked | ||
162 | */ | ||
163 | static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue, | ||
164 | u16 wIndex, | ||
165 | struct usb_hub_descriptor *descr, | ||
166 | u16 wLength) | ||
167 | { | ||
168 | u16 temp = 1 + (wusbhc->ports_max / 8); | ||
169 | u8 length = 7 + 2 * temp; | ||
170 | |||
171 | if (wLength < length) | ||
172 | return -ENOSPC; | ||
173 | descr->bDescLength = 7 + 2 * temp; | ||
174 | descr->bDescriptorType = 0x29; /* HUB type */ | ||
175 | descr->bNbrPorts = wusbhc->ports_max; | ||
176 | descr->wHubCharacteristics = cpu_to_le16( | ||
177 | 0x00 /* All ports power at once */ | ||
178 | | 0x00 /* not part of compound device */ | ||
179 | | 0x10 /* No overcurrent protection */ | ||
180 | | 0x00 /* 8 FS think time FIXME ?? */ | ||
181 | | 0x00); /* No port indicators */ | ||
182 | descr->bPwrOn2PwrGood = 0; | ||
183 | descr->bHubContrCurrent = 0; | ||
184 | /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ | ||
185 | memset(&descr->bitmap[0], 0, temp); | ||
186 | memset(&descr->bitmap[temp], 0xff, temp); | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Clear a hub feature | ||
192 | * | ||
193 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
194 | * | ||
195 | * Nothing to do, so no locking needed ;) | ||
196 | */ | ||
197 | static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature) | ||
198 | { | ||
199 | int result; | ||
200 | struct device *dev = wusbhc->dev; | ||
201 | |||
202 | d_fnstart(4, dev, "(%p, feature 0x%04u)\n", wusbhc, feature); | ||
203 | switch (feature) { | ||
204 | case C_HUB_LOCAL_POWER: | ||
205 | /* FIXME: maybe plug bit 0 to the power input status, | ||
206 | * if any? | ||
207 | * see wusbhc_rh_get_hub_status() */ | ||
208 | case C_HUB_OVER_CURRENT: | ||
209 | result = 0; | ||
210 | break; | ||
211 | default: | ||
212 | result = -EPIPE; | ||
213 | } | ||
214 | d_fnend(4, dev, "(%p, feature 0x%04u), %d\n", wusbhc, feature, result); | ||
215 | return result; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Return hub status (it is always zero...) | ||
220 | * | ||
221 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
222 | * | ||
223 | * Nothing to do, so no locking needed ;) | ||
224 | */ | ||
225 | static int wusbhc_rh_get_hub_status(struct wusbhc *wusbhc, u32 *buf, | ||
226 | u16 wLength) | ||
227 | { | ||
228 | /* FIXME: maybe plug bit 0 to the power input status (if any)? */ | ||
229 | *buf = 0; | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * Set a port feature | ||
235 | * | ||
236 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
237 | */ | ||
238 | static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature, | ||
239 | u8 selector, u8 port_idx) | ||
240 | { | ||
241 | int result = -EINVAL; | ||
242 | struct device *dev = wusbhc->dev; | ||
243 | |||
244 | d_fnstart(4, dev, "(feat 0x%04u, selector 0x%u, port_idx %d)\n", | ||
245 | feature, selector, port_idx); | ||
246 | |||
247 | if (port_idx > wusbhc->ports_max) | ||
248 | goto error; | ||
249 | |||
250 | switch (feature) { | ||
251 | /* According to USB2.0[11.24.2.13]p2, these features | ||
252 | * are not required to be implemented. */ | ||
253 | case USB_PORT_FEAT_C_OVER_CURRENT: | ||
254 | case USB_PORT_FEAT_C_ENABLE: | ||
255 | case USB_PORT_FEAT_C_SUSPEND: | ||
256 | case USB_PORT_FEAT_C_CONNECTION: | ||
257 | case USB_PORT_FEAT_C_RESET: | ||
258 | result = 0; | ||
259 | break; | ||
260 | |||
261 | case USB_PORT_FEAT_POWER: | ||
262 | /* No such thing, but we fake it works */ | ||
263 | mutex_lock(&wusbhc->mutex); | ||
264 | wusb_port_by_idx(wusbhc, port_idx)->status |= USB_PORT_STAT_POWER; | ||
265 | mutex_unlock(&wusbhc->mutex); | ||
266 | result = 0; | ||
267 | break; | ||
268 | case USB_PORT_FEAT_RESET: | ||
269 | result = wusbhc_rh_port_reset(wusbhc, port_idx); | ||
270 | break; | ||
271 | case USB_PORT_FEAT_ENABLE: | ||
272 | case USB_PORT_FEAT_SUSPEND: | ||
273 | dev_err(dev, "(port_idx %d) set feat %d/%d UNIMPLEMENTED\n", | ||
274 | port_idx, feature, selector); | ||
275 | result = -ENOSYS; | ||
276 | break; | ||
277 | default: | ||
278 | dev_err(dev, "(port_idx %d) set feat %d/%d UNKNOWN\n", | ||
279 | port_idx, feature, selector); | ||
280 | result = -EPIPE; | ||
281 | break; | ||
282 | } | ||
283 | error: | ||
284 | d_fnend(4, dev, "(feat 0x%04u, selector 0x%u, port_idx %d) = %d\n", | ||
285 | feature, selector, port_idx, result); | ||
286 | return result; | ||
287 | } | ||
288 | |||
289 | /* | ||
290 | * Clear a port feature... | ||
291 | * | ||
292 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
293 | */ | ||
294 | static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature, | ||
295 | u8 selector, u8 port_idx) | ||
296 | { | ||
297 | int result = -EINVAL; | ||
298 | struct device *dev = wusbhc->dev; | ||
299 | |||
300 | d_fnstart(4, dev, "(wusbhc %p feat 0x%04x selector %d port_idx %d)\n", | ||
301 | wusbhc, feature, selector, port_idx); | ||
302 | |||
303 | if (port_idx > wusbhc->ports_max) | ||
304 | goto error; | ||
305 | |||
306 | mutex_lock(&wusbhc->mutex); | ||
307 | result = 0; | ||
308 | switch (feature) { | ||
309 | case USB_PORT_FEAT_POWER: /* fake port always on */ | ||
310 | /* According to USB2.0[11.24.2.7.1.4], no need to implement? */ | ||
311 | case USB_PORT_FEAT_C_OVER_CURRENT: | ||
312 | break; | ||
313 | case USB_PORT_FEAT_C_RESET: | ||
314 | wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_RESET; | ||
315 | break; | ||
316 | case USB_PORT_FEAT_C_CONNECTION: | ||
317 | wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_CONNECTION; | ||
318 | break; | ||
319 | case USB_PORT_FEAT_ENABLE: | ||
320 | __wusbhc_dev_disable(wusbhc, port_idx); | ||
321 | break; | ||
322 | case USB_PORT_FEAT_C_ENABLE: | ||
323 | wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_ENABLE; | ||
324 | break; | ||
325 | case USB_PORT_FEAT_SUSPEND: | ||
326 | case USB_PORT_FEAT_C_SUSPEND: | ||
327 | case 0xffff: /* ??? FIXME */ | ||
328 | dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n", | ||
329 | port_idx, feature, selector); | ||
330 | /* dump_stack(); */ | ||
331 | result = -ENOSYS; | ||
332 | break; | ||
333 | default: | ||
334 | dev_err(dev, "(port_idx %d) Clear feat %d/%d UNKNOWN\n", | ||
335 | port_idx, feature, selector); | ||
336 | result = -EPIPE; | ||
337 | break; | ||
338 | } | ||
339 | mutex_unlock(&wusbhc->mutex); | ||
340 | error: | ||
341 | d_fnend(4, dev, "(wusbhc %p feat 0x%04x selector %d port_idx %d) = " | ||
342 | "%d\n", wusbhc, feature, selector, port_idx, result); | ||
343 | return result; | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * Return the port's status | ||
348 | * | ||
349 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
350 | */ | ||
351 | static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx, | ||
352 | u32 *_buf, u16 wLength) | ||
353 | { | ||
354 | int result = -EINVAL; | ||
355 | u16 *buf = (u16 *) _buf; | ||
356 | |||
357 | d_fnstart(1, wusbhc->dev, "(wusbhc %p port_idx %u wLength %u)\n", | ||
358 | wusbhc, port_idx, wLength); | ||
359 | if (port_idx > wusbhc->ports_max) | ||
360 | goto error; | ||
361 | mutex_lock(&wusbhc->mutex); | ||
362 | buf[0] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->status); | ||
363 | buf[1] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->change); | ||
364 | result = 0; | ||
365 | mutex_unlock(&wusbhc->mutex); | ||
366 | error: | ||
367 | d_fnend(1, wusbhc->dev, "(wusbhc %p) = %d, buffer:\n", wusbhc, result); | ||
368 | d_dump(1, wusbhc->dev, _buf, wLength); | ||
369 | return result; | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * Entry point for Root Hub operations | ||
374 | * | ||
375 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
376 | */ | ||
377 | int wusbhc_rh_control(struct usb_hcd *usb_hcd, u16 reqntype, u16 wValue, | ||
378 | u16 wIndex, char *buf, u16 wLength) | ||
379 | { | ||
380 | int result = -ENOSYS; | ||
381 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
382 | |||
383 | switch (reqntype) { | ||
384 | case GetHubDescriptor: | ||
385 | result = wusbhc_rh_get_hub_descr( | ||
386 | wusbhc, wValue, wIndex, | ||
387 | (struct usb_hub_descriptor *) buf, wLength); | ||
388 | break; | ||
389 | case ClearHubFeature: | ||
390 | result = wusbhc_rh_clear_hub_feat(wusbhc, wValue); | ||
391 | break; | ||
392 | case GetHubStatus: | ||
393 | result = wusbhc_rh_get_hub_status(wusbhc, (u32 *)buf, wLength); | ||
394 | break; | ||
395 | |||
396 | case SetPortFeature: | ||
397 | result = wusbhc_rh_set_port_feat(wusbhc, wValue, wIndex >> 8, | ||
398 | (wIndex & 0xff) - 1); | ||
399 | break; | ||
400 | case ClearPortFeature: | ||
401 | result = wusbhc_rh_clear_port_feat(wusbhc, wValue, wIndex >> 8, | ||
402 | (wIndex & 0xff) - 1); | ||
403 | break; | ||
404 | case GetPortStatus: | ||
405 | result = wusbhc_rh_get_port_status(wusbhc, wIndex - 1, | ||
406 | (u32 *)buf, wLength); | ||
407 | break; | ||
408 | |||
409 | case SetHubFeature: | ||
410 | default: | ||
411 | dev_err(wusbhc->dev, "%s (%p [%p], %x, %x, %x, %p, %x) " | ||
412 | "UNIMPLEMENTED\n", __func__, usb_hcd, wusbhc, reqntype, | ||
413 | wValue, wIndex, buf, wLength); | ||
414 | /* dump_stack(); */ | ||
415 | result = -ENOSYS; | ||
416 | } | ||
417 | return result; | ||
418 | } | ||
419 | EXPORT_SYMBOL_GPL(wusbhc_rh_control); | ||
420 | |||
421 | int wusbhc_rh_suspend(struct usb_hcd *usb_hcd) | ||
422 | { | ||
423 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
424 | dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, | ||
425 | usb_hcd, wusbhc); | ||
426 | /* dump_stack(); */ | ||
427 | return -ENOSYS; | ||
428 | } | ||
429 | EXPORT_SYMBOL_GPL(wusbhc_rh_suspend); | ||
430 | |||
431 | int wusbhc_rh_resume(struct usb_hcd *usb_hcd) | ||
432 | { | ||
433 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
434 | dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, | ||
435 | usb_hcd, wusbhc); | ||
436 | /* dump_stack(); */ | ||
437 | return -ENOSYS; | ||
438 | } | ||
439 | EXPORT_SYMBOL_GPL(wusbhc_rh_resume); | ||
440 | |||
441 | int wusbhc_rh_start_port_reset(struct usb_hcd *usb_hcd, unsigned port_idx) | ||
442 | { | ||
443 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
444 | dev_err(wusbhc->dev, "%s (%p [%p], port_idx %u) UNIMPLEMENTED\n", | ||
445 | __func__, usb_hcd, wusbhc, port_idx); | ||
446 | WARN_ON(1); | ||
447 | return -ENOSYS; | ||
448 | } | ||
449 | EXPORT_SYMBOL_GPL(wusbhc_rh_start_port_reset); | ||
450 | |||
451 | static void wusb_port_init(struct wusb_port *port) | ||
452 | { | ||
453 | port->status |= USB_PORT_STAT_HIGH_SPEED; | ||
454 | } | ||
455 | |||
456 | /* | ||
457 | * Alloc fake port specific fields and status. | ||
458 | */ | ||
459 | int wusbhc_rh_create(struct wusbhc *wusbhc) | ||
460 | { | ||
461 | int result = -ENOMEM; | ||
462 | size_t port_size, itr; | ||
463 | port_size = wusbhc->ports_max * sizeof(wusbhc->port[0]); | ||
464 | wusbhc->port = kzalloc(port_size, GFP_KERNEL); | ||
465 | if (wusbhc->port == NULL) | ||
466 | goto error_port_alloc; | ||
467 | for (itr = 0; itr < wusbhc->ports_max; itr++) | ||
468 | wusb_port_init(&wusbhc->port[itr]); | ||
469 | result = 0; | ||
470 | error_port_alloc: | ||
471 | return result; | ||
472 | } | ||
473 | |||
474 | void wusbhc_rh_destroy(struct wusbhc *wusbhc) | ||
475 | { | ||
476 | kfree(wusbhc->port); | ||
477 | } | ||
diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c new file mode 100644 index 000000000000..a101cad6a8d4 --- /dev/null +++ b/drivers/usb/wusbcore/security.c | |||
@@ -0,0 +1,642 @@ | |||
1 | /* | ||
2 | * Wireless USB Host Controller | ||
3 | * Security support: encryption enablement, etc | ||
4 | * | ||
5 | * Copyright (C) 2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | */ | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/usb/ch9.h> | ||
27 | #include <linux/random.h> | ||
28 | #include "wusbhc.h" | ||
29 | |||
30 | /* | ||
31 | * DEBUG & SECURITY WARNING!!!! | ||
32 | * | ||
33 | * If you enable this past 1, the debug code will weaken the | ||
34 | * cryptographic safety of the system (on purpose, for debugging). | ||
35 | * | ||
36 | * Weaken means: | ||
37 | * we print secret keys and intermediate values all the way, | ||
38 | */ | ||
39 | #undef D_LOCAL | ||
40 | #define D_LOCAL 2 | ||
41 | #include <linux/uwb/debug.h> | ||
42 | |||
43 | static void wusbhc_set_gtk_callback(struct urb *urb); | ||
44 | static void wusbhc_gtk_rekey_done_work(struct work_struct *work); | ||
45 | |||
46 | int wusbhc_sec_create(struct wusbhc *wusbhc) | ||
47 | { | ||
48 | wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) + sizeof(wusbhc->gtk.data); | ||
49 | wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY; | ||
50 | wusbhc->gtk.descr.bReserved = 0; | ||
51 | |||
52 | wusbhc->gtk_index = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK, | ||
53 | WUSB_KEY_INDEX_ORIGINATOR_HOST); | ||
54 | |||
55 | INIT_WORK(&wusbhc->gtk_rekey_done_work, wusbhc_gtk_rekey_done_work); | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | |||
61 | /* Called when the HC is destroyed */ | ||
62 | void wusbhc_sec_destroy(struct wusbhc *wusbhc) | ||
63 | { | ||
64 | } | ||
65 | |||
66 | |||
67 | /** | ||
68 | * wusbhc_next_tkid - generate a new, currently unused, TKID | ||
69 | * @wusbhc: the WUSB host controller | ||
70 | * @wusb_dev: the device whose PTK the TKID is for | ||
71 | * (or NULL for a TKID for a GTK) | ||
72 | * | ||
73 | * The generated TKID consist of two parts: the device's authenicated | ||
74 | * address (or 0 or a GTK); and an incrementing number. This ensures | ||
75 | * that TKIDs cannot be shared between devices and by the time the | ||
76 | * incrementing number wraps around the older TKIDs will no longer be | ||
77 | * in use (a maximum of two keys may be active at any one time). | ||
78 | */ | ||
79 | static u32 wusbhc_next_tkid(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
80 | { | ||
81 | u32 *tkid; | ||
82 | u32 addr; | ||
83 | |||
84 | if (wusb_dev == NULL) { | ||
85 | tkid = &wusbhc->gtk_tkid; | ||
86 | addr = 0; | ||
87 | } else { | ||
88 | tkid = &wusb_port_by_idx(wusbhc, wusb_dev->port_idx)->ptk_tkid; | ||
89 | addr = wusb_dev->addr & 0x7f; | ||
90 | } | ||
91 | |||
92 | *tkid = (addr << 8) | ((*tkid + 1) & 0xff); | ||
93 | |||
94 | return *tkid; | ||
95 | } | ||
96 | |||
97 | static void wusbhc_generate_gtk(struct wusbhc *wusbhc) | ||
98 | { | ||
99 | const size_t key_size = sizeof(wusbhc->gtk.data); | ||
100 | u32 tkid; | ||
101 | |||
102 | tkid = wusbhc_next_tkid(wusbhc, NULL); | ||
103 | |||
104 | wusbhc->gtk.descr.tTKID[0] = (tkid >> 0) & 0xff; | ||
105 | wusbhc->gtk.descr.tTKID[1] = (tkid >> 8) & 0xff; | ||
106 | wusbhc->gtk.descr.tTKID[2] = (tkid >> 16) & 0xff; | ||
107 | |||
108 | get_random_bytes(wusbhc->gtk.descr.bKeyData, key_size); | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * wusbhc_sec_start - start the security management process | ||
113 | * @wusbhc: the WUSB host controller | ||
114 | * | ||
115 | * Generate and set an initial GTK on the host controller. | ||
116 | * | ||
117 | * Called when the HC is started. | ||
118 | */ | ||
119 | int wusbhc_sec_start(struct wusbhc *wusbhc) | ||
120 | { | ||
121 | const size_t key_size = sizeof(wusbhc->gtk.data); | ||
122 | int result; | ||
123 | |||
124 | wusbhc_generate_gtk(wusbhc); | ||
125 | |||
126 | result = wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, | ||
127 | &wusbhc->gtk.descr.bKeyData, key_size); | ||
128 | if (result < 0) | ||
129 | dev_err(wusbhc->dev, "cannot set GTK for the host: %d\n", | ||
130 | result); | ||
131 | |||
132 | return result; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * wusbhc_sec_stop - stop the security management process | ||
137 | * @wusbhc: the WUSB host controller | ||
138 | * | ||
139 | * Wait for any pending GTK rekeys to stop. | ||
140 | */ | ||
141 | void wusbhc_sec_stop(struct wusbhc *wusbhc) | ||
142 | { | ||
143 | cancel_work_sync(&wusbhc->gtk_rekey_done_work); | ||
144 | } | ||
145 | |||
146 | |||
147 | /** @returns encryption type name */ | ||
148 | const char *wusb_et_name(u8 x) | ||
149 | { | ||
150 | switch (x) { | ||
151 | case USB_ENC_TYPE_UNSECURE: return "unsecure"; | ||
152 | case USB_ENC_TYPE_WIRED: return "wired"; | ||
153 | case USB_ENC_TYPE_CCM_1: return "CCM-1"; | ||
154 | case USB_ENC_TYPE_RSA_1: return "RSA-1"; | ||
155 | default: return "unknown"; | ||
156 | } | ||
157 | } | ||
158 | EXPORT_SYMBOL_GPL(wusb_et_name); | ||
159 | |||
160 | /* | ||
161 | * Set the device encryption method | ||
162 | * | ||
163 | * We tell the device which encryption method to use; we do this when | ||
164 | * setting up the device's security. | ||
165 | */ | ||
166 | static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value) | ||
167 | { | ||
168 | int result; | ||
169 | struct device *dev = &usb_dev->dev; | ||
170 | struct wusb_dev *wusb_dev = usb_dev->wusb_dev; | ||
171 | |||
172 | if (value) { | ||
173 | value = wusb_dev->ccm1_etd.bEncryptionValue; | ||
174 | } else { | ||
175 | /* FIXME: should be wusb_dev->etd[UNSECURE].bEncryptionValue */ | ||
176 | value = 0; | ||
177 | } | ||
178 | /* Set device's */ | ||
179 | result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
180 | USB_REQ_SET_ENCRYPTION, | ||
181 | USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | ||
182 | value, 0, NULL, 0, 1000 /* FIXME: arbitrary */); | ||
183 | if (result < 0) | ||
184 | dev_err(dev, "Can't set device's WUSB encryption to " | ||
185 | "%s (value %d): %d\n", | ||
186 | wusb_et_name(wusb_dev->ccm1_etd.bEncryptionType), | ||
187 | wusb_dev->ccm1_etd.bEncryptionValue, result); | ||
188 | return result; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * Set the GTK to be used by a device. | ||
193 | * | ||
194 | * The device must be authenticated. | ||
195 | */ | ||
196 | static int wusb_dev_set_gtk(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
197 | { | ||
198 | struct usb_device *usb_dev = wusb_dev->usb_dev; | ||
199 | |||
200 | return usb_control_msg( | ||
201 | usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
202 | USB_REQ_SET_DESCRIPTOR, | ||
203 | USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | ||
204 | USB_DT_KEY << 8 | wusbhc->gtk_index, 0, | ||
205 | &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength, | ||
206 | 1000); | ||
207 | } | ||
208 | |||
209 | |||
210 | /* FIXME: prototype for adding security */ | ||
211 | int wusb_dev_sec_add(struct wusbhc *wusbhc, | ||
212 | struct usb_device *usb_dev, struct wusb_dev *wusb_dev) | ||
213 | { | ||
214 | int result, bytes, secd_size; | ||
215 | struct device *dev = &usb_dev->dev; | ||
216 | struct usb_security_descriptor secd; | ||
217 | const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL; | ||
218 | void *secd_buf; | ||
219 | const void *itr, *top; | ||
220 | char buf[64]; | ||
221 | |||
222 | d_fnstart(3, dev, "(usb_dev %p, wusb_dev %p)\n", usb_dev, wusb_dev); | ||
223 | result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, | ||
224 | 0, &secd, sizeof(secd)); | ||
225 | if (result < sizeof(secd)) { | ||
226 | dev_err(dev, "Can't read security descriptor or " | ||
227 | "not enough data: %d\n", result); | ||
228 | goto error_secd; | ||
229 | } | ||
230 | secd_size = le16_to_cpu(secd.wTotalLength); | ||
231 | d_printf(5, dev, "got %d bytes of sec descriptor, total is %d\n", | ||
232 | result, secd_size); | ||
233 | secd_buf = kmalloc(secd_size, GFP_KERNEL); | ||
234 | if (secd_buf == NULL) { | ||
235 | dev_err(dev, "Can't allocate space for security descriptors\n"); | ||
236 | goto error_secd_alloc; | ||
237 | } | ||
238 | result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, | ||
239 | 0, secd_buf, secd_size); | ||
240 | if (result < secd_size) { | ||
241 | dev_err(dev, "Can't read security descriptor or " | ||
242 | "not enough data: %d\n", result); | ||
243 | goto error_secd_all; | ||
244 | } | ||
245 | d_printf(5, dev, "got %d bytes of sec descriptors\n", result); | ||
246 | bytes = 0; | ||
247 | itr = secd_buf + sizeof(secd); | ||
248 | top = secd_buf + result; | ||
249 | while (itr < top) { | ||
250 | etd = itr; | ||
251 | if (top - itr < sizeof(*etd)) { | ||
252 | dev_err(dev, "BUG: bad device security descriptor; " | ||
253 | "not enough data (%zu vs %zu bytes left)\n", | ||
254 | top - itr, sizeof(*etd)); | ||
255 | break; | ||
256 | } | ||
257 | if (etd->bLength < sizeof(*etd)) { | ||
258 | dev_err(dev, "BUG: bad device encryption descriptor; " | ||
259 | "descriptor is too short " | ||
260 | "(%u vs %zu needed)\n", | ||
261 | etd->bLength, sizeof(*etd)); | ||
262 | break; | ||
263 | } | ||
264 | itr += etd->bLength; | ||
265 | bytes += snprintf(buf + bytes, sizeof(buf) - bytes, | ||
266 | "%s (0x%02x/%02x) ", | ||
267 | wusb_et_name(etd->bEncryptionType), | ||
268 | etd->bEncryptionValue, etd->bAuthKeyIndex); | ||
269 | if (etd->bEncryptionType == USB_ENC_TYPE_CCM_1) | ||
270 | ccm1_etd = etd; | ||
271 | } | ||
272 | /* This code only supports CCM1 as of now. */ | ||
273 | /* FIXME: user has to choose which sec mode to use? | ||
274 | * In theory we want CCM */ | ||
275 | if (ccm1_etd == NULL) { | ||
276 | dev_err(dev, "WUSB device doesn't support CCM1 encryption, " | ||
277 | "can't use!\n"); | ||
278 | result = -EINVAL; | ||
279 | goto error_no_ccm1; | ||
280 | } | ||
281 | wusb_dev->ccm1_etd = *ccm1_etd; | ||
282 | dev_info(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n", | ||
283 | buf, wusb_et_name(ccm1_etd->bEncryptionType), | ||
284 | ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex); | ||
285 | result = 0; | ||
286 | kfree(secd_buf); | ||
287 | out: | ||
288 | d_fnend(3, dev, "(usb_dev %p, wusb_dev %p) = %d\n", | ||
289 | usb_dev, wusb_dev, result); | ||
290 | return result; | ||
291 | |||
292 | |||
293 | error_no_ccm1: | ||
294 | error_secd_all: | ||
295 | kfree(secd_buf); | ||
296 | error_secd_alloc: | ||
297 | error_secd: | ||
298 | goto out; | ||
299 | } | ||
300 | |||
301 | void wusb_dev_sec_rm(struct wusb_dev *wusb_dev) | ||
302 | { | ||
303 | /* Nothing so far */ | ||
304 | } | ||
305 | |||
306 | static void hs_printk(unsigned level, struct device *dev, | ||
307 | struct usb_handshake *hs) | ||
308 | { | ||
309 | d_printf(level, dev, | ||
310 | " bMessageNumber: %u\n" | ||
311 | " bStatus: %u\n" | ||
312 | " tTKID: %02x %02x %02x\n" | ||
313 | " CDID: %02x %02x %02x %02x %02x %02x %02x %02x\n" | ||
314 | " %02x %02x %02x %02x %02x %02x %02x %02x\n" | ||
315 | " nonce: %02x %02x %02x %02x %02x %02x %02x %02x\n" | ||
316 | " %02x %02x %02x %02x %02x %02x %02x %02x\n" | ||
317 | " MIC: %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
318 | hs->bMessageNumber, hs->bStatus, | ||
319 | hs->tTKID[2], hs->tTKID[1], hs->tTKID[0], | ||
320 | hs->CDID[0], hs->CDID[1], hs->CDID[2], hs->CDID[3], | ||
321 | hs->CDID[4], hs->CDID[5], hs->CDID[6], hs->CDID[7], | ||
322 | hs->CDID[8], hs->CDID[9], hs->CDID[10], hs->CDID[11], | ||
323 | hs->CDID[12], hs->CDID[13], hs->CDID[14], hs->CDID[15], | ||
324 | hs->nonce[0], hs->nonce[1], hs->nonce[2], hs->nonce[3], | ||
325 | hs->nonce[4], hs->nonce[5], hs->nonce[6], hs->nonce[7], | ||
326 | hs->nonce[8], hs->nonce[9], hs->nonce[10], hs->nonce[11], | ||
327 | hs->nonce[12], hs->nonce[13], hs->nonce[14], hs->nonce[15], | ||
328 | hs->MIC[0], hs->MIC[1], hs->MIC[2], hs->MIC[3], | ||
329 | hs->MIC[4], hs->MIC[5], hs->MIC[6], hs->MIC[7]); | ||
330 | } | ||
331 | |||
332 | /** | ||
333 | * Update the address of an unauthenticated WUSB device | ||
334 | * | ||
335 | * Once we have successfully authenticated, we take it to addr0 state | ||
336 | * and then to a normal address. | ||
337 | * | ||
338 | * Before the device's address (as known by it) was usb_dev->devnum | | ||
339 | * 0x80 (unauthenticated address). With this we update it to usb_dev->devnum. | ||
340 | */ | ||
341 | static int wusb_dev_update_address(struct wusbhc *wusbhc, | ||
342 | struct wusb_dev *wusb_dev) | ||
343 | { | ||
344 | int result = -ENOMEM; | ||
345 | struct usb_device *usb_dev = wusb_dev->usb_dev; | ||
346 | struct device *dev = &usb_dev->dev; | ||
347 | u8 new_address = wusb_dev->addr & 0x7F; | ||
348 | |||
349 | /* Set address 0 */ | ||
350 | result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
351 | USB_REQ_SET_ADDRESS, 0, | ||
352 | 0, 0, NULL, 0, 1000 /* FIXME: arbitrary */); | ||
353 | if (result < 0) { | ||
354 | dev_err(dev, "auth failed: can't set address 0: %d\n", | ||
355 | result); | ||
356 | goto error_addr0; | ||
357 | } | ||
358 | result = wusb_set_dev_addr(wusbhc, wusb_dev, 0); | ||
359 | if (result < 0) | ||
360 | goto error_addr0; | ||
361 | usb_ep0_reinit(usb_dev); | ||
362 | |||
363 | /* Set new (authenticated) address. */ | ||
364 | result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
365 | USB_REQ_SET_ADDRESS, 0, | ||
366 | new_address, 0, NULL, 0, | ||
367 | 1000 /* FIXME: arbitrary */); | ||
368 | if (result < 0) { | ||
369 | dev_err(dev, "auth failed: can't set address %u: %d\n", | ||
370 | new_address, result); | ||
371 | goto error_addr; | ||
372 | } | ||
373 | result = wusb_set_dev_addr(wusbhc, wusb_dev, new_address); | ||
374 | if (result < 0) | ||
375 | goto error_addr; | ||
376 | usb_ep0_reinit(usb_dev); | ||
377 | usb_dev->authenticated = 1; | ||
378 | error_addr: | ||
379 | error_addr0: | ||
380 | return result; | ||
381 | } | ||
382 | |||
383 | /* | ||
384 | * | ||
385 | * | ||
386 | */ | ||
387 | /* FIXME: split and cleanup */ | ||
388 | int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, | ||
389 | struct wusb_ckhdid *ck) | ||
390 | { | ||
391 | int result = -ENOMEM; | ||
392 | struct usb_device *usb_dev = wusb_dev->usb_dev; | ||
393 | struct device *dev = &usb_dev->dev; | ||
394 | u32 tkid; | ||
395 | __le32 tkid_le; | ||
396 | struct usb_handshake *hs; | ||
397 | struct aes_ccm_nonce ccm_n; | ||
398 | u8 mic[8]; | ||
399 | struct wusb_keydvt_in keydvt_in; | ||
400 | struct wusb_keydvt_out keydvt_out; | ||
401 | |||
402 | hs = kzalloc(3*sizeof(hs[0]), GFP_KERNEL); | ||
403 | if (hs == NULL) { | ||
404 | dev_err(dev, "can't allocate handshake data\n"); | ||
405 | goto error_kzalloc; | ||
406 | } | ||
407 | |||
408 | /* We need to turn encryption before beginning the 4way | ||
409 | * hshake (WUSB1.0[.3.2.2]) */ | ||
410 | result = wusb_dev_set_encryption(usb_dev, 1); | ||
411 | if (result < 0) | ||
412 | goto error_dev_set_encryption; | ||
413 | |||
414 | tkid = wusbhc_next_tkid(wusbhc, wusb_dev); | ||
415 | tkid_le = cpu_to_le32(tkid); | ||
416 | |||
417 | hs[0].bMessageNumber = 1; | ||
418 | hs[0].bStatus = 0; | ||
419 | memcpy(hs[0].tTKID, &tkid_le, sizeof(hs[0].tTKID)); | ||
420 | hs[0].bReserved = 0; | ||
421 | memcpy(hs[0].CDID, &wusb_dev->cdid, sizeof(hs[0].CDID)); | ||
422 | get_random_bytes(&hs[0].nonce, sizeof(hs[0].nonce)); | ||
423 | memset(hs[0].MIC, 0, sizeof(hs[0].MIC)); /* Per WUSB1.0[T7-22] */ | ||
424 | |||
425 | d_printf(1, dev, "I: sending hs1:\n"); | ||
426 | hs_printk(2, dev, &hs[0]); | ||
427 | |||
428 | result = usb_control_msg( | ||
429 | usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
430 | USB_REQ_SET_HANDSHAKE, | ||
431 | USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | ||
432 | 1, 0, &hs[0], sizeof(hs[0]), 1000 /* FIXME: arbitrary */); | ||
433 | if (result < 0) { | ||
434 | dev_err(dev, "Handshake1: request failed: %d\n", result); | ||
435 | goto error_hs1; | ||
436 | } | ||
437 | |||
438 | /* Handshake 2, from the device -- need to verify fields */ | ||
439 | result = usb_control_msg( | ||
440 | usb_dev, usb_rcvctrlpipe(usb_dev, 0), | ||
441 | USB_REQ_GET_HANDSHAKE, | ||
442 | USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | ||
443 | 2, 0, &hs[1], sizeof(hs[1]), 1000 /* FIXME: arbitrary */); | ||
444 | if (result < 0) { | ||
445 | dev_err(dev, "Handshake2: request failed: %d\n", result); | ||
446 | goto error_hs2; | ||
447 | } | ||
448 | d_printf(1, dev, "got HS2:\n"); | ||
449 | hs_printk(2, dev, &hs[1]); | ||
450 | |||
451 | result = -EINVAL; | ||
452 | if (hs[1].bMessageNumber != 2) { | ||
453 | dev_err(dev, "Handshake2 failed: bad message number %u\n", | ||
454 | hs[1].bMessageNumber); | ||
455 | goto error_hs2; | ||
456 | } | ||
457 | if (hs[1].bStatus != 0) { | ||
458 | dev_err(dev, "Handshake2 failed: bad status %u\n", | ||
459 | hs[1].bStatus); | ||
460 | goto error_hs2; | ||
461 | } | ||
462 | if (memcmp(hs[0].tTKID, hs[1].tTKID, sizeof(hs[0].tTKID))) { | ||
463 | dev_err(dev, "Handshake2 failed: TKID mismatch " | ||
464 | "(#1 0x%02x%02x%02x vs #2 0x%02x%02x%02x)\n", | ||
465 | hs[0].tTKID[0], hs[0].tTKID[1], hs[0].tTKID[2], | ||
466 | hs[1].tTKID[0], hs[1].tTKID[1], hs[1].tTKID[2]); | ||
467 | goto error_hs2; | ||
468 | } | ||
469 | if (memcmp(hs[0].CDID, hs[1].CDID, sizeof(hs[0].CDID))) { | ||
470 | dev_err(dev, "Handshake2 failed: CDID mismatch\n"); | ||
471 | goto error_hs2; | ||
472 | } | ||
473 | |||
474 | /* Setup the CCM nonce */ | ||
475 | memset(&ccm_n.sfn, 0, sizeof(ccm_n.sfn)); /* Per WUSB1.0[6.5.2] */ | ||
476 | memcpy(ccm_n.tkid, &tkid_le, sizeof(ccm_n.tkid)); | ||
477 | ccm_n.src_addr = wusbhc->uwb_rc->uwb_dev.dev_addr; | ||
478 | ccm_n.dest_addr.data[0] = wusb_dev->addr; | ||
479 | ccm_n.dest_addr.data[1] = 0; | ||
480 | |||
481 | /* Derive the KCK and PTK from CK, the CCM, H and D nonces */ | ||
482 | memcpy(keydvt_in.hnonce, hs[0].nonce, sizeof(keydvt_in.hnonce)); | ||
483 | memcpy(keydvt_in.dnonce, hs[1].nonce, sizeof(keydvt_in.dnonce)); | ||
484 | result = wusb_key_derive(&keydvt_out, ck->data, &ccm_n, &keydvt_in); | ||
485 | if (result < 0) { | ||
486 | dev_err(dev, "Handshake2 failed: cannot derive keys: %d\n", | ||
487 | result); | ||
488 | goto error_hs2; | ||
489 | } | ||
490 | d_printf(2, dev, "KCK:\n"); | ||
491 | d_dump(2, dev, keydvt_out.kck, sizeof(keydvt_out.kck)); | ||
492 | d_printf(2, dev, "PTK:\n"); | ||
493 | d_dump(2, dev, keydvt_out.ptk, sizeof(keydvt_out.ptk)); | ||
494 | |||
495 | /* Compute MIC and verify it */ | ||
496 | result = wusb_oob_mic(mic, keydvt_out.kck, &ccm_n, &hs[1]); | ||
497 | if (result < 0) { | ||
498 | dev_err(dev, "Handshake2 failed: cannot compute MIC: %d\n", | ||
499 | result); | ||
500 | goto error_hs2; | ||
501 | } | ||
502 | |||
503 | d_printf(2, dev, "MIC:\n"); | ||
504 | d_dump(2, dev, mic, sizeof(mic)); | ||
505 | if (memcmp(hs[1].MIC, mic, sizeof(hs[1].MIC))) { | ||
506 | dev_err(dev, "Handshake2 failed: MIC mismatch\n"); | ||
507 | goto error_hs2; | ||
508 | } | ||
509 | |||
510 | /* Send Handshake3 */ | ||
511 | hs[2].bMessageNumber = 3; | ||
512 | hs[2].bStatus = 0; | ||
513 | memcpy(hs[2].tTKID, &tkid_le, sizeof(hs[2].tTKID)); | ||
514 | hs[2].bReserved = 0; | ||
515 | memcpy(hs[2].CDID, &wusb_dev->cdid, sizeof(hs[2].CDID)); | ||
516 | memcpy(hs[2].nonce, hs[0].nonce, sizeof(hs[2].nonce)); | ||
517 | result = wusb_oob_mic(hs[2].MIC, keydvt_out.kck, &ccm_n, &hs[2]); | ||
518 | if (result < 0) { | ||
519 | dev_err(dev, "Handshake3 failed: cannot compute MIC: %d\n", | ||
520 | result); | ||
521 | goto error_hs2; | ||
522 | } | ||
523 | |||
524 | d_printf(1, dev, "I: sending hs3:\n"); | ||
525 | hs_printk(2, dev, &hs[2]); | ||
526 | |||
527 | result = usb_control_msg( | ||
528 | usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
529 | USB_REQ_SET_HANDSHAKE, | ||
530 | USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | ||
531 | 3, 0, &hs[2], sizeof(hs[2]), 1000 /* FIXME: arbitrary */); | ||
532 | if (result < 0) { | ||
533 | dev_err(dev, "Handshake3: request failed: %d\n", result); | ||
534 | goto error_hs3; | ||
535 | } | ||
536 | |||
537 | d_printf(1, dev, "I: turning on encryption on host for device\n"); | ||
538 | d_dump(2, dev, keydvt_out.ptk, sizeof(keydvt_out.ptk)); | ||
539 | result = wusbhc->set_ptk(wusbhc, wusb_dev->port_idx, tkid, | ||
540 | keydvt_out.ptk, sizeof(keydvt_out.ptk)); | ||
541 | if (result < 0) | ||
542 | goto error_wusbhc_set_ptk; | ||
543 | |||
544 | d_printf(1, dev, "I: setting a GTK\n"); | ||
545 | result = wusb_dev_set_gtk(wusbhc, wusb_dev); | ||
546 | if (result < 0) { | ||
547 | dev_err(dev, "Set GTK for device: request failed: %d\n", | ||
548 | result); | ||
549 | goto error_wusbhc_set_gtk; | ||
550 | } | ||
551 | |||
552 | /* Update the device's address from unauth to auth */ | ||
553 | if (usb_dev->authenticated == 0) { | ||
554 | d_printf(1, dev, "I: updating addres to auth from non-auth\n"); | ||
555 | result = wusb_dev_update_address(wusbhc, wusb_dev); | ||
556 | if (result < 0) | ||
557 | goto error_dev_update_address; | ||
558 | } | ||
559 | result = 0; | ||
560 | d_printf(1, dev, "I: 4way handshke done, device authenticated\n"); | ||
561 | |||
562 | error_dev_update_address: | ||
563 | error_wusbhc_set_gtk: | ||
564 | error_wusbhc_set_ptk: | ||
565 | error_hs3: | ||
566 | error_hs2: | ||
567 | error_hs1: | ||
568 | memset(hs, 0, 3*sizeof(hs[0])); | ||
569 | memset(&keydvt_out, 0, sizeof(keydvt_out)); | ||
570 | memset(&keydvt_in, 0, sizeof(keydvt_in)); | ||
571 | memset(&ccm_n, 0, sizeof(ccm_n)); | ||
572 | memset(mic, 0, sizeof(mic)); | ||
573 | if (result < 0) { | ||
574 | /* error path */ | ||
575 | wusb_dev_set_encryption(usb_dev, 0); | ||
576 | } | ||
577 | error_dev_set_encryption: | ||
578 | kfree(hs); | ||
579 | error_kzalloc: | ||
580 | return result; | ||
581 | } | ||
582 | |||
583 | /* | ||
584 | * Once all connected and authenticated devices have received the new | ||
585 | * GTK, switch the host to using it. | ||
586 | */ | ||
587 | static void wusbhc_gtk_rekey_done_work(struct work_struct *work) | ||
588 | { | ||
589 | struct wusbhc *wusbhc = container_of(work, struct wusbhc, gtk_rekey_done_work); | ||
590 | size_t key_size = sizeof(wusbhc->gtk.data); | ||
591 | |||
592 | mutex_lock(&wusbhc->mutex); | ||
593 | |||
594 | if (--wusbhc->pending_set_gtks == 0) | ||
595 | wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size); | ||
596 | |||
597 | mutex_unlock(&wusbhc->mutex); | ||
598 | } | ||
599 | |||
600 | static void wusbhc_set_gtk_callback(struct urb *urb) | ||
601 | { | ||
602 | struct wusbhc *wusbhc = urb->context; | ||
603 | |||
604 | queue_work(wusbd, &wusbhc->gtk_rekey_done_work); | ||
605 | } | ||
606 | |||
607 | /** | ||
608 | * wusbhc_gtk_rekey - generate and distribute a new GTK | ||
609 | * @wusbhc: the WUSB host controller | ||
610 | * | ||
611 | * Generate a new GTK and distribute it to all connected and | ||
612 | * authenticated devices. When all devices have the new GTK, the host | ||
613 | * starts using it. | ||
614 | * | ||
615 | * This must be called after every device disconnect (see [WUSB] | ||
616 | * section 6.2.11.2). | ||
617 | */ | ||
618 | void wusbhc_gtk_rekey(struct wusbhc *wusbhc) | ||
619 | { | ||
620 | static const size_t key_size = sizeof(wusbhc->gtk.data); | ||
621 | int p; | ||
622 | |||
623 | wusbhc_generate_gtk(wusbhc); | ||
624 | |||
625 | for (p = 0; p < wusbhc->ports_max; p++) { | ||
626 | struct wusb_dev *wusb_dev; | ||
627 | |||
628 | wusb_dev = wusbhc->port[p].wusb_dev; | ||
629 | if (!wusb_dev || !wusb_dev->usb_dev | !wusb_dev->usb_dev->authenticated) | ||
630 | continue; | ||
631 | |||
632 | usb_fill_control_urb(wusb_dev->set_gtk_urb, wusb_dev->usb_dev, | ||
633 | usb_sndctrlpipe(wusb_dev->usb_dev, 0), | ||
634 | (void *)wusb_dev->set_gtk_req, | ||
635 | &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength, | ||
636 | wusbhc_set_gtk_callback, wusbhc); | ||
637 | if (usb_submit_urb(wusb_dev->set_gtk_urb, GFP_KERNEL) == 0) | ||
638 | wusbhc->pending_set_gtks++; | ||
639 | } | ||
640 | if (wusbhc->pending_set_gtks == 0) | ||
641 | wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size); | ||
642 | } | ||
diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c new file mode 100644 index 000000000000..9d04722415bb --- /dev/null +++ b/drivers/usb/wusbcore/wa-hc.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Wire Adapter Host Controller Driver | ||
3 | * Common items to HWA and DWA based HCDs | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | */ | ||
25 | #include "wusbhc.h" | ||
26 | #include "wa-hc.h" | ||
27 | |||
28 | /** | ||
29 | * Assumes | ||
30 | * | ||
31 | * wa->usb_dev and wa->usb_iface initialized and refcounted, | ||
32 | * wa->wa_descr initialized. | ||
33 | */ | ||
34 | int wa_create(struct wahc *wa, struct usb_interface *iface) | ||
35 | { | ||
36 | int result; | ||
37 | struct device *dev = &iface->dev; | ||
38 | |||
39 | result = wa_rpipes_create(wa); | ||
40 | if (result < 0) | ||
41 | goto error_rpipes_create; | ||
42 | /* Fill up Data Transfer EP pointers */ | ||
43 | wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc; | ||
44 | wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc; | ||
45 | wa->xfer_result_size = le16_to_cpu(wa->dti_epd->wMaxPacketSize); | ||
46 | wa->xfer_result = kmalloc(wa->xfer_result_size, GFP_KERNEL); | ||
47 | if (wa->xfer_result == NULL) | ||
48 | goto error_xfer_result_alloc; | ||
49 | result = wa_nep_create(wa, iface); | ||
50 | if (result < 0) { | ||
51 | dev_err(dev, "WA-CDS: can't initialize notif endpoint: %d\n", | ||
52 | result); | ||
53 | goto error_nep_create; | ||
54 | } | ||
55 | return 0; | ||
56 | |||
57 | error_nep_create: | ||
58 | kfree(wa->xfer_result); | ||
59 | error_xfer_result_alloc: | ||
60 | wa_rpipes_destroy(wa); | ||
61 | error_rpipes_create: | ||
62 | return result; | ||
63 | } | ||
64 | EXPORT_SYMBOL_GPL(wa_create); | ||
65 | |||
66 | |||
67 | void __wa_destroy(struct wahc *wa) | ||
68 | { | ||
69 | if (wa->dti_urb) { | ||
70 | usb_kill_urb(wa->dti_urb); | ||
71 | usb_put_urb(wa->dti_urb); | ||
72 | usb_kill_urb(wa->buf_in_urb); | ||
73 | usb_put_urb(wa->buf_in_urb); | ||
74 | } | ||
75 | kfree(wa->xfer_result); | ||
76 | wa_nep_destroy(wa); | ||
77 | wa_rpipes_destroy(wa); | ||
78 | } | ||
79 | EXPORT_SYMBOL_GPL(__wa_destroy); | ||
80 | |||
81 | /** | ||
82 | * wa_reset_all - reset the WA device | ||
83 | * @wa: the WA to be reset | ||
84 | * | ||
85 | * For HWAs the radio controller and all other PALs are also reset. | ||
86 | */ | ||
87 | void wa_reset_all(struct wahc *wa) | ||
88 | { | ||
89 | /* FIXME: assuming HWA. */ | ||
90 | wusbhc_reset_all(wa->wusb); | ||
91 | } | ||
92 | |||
93 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
94 | MODULE_DESCRIPTION("Wireless USB Wire Adapter core"); | ||
95 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h new file mode 100644 index 000000000000..586d350cdb4d --- /dev/null +++ b/drivers/usb/wusbcore/wa-hc.h | |||
@@ -0,0 +1,417 @@ | |||
1 | /* | ||
2 | * HWA Host Controller Driver | ||
3 | * Wire Adapter Control/Data Streaming Iface (WUSB1.0[8]) | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * This driver implements a USB Host Controller (struct usb_hcd) for a | ||
24 | * Wireless USB Host Controller based on the Wireless USB 1.0 | ||
25 | * Host-Wire-Adapter specification (in layman terms, a USB-dongle that | ||
26 | * implements a Wireless USB host). | ||
27 | * | ||
28 | * Check out the Design-overview.txt file in the source documentation | ||
29 | * for other details on the implementation. | ||
30 | * | ||
31 | * Main blocks: | ||
32 | * | ||
33 | * driver glue with the driver API, workqueue daemon | ||
34 | * | ||
35 | * lc RC instance life cycle management (create, destroy...) | ||
36 | * | ||
37 | * hcd glue with the USB API Host Controller Interface API. | ||
38 | * | ||
39 | * nep Notification EndPoint managent: collect notifications | ||
40 | * and queue them with the workqueue daemon. | ||
41 | * | ||
42 | * Handle notifications as coming from the NEP. Sends them | ||
43 | * off others to their respective modules (eg: connect, | ||
44 | * disconnect and reset go to devconnect). | ||
45 | * | ||
46 | * rpipe Remote Pipe management; rpipe is what we use to write | ||
47 | * to an endpoint on a WUSB device that is connected to a | ||
48 | * HWA RC. | ||
49 | * | ||
50 | * xfer Transfer managment -- this is all the code that gets a | ||
51 | * buffer and pushes it to a device (or viceversa). * | ||
52 | * | ||
53 | * Some day a lot of this code will be shared between this driver and | ||
54 | * the drivers for DWA (xfer, rpipe). | ||
55 | * | ||
56 | * All starts at driver.c:hwahc_probe(), when one of this guys is | ||
57 | * connected. hwahc_disconnect() stops it. | ||
58 | * | ||
59 | * During operation, the main driver is devices connecting or | ||
60 | * disconnecting. They cause the HWA RC to send notifications into | ||
61 | * nep.c:hwahc_nep_cb() that will dispatch them to | ||
62 | * notif.c:wa_notif_dispatch(). From there they will fan to cause | ||
63 | * device connects, disconnects, etc. | ||
64 | * | ||
65 | * Note much of the activity is difficult to follow. For example a | ||
66 | * device connect goes to devconnect, which will cause the "fake" root | ||
67 | * hub port to show a connect and stop there. Then khubd will notice | ||
68 | * and call into the rh.c:hwahc_rc_port_reset() code to authenticate | ||
69 | * the device (and this might require user intervention) and enable | ||
70 | * the port. | ||
71 | * | ||
72 | * We also have a timer workqueue going from devconnect.c that | ||
73 | * schedules in hwahc_devconnect_create(). | ||
74 | * | ||
75 | * The rest of the traffic is in the usual entry points of a USB HCD, | ||
76 | * which are hooked up in driver.c:hwahc_rc_driver, and defined in | ||
77 | * hcd.c. | ||
78 | */ | ||
79 | |||
80 | #ifndef __HWAHC_INTERNAL_H__ | ||
81 | #define __HWAHC_INTERNAL_H__ | ||
82 | |||
83 | #include <linux/completion.h> | ||
84 | #include <linux/usb.h> | ||
85 | #include <linux/mutex.h> | ||
86 | #include <linux/spinlock.h> | ||
87 | #include <linux/uwb.h> | ||
88 | #include <linux/usb/wusb.h> | ||
89 | #include <linux/usb/wusb-wa.h> | ||
90 | |||
91 | struct wusbhc; | ||
92 | struct wahc; | ||
93 | extern void wa_urb_enqueue_run(struct work_struct *ws); | ||
94 | |||
95 | /** | ||
96 | * RPipe instance | ||
97 | * | ||
98 | * @descr's fields are kept in LE, as we need to send it back and | ||
99 | * forth. | ||
100 | * | ||
101 | * @wa is referenced when set | ||
102 | * | ||
103 | * @segs_available is the number of requests segments that still can | ||
104 | * be submitted to the controller without overloading | ||
105 | * it. It is initialized to descr->wRequests when | ||
106 | * aiming. | ||
107 | * | ||
108 | * A rpipe supports a max of descr->wRequests at the same time; before | ||
109 | * submitting seg_lock has to be taken. If segs_avail > 0, then we can | ||
110 | * submit; if not, we have to queue them. | ||
111 | */ | ||
112 | struct wa_rpipe { | ||
113 | struct kref refcnt; | ||
114 | struct usb_rpipe_descriptor descr; | ||
115 | struct usb_host_endpoint *ep; | ||
116 | struct wahc *wa; | ||
117 | spinlock_t seg_lock; | ||
118 | struct list_head seg_list; | ||
119 | atomic_t segs_available; | ||
120 | u8 buffer[1]; /* For reads/writes on USB */ | ||
121 | }; | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Instance of a HWA Host Controller | ||
126 | * | ||
127 | * Except where a more specific lock/mutex applies or atomic, all | ||
128 | * fields protected by @mutex. | ||
129 | * | ||
130 | * @wa_descr Can be accessed without locking because it is in | ||
131 | * the same area where the device descriptors were | ||
132 | * read, so it is guaranteed to exist umodified while | ||
133 | * the device exists. | ||
134 | * | ||
135 | * Endianess has been converted to CPU's. | ||
136 | * | ||
137 | * @nep_* can be accessed without locking as its processing is | ||
138 | * serialized; we submit a NEP URB and it comes to | ||
139 | * hwahc_nep_cb(), which won't issue another URB until it is | ||
140 | * done processing it. | ||
141 | * | ||
142 | * @xfer_list: | ||
143 | * | ||
144 | * List of active transfers to verify existence from a xfer id | ||
145 | * gotten from the xfer result message. Can't use urb->list because | ||
146 | * it goes by endpoint, and we don't know the endpoint at the time | ||
147 | * when we get the xfer result message. We can't really rely on the | ||
148 | * pointer (will have to change for 64 bits) as the xfer id is 32 bits. | ||
149 | * | ||
150 | * @xfer_delayed_list: List of transfers that need to be started | ||
151 | * (with a workqueue, because they were | ||
152 | * submitted from an atomic context). | ||
153 | * | ||
154 | * FIXME: this needs to be layered up: a wusbhc layer (for sharing | ||
155 | * comonalities with WHCI), a wa layer (for sharing | ||
156 | * comonalities with DWA-RC). | ||
157 | */ | ||
158 | struct wahc { | ||
159 | struct usb_device *usb_dev; | ||
160 | struct usb_interface *usb_iface; | ||
161 | |||
162 | /* HC to deliver notifications */ | ||
163 | union { | ||
164 | struct wusbhc *wusb; | ||
165 | struct dwahc *dwa; | ||
166 | }; | ||
167 | |||
168 | const struct usb_endpoint_descriptor *dto_epd, *dti_epd; | ||
169 | const struct usb_wa_descriptor *wa_descr; | ||
170 | |||
171 | struct urb *nep_urb; /* Notification EndPoint [lockless] */ | ||
172 | struct edc nep_edc; | ||
173 | void *nep_buffer; | ||
174 | size_t nep_buffer_size; | ||
175 | |||
176 | atomic_t notifs_queued; | ||
177 | |||
178 | u16 rpipes; | ||
179 | unsigned long *rpipe_bm; /* rpipe usage bitmap */ | ||
180 | spinlock_t rpipe_bm_lock; /* protect rpipe_bm */ | ||
181 | struct mutex rpipe_mutex; /* assigning resources to endpoints */ | ||
182 | |||
183 | struct urb *dti_urb; /* URB for reading xfer results */ | ||
184 | struct urb *buf_in_urb; /* URB for reading data in */ | ||
185 | struct edc dti_edc; /* DTI error density counter */ | ||
186 | struct wa_xfer_result *xfer_result; /* real size = dti_ep maxpktsize */ | ||
187 | size_t xfer_result_size; | ||
188 | |||
189 | s32 status; /* For reading status */ | ||
190 | |||
191 | struct list_head xfer_list; | ||
192 | struct list_head xfer_delayed_list; | ||
193 | spinlock_t xfer_list_lock; | ||
194 | struct work_struct xfer_work; | ||
195 | atomic_t xfer_id_count; | ||
196 | }; | ||
197 | |||
198 | |||
199 | extern int wa_create(struct wahc *wa, struct usb_interface *iface); | ||
200 | extern void __wa_destroy(struct wahc *wa); | ||
201 | void wa_reset_all(struct wahc *wa); | ||
202 | |||
203 | |||
204 | /* Miscellaneous constants */ | ||
205 | enum { | ||
206 | /** Max number of EPROTO errors we tolerate on the NEP in a | ||
207 | * period of time */ | ||
208 | HWAHC_EPROTO_MAX = 16, | ||
209 | /** Period of time for EPROTO errors (in jiffies) */ | ||
210 | HWAHC_EPROTO_PERIOD = 4 * HZ, | ||
211 | }; | ||
212 | |||
213 | |||
214 | /* Notification endpoint handling */ | ||
215 | extern int wa_nep_create(struct wahc *, struct usb_interface *); | ||
216 | extern void wa_nep_destroy(struct wahc *); | ||
217 | |||
218 | static inline int wa_nep_arm(struct wahc *wa, gfp_t gfp_mask) | ||
219 | { | ||
220 | struct urb *urb = wa->nep_urb; | ||
221 | urb->transfer_buffer = wa->nep_buffer; | ||
222 | urb->transfer_buffer_length = wa->nep_buffer_size; | ||
223 | return usb_submit_urb(urb, gfp_mask); | ||
224 | } | ||
225 | |||
226 | static inline void wa_nep_disarm(struct wahc *wa) | ||
227 | { | ||
228 | usb_kill_urb(wa->nep_urb); | ||
229 | } | ||
230 | |||
231 | |||
232 | /* RPipes */ | ||
233 | static inline void wa_rpipe_init(struct wahc *wa) | ||
234 | { | ||
235 | spin_lock_init(&wa->rpipe_bm_lock); | ||
236 | mutex_init(&wa->rpipe_mutex); | ||
237 | } | ||
238 | |||
239 | static inline void wa_init(struct wahc *wa) | ||
240 | { | ||
241 | edc_init(&wa->nep_edc); | ||
242 | atomic_set(&wa->notifs_queued, 0); | ||
243 | wa_rpipe_init(wa); | ||
244 | edc_init(&wa->dti_edc); | ||
245 | INIT_LIST_HEAD(&wa->xfer_list); | ||
246 | INIT_LIST_HEAD(&wa->xfer_delayed_list); | ||
247 | spin_lock_init(&wa->xfer_list_lock); | ||
248 | INIT_WORK(&wa->xfer_work, wa_urb_enqueue_run); | ||
249 | atomic_set(&wa->xfer_id_count, 1); | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * Destroy a pipe (when refcount drops to zero) | ||
254 | * | ||
255 | * Assumes it has been moved to the "QUIESCING" state. | ||
256 | */ | ||
257 | struct wa_xfer; | ||
258 | extern void rpipe_destroy(struct kref *_rpipe); | ||
259 | static inline | ||
260 | void __rpipe_get(struct wa_rpipe *rpipe) | ||
261 | { | ||
262 | kref_get(&rpipe->refcnt); | ||
263 | } | ||
264 | extern int rpipe_get_by_ep(struct wahc *, struct usb_host_endpoint *, | ||
265 | struct urb *, gfp_t); | ||
266 | static inline void rpipe_put(struct wa_rpipe *rpipe) | ||
267 | { | ||
268 | kref_put(&rpipe->refcnt, rpipe_destroy); | ||
269 | |||
270 | } | ||
271 | extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *); | ||
272 | extern int wa_rpipes_create(struct wahc *); | ||
273 | extern void wa_rpipes_destroy(struct wahc *); | ||
274 | static inline void rpipe_avail_dec(struct wa_rpipe *rpipe) | ||
275 | { | ||
276 | atomic_dec(&rpipe->segs_available); | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * Returns true if the rpipe is ready to submit more segments. | ||
281 | */ | ||
282 | static inline int rpipe_avail_inc(struct wa_rpipe *rpipe) | ||
283 | { | ||
284 | return atomic_inc_return(&rpipe->segs_available) > 0 | ||
285 | && !list_empty(&rpipe->seg_list); | ||
286 | } | ||
287 | |||
288 | |||
289 | /* Transferring data */ | ||
290 | extern int wa_urb_enqueue(struct wahc *, struct usb_host_endpoint *, | ||
291 | struct urb *, gfp_t); | ||
292 | extern int wa_urb_dequeue(struct wahc *, struct urb *); | ||
293 | extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *); | ||
294 | |||
295 | |||
296 | /* Misc | ||
297 | * | ||
298 | * FIXME: Refcounting for the actual @hwahc object is not correct; I | ||
299 | * mean, this should be refcounting on the HCD underneath, but | ||
300 | * it is not. In any case, the semantics for HCD refcounting | ||
301 | * are *weird*...on refcount reaching zero it just frees | ||
302 | * it...no RC specific function is called...unless I miss | ||
303 | * something. | ||
304 | * | ||
305 | * FIXME: has to go away in favour of an 'struct' hcd based sollution | ||
306 | */ | ||
307 | static inline struct wahc *wa_get(struct wahc *wa) | ||
308 | { | ||
309 | usb_get_intf(wa->usb_iface); | ||
310 | return wa; | ||
311 | } | ||
312 | |||
313 | static inline void wa_put(struct wahc *wa) | ||
314 | { | ||
315 | usb_put_intf(wa->usb_iface); | ||
316 | } | ||
317 | |||
318 | |||
319 | static inline int __wa_feature(struct wahc *wa, unsigned op, u16 feature) | ||
320 | { | ||
321 | return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
322 | op ? USB_REQ_SET_FEATURE : USB_REQ_CLEAR_FEATURE, | ||
323 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
324 | feature, | ||
325 | wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
326 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
327 | } | ||
328 | |||
329 | |||
330 | static inline int __wa_set_feature(struct wahc *wa, u16 feature) | ||
331 | { | ||
332 | return __wa_feature(wa, 1, feature); | ||
333 | } | ||
334 | |||
335 | |||
336 | static inline int __wa_clear_feature(struct wahc *wa, u16 feature) | ||
337 | { | ||
338 | return __wa_feature(wa, 0, feature); | ||
339 | } | ||
340 | |||
341 | |||
342 | /** | ||
343 | * Return the status of a Wire Adapter | ||
344 | * | ||
345 | * @wa: Wire Adapter instance | ||
346 | * @returns < 0 errno code on error, or status bitmap as described | ||
347 | * in WUSB1.0[8.3.1.6]. | ||
348 | * | ||
349 | * NOTE: need malloc, some arches don't take USB from the stack | ||
350 | */ | ||
351 | static inline | ||
352 | s32 __wa_get_status(struct wahc *wa) | ||
353 | { | ||
354 | s32 result; | ||
355 | result = usb_control_msg( | ||
356 | wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), | ||
357 | USB_REQ_GET_STATUS, | ||
358 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
359 | 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
360 | &wa->status, sizeof(wa->status), | ||
361 | 1000 /* FIXME: arbitrary */); | ||
362 | if (result >= 0) | ||
363 | result = wa->status; | ||
364 | return result; | ||
365 | } | ||
366 | |||
367 | |||
368 | /** | ||
369 | * Waits until the Wire Adapter's status matches @mask/@value | ||
370 | * | ||
371 | * @wa: Wire Adapter instance. | ||
372 | * @returns < 0 errno code on error, otherwise status. | ||
373 | * | ||
374 | * Loop until the WAs status matches the mask and value (status & mask | ||
375 | * == value). Timeout if it doesn't happen. | ||
376 | * | ||
377 | * FIXME: is there an official specification on how long status | ||
378 | * changes can take? | ||
379 | */ | ||
380 | static inline s32 __wa_wait_status(struct wahc *wa, u32 mask, u32 value) | ||
381 | { | ||
382 | s32 result; | ||
383 | unsigned loops = 10; | ||
384 | do { | ||
385 | msleep(50); | ||
386 | result = __wa_get_status(wa); | ||
387 | if ((result & mask) == value) | ||
388 | break; | ||
389 | if (loops-- == 0) { | ||
390 | result = -ETIMEDOUT; | ||
391 | break; | ||
392 | } | ||
393 | } while (result >= 0); | ||
394 | return result; | ||
395 | } | ||
396 | |||
397 | |||
398 | /** Command @hwahc to stop, @returns 0 if ok, < 0 errno code on error */ | ||
399 | static inline int __wa_stop(struct wahc *wa) | ||
400 | { | ||
401 | int result; | ||
402 | struct device *dev = &wa->usb_iface->dev; | ||
403 | |||
404 | result = __wa_clear_feature(wa, WA_ENABLE); | ||
405 | if (result < 0 && result != -ENODEV) { | ||
406 | dev_err(dev, "error commanding HC to stop: %d\n", result); | ||
407 | goto out; | ||
408 | } | ||
409 | result = __wa_wait_status(wa, WA_ENABLE, 0); | ||
410 | if (result < 0 && result != -ENODEV) | ||
411 | dev_err(dev, "error waiting for HC to stop: %d\n", result); | ||
412 | out: | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | |||
417 | #endif /* #ifndef __HWAHC_INTERNAL_H__ */ | ||
diff --git a/drivers/usb/wusbcore/wa-nep.c b/drivers/usb/wusbcore/wa-nep.c new file mode 100644 index 000000000000..3f542990c73f --- /dev/null +++ b/drivers/usb/wusbcore/wa-nep.c | |||
@@ -0,0 +1,310 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8]) | ||
3 | * Notification EndPoint support | ||
4 | * | ||
5 | * Copyright (C) 2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * This part takes care of getting the notification from the hw | ||
24 | * only and dispatching through wusbwad into | ||
25 | * wa_notif_dispatch. Handling is done there. | ||
26 | * | ||
27 | * WA notifications are limited in size; most of them are three or | ||
28 | * four bytes long, and the longest is the HWA Device Notification, | ||
29 | * which would not exceed 38 bytes (DNs are limited in payload to 32 | ||
30 | * bytes plus 3 bytes header (WUSB1.0[7.6p2]), plus 3 bytes HWA | ||
31 | * header (WUSB1.0[8.5.4.2]). | ||
32 | * | ||
33 | * It is not clear if more than one Device Notification can be packed | ||
34 | * in a HWA Notification, I assume no because of the wording in | ||
35 | * WUSB1.0[8.5.4.2]. In any case, the bigger any notification could | ||
36 | * get is 256 bytes (as the bLength field is a byte). | ||
37 | * | ||
38 | * So what we do is we have this buffer and read into it; when a | ||
39 | * notification arrives we schedule work to a specific, single thread | ||
40 | * workqueue (so notifications are serialized) and copy the | ||
41 | * notification data. After scheduling the work, we rearm the read from | ||
42 | * the notification endpoint. | ||
43 | * | ||
44 | * Entry points here are: | ||
45 | * | ||
46 | * wa_nep_[create|destroy]() To initialize/release this subsystem | ||
47 | * | ||
48 | * wa_nep_cb() Callback for the notification | ||
49 | * endpoint; when data is ready, this | ||
50 | * does the dispatching. | ||
51 | */ | ||
52 | #include <linux/workqueue.h> | ||
53 | #include <linux/ctype.h> | ||
54 | #include <linux/uwb/debug.h> | ||
55 | #include "wa-hc.h" | ||
56 | #include "wusbhc.h" | ||
57 | |||
58 | /* Structure for queueing notifications to the workqueue */ | ||
59 | struct wa_notif_work { | ||
60 | struct work_struct work; | ||
61 | struct wahc *wa; | ||
62 | size_t size; | ||
63 | u8 data[]; | ||
64 | }; | ||
65 | |||
66 | /* | ||
67 | * Process incoming notifications from the WA's Notification EndPoint | ||
68 | * [the wuswad daemon, basically] | ||
69 | * | ||
70 | * @_nw: Pointer to a descriptor which has the pointer to the | ||
71 | * @wa, the size of the buffer and the work queue | ||
72 | * structure (so we can free all when done). | ||
73 | * @returns 0 if ok, < 0 errno code on error. | ||
74 | * | ||
75 | * All notifications follow the same format; they need to start with a | ||
76 | * 'struct wa_notif_hdr' header, so it is easy to parse through | ||
77 | * them. We just break the buffer in individual notifications (the | ||
78 | * standard doesn't say if it can be done or is forbidden, so we are | ||
79 | * cautious) and dispatch each. | ||
80 | * | ||
81 | * So the handling layers are is: | ||
82 | * | ||
83 | * WA specific notification (from NEP) | ||
84 | * Device Notification Received -> wa_handle_notif_dn() | ||
85 | * WUSB Device notification generic handling | ||
86 | * BPST Adjustment -> wa_handle_notif_bpst_adj() | ||
87 | * ... -> ... | ||
88 | * | ||
89 | * @wa has to be referenced | ||
90 | */ | ||
91 | static void wa_notif_dispatch(struct work_struct *ws) | ||
92 | { | ||
93 | void *itr; | ||
94 | u8 missing = 0; | ||
95 | struct wa_notif_work *nw = container_of(ws, struct wa_notif_work, work); | ||
96 | struct wahc *wa = nw->wa; | ||
97 | struct wa_notif_hdr *notif_hdr; | ||
98 | size_t size; | ||
99 | |||
100 | struct device *dev = &wa->usb_iface->dev; | ||
101 | |||
102 | #if 0 | ||
103 | /* FIXME: need to check for this??? */ | ||
104 | if (usb_hcd->state == HC_STATE_QUIESCING) /* Going down? */ | ||
105 | goto out; /* screw it */ | ||
106 | #endif | ||
107 | atomic_dec(&wa->notifs_queued); /* Throttling ctl */ | ||
108 | dev = &wa->usb_iface->dev; | ||
109 | size = nw->size; | ||
110 | itr = nw->data; | ||
111 | |||
112 | while (size) { | ||
113 | if (size < sizeof(*notif_hdr)) { | ||
114 | missing = sizeof(*notif_hdr) - size; | ||
115 | goto exhausted_buffer; | ||
116 | } | ||
117 | notif_hdr = itr; | ||
118 | if (size < notif_hdr->bLength) | ||
119 | goto exhausted_buffer; | ||
120 | itr += notif_hdr->bLength; | ||
121 | size -= notif_hdr->bLength; | ||
122 | /* Dispatch the notification [don't use itr or size!] */ | ||
123 | switch (notif_hdr->bNotifyType) { | ||
124 | case HWA_NOTIF_DN: { | ||
125 | struct hwa_notif_dn *hwa_dn; | ||
126 | hwa_dn = container_of(notif_hdr, struct hwa_notif_dn, | ||
127 | hdr); | ||
128 | wusbhc_handle_dn(wa->wusb, hwa_dn->bSourceDeviceAddr, | ||
129 | hwa_dn->dndata, | ||
130 | notif_hdr->bLength - sizeof(*hwa_dn)); | ||
131 | break; | ||
132 | } | ||
133 | case WA_NOTIF_TRANSFER: | ||
134 | wa_handle_notif_xfer(wa, notif_hdr); | ||
135 | break; | ||
136 | case DWA_NOTIF_RWAKE: | ||
137 | case DWA_NOTIF_PORTSTATUS: | ||
138 | case HWA_NOTIF_BPST_ADJ: | ||
139 | /* FIXME: unimplemented WA NOTIFs */ | ||
140 | /* fallthru */ | ||
141 | default: | ||
142 | if (printk_ratelimit()) { | ||
143 | dev_err(dev, "HWA: unknown notification 0x%x, " | ||
144 | "%zu bytes; discarding\n", | ||
145 | notif_hdr->bNotifyType, | ||
146 | (size_t)notif_hdr->bLength); | ||
147 | dump_bytes(dev, notif_hdr, 16); | ||
148 | } | ||
149 | break; | ||
150 | } | ||
151 | } | ||
152 | out: | ||
153 | wa_put(wa); | ||
154 | kfree(nw); | ||
155 | return; | ||
156 | |||
157 | /* THIS SHOULD NOT HAPPEN | ||
158 | * | ||
159 | * Buffer exahusted with partial data remaining; just warn and | ||
160 | * discard the data, as this should not happen. | ||
161 | */ | ||
162 | exhausted_buffer: | ||
163 | if (!printk_ratelimit()) | ||
164 | goto out; | ||
165 | dev_warn(dev, "HWA: device sent short notification, " | ||
166 | "%d bytes missing; discarding %d bytes.\n", | ||
167 | missing, (int)size); | ||
168 | dump_bytes(dev, itr, size); | ||
169 | goto out; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * Deliver incoming WA notifications to the wusbwa workqueue | ||
174 | * | ||
175 | * @wa: Pointer the Wire Adapter Controller Data Streaming | ||
176 | * instance (part of an 'struct usb_hcd'). | ||
177 | * @size: Size of the received buffer | ||
178 | * @returns 0 if ok, < 0 errno code on error. | ||
179 | * | ||
180 | * The input buffer is @wa->nep_buffer, with @size bytes | ||
181 | * (guaranteed to fit in the allocated space, | ||
182 | * @wa->nep_buffer_size). | ||
183 | */ | ||
184 | static int wa_nep_queue(struct wahc *wa, size_t size) | ||
185 | { | ||
186 | int result = 0; | ||
187 | struct device *dev = &wa->usb_iface->dev; | ||
188 | struct wa_notif_work *nw; | ||
189 | |||
190 | /* dev_fnstart(dev, "(wa %p, size %zu)\n", wa, size); */ | ||
191 | BUG_ON(size > wa->nep_buffer_size); | ||
192 | if (size == 0) | ||
193 | goto out; | ||
194 | if (atomic_read(&wa->notifs_queued) > 200) { | ||
195 | if (printk_ratelimit()) | ||
196 | dev_err(dev, "Too many notifications queued, " | ||
197 | "throttling back\n"); | ||
198 | goto out; | ||
199 | } | ||
200 | nw = kzalloc(sizeof(*nw) + size, GFP_ATOMIC); | ||
201 | if (nw == NULL) { | ||
202 | if (printk_ratelimit()) | ||
203 | dev_err(dev, "No memory to queue notification\n"); | ||
204 | goto out; | ||
205 | } | ||
206 | INIT_WORK(&nw->work, wa_notif_dispatch); | ||
207 | nw->wa = wa_get(wa); | ||
208 | nw->size = size; | ||
209 | memcpy(nw->data, wa->nep_buffer, size); | ||
210 | atomic_inc(&wa->notifs_queued); /* Throttling ctl */ | ||
211 | queue_work(wusbd, &nw->work); | ||
212 | out: | ||
213 | /* dev_fnend(dev, "(wa %p, size %zu) = result\n", wa, size, result); */ | ||
214 | return result; | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Callback for the notification event endpoint | ||
219 | * | ||
220 | * Check's that everything is fine and then passes the data to be | ||
221 | * queued to the workqueue. | ||
222 | */ | ||
223 | static void wa_nep_cb(struct urb *urb) | ||
224 | { | ||
225 | int result; | ||
226 | struct wahc *wa = urb->context; | ||
227 | struct device *dev = &wa->usb_iface->dev; | ||
228 | |||
229 | switch (result = urb->status) { | ||
230 | case 0: | ||
231 | result = wa_nep_queue(wa, urb->actual_length); | ||
232 | if (result < 0) | ||
233 | dev_err(dev, "NEP: unable to process notification(s): " | ||
234 | "%d\n", result); | ||
235 | break; | ||
236 | case -ECONNRESET: /* Not an error, but a controlled situation; */ | ||
237 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
238 | case -ESHUTDOWN: | ||
239 | dev_dbg(dev, "NEP: going down %d\n", urb->status); | ||
240 | goto out; | ||
241 | default: /* On general errors, we retry unless it gets ugly */ | ||
242 | if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, | ||
243 | EDC_ERROR_TIMEFRAME)) { | ||
244 | dev_err(dev, "NEP: URB max acceptable errors " | ||
245 | "exceeded, resetting device\n"); | ||
246 | wa_reset_all(wa); | ||
247 | goto out; | ||
248 | } | ||
249 | dev_err(dev, "NEP: URB error %d\n", urb->status); | ||
250 | } | ||
251 | result = wa_nep_arm(wa, GFP_ATOMIC); | ||
252 | if (result < 0) { | ||
253 | dev_err(dev, "NEP: cannot submit URB: %d\n", result); | ||
254 | wa_reset_all(wa); | ||
255 | } | ||
256 | out: | ||
257 | return; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * Initialize @wa's notification and event's endpoint stuff | ||
262 | * | ||
263 | * This includes the allocating the read buffer, the context ID | ||
264 | * allocation bitmap, the URB and submitting the URB. | ||
265 | */ | ||
266 | int wa_nep_create(struct wahc *wa, struct usb_interface *iface) | ||
267 | { | ||
268 | int result; | ||
269 | struct usb_endpoint_descriptor *epd; | ||
270 | struct usb_device *usb_dev = interface_to_usbdev(iface); | ||
271 | struct device *dev = &iface->dev; | ||
272 | |||
273 | edc_init(&wa->nep_edc); | ||
274 | epd = &iface->cur_altsetting->endpoint[0].desc; | ||
275 | wa->nep_buffer_size = 1024; | ||
276 | wa->nep_buffer = kmalloc(wa->nep_buffer_size, GFP_KERNEL); | ||
277 | if (wa->nep_buffer == NULL) { | ||
278 | dev_err(dev, "Unable to allocate notification's read buffer\n"); | ||
279 | goto error_nep_buffer; | ||
280 | } | ||
281 | wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
282 | if (wa->nep_urb == NULL) { | ||
283 | dev_err(dev, "Unable to allocate notification URB\n"); | ||
284 | goto error_urb_alloc; | ||
285 | } | ||
286 | usb_fill_int_urb(wa->nep_urb, usb_dev, | ||
287 | usb_rcvintpipe(usb_dev, epd->bEndpointAddress), | ||
288 | wa->nep_buffer, wa->nep_buffer_size, | ||
289 | wa_nep_cb, wa, epd->bInterval); | ||
290 | result = wa_nep_arm(wa, GFP_KERNEL); | ||
291 | if (result < 0) { | ||
292 | dev_err(dev, "Cannot submit notification URB: %d\n", result); | ||
293 | goto error_nep_arm; | ||
294 | } | ||
295 | return 0; | ||
296 | |||
297 | error_nep_arm: | ||
298 | usb_free_urb(wa->nep_urb); | ||
299 | error_urb_alloc: | ||
300 | kfree(wa->nep_buffer); | ||
301 | error_nep_buffer: | ||
302 | return -ENOMEM; | ||
303 | } | ||
304 | |||
305 | void wa_nep_destroy(struct wahc *wa) | ||
306 | { | ||
307 | wa_nep_disarm(wa); | ||
308 | usb_free_urb(wa->nep_urb); | ||
309 | kfree(wa->nep_buffer); | ||
310 | } | ||
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c new file mode 100644 index 000000000000..f18e4aae66e9 --- /dev/null +++ b/drivers/usb/wusbcore/wa-rpipe.c | |||
@@ -0,0 +1,562 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter | ||
3 | * rpipe management | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * | ||
25 | * RPIPE | ||
26 | * | ||
27 | * Targetted at different downstream endpoints | ||
28 | * | ||
29 | * Descriptor: use to config the remote pipe. | ||
30 | * | ||
31 | * The number of blocks could be dynamic (wBlocks in descriptor is | ||
32 | * 0)--need to schedule them then. | ||
33 | * | ||
34 | * Each bit in wa->rpipe_bm represents if an rpipe is being used or | ||
35 | * not. Rpipes are represented with a 'struct wa_rpipe' that is | ||
36 | * attached to the hcpriv member of a 'struct usb_host_endpoint'. | ||
37 | * | ||
38 | * When you need to xfer data to an endpoint, you get an rpipe for it | ||
39 | * with wa_ep_rpipe_get(), which gives you a reference to the rpipe | ||
40 | * and keeps a single one (the first one) with the endpoint. When you | ||
41 | * are done transferring, you drop that reference. At the end the | ||
42 | * rpipe is always allocated and bound to the endpoint. There it might | ||
43 | * be recycled when not used. | ||
44 | * | ||
45 | * Addresses: | ||
46 | * | ||
47 | * We use a 1:1 mapping mechanism between port address (0 based | ||
48 | * index, actually) and the address. The USB stack knows about this. | ||
49 | * | ||
50 | * USB Stack port number 4 (1 based) | ||
51 | * WUSB code port index 3 (0 based) | ||
52 | * USB Addresss 5 (2 based -- 0 is for default, 1 for root hub) | ||
53 | * | ||
54 | * Now, because we don't use the concept as default address exactly | ||
55 | * like the (wired) USB code does, we need to kind of skip it. So we | ||
56 | * never take addresses from the urb->pipe, but from the | ||
57 | * urb->dev->devnum, to make sure that we always have the right | ||
58 | * destination address. | ||
59 | */ | ||
60 | #include <linux/init.h> | ||
61 | #include <asm/atomic.h> | ||
62 | #include <linux/bitmap.h> | ||
63 | #include "wusbhc.h" | ||
64 | #include "wa-hc.h" | ||
65 | |||
66 | #define D_LOCAL 0 | ||
67 | #include <linux/uwb/debug.h> | ||
68 | |||
69 | |||
70 | static int __rpipe_get_descr(struct wahc *wa, | ||
71 | struct usb_rpipe_descriptor *descr, u16 index) | ||
72 | { | ||
73 | ssize_t result; | ||
74 | struct device *dev = &wa->usb_iface->dev; | ||
75 | |||
76 | /* Get the RPIPE descriptor -- we cannot use the usb_get_descriptor() | ||
77 | * function because the arguments are different. | ||
78 | */ | ||
79 | d_printf(1, dev, "rpipe %u: get descr\n", index); | ||
80 | result = usb_control_msg( | ||
81 | wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), | ||
82 | USB_REQ_GET_DESCRIPTOR, | ||
83 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_RPIPE, | ||
84 | USB_DT_RPIPE<<8, index, descr, sizeof(*descr), | ||
85 | 1000 /* FIXME: arbitrary */); | ||
86 | if (result < 0) { | ||
87 | dev_err(dev, "rpipe %u: get descriptor failed: %d\n", | ||
88 | index, (int)result); | ||
89 | goto error; | ||
90 | } | ||
91 | if (result < sizeof(*descr)) { | ||
92 | dev_err(dev, "rpipe %u: got short descriptor " | ||
93 | "(%zd vs %zd bytes needed)\n", | ||
94 | index, result, sizeof(*descr)); | ||
95 | result = -EINVAL; | ||
96 | goto error; | ||
97 | } | ||
98 | result = 0; | ||
99 | |||
100 | error: | ||
101 | return result; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * | ||
106 | * The descriptor is assumed to be properly initialized (ie: you got | ||
107 | * it through __rpipe_get_descr()). | ||
108 | */ | ||
109 | static int __rpipe_set_descr(struct wahc *wa, | ||
110 | struct usb_rpipe_descriptor *descr, u16 index) | ||
111 | { | ||
112 | ssize_t result; | ||
113 | struct device *dev = &wa->usb_iface->dev; | ||
114 | |||
115 | /* we cannot use the usb_get_descriptor() function because the | ||
116 | * arguments are different. | ||
117 | */ | ||
118 | d_printf(1, dev, "rpipe %u: set descr\n", index); | ||
119 | result = usb_control_msg( | ||
120 | wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
121 | USB_REQ_SET_DESCRIPTOR, | ||
122 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, | ||
123 | USB_DT_RPIPE<<8, index, descr, sizeof(*descr), | ||
124 | HZ / 10); | ||
125 | if (result < 0) { | ||
126 | dev_err(dev, "rpipe %u: set descriptor failed: %d\n", | ||
127 | index, (int)result); | ||
128 | goto error; | ||
129 | } | ||
130 | if (result < sizeof(*descr)) { | ||
131 | dev_err(dev, "rpipe %u: sent short descriptor " | ||
132 | "(%zd vs %zd bytes required)\n", | ||
133 | index, result, sizeof(*descr)); | ||
134 | result = -EINVAL; | ||
135 | goto error; | ||
136 | } | ||
137 | result = 0; | ||
138 | |||
139 | error: | ||
140 | return result; | ||
141 | |||
142 | } | ||
143 | |||
144 | static void rpipe_init(struct wa_rpipe *rpipe) | ||
145 | { | ||
146 | kref_init(&rpipe->refcnt); | ||
147 | spin_lock_init(&rpipe->seg_lock); | ||
148 | INIT_LIST_HEAD(&rpipe->seg_list); | ||
149 | } | ||
150 | |||
151 | static unsigned rpipe_get_idx(struct wahc *wa, unsigned rpipe_idx) | ||
152 | { | ||
153 | unsigned long flags; | ||
154 | |||
155 | spin_lock_irqsave(&wa->rpipe_bm_lock, flags); | ||
156 | rpipe_idx = find_next_zero_bit(wa->rpipe_bm, wa->rpipes, rpipe_idx); | ||
157 | if (rpipe_idx < wa->rpipes) | ||
158 | set_bit(rpipe_idx, wa->rpipe_bm); | ||
159 | spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags); | ||
160 | |||
161 | return rpipe_idx; | ||
162 | } | ||
163 | |||
164 | static void rpipe_put_idx(struct wahc *wa, unsigned rpipe_idx) | ||
165 | { | ||
166 | unsigned long flags; | ||
167 | |||
168 | spin_lock_irqsave(&wa->rpipe_bm_lock, flags); | ||
169 | clear_bit(rpipe_idx, wa->rpipe_bm); | ||
170 | spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags); | ||
171 | } | ||
172 | |||
173 | void rpipe_destroy(struct kref *_rpipe) | ||
174 | { | ||
175 | struct wa_rpipe *rpipe = container_of(_rpipe, struct wa_rpipe, refcnt); | ||
176 | u8 index = le16_to_cpu(rpipe->descr.wRPipeIndex); | ||
177 | d_fnstart(1, NULL, "(rpipe %p %u)\n", rpipe, index); | ||
178 | if (rpipe->ep) | ||
179 | rpipe->ep->hcpriv = NULL; | ||
180 | rpipe_put_idx(rpipe->wa, index); | ||
181 | wa_put(rpipe->wa); | ||
182 | kfree(rpipe); | ||
183 | d_fnend(1, NULL, "(rpipe %p %u)\n", rpipe, index); | ||
184 | } | ||
185 | EXPORT_SYMBOL_GPL(rpipe_destroy); | ||
186 | |||
187 | /* | ||
188 | * Locate an idle rpipe, create an structure for it and return it | ||
189 | * | ||
190 | * @wa is referenced and unlocked | ||
191 | * @crs enum rpipe_attr, required endpoint characteristics | ||
192 | * | ||
193 | * The rpipe can be used only sequentially (not in parallel). | ||
194 | * | ||
195 | * The rpipe is moved into the "ready" state. | ||
196 | */ | ||
197 | static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs, | ||
198 | gfp_t gfp) | ||
199 | { | ||
200 | int result; | ||
201 | unsigned rpipe_idx; | ||
202 | struct wa_rpipe *rpipe; | ||
203 | struct device *dev = &wa->usb_iface->dev; | ||
204 | |||
205 | d_fnstart(3, dev, "(wa %p crs 0x%02x)\n", wa, crs); | ||
206 | rpipe = kzalloc(sizeof(*rpipe), gfp); | ||
207 | if (rpipe == NULL) | ||
208 | return -ENOMEM; | ||
209 | rpipe_init(rpipe); | ||
210 | |||
211 | /* Look for an idle pipe */ | ||
212 | for (rpipe_idx = 0; rpipe_idx < wa->rpipes; rpipe_idx++) { | ||
213 | rpipe_idx = rpipe_get_idx(wa, rpipe_idx); | ||
214 | if (rpipe_idx >= wa->rpipes) /* no more pipes :( */ | ||
215 | break; | ||
216 | result = __rpipe_get_descr(wa, &rpipe->descr, rpipe_idx); | ||
217 | if (result < 0) | ||
218 | dev_err(dev, "Can't get descriptor for rpipe %u: %d\n", | ||
219 | rpipe_idx, result); | ||
220 | else if ((rpipe->descr.bmCharacteristics & crs) != 0) | ||
221 | goto found; | ||
222 | rpipe_put_idx(wa, rpipe_idx); | ||
223 | } | ||
224 | *prpipe = NULL; | ||
225 | kfree(rpipe); | ||
226 | d_fnend(3, dev, "(wa %p crs 0x%02x) = -ENXIO\n", wa, crs); | ||
227 | return -ENXIO; | ||
228 | |||
229 | found: | ||
230 | set_bit(rpipe_idx, wa->rpipe_bm); | ||
231 | rpipe->wa = wa_get(wa); | ||
232 | *prpipe = rpipe; | ||
233 | d_fnstart(3, dev, "(wa %p crs 0x%02x) = 0\n", wa, crs); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int __rpipe_reset(struct wahc *wa, unsigned index) | ||
238 | { | ||
239 | int result; | ||
240 | struct device *dev = &wa->usb_iface->dev; | ||
241 | |||
242 | d_printf(1, dev, "rpipe %u: reset\n", index); | ||
243 | result = usb_control_msg( | ||
244 | wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
245 | USB_REQ_RPIPE_RESET, | ||
246 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, | ||
247 | 0, index, NULL, 0, 1000 /* FIXME: arbitrary */); | ||
248 | if (result < 0) | ||
249 | dev_err(dev, "rpipe %u: reset failed: %d\n", | ||
250 | index, result); | ||
251 | return result; | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Fake companion descriptor for ep0 | ||
256 | * | ||
257 | * See WUSB1.0[7.4.4], most of this is zero for bulk/int/ctl | ||
258 | */ | ||
259 | static struct usb_wireless_ep_comp_descriptor epc0 = { | ||
260 | .bLength = sizeof(epc0), | ||
261 | .bDescriptorType = USB_DT_WIRELESS_ENDPOINT_COMP, | ||
262 | /* .bMaxBurst = 1, */ | ||
263 | .bMaxSequence = 31, | ||
264 | }; | ||
265 | |||
266 | /* | ||
267 | * Look for EP companion descriptor | ||
268 | * | ||
269 | * Get there, look for Inara in the endpoint's extra descriptors | ||
270 | */ | ||
271 | static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find( | ||
272 | struct device *dev, struct usb_host_endpoint *ep) | ||
273 | { | ||
274 | void *itr; | ||
275 | size_t itr_size; | ||
276 | struct usb_descriptor_header *hdr; | ||
277 | struct usb_wireless_ep_comp_descriptor *epcd; | ||
278 | |||
279 | d_fnstart(3, dev, "(ep %p)\n", ep); | ||
280 | if (ep->desc.bEndpointAddress == 0) { | ||
281 | epcd = &epc0; | ||
282 | goto out; | ||
283 | } | ||
284 | itr = ep->extra; | ||
285 | itr_size = ep->extralen; | ||
286 | epcd = NULL; | ||
287 | while (itr_size > 0) { | ||
288 | if (itr_size < sizeof(*hdr)) { | ||
289 | dev_err(dev, "HW Bug? ep 0x%02x: extra descriptors " | ||
290 | "at offset %zu: only %zu bytes left\n", | ||
291 | ep->desc.bEndpointAddress, | ||
292 | itr - (void *) ep->extra, itr_size); | ||
293 | break; | ||
294 | } | ||
295 | hdr = itr; | ||
296 | if (hdr->bDescriptorType == USB_DT_WIRELESS_ENDPOINT_COMP) { | ||
297 | epcd = itr; | ||
298 | break; | ||
299 | } | ||
300 | if (hdr->bLength > itr_size) { | ||
301 | dev_err(dev, "HW Bug? ep 0x%02x: extra descriptor " | ||
302 | "at offset %zu (type 0x%02x) " | ||
303 | "length %d but only %zu bytes left\n", | ||
304 | ep->desc.bEndpointAddress, | ||
305 | itr - (void *) ep->extra, hdr->bDescriptorType, | ||
306 | hdr->bLength, itr_size); | ||
307 | break; | ||
308 | } | ||
309 | itr += hdr->bLength; | ||
310 | itr_size -= hdr->bDescriptorType; | ||
311 | } | ||
312 | out: | ||
313 | d_fnend(3, dev, "(ep %p) = %p\n", ep, epcd); | ||
314 | return epcd; | ||
315 | } | ||
316 | |||
317 | /* | ||
318 | * Aim an rpipe to its device & endpoint destination | ||
319 | * | ||
320 | * Make sure we change the address to unauthenticathed if the device | ||
321 | * is WUSB and it is not authenticated. | ||
322 | */ | ||
323 | static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa, | ||
324 | struct usb_host_endpoint *ep, struct urb *urb, gfp_t gfp) | ||
325 | { | ||
326 | int result = -ENOMSG; /* better code for lack of companion? */ | ||
327 | struct device *dev = &wa->usb_iface->dev; | ||
328 | struct usb_device *usb_dev = urb->dev; | ||
329 | struct usb_wireless_ep_comp_descriptor *epcd; | ||
330 | u8 unauth; | ||
331 | |||
332 | d_fnstart(3, dev, "(rpipe %p wa %p ep %p, urb %p)\n", | ||
333 | rpipe, wa, ep, urb); | ||
334 | epcd = rpipe_epc_find(dev, ep); | ||
335 | if (epcd == NULL) { | ||
336 | dev_err(dev, "ep 0x%02x: can't find companion descriptor\n", | ||
337 | ep->desc.bEndpointAddress); | ||
338 | goto error; | ||
339 | } | ||
340 | unauth = usb_dev->wusb && !usb_dev->authenticated ? 0x80 : 0; | ||
341 | __rpipe_reset(wa, le16_to_cpu(rpipe->descr.wRPipeIndex)); | ||
342 | atomic_set(&rpipe->segs_available, le16_to_cpu(rpipe->descr.wRequests)); | ||
343 | /* FIXME: block allocation system; request with queuing and timeout */ | ||
344 | /* FIXME: compute so seg_size > ep->maxpktsize */ | ||
345 | rpipe->descr.wBlocks = cpu_to_le16(16); /* given */ | ||
346 | /* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */ | ||
347 | rpipe->descr.wMaxPacketSize = cpu_to_le16(ep->desc.wMaxPacketSize); | ||
348 | rpipe->descr.bHSHubAddress = 0; /* reserved: zero */ | ||
349 | rpipe->descr.bHSHubPort = wusb_port_no_to_idx(urb->dev->portnum); | ||
350 | /* FIXME: use maximum speed as supported or recommended by device */ | ||
351 | rpipe->descr.bSpeed = usb_pipeendpoint(urb->pipe) == 0 ? | ||
352 | UWB_PHY_RATE_53 : UWB_PHY_RATE_200; | ||
353 | d_printf(2, dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n", | ||
354 | urb->dev->devnum, urb->dev->devnum | unauth, | ||
355 | le16_to_cpu(rpipe->descr.wRPipeIndex), | ||
356 | usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed); | ||
357 | /* see security.c:wusb_update_address() */ | ||
358 | if (unlikely(urb->dev->devnum == 0x80)) | ||
359 | rpipe->descr.bDeviceAddress = 0; | ||
360 | else | ||
361 | rpipe->descr.bDeviceAddress = urb->dev->devnum | unauth; | ||
362 | rpipe->descr.bEndpointAddress = ep->desc.bEndpointAddress; | ||
363 | /* FIXME: bDataSequence */ | ||
364 | rpipe->descr.bDataSequence = 0; | ||
365 | /* FIXME: dwCurrentWindow */ | ||
366 | rpipe->descr.dwCurrentWindow = cpu_to_le32(1); | ||
367 | /* FIXME: bMaxDataSequence */ | ||
368 | rpipe->descr.bMaxDataSequence = epcd->bMaxSequence - 1; | ||
369 | rpipe->descr.bInterval = ep->desc.bInterval; | ||
370 | /* FIXME: bOverTheAirInterval */ | ||
371 | rpipe->descr.bOverTheAirInterval = 0; /* 0 if not isoc */ | ||
372 | /* FIXME: xmit power & preamble blah blah */ | ||
373 | rpipe->descr.bmAttribute = ep->desc.bmAttributes & 0x03; | ||
374 | /* rpipe->descr.bmCharacteristics RO */ | ||
375 | /* FIXME: bmRetryOptions */ | ||
376 | rpipe->descr.bmRetryOptions = 15; | ||
377 | /* FIXME: use for assessing link quality? */ | ||
378 | rpipe->descr.wNumTransactionErrors = 0; | ||
379 | result = __rpipe_set_descr(wa, &rpipe->descr, | ||
380 | le16_to_cpu(rpipe->descr.wRPipeIndex)); | ||
381 | if (result < 0) { | ||
382 | dev_err(dev, "Cannot aim rpipe: %d\n", result); | ||
383 | goto error; | ||
384 | } | ||
385 | result = 0; | ||
386 | error: | ||
387 | d_fnend(3, dev, "(rpipe %p wa %p ep %p urb %p) = %d\n", | ||
388 | rpipe, wa, ep, urb, result); | ||
389 | return result; | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * Check an aimed rpipe to make sure it points to where we want | ||
394 | * | ||
395 | * We use bit 19 of the Linux USB pipe bitmap for unauth vs auth | ||
396 | * space; when it is like that, we or 0x80 to make an unauth address. | ||
397 | */ | ||
398 | static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa, | ||
399 | const struct usb_host_endpoint *ep, | ||
400 | const struct urb *urb, gfp_t gfp) | ||
401 | { | ||
402 | int result = 0; /* better code for lack of companion? */ | ||
403 | struct device *dev = &wa->usb_iface->dev; | ||
404 | struct usb_device *usb_dev = urb->dev; | ||
405 | u8 unauth = (usb_dev->wusb && !usb_dev->authenticated) ? 0x80 : 0; | ||
406 | u8 portnum = wusb_port_no_to_idx(urb->dev->portnum); | ||
407 | |||
408 | d_fnstart(3, dev, "(rpipe %p wa %p ep %p, urb %p)\n", | ||
409 | rpipe, wa, ep, urb); | ||
410 | #define AIM_CHECK(rdf, val, text) \ | ||
411 | do { \ | ||
412 | if (rpipe->descr.rdf != (val)) { \ | ||
413 | dev_err(dev, \ | ||
414 | "rpipe aim discrepancy: " #rdf " " text "\n", \ | ||
415 | rpipe->descr.rdf, (val)); \ | ||
416 | result = -EINVAL; \ | ||
417 | WARN_ON(1); \ | ||
418 | } \ | ||
419 | } while (0) | ||
420 | AIM_CHECK(wMaxPacketSize, cpu_to_le16(ep->desc.wMaxPacketSize), | ||
421 | "(%u vs %u)"); | ||
422 | AIM_CHECK(bHSHubPort, portnum, "(%u vs %u)"); | ||
423 | AIM_CHECK(bSpeed, usb_pipeendpoint(urb->pipe) == 0 ? | ||
424 | UWB_PHY_RATE_53 : UWB_PHY_RATE_200, | ||
425 | "(%u vs %u)"); | ||
426 | AIM_CHECK(bDeviceAddress, urb->dev->devnum | unauth, "(%u vs %u)"); | ||
427 | AIM_CHECK(bEndpointAddress, ep->desc.bEndpointAddress, "(%u vs %u)"); | ||
428 | AIM_CHECK(bInterval, ep->desc.bInterval, "(%u vs %u)"); | ||
429 | AIM_CHECK(bmAttribute, ep->desc.bmAttributes & 0x03, "(%u vs %u)"); | ||
430 | #undef AIM_CHECK | ||
431 | return result; | ||
432 | } | ||
433 | |||
434 | #ifndef CONFIG_BUG | ||
435 | #define CONFIG_BUG 0 | ||
436 | #endif | ||
437 | |||
438 | /* | ||
439 | * Make sure there is an rpipe allocated for an endpoint | ||
440 | * | ||
441 | * If already allocated, we just refcount it; if not, we get an | ||
442 | * idle one, aim it to the right location and take it. | ||
443 | * | ||
444 | * Attaches to ep->hcpriv and rpipe->ep to ep. | ||
445 | */ | ||
446 | int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep, | ||
447 | struct urb *urb, gfp_t gfp) | ||
448 | { | ||
449 | int result = 0; | ||
450 | struct device *dev = &wa->usb_iface->dev; | ||
451 | struct wa_rpipe *rpipe; | ||
452 | u8 eptype; | ||
453 | |||
454 | d_fnstart(3, dev, "(wa %p ep %p urb %p gfp 0x%08x)\n", wa, ep, urb, | ||
455 | gfp); | ||
456 | mutex_lock(&wa->rpipe_mutex); | ||
457 | rpipe = ep->hcpriv; | ||
458 | if (rpipe != NULL) { | ||
459 | if (CONFIG_BUG == 1) { | ||
460 | result = rpipe_check_aim(rpipe, wa, ep, urb, gfp); | ||
461 | if (result < 0) | ||
462 | goto error; | ||
463 | } | ||
464 | __rpipe_get(rpipe); | ||
465 | d_printf(2, dev, "ep 0x%02x: reusing rpipe %u\n", | ||
466 | ep->desc.bEndpointAddress, | ||
467 | le16_to_cpu(rpipe->descr.wRPipeIndex)); | ||
468 | } else { | ||
469 | /* hmm, assign idle rpipe, aim it */ | ||
470 | result = -ENOBUFS; | ||
471 | eptype = ep->desc.bmAttributes & 0x03; | ||
472 | result = rpipe_get_idle(&rpipe, wa, 1 << eptype, gfp); | ||
473 | if (result < 0) | ||
474 | goto error; | ||
475 | result = rpipe_aim(rpipe, wa, ep, urb, gfp); | ||
476 | if (result < 0) { | ||
477 | rpipe_put(rpipe); | ||
478 | goto error; | ||
479 | } | ||
480 | ep->hcpriv = rpipe; | ||
481 | rpipe->ep = ep; | ||
482 | __rpipe_get(rpipe); /* for caching into ep->hcpriv */ | ||
483 | d_printf(2, dev, "ep 0x%02x: using rpipe %u\n", | ||
484 | ep->desc.bEndpointAddress, | ||
485 | le16_to_cpu(rpipe->descr.wRPipeIndex)); | ||
486 | } | ||
487 | d_dump(4, dev, &rpipe->descr, sizeof(rpipe->descr)); | ||
488 | error: | ||
489 | mutex_unlock(&wa->rpipe_mutex); | ||
490 | d_fnend(3, dev, "(wa %p ep %p urb %p gfp 0x%08x)\n", wa, ep, urb, gfp); | ||
491 | return result; | ||
492 | } | ||
493 | |||
494 | /* | ||
495 | * Allocate the bitmap for each rpipe. | ||
496 | */ | ||
497 | int wa_rpipes_create(struct wahc *wa) | ||
498 | { | ||
499 | wa->rpipes = wa->wa_descr->wNumRPipes; | ||
500 | wa->rpipe_bm = kzalloc(BITS_TO_LONGS(wa->rpipes)*sizeof(unsigned long), | ||
501 | GFP_KERNEL); | ||
502 | if (wa->rpipe_bm == NULL) | ||
503 | return -ENOMEM; | ||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | void wa_rpipes_destroy(struct wahc *wa) | ||
508 | { | ||
509 | struct device *dev = &wa->usb_iface->dev; | ||
510 | d_fnstart(3, dev, "(wa %p)\n", wa); | ||
511 | if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) { | ||
512 | char buf[256]; | ||
513 | WARN_ON(1); | ||
514 | bitmap_scnprintf(buf, sizeof(buf), wa->rpipe_bm, wa->rpipes); | ||
515 | dev_err(dev, "BUG: pipes not released on exit: %s\n", buf); | ||
516 | } | ||
517 | kfree(wa->rpipe_bm); | ||
518 | d_fnend(3, dev, "(wa %p)\n", wa); | ||
519 | } | ||
520 | |||
521 | /* | ||
522 | * Release resources allocated for an endpoint | ||
523 | * | ||
524 | * If there is an associated rpipe to this endpoint, Abort any pending | ||
525 | * transfers and put it. If the rpipe ends up being destroyed, | ||
526 | * __rpipe_destroy() will cleanup ep->hcpriv. | ||
527 | * | ||
528 | * This is called before calling hcd->stop(), so you don't need to do | ||
529 | * anything else in there. | ||
530 | */ | ||
531 | void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep) | ||
532 | { | ||
533 | struct device *dev = &wa->usb_iface->dev; | ||
534 | struct wa_rpipe *rpipe; | ||
535 | d_fnstart(2, dev, "(wa %p ep %p)\n", wa, ep); | ||
536 | mutex_lock(&wa->rpipe_mutex); | ||
537 | rpipe = ep->hcpriv; | ||
538 | if (rpipe != NULL) { | ||
539 | unsigned rc = atomic_read(&rpipe->refcnt.refcount); | ||
540 | int result; | ||
541 | u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex); | ||
542 | |||
543 | if (rc != 1) | ||
544 | d_printf(1, dev, "(wa %p ep %p) rpipe %p refcnt %u\n", | ||
545 | wa, ep, rpipe, rc); | ||
546 | |||
547 | d_printf(1, dev, "rpipe %u: abort\n", index); | ||
548 | result = usb_control_msg( | ||
549 | wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), | ||
550 | USB_REQ_RPIPE_ABORT, | ||
551 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, | ||
552 | 0, index, NULL, 0, 1000 /* FIXME: arbitrary */); | ||
553 | if (result < 0 && result != -ENODEV /* dev is gone */) | ||
554 | d_printf(1, dev, "(wa %p rpipe %u): abort failed: %d\n", | ||
555 | wa, index, result); | ||
556 | rpipe_put(rpipe); | ||
557 | } | ||
558 | mutex_unlock(&wa->rpipe_mutex); | ||
559 | d_fnend(2, dev, "(wa %p ep %p)\n", wa, ep); | ||
560 | return; | ||
561 | } | ||
562 | EXPORT_SYMBOL_GPL(rpipe_ep_disable); | ||
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c new file mode 100644 index 000000000000..7d192f3e6742 --- /dev/null +++ b/drivers/usb/wusbcore/wa-xfer.c | |||
@@ -0,0 +1,1709 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter | ||
3 | * Data transfer and URB enqueing | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * How transfers work: get a buffer, break it up in segments (segment | ||
24 | * size is a multiple of the maxpacket size). For each segment issue a | ||
25 | * segment request (struct wa_xfer_*), then send the data buffer if | ||
26 | * out or nothing if in (all over the DTO endpoint). | ||
27 | * | ||
28 | * For each submitted segment request, a notification will come over | ||
29 | * the NEP endpoint and a transfer result (struct xfer_result) will | ||
30 | * arrive in the DTI URB. Read it, get the xfer ID, see if there is | ||
31 | * data coming (inbound transfer), schedule a read and handle it. | ||
32 | * | ||
33 | * Sounds simple, it is a pain to implement. | ||
34 | * | ||
35 | * | ||
36 | * ENTRY POINTS | ||
37 | * | ||
38 | * FIXME | ||
39 | * | ||
40 | * LIFE CYCLE / STATE DIAGRAM | ||
41 | * | ||
42 | * FIXME | ||
43 | * | ||
44 | * THIS CODE IS DISGUSTING | ||
45 | * | ||
46 | * Warned you are; it's my second try and still not happy with it. | ||
47 | * | ||
48 | * NOTES: | ||
49 | * | ||
50 | * - No iso | ||
51 | * | ||
52 | * - Supports DMA xfers, control, bulk and maybe interrupt | ||
53 | * | ||
54 | * - Does not recycle unused rpipes | ||
55 | * | ||
56 | * An rpipe is assigned to an endpoint the first time it is used, | ||
57 | * and then it's there, assigned, until the endpoint is disabled | ||
58 | * (destroyed [{h,d}wahc_op_ep_disable()]. The assignment of the | ||
59 | * rpipe to the endpoint is done under the wa->rpipe_sem semaphore | ||
60 | * (should be a mutex). | ||
61 | * | ||
62 | * Two methods it could be done: | ||
63 | * | ||
64 | * (a) set up a timer everytime an rpipe's use count drops to 1 | ||
65 | * (which means unused) or when a transfer ends. Reset the | ||
66 | * timer when a xfer is queued. If the timer expires, release | ||
67 | * the rpipe [see rpipe_ep_disable()]. | ||
68 | * | ||
69 | * (b) when looking for free rpipes to attach [rpipe_get_by_ep()], | ||
70 | * when none are found go over the list, check their endpoint | ||
71 | * and their activity record (if no last-xfer-done-ts in the | ||
72 | * last x seconds) take it | ||
73 | * | ||
74 | * However, due to the fact that we have a set of limited | ||
75 | * resources (max-segments-at-the-same-time per xfer, | ||
76 | * xfers-per-ripe, blocks-per-rpipe, rpipes-per-host), at the end | ||
77 | * we are going to have to rebuild all this based on an scheduler, | ||
78 | * to where we have a list of transactions to do and based on the | ||
79 | * availability of the different requried components (blocks, | ||
80 | * rpipes, segment slots, etc), we go scheduling them. Painful. | ||
81 | */ | ||
82 | #include <linux/init.h> | ||
83 | #include <linux/spinlock.h> | ||
84 | #include <linux/hash.h> | ||
85 | #include "wa-hc.h" | ||
86 | #include "wusbhc.h" | ||
87 | |||
88 | #undef D_LOCAL | ||
89 | #define D_LOCAL 0 /* 0 disabled, > 0 different levels... */ | ||
90 | #include <linux/uwb/debug.h> | ||
91 | |||
92 | enum { | ||
93 | WA_SEGS_MAX = 255, | ||
94 | }; | ||
95 | |||
96 | enum wa_seg_status { | ||
97 | WA_SEG_NOTREADY, | ||
98 | WA_SEG_READY, | ||
99 | WA_SEG_DELAYED, | ||
100 | WA_SEG_SUBMITTED, | ||
101 | WA_SEG_PENDING, | ||
102 | WA_SEG_DTI_PENDING, | ||
103 | WA_SEG_DONE, | ||
104 | WA_SEG_ERROR, | ||
105 | WA_SEG_ABORTED, | ||
106 | }; | ||
107 | |||
108 | static void wa_xfer_delayed_run(struct wa_rpipe *); | ||
109 | |||
110 | /* | ||
111 | * Life cycle governed by 'struct urb' (the refcount of the struct is | ||
112 | * that of the 'struct urb' and usb_free_urb() would free the whole | ||
113 | * struct). | ||
114 | */ | ||
115 | struct wa_seg { | ||
116 | struct urb urb; | ||
117 | struct urb *dto_urb; /* for data output? */ | ||
118 | struct list_head list_node; /* for rpipe->req_list */ | ||
119 | struct wa_xfer *xfer; /* out xfer */ | ||
120 | u8 index; /* which segment we are */ | ||
121 | enum wa_seg_status status; | ||
122 | ssize_t result; /* bytes xfered or error */ | ||
123 | struct wa_xfer_hdr xfer_hdr; | ||
124 | u8 xfer_extra[]; /* xtra space for xfer_hdr_ctl */ | ||
125 | }; | ||
126 | |||
127 | static void wa_seg_init(struct wa_seg *seg) | ||
128 | { | ||
129 | /* usb_init_urb() repeats a lot of work, so we do it here */ | ||
130 | kref_init(&seg->urb.kref); | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * Protected by xfer->lock | ||
135 | * | ||
136 | */ | ||
137 | struct wa_xfer { | ||
138 | struct kref refcnt; | ||
139 | struct list_head list_node; | ||
140 | spinlock_t lock; | ||
141 | u32 id; | ||
142 | |||
143 | struct wahc *wa; /* Wire adapter we are plugged to */ | ||
144 | struct usb_host_endpoint *ep; | ||
145 | struct urb *urb; /* URB we are transfering for */ | ||
146 | struct wa_seg **seg; /* transfer segments */ | ||
147 | u8 segs, segs_submitted, segs_done; | ||
148 | unsigned is_inbound:1; | ||
149 | unsigned is_dma:1; | ||
150 | size_t seg_size; | ||
151 | int result; | ||
152 | |||
153 | gfp_t gfp; /* allocation mask */ | ||
154 | |||
155 | struct wusb_dev *wusb_dev; /* for activity timestamps */ | ||
156 | }; | ||
157 | |||
158 | static inline void wa_xfer_init(struct wa_xfer *xfer) | ||
159 | { | ||
160 | kref_init(&xfer->refcnt); | ||
161 | INIT_LIST_HEAD(&xfer->list_node); | ||
162 | spin_lock_init(&xfer->lock); | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * Destory a transfer structure | ||
167 | * | ||
168 | * Note that the xfer->seg[index] thingies follow the URB life cycle, | ||
169 | * so we need to put them, not free them. | ||
170 | */ | ||
171 | static void wa_xfer_destroy(struct kref *_xfer) | ||
172 | { | ||
173 | struct wa_xfer *xfer = container_of(_xfer, struct wa_xfer, refcnt); | ||
174 | if (xfer->seg) { | ||
175 | unsigned cnt; | ||
176 | for (cnt = 0; cnt < xfer->segs; cnt++) { | ||
177 | if (xfer->is_inbound) | ||
178 | usb_put_urb(xfer->seg[cnt]->dto_urb); | ||
179 | usb_put_urb(&xfer->seg[cnt]->urb); | ||
180 | } | ||
181 | } | ||
182 | kfree(xfer); | ||
183 | d_printf(2, NULL, "xfer %p destroyed\n", xfer); | ||
184 | } | ||
185 | |||
186 | static void wa_xfer_get(struct wa_xfer *xfer) | ||
187 | { | ||
188 | kref_get(&xfer->refcnt); | ||
189 | } | ||
190 | |||
191 | static void wa_xfer_put(struct wa_xfer *xfer) | ||
192 | { | ||
193 | d_fnstart(3, NULL, "(xfer %p) -- ref count bef put %d\n", | ||
194 | xfer, atomic_read(&xfer->refcnt.refcount)); | ||
195 | kref_put(&xfer->refcnt, wa_xfer_destroy); | ||
196 | d_fnend(3, NULL, "(xfer %p) = void\n", xfer); | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * xfer is referenced | ||
201 | * | ||
202 | * xfer->lock has to be unlocked | ||
203 | * | ||
204 | * We take xfer->lock for setting the result; this is a barrier | ||
205 | * against drivers/usb/core/hcd.c:unlink1() being called after we call | ||
206 | * usb_hcd_giveback_urb() and wa_urb_dequeue() trying to get a | ||
207 | * reference to the transfer. | ||
208 | */ | ||
209 | static void wa_xfer_giveback(struct wa_xfer *xfer) | ||
210 | { | ||
211 | unsigned long flags; | ||
212 | d_fnstart(3, NULL, "(xfer %p)\n", xfer); | ||
213 | spin_lock_irqsave(&xfer->wa->xfer_list_lock, flags); | ||
214 | list_del_init(&xfer->list_node); | ||
215 | spin_unlock_irqrestore(&xfer->wa->xfer_list_lock, flags); | ||
216 | /* FIXME: segmentation broken -- kills DWA */ | ||
217 | wusbhc_giveback_urb(xfer->wa->wusb, xfer->urb, xfer->result); | ||
218 | wa_put(xfer->wa); | ||
219 | wa_xfer_put(xfer); | ||
220 | d_fnend(3, NULL, "(xfer %p) = void\n", xfer); | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * xfer is referenced | ||
225 | * | ||
226 | * xfer->lock has to be unlocked | ||
227 | */ | ||
228 | static void wa_xfer_completion(struct wa_xfer *xfer) | ||
229 | { | ||
230 | d_fnstart(3, NULL, "(xfer %p)\n", xfer); | ||
231 | if (xfer->wusb_dev) | ||
232 | wusb_dev_put(xfer->wusb_dev); | ||
233 | rpipe_put(xfer->ep->hcpriv); | ||
234 | wa_xfer_giveback(xfer); | ||
235 | d_fnend(3, NULL, "(xfer %p) = void\n", xfer); | ||
236 | return; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * If transfer is done, wrap it up and return true | ||
241 | * | ||
242 | * xfer->lock has to be locked | ||
243 | */ | ||
244 | static unsigned __wa_xfer_is_done(struct wa_xfer *xfer) | ||
245 | { | ||
246 | unsigned result, cnt; | ||
247 | struct wa_seg *seg; | ||
248 | struct urb *urb = xfer->urb; | ||
249 | unsigned found_short = 0; | ||
250 | |||
251 | d_fnstart(3, NULL, "(xfer %p)\n", xfer); | ||
252 | result = xfer->segs_done == xfer->segs_submitted; | ||
253 | if (result == 0) | ||
254 | goto out; | ||
255 | urb->actual_length = 0; | ||
256 | for (cnt = 0; cnt < xfer->segs; cnt++) { | ||
257 | seg = xfer->seg[cnt]; | ||
258 | switch (seg->status) { | ||
259 | case WA_SEG_DONE: | ||
260 | if (found_short && seg->result > 0) { | ||
261 | if (printk_ratelimit()) | ||
262 | printk(KERN_ERR "xfer %p#%u: bad short " | ||
263 | "segments (%zu)\n", xfer, cnt, | ||
264 | seg->result); | ||
265 | urb->status = -EINVAL; | ||
266 | goto out; | ||
267 | } | ||
268 | urb->actual_length += seg->result; | ||
269 | if (seg->result < xfer->seg_size | ||
270 | && cnt != xfer->segs-1) | ||
271 | found_short = 1; | ||
272 | d_printf(2, NULL, "xfer %p#%u: DONE short %d " | ||
273 | "result %zu urb->actual_length %d\n", | ||
274 | xfer, seg->index, found_short, seg->result, | ||
275 | urb->actual_length); | ||
276 | break; | ||
277 | case WA_SEG_ERROR: | ||
278 | xfer->result = seg->result; | ||
279 | d_printf(2, NULL, "xfer %p#%u: ERROR result %zu\n", | ||
280 | xfer, seg->index, seg->result); | ||
281 | goto out; | ||
282 | case WA_SEG_ABORTED: | ||
283 | WARN_ON(urb->status != -ECONNRESET | ||
284 | && urb->status != -ENOENT); | ||
285 | d_printf(2, NULL, "xfer %p#%u ABORTED: result %d\n", | ||
286 | xfer, seg->index, urb->status); | ||
287 | xfer->result = urb->status; | ||
288 | goto out; | ||
289 | default: | ||
290 | /* if (printk_ratelimit()) */ | ||
291 | printk(KERN_ERR "xfer %p#%u: " | ||
292 | "is_done bad state %d\n", | ||
293 | xfer, cnt, seg->status); | ||
294 | xfer->result = -EINVAL; | ||
295 | WARN_ON(1); | ||
296 | goto out; | ||
297 | } | ||
298 | } | ||
299 | xfer->result = 0; | ||
300 | out: | ||
301 | d_fnend(3, NULL, "(xfer %p) = void\n", xfer); | ||
302 | return result; | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * Initialize a transfer's ID | ||
307 | * | ||
308 | * We need to use a sequential number; if we use the pointer or the | ||
309 | * hash of the pointer, it can repeat over sequential transfers and | ||
310 | * then it will confuse the HWA....wonder why in hell they put a 32 | ||
311 | * bit handle in there then. | ||
312 | */ | ||
313 | static void wa_xfer_id_init(struct wa_xfer *xfer) | ||
314 | { | ||
315 | xfer->id = atomic_add_return(1, &xfer->wa->xfer_id_count); | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Return the xfer's ID associated with xfer | ||
320 | * | ||
321 | * Need to generate a | ||
322 | */ | ||
323 | static u32 wa_xfer_id(struct wa_xfer *xfer) | ||
324 | { | ||
325 | return xfer->id; | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * Search for a transfer list ID on the HCD's URB list | ||
330 | * | ||
331 | * For 32 bit architectures, we use the pointer itself; for 64 bits, a | ||
332 | * 32-bit hash of the pointer. | ||
333 | * | ||
334 | * @returns NULL if not found. | ||
335 | */ | ||
336 | static struct wa_xfer *wa_xfer_get_by_id(struct wahc *wa, u32 id) | ||
337 | { | ||
338 | unsigned long flags; | ||
339 | struct wa_xfer *xfer_itr; | ||
340 | spin_lock_irqsave(&wa->xfer_list_lock, flags); | ||
341 | list_for_each_entry(xfer_itr, &wa->xfer_list, list_node) { | ||
342 | if (id == xfer_itr->id) { | ||
343 | wa_xfer_get(xfer_itr); | ||
344 | goto out; | ||
345 | } | ||
346 | } | ||
347 | xfer_itr = NULL; | ||
348 | out: | ||
349 | spin_unlock_irqrestore(&wa->xfer_list_lock, flags); | ||
350 | return xfer_itr; | ||
351 | } | ||
352 | |||
353 | struct wa_xfer_abort_buffer { | ||
354 | struct urb urb; | ||
355 | struct wa_xfer_abort cmd; | ||
356 | }; | ||
357 | |||
358 | static void __wa_xfer_abort_cb(struct urb *urb) | ||
359 | { | ||
360 | struct wa_xfer_abort_buffer *b = urb->context; | ||
361 | usb_put_urb(&b->urb); | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * Aborts an ongoing transaction | ||
366 | * | ||
367 | * Assumes the transfer is referenced and locked and in a submitted | ||
368 | * state (mainly that there is an endpoint/rpipe assigned). | ||
369 | * | ||
370 | * The callback (see above) does nothing but freeing up the data by | ||
371 | * putting the URB. Because the URB is allocated at the head of the | ||
372 | * struct, the whole space we allocated is kfreed. | ||
373 | * | ||
374 | * We'll get an 'aborted transaction' xfer result on DTI, that'll | ||
375 | * politely ignore because at this point the transaction has been | ||
376 | * marked as aborted already. | ||
377 | */ | ||
378 | static void __wa_xfer_abort(struct wa_xfer *xfer) | ||
379 | { | ||
380 | int result; | ||
381 | struct device *dev = &xfer->wa->usb_iface->dev; | ||
382 | struct wa_xfer_abort_buffer *b; | ||
383 | struct wa_rpipe *rpipe = xfer->ep->hcpriv; | ||
384 | |||
385 | b = kmalloc(sizeof(*b), GFP_ATOMIC); | ||
386 | if (b == NULL) | ||
387 | goto error_kmalloc; | ||
388 | b->cmd.bLength = sizeof(b->cmd); | ||
389 | b->cmd.bRequestType = WA_XFER_ABORT; | ||
390 | b->cmd.wRPipe = rpipe->descr.wRPipeIndex; | ||
391 | b->cmd.dwTransferID = wa_xfer_id(xfer); | ||
392 | |||
393 | usb_init_urb(&b->urb); | ||
394 | usb_fill_bulk_urb(&b->urb, xfer->wa->usb_dev, | ||
395 | usb_sndbulkpipe(xfer->wa->usb_dev, | ||
396 | xfer->wa->dto_epd->bEndpointAddress), | ||
397 | &b->cmd, sizeof(b->cmd), __wa_xfer_abort_cb, b); | ||
398 | result = usb_submit_urb(&b->urb, GFP_ATOMIC); | ||
399 | if (result < 0) | ||
400 | goto error_submit; | ||
401 | return; /* callback frees! */ | ||
402 | |||
403 | |||
404 | error_submit: | ||
405 | if (printk_ratelimit()) | ||
406 | dev_err(dev, "xfer %p: Can't submit abort request: %d\n", | ||
407 | xfer, result); | ||
408 | kfree(b); | ||
409 | error_kmalloc: | ||
410 | return; | ||
411 | |||
412 | } | ||
413 | |||
414 | /* | ||
415 | * | ||
416 | * @returns < 0 on error, transfer segment request size if ok | ||
417 | */ | ||
418 | static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer, | ||
419 | enum wa_xfer_type *pxfer_type) | ||
420 | { | ||
421 | ssize_t result; | ||
422 | struct device *dev = &xfer->wa->usb_iface->dev; | ||
423 | size_t maxpktsize; | ||
424 | struct urb *urb = xfer->urb; | ||
425 | struct wa_rpipe *rpipe = xfer->ep->hcpriv; | ||
426 | |||
427 | d_fnstart(3, dev, "(xfer %p [rpipe %p] urb %p)\n", | ||
428 | xfer, rpipe, urb); | ||
429 | switch (rpipe->descr.bmAttribute & 0x3) { | ||
430 | case USB_ENDPOINT_XFER_CONTROL: | ||
431 | *pxfer_type = WA_XFER_TYPE_CTL; | ||
432 | result = sizeof(struct wa_xfer_ctl); | ||
433 | break; | ||
434 | case USB_ENDPOINT_XFER_INT: | ||
435 | case USB_ENDPOINT_XFER_BULK: | ||
436 | *pxfer_type = WA_XFER_TYPE_BI; | ||
437 | result = sizeof(struct wa_xfer_bi); | ||
438 | break; | ||
439 | case USB_ENDPOINT_XFER_ISOC: | ||
440 | dev_err(dev, "FIXME: ISOC not implemented\n"); | ||
441 | result = -ENOSYS; | ||
442 | goto error; | ||
443 | default: | ||
444 | /* never happens */ | ||
445 | BUG(); | ||
446 | result = -EINVAL; /* shut gcc up */ | ||
447 | }; | ||
448 | xfer->is_inbound = urb->pipe & USB_DIR_IN ? 1 : 0; | ||
449 | xfer->is_dma = urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? 1 : 0; | ||
450 | xfer->seg_size = le16_to_cpu(rpipe->descr.wBlocks) | ||
451 | * 1 << (xfer->wa->wa_descr->bRPipeBlockSize - 1); | ||
452 | /* Compute the segment size and make sure it is a multiple of | ||
453 | * the maxpktsize (WUSB1.0[8.3.3.1])...not really too much of | ||
454 | * a check (FIXME) */ | ||
455 | maxpktsize = le16_to_cpu(rpipe->descr.wMaxPacketSize); | ||
456 | if (xfer->seg_size < maxpktsize) { | ||
457 | dev_err(dev, "HW BUG? seg_size %zu smaller than maxpktsize " | ||
458 | "%zu\n", xfer->seg_size, maxpktsize); | ||
459 | result = -EINVAL; | ||
460 | goto error; | ||
461 | } | ||
462 | xfer->seg_size = (xfer->seg_size / maxpktsize) * maxpktsize; | ||
463 | xfer->segs = (urb->transfer_buffer_length + xfer->seg_size - 1) | ||
464 | / xfer->seg_size; | ||
465 | if (xfer->segs >= WA_SEGS_MAX) { | ||
466 | dev_err(dev, "BUG? ops, number of segments %d bigger than %d\n", | ||
467 | (int)(urb->transfer_buffer_length / xfer->seg_size), | ||
468 | WA_SEGS_MAX); | ||
469 | result = -EINVAL; | ||
470 | goto error; | ||
471 | } | ||
472 | if (xfer->segs == 0 && *pxfer_type == WA_XFER_TYPE_CTL) | ||
473 | xfer->segs = 1; | ||
474 | error: | ||
475 | d_fnend(3, dev, "(xfer %p [rpipe %p] urb %p) = %d\n", | ||
476 | xfer, rpipe, urb, (int)result); | ||
477 | return result; | ||
478 | } | ||
479 | |||
480 | /** Fill in the common request header and xfer-type specific data. */ | ||
481 | static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer, | ||
482 | struct wa_xfer_hdr *xfer_hdr0, | ||
483 | enum wa_xfer_type xfer_type, | ||
484 | size_t xfer_hdr_size) | ||
485 | { | ||
486 | struct wa_rpipe *rpipe = xfer->ep->hcpriv; | ||
487 | |||
488 | xfer_hdr0 = &xfer->seg[0]->xfer_hdr; | ||
489 | xfer_hdr0->bLength = xfer_hdr_size; | ||
490 | xfer_hdr0->bRequestType = xfer_type; | ||
491 | xfer_hdr0->wRPipe = rpipe->descr.wRPipeIndex; | ||
492 | xfer_hdr0->dwTransferID = wa_xfer_id(xfer); | ||
493 | xfer_hdr0->bTransferSegment = 0; | ||
494 | switch (xfer_type) { | ||
495 | case WA_XFER_TYPE_CTL: { | ||
496 | struct wa_xfer_ctl *xfer_ctl = | ||
497 | container_of(xfer_hdr0, struct wa_xfer_ctl, hdr); | ||
498 | xfer_ctl->bmAttribute = xfer->is_inbound ? 1 : 0; | ||
499 | BUG_ON(xfer->urb->transfer_flags & URB_NO_SETUP_DMA_MAP | ||
500 | && xfer->urb->setup_packet == NULL); | ||
501 | memcpy(&xfer_ctl->baSetupData, xfer->urb->setup_packet, | ||
502 | sizeof(xfer_ctl->baSetupData)); | ||
503 | break; | ||
504 | } | ||
505 | case WA_XFER_TYPE_BI: | ||
506 | break; | ||
507 | case WA_XFER_TYPE_ISO: | ||
508 | printk(KERN_ERR "FIXME: ISOC not implemented\n"); | ||
509 | default: | ||
510 | BUG(); | ||
511 | }; | ||
512 | } | ||
513 | |||
514 | /* | ||
515 | * Callback for the OUT data phase of the segment request | ||
516 | * | ||
517 | * Check wa_seg_cb(); most comments also apply here because this | ||
518 | * function does almost the same thing and they work closely | ||
519 | * together. | ||
520 | * | ||
521 | * If the seg request has failed but this DTO phase has suceeded, | ||
522 | * wa_seg_cb() has already failed the segment and moved the | ||
523 | * status to WA_SEG_ERROR, so this will go through 'case 0' and | ||
524 | * effectively do nothing. | ||
525 | */ | ||
526 | static void wa_seg_dto_cb(struct urb *urb) | ||
527 | { | ||
528 | struct wa_seg *seg = urb->context; | ||
529 | struct wa_xfer *xfer = seg->xfer; | ||
530 | struct wahc *wa; | ||
531 | struct device *dev; | ||
532 | struct wa_rpipe *rpipe; | ||
533 | unsigned long flags; | ||
534 | unsigned rpipe_ready = 0; | ||
535 | u8 done = 0; | ||
536 | |||
537 | d_fnstart(3, NULL, "(urb %p [%d])\n", urb, urb->status); | ||
538 | switch (urb->status) { | ||
539 | case 0: | ||
540 | spin_lock_irqsave(&xfer->lock, flags); | ||
541 | wa = xfer->wa; | ||
542 | dev = &wa->usb_iface->dev; | ||
543 | d_printf(2, dev, "xfer %p#%u: data out done (%d bytes)\n", | ||
544 | xfer, seg->index, urb->actual_length); | ||
545 | if (seg->status < WA_SEG_PENDING) | ||
546 | seg->status = WA_SEG_PENDING; | ||
547 | seg->result = urb->actual_length; | ||
548 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
549 | break; | ||
550 | case -ECONNRESET: /* URB unlinked; no need to do anything */ | ||
551 | case -ENOENT: /* as it was done by the who unlinked us */ | ||
552 | break; | ||
553 | default: /* Other errors ... */ | ||
554 | spin_lock_irqsave(&xfer->lock, flags); | ||
555 | wa = xfer->wa; | ||
556 | dev = &wa->usb_iface->dev; | ||
557 | rpipe = xfer->ep->hcpriv; | ||
558 | if (printk_ratelimit()) | ||
559 | dev_err(dev, "xfer %p#%u: data out error %d\n", | ||
560 | xfer, seg->index, urb->status); | ||
561 | if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, | ||
562 | EDC_ERROR_TIMEFRAME)){ | ||
563 | dev_err(dev, "DTO: URB max acceptable errors " | ||
564 | "exceeded, resetting device\n"); | ||
565 | wa_reset_all(wa); | ||
566 | } | ||
567 | if (seg->status != WA_SEG_ERROR) { | ||
568 | seg->status = WA_SEG_ERROR; | ||
569 | seg->result = urb->status; | ||
570 | xfer->segs_done++; | ||
571 | __wa_xfer_abort(xfer); | ||
572 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
573 | done = __wa_xfer_is_done(xfer); | ||
574 | } | ||
575 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
576 | if (done) | ||
577 | wa_xfer_completion(xfer); | ||
578 | if (rpipe_ready) | ||
579 | wa_xfer_delayed_run(rpipe); | ||
580 | } | ||
581 | d_fnend(3, NULL, "(urb %p [%d]) = void\n", urb, urb->status); | ||
582 | } | ||
583 | |||
584 | /* | ||
585 | * Callback for the segment request | ||
586 | * | ||
587 | * If succesful transition state (unless already transitioned or | ||
588 | * outbound transfer); otherwise, take a note of the error, mark this | ||
589 | * segment done and try completion. | ||
590 | * | ||
591 | * Note we don't access until we are sure that the transfer hasn't | ||
592 | * been cancelled (ECONNRESET, ENOENT), which could mean that | ||
593 | * seg->xfer could be already gone. | ||
594 | * | ||
595 | * We have to check before setting the status to WA_SEG_PENDING | ||
596 | * because sometimes the xfer result callback arrives before this | ||
597 | * callback (geeeeeeze), so it might happen that we are already in | ||
598 | * another state. As well, we don't set it if the transfer is inbound, | ||
599 | * as in that case, wa_seg_dto_cb will do it when the OUT data phase | ||
600 | * finishes. | ||
601 | */ | ||
602 | static void wa_seg_cb(struct urb *urb) | ||
603 | { | ||
604 | struct wa_seg *seg = urb->context; | ||
605 | struct wa_xfer *xfer = seg->xfer; | ||
606 | struct wahc *wa; | ||
607 | struct device *dev; | ||
608 | struct wa_rpipe *rpipe; | ||
609 | unsigned long flags; | ||
610 | unsigned rpipe_ready; | ||
611 | u8 done = 0; | ||
612 | |||
613 | d_fnstart(3, NULL, "(urb %p [%d])\n", urb, urb->status); | ||
614 | switch (urb->status) { | ||
615 | case 0: | ||
616 | spin_lock_irqsave(&xfer->lock, flags); | ||
617 | wa = xfer->wa; | ||
618 | dev = &wa->usb_iface->dev; | ||
619 | d_printf(2, dev, "xfer %p#%u: request done\n", | ||
620 | xfer, seg->index); | ||
621 | if (xfer->is_inbound && seg->status < WA_SEG_PENDING) | ||
622 | seg->status = WA_SEG_PENDING; | ||
623 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
624 | break; | ||
625 | case -ECONNRESET: /* URB unlinked; no need to do anything */ | ||
626 | case -ENOENT: /* as it was done by the who unlinked us */ | ||
627 | break; | ||
628 | default: /* Other errors ... */ | ||
629 | spin_lock_irqsave(&xfer->lock, flags); | ||
630 | wa = xfer->wa; | ||
631 | dev = &wa->usb_iface->dev; | ||
632 | rpipe = xfer->ep->hcpriv; | ||
633 | if (printk_ratelimit()) | ||
634 | dev_err(dev, "xfer %p#%u: request error %d\n", | ||
635 | xfer, seg->index, urb->status); | ||
636 | if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, | ||
637 | EDC_ERROR_TIMEFRAME)){ | ||
638 | dev_err(dev, "DTO: URB max acceptable errors " | ||
639 | "exceeded, resetting device\n"); | ||
640 | wa_reset_all(wa); | ||
641 | } | ||
642 | usb_unlink_urb(seg->dto_urb); | ||
643 | seg->status = WA_SEG_ERROR; | ||
644 | seg->result = urb->status; | ||
645 | xfer->segs_done++; | ||
646 | __wa_xfer_abort(xfer); | ||
647 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
648 | done = __wa_xfer_is_done(xfer); | ||
649 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
650 | if (done) | ||
651 | wa_xfer_completion(xfer); | ||
652 | if (rpipe_ready) | ||
653 | wa_xfer_delayed_run(rpipe); | ||
654 | } | ||
655 | d_fnend(3, NULL, "(urb %p [%d]) = void\n", urb, urb->status); | ||
656 | } | ||
657 | |||
658 | /* | ||
659 | * Allocate the segs array and initialize each of them | ||
660 | * | ||
661 | * The segments are freed by wa_xfer_destroy() when the xfer use count | ||
662 | * drops to zero; however, because each segment is given the same life | ||
663 | * cycle as the USB URB it contains, it is actually freed by | ||
664 | * usb_put_urb() on the contained USB URB (twisted, eh?). | ||
665 | */ | ||
666 | static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size) | ||
667 | { | ||
668 | int result, cnt; | ||
669 | size_t alloc_size = sizeof(*xfer->seg[0]) | ||
670 | - sizeof(xfer->seg[0]->xfer_hdr) + xfer_hdr_size; | ||
671 | struct usb_device *usb_dev = xfer->wa->usb_dev; | ||
672 | const struct usb_endpoint_descriptor *dto_epd = xfer->wa->dto_epd; | ||
673 | struct wa_seg *seg; | ||
674 | size_t buf_itr, buf_size, buf_itr_size; | ||
675 | |||
676 | result = -ENOMEM; | ||
677 | xfer->seg = kzalloc(xfer->segs * sizeof(xfer->seg[0]), GFP_ATOMIC); | ||
678 | if (xfer->seg == NULL) | ||
679 | goto error_segs_kzalloc; | ||
680 | buf_itr = 0; | ||
681 | buf_size = xfer->urb->transfer_buffer_length; | ||
682 | for (cnt = 0; cnt < xfer->segs; cnt++) { | ||
683 | seg = xfer->seg[cnt] = kzalloc(alloc_size, GFP_ATOMIC); | ||
684 | if (seg == NULL) | ||
685 | goto error_seg_kzalloc; | ||
686 | wa_seg_init(seg); | ||
687 | seg->xfer = xfer; | ||
688 | seg->index = cnt; | ||
689 | usb_fill_bulk_urb(&seg->urb, usb_dev, | ||
690 | usb_sndbulkpipe(usb_dev, | ||
691 | dto_epd->bEndpointAddress), | ||
692 | &seg->xfer_hdr, xfer_hdr_size, | ||
693 | wa_seg_cb, seg); | ||
694 | buf_itr_size = buf_size > xfer->seg_size ? | ||
695 | xfer->seg_size : buf_size; | ||
696 | if (xfer->is_inbound == 0 && buf_size > 0) { | ||
697 | seg->dto_urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
698 | if (seg->dto_urb == NULL) | ||
699 | goto error_dto_alloc; | ||
700 | usb_fill_bulk_urb( | ||
701 | seg->dto_urb, usb_dev, | ||
702 | usb_sndbulkpipe(usb_dev, | ||
703 | dto_epd->bEndpointAddress), | ||
704 | NULL, 0, wa_seg_dto_cb, seg); | ||
705 | if (xfer->is_dma) { | ||
706 | seg->dto_urb->transfer_dma = | ||
707 | xfer->urb->transfer_dma + buf_itr; | ||
708 | seg->dto_urb->transfer_flags |= | ||
709 | URB_NO_TRANSFER_DMA_MAP; | ||
710 | } else | ||
711 | seg->dto_urb->transfer_buffer = | ||
712 | xfer->urb->transfer_buffer + buf_itr; | ||
713 | seg->dto_urb->transfer_buffer_length = buf_itr_size; | ||
714 | } | ||
715 | seg->status = WA_SEG_READY; | ||
716 | buf_itr += buf_itr_size; | ||
717 | buf_size -= buf_itr_size; | ||
718 | } | ||
719 | return 0; | ||
720 | |||
721 | error_dto_alloc: | ||
722 | kfree(xfer->seg[cnt]); | ||
723 | cnt--; | ||
724 | error_seg_kzalloc: | ||
725 | /* use the fact that cnt is left at were it failed */ | ||
726 | for (; cnt > 0; cnt--) { | ||
727 | if (xfer->is_inbound == 0) | ||
728 | kfree(xfer->seg[cnt]->dto_urb); | ||
729 | kfree(xfer->seg[cnt]); | ||
730 | } | ||
731 | error_segs_kzalloc: | ||
732 | return result; | ||
733 | } | ||
734 | |||
735 | /* | ||
736 | * Allocates all the stuff needed to submit a transfer | ||
737 | * | ||
738 | * Breaks the whole data buffer in a list of segments, each one has a | ||
739 | * structure allocated to it and linked in xfer->seg[index] | ||
740 | * | ||
741 | * FIXME: merge setup_segs() and the last part of this function, no | ||
742 | * need to do two for loops when we could run everything in a | ||
743 | * single one | ||
744 | */ | ||
745 | static int __wa_xfer_setup(struct wa_xfer *xfer, struct urb *urb) | ||
746 | { | ||
747 | int result; | ||
748 | struct device *dev = &xfer->wa->usb_iface->dev; | ||
749 | enum wa_xfer_type xfer_type = 0; /* shut up GCC */ | ||
750 | size_t xfer_hdr_size, cnt, transfer_size; | ||
751 | struct wa_xfer_hdr *xfer_hdr0, *xfer_hdr; | ||
752 | |||
753 | d_fnstart(3, dev, "(xfer %p [rpipe %p] urb %p)\n", | ||
754 | xfer, xfer->ep->hcpriv, urb); | ||
755 | |||
756 | result = __wa_xfer_setup_sizes(xfer, &xfer_type); | ||
757 | if (result < 0) | ||
758 | goto error_setup_sizes; | ||
759 | xfer_hdr_size = result; | ||
760 | result = __wa_xfer_setup_segs(xfer, xfer_hdr_size); | ||
761 | if (result < 0) { | ||
762 | dev_err(dev, "xfer %p: Failed to allocate %d segments: %d\n", | ||
763 | xfer, xfer->segs, result); | ||
764 | goto error_setup_segs; | ||
765 | } | ||
766 | /* Fill the first header */ | ||
767 | xfer_hdr0 = &xfer->seg[0]->xfer_hdr; | ||
768 | wa_xfer_id_init(xfer); | ||
769 | __wa_xfer_setup_hdr0(xfer, xfer_hdr0, xfer_type, xfer_hdr_size); | ||
770 | |||
771 | /* Fill remainig headers */ | ||
772 | xfer_hdr = xfer_hdr0; | ||
773 | transfer_size = urb->transfer_buffer_length; | ||
774 | xfer_hdr0->dwTransferLength = transfer_size > xfer->seg_size ? | ||
775 | xfer->seg_size : transfer_size; | ||
776 | transfer_size -= xfer->seg_size; | ||
777 | for (cnt = 1; cnt < xfer->segs; cnt++) { | ||
778 | xfer_hdr = &xfer->seg[cnt]->xfer_hdr; | ||
779 | memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size); | ||
780 | xfer_hdr->bTransferSegment = cnt; | ||
781 | xfer_hdr->dwTransferLength = transfer_size > xfer->seg_size ? | ||
782 | cpu_to_le32(xfer->seg_size) | ||
783 | : cpu_to_le32(transfer_size); | ||
784 | xfer->seg[cnt]->status = WA_SEG_READY; | ||
785 | transfer_size -= xfer->seg_size; | ||
786 | } | ||
787 | xfer_hdr->bTransferSegment |= 0x80; /* this is the last segment */ | ||
788 | result = 0; | ||
789 | error_setup_segs: | ||
790 | error_setup_sizes: | ||
791 | d_fnend(3, dev, "(xfer %p [rpipe %p] urb %p) = %d\n", | ||
792 | xfer, xfer->ep->hcpriv, urb, result); | ||
793 | return result; | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * | ||
798 | * | ||
799 | * rpipe->seg_lock is held! | ||
800 | */ | ||
801 | static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer, | ||
802 | struct wa_seg *seg) | ||
803 | { | ||
804 | int result; | ||
805 | result = usb_submit_urb(&seg->urb, GFP_ATOMIC); | ||
806 | if (result < 0) { | ||
807 | printk(KERN_ERR "xfer %p#%u: REQ submit failed: %d\n", | ||
808 | xfer, seg->index, result); | ||
809 | goto error_seg_submit; | ||
810 | } | ||
811 | if (seg->dto_urb) { | ||
812 | result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC); | ||
813 | if (result < 0) { | ||
814 | printk(KERN_ERR "xfer %p#%u: DTO submit failed: %d\n", | ||
815 | xfer, seg->index, result); | ||
816 | goto error_dto_submit; | ||
817 | } | ||
818 | } | ||
819 | seg->status = WA_SEG_SUBMITTED; | ||
820 | rpipe_avail_dec(rpipe); | ||
821 | return 0; | ||
822 | |||
823 | error_dto_submit: | ||
824 | usb_unlink_urb(&seg->urb); | ||
825 | error_seg_submit: | ||
826 | seg->status = WA_SEG_ERROR; | ||
827 | seg->result = result; | ||
828 | return result; | ||
829 | } | ||
830 | |||
831 | /* | ||
832 | * Execute more queued request segments until the maximum concurrent allowed | ||
833 | * | ||
834 | * The ugly unlock/lock sequence on the error path is needed as the | ||
835 | * xfer->lock normally nests the seg_lock and not viceversa. | ||
836 | * | ||
837 | */ | ||
838 | static void wa_xfer_delayed_run(struct wa_rpipe *rpipe) | ||
839 | { | ||
840 | int result; | ||
841 | struct device *dev = &rpipe->wa->usb_iface->dev; | ||
842 | struct wa_seg *seg; | ||
843 | struct wa_xfer *xfer; | ||
844 | unsigned long flags; | ||
845 | |||
846 | d_fnstart(1, dev, "(rpipe #%d) %d segments available\n", | ||
847 | le16_to_cpu(rpipe->descr.wRPipeIndex), | ||
848 | atomic_read(&rpipe->segs_available)); | ||
849 | spin_lock_irqsave(&rpipe->seg_lock, flags); | ||
850 | while (atomic_read(&rpipe->segs_available) > 0 | ||
851 | && !list_empty(&rpipe->seg_list)) { | ||
852 | seg = list_entry(rpipe->seg_list.next, struct wa_seg, | ||
853 | list_node); | ||
854 | list_del(&seg->list_node); | ||
855 | xfer = seg->xfer; | ||
856 | result = __wa_seg_submit(rpipe, xfer, seg); | ||
857 | d_printf(1, dev, "xfer %p#%u submitted from delayed " | ||
858 | "[%d segments available] %d\n", | ||
859 | xfer, seg->index, | ||
860 | atomic_read(&rpipe->segs_available), result); | ||
861 | if (unlikely(result < 0)) { | ||
862 | spin_unlock_irqrestore(&rpipe->seg_lock, flags); | ||
863 | spin_lock_irqsave(&xfer->lock, flags); | ||
864 | __wa_xfer_abort(xfer); | ||
865 | xfer->segs_done++; | ||
866 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
867 | spin_lock_irqsave(&rpipe->seg_lock, flags); | ||
868 | } | ||
869 | } | ||
870 | spin_unlock_irqrestore(&rpipe->seg_lock, flags); | ||
871 | d_fnend(1, dev, "(rpipe #%d) = void, %d segments available\n", | ||
872 | le16_to_cpu(rpipe->descr.wRPipeIndex), | ||
873 | atomic_read(&rpipe->segs_available)); | ||
874 | |||
875 | } | ||
876 | |||
877 | /* | ||
878 | * | ||
879 | * xfer->lock is taken | ||
880 | * | ||
881 | * On failure submitting we just stop submitting and return error; | ||
882 | * wa_urb_enqueue_b() will execute the completion path | ||
883 | */ | ||
884 | static int __wa_xfer_submit(struct wa_xfer *xfer) | ||
885 | { | ||
886 | int result; | ||
887 | struct wahc *wa = xfer->wa; | ||
888 | struct device *dev = &wa->usb_iface->dev; | ||
889 | unsigned cnt; | ||
890 | struct wa_seg *seg; | ||
891 | unsigned long flags; | ||
892 | struct wa_rpipe *rpipe = xfer->ep->hcpriv; | ||
893 | size_t maxrequests = le16_to_cpu(rpipe->descr.wRequests); | ||
894 | u8 available; | ||
895 | u8 empty; | ||
896 | |||
897 | d_fnstart(3, dev, "(xfer %p [rpipe %p])\n", | ||
898 | xfer, xfer->ep->hcpriv); | ||
899 | |||
900 | spin_lock_irqsave(&wa->xfer_list_lock, flags); | ||
901 | list_add_tail(&xfer->list_node, &wa->xfer_list); | ||
902 | spin_unlock_irqrestore(&wa->xfer_list_lock, flags); | ||
903 | |||
904 | BUG_ON(atomic_read(&rpipe->segs_available) > maxrequests); | ||
905 | result = 0; | ||
906 | spin_lock_irqsave(&rpipe->seg_lock, flags); | ||
907 | for (cnt = 0; cnt < xfer->segs; cnt++) { | ||
908 | available = atomic_read(&rpipe->segs_available); | ||
909 | empty = list_empty(&rpipe->seg_list); | ||
910 | seg = xfer->seg[cnt]; | ||
911 | d_printf(2, dev, "xfer %p#%u: available %u empty %u (%s)\n", | ||
912 | xfer, cnt, available, empty, | ||
913 | available == 0 || !empty ? "delayed" : "submitted"); | ||
914 | if (available == 0 || !empty) { | ||
915 | d_printf(1, dev, "xfer %p#%u: delayed\n", xfer, cnt); | ||
916 | seg->status = WA_SEG_DELAYED; | ||
917 | list_add_tail(&seg->list_node, &rpipe->seg_list); | ||
918 | } else { | ||
919 | result = __wa_seg_submit(rpipe, xfer, seg); | ||
920 | if (result < 0) | ||
921 | goto error_seg_submit; | ||
922 | } | ||
923 | xfer->segs_submitted++; | ||
924 | } | ||
925 | spin_unlock_irqrestore(&rpipe->seg_lock, flags); | ||
926 | d_fnend(3, dev, "(xfer %p [rpipe %p]) = void\n", xfer, | ||
927 | xfer->ep->hcpriv); | ||
928 | return result; | ||
929 | |||
930 | error_seg_submit: | ||
931 | __wa_xfer_abort(xfer); | ||
932 | spin_unlock_irqrestore(&rpipe->seg_lock, flags); | ||
933 | d_fnend(3, dev, "(xfer %p [rpipe %p]) = void\n", xfer, | ||
934 | xfer->ep->hcpriv); | ||
935 | return result; | ||
936 | } | ||
937 | |||
938 | /* | ||
939 | * Second part of a URB/transfer enqueuement | ||
940 | * | ||
941 | * Assumes this comes from wa_urb_enqueue() [maybe through | ||
942 | * wa_urb_enqueue_run()]. At this point: | ||
943 | * | ||
944 | * xfer->wa filled and refcounted | ||
945 | * xfer->ep filled with rpipe refcounted if | ||
946 | * delayed == 0 | ||
947 | * xfer->urb filled and refcounted (this is the case when called | ||
948 | * from wa_urb_enqueue() as we come from usb_submit_urb() | ||
949 | * and when called by wa_urb_enqueue_run(), as we took an | ||
950 | * extra ref dropped by _run() after we return). | ||
951 | * xfer->gfp filled | ||
952 | * | ||
953 | * If we fail at __wa_xfer_submit(), then we just check if we are done | ||
954 | * and if so, we run the completion procedure. However, if we are not | ||
955 | * yet done, we do nothing and wait for the completion handlers from | ||
956 | * the submitted URBs or from the xfer-result path to kick in. If xfer | ||
957 | * result never kicks in, the xfer will timeout from the USB code and | ||
958 | * dequeue() will be called. | ||
959 | */ | ||
960 | static void wa_urb_enqueue_b(struct wa_xfer *xfer) | ||
961 | { | ||
962 | int result; | ||
963 | unsigned long flags; | ||
964 | struct urb *urb = xfer->urb; | ||
965 | struct wahc *wa = xfer->wa; | ||
966 | struct wusbhc *wusbhc = wa->wusb; | ||
967 | struct device *dev = &wa->usb_iface->dev; | ||
968 | struct wusb_dev *wusb_dev; | ||
969 | unsigned done; | ||
970 | |||
971 | d_fnstart(3, dev, "(wa %p urb %p)\n", wa, urb); | ||
972 | result = rpipe_get_by_ep(wa, xfer->ep, urb, xfer->gfp); | ||
973 | if (result < 0) | ||
974 | goto error_rpipe_get; | ||
975 | result = -ENODEV; | ||
976 | /* FIXME: segmentation broken -- kills DWA */ | ||
977 | mutex_lock(&wusbhc->mutex); /* get a WUSB dev */ | ||
978 | if (urb->dev == NULL) | ||
979 | goto error_dev_gone; | ||
980 | wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev); | ||
981 | if (wusb_dev == NULL) { | ||
982 | mutex_unlock(&wusbhc->mutex); | ||
983 | goto error_dev_gone; | ||
984 | } | ||
985 | mutex_unlock(&wusbhc->mutex); | ||
986 | |||
987 | spin_lock_irqsave(&xfer->lock, flags); | ||
988 | xfer->wusb_dev = wusb_dev; | ||
989 | result = urb->status; | ||
990 | if (urb->status != -EINPROGRESS) | ||
991 | goto error_dequeued; | ||
992 | |||
993 | result = __wa_xfer_setup(xfer, urb); | ||
994 | if (result < 0) | ||
995 | goto error_xfer_setup; | ||
996 | result = __wa_xfer_submit(xfer); | ||
997 | if (result < 0) | ||
998 | goto error_xfer_submit; | ||
999 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1000 | d_fnend(3, dev, "(wa %p urb %p) = void\n", wa, urb); | ||
1001 | return; | ||
1002 | |||
1003 | /* this is basically wa_xfer_completion() broken up wa_xfer_giveback() | ||
1004 | * does a wa_xfer_put() that will call wa_xfer_destroy() and clean | ||
1005 | * upundo setup(). | ||
1006 | */ | ||
1007 | error_xfer_setup: | ||
1008 | error_dequeued: | ||
1009 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1010 | /* FIXME: segmentation broken, kills DWA */ | ||
1011 | if (wusb_dev) | ||
1012 | wusb_dev_put(wusb_dev); | ||
1013 | error_dev_gone: | ||
1014 | rpipe_put(xfer->ep->hcpriv); | ||
1015 | error_rpipe_get: | ||
1016 | xfer->result = result; | ||
1017 | wa_xfer_giveback(xfer); | ||
1018 | d_fnend(3, dev, "(wa %p urb %p) = (void) %d\n", wa, urb, result); | ||
1019 | return; | ||
1020 | |||
1021 | error_xfer_submit: | ||
1022 | done = __wa_xfer_is_done(xfer); | ||
1023 | xfer->result = result; | ||
1024 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1025 | if (done) | ||
1026 | wa_xfer_completion(xfer); | ||
1027 | d_fnend(3, dev, "(wa %p urb %p) = (void) %d\n", wa, urb, result); | ||
1028 | return; | ||
1029 | } | ||
1030 | |||
1031 | /* | ||
1032 | * Execute the delayed transfers in the Wire Adapter @wa | ||
1033 | * | ||
1034 | * We need to be careful here, as dequeue() could be called in the | ||
1035 | * middle. That's why we do the whole thing under the | ||
1036 | * wa->xfer_list_lock. If dequeue() jumps in, it first locks urb->lock | ||
1037 | * and then checks the list -- so as we would be acquiring in inverse | ||
1038 | * order, we just drop the lock once we have the xfer and reacquire it | ||
1039 | * later. | ||
1040 | */ | ||
1041 | void wa_urb_enqueue_run(struct work_struct *ws) | ||
1042 | { | ||
1043 | struct wahc *wa = container_of(ws, struct wahc, xfer_work); | ||
1044 | struct device *dev = &wa->usb_iface->dev; | ||
1045 | struct wa_xfer *xfer, *next; | ||
1046 | struct urb *urb; | ||
1047 | |||
1048 | d_fnstart(3, dev, "(wa %p)\n", wa); | ||
1049 | spin_lock_irq(&wa->xfer_list_lock); | ||
1050 | list_for_each_entry_safe(xfer, next, &wa->xfer_delayed_list, | ||
1051 | list_node) { | ||
1052 | list_del_init(&xfer->list_node); | ||
1053 | spin_unlock_irq(&wa->xfer_list_lock); | ||
1054 | |||
1055 | urb = xfer->urb; | ||
1056 | wa_urb_enqueue_b(xfer); | ||
1057 | usb_put_urb(urb); /* taken when queuing */ | ||
1058 | |||
1059 | spin_lock_irq(&wa->xfer_list_lock); | ||
1060 | } | ||
1061 | spin_unlock_irq(&wa->xfer_list_lock); | ||
1062 | d_fnend(3, dev, "(wa %p) = void\n", wa); | ||
1063 | } | ||
1064 | EXPORT_SYMBOL_GPL(wa_urb_enqueue_run); | ||
1065 | |||
1066 | /* | ||
1067 | * Submit a transfer to the Wire Adapter in a delayed way | ||
1068 | * | ||
1069 | * The process of enqueuing involves possible sleeps() [see | ||
1070 | * enqueue_b(), for the rpipe_get() and the mutex_lock()]. If we are | ||
1071 | * in an atomic section, we defer the enqueue_b() call--else we call direct. | ||
1072 | * | ||
1073 | * @urb: We own a reference to it done by the HCI Linux USB stack that | ||
1074 | * will be given up by calling usb_hcd_giveback_urb() or by | ||
1075 | * returning error from this function -> ergo we don't have to | ||
1076 | * refcount it. | ||
1077 | */ | ||
1078 | int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep, | ||
1079 | struct urb *urb, gfp_t gfp) | ||
1080 | { | ||
1081 | int result; | ||
1082 | struct device *dev = &wa->usb_iface->dev; | ||
1083 | struct wa_xfer *xfer; | ||
1084 | unsigned long my_flags; | ||
1085 | unsigned cant_sleep = irqs_disabled() | in_atomic(); | ||
1086 | |||
1087 | d_fnstart(3, dev, "(wa %p ep %p urb %p [%d] gfp 0x%x)\n", | ||
1088 | wa, ep, urb, urb->transfer_buffer_length, gfp); | ||
1089 | |||
1090 | if (urb->transfer_buffer == NULL | ||
1091 | && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) | ||
1092 | && urb->transfer_buffer_length != 0) { | ||
1093 | dev_err(dev, "BUG? urb %p: NULL xfer buffer & NODMA\n", urb); | ||
1094 | dump_stack(); | ||
1095 | } | ||
1096 | |||
1097 | result = -ENOMEM; | ||
1098 | xfer = kzalloc(sizeof(*xfer), gfp); | ||
1099 | if (xfer == NULL) | ||
1100 | goto error_kmalloc; | ||
1101 | |||
1102 | result = -ENOENT; | ||
1103 | if (urb->status != -EINPROGRESS) /* cancelled */ | ||
1104 | goto error_dequeued; /* before starting? */ | ||
1105 | wa_xfer_init(xfer); | ||
1106 | xfer->wa = wa_get(wa); | ||
1107 | xfer->urb = urb; | ||
1108 | xfer->gfp = gfp; | ||
1109 | xfer->ep = ep; | ||
1110 | urb->hcpriv = xfer; | ||
1111 | d_printf(2, dev, "xfer %p urb %p pipe 0x%02x [%d bytes] %s %s %s\n", | ||
1112 | xfer, urb, urb->pipe, urb->transfer_buffer_length, | ||
1113 | urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? "dma" : "nodma", | ||
1114 | urb->pipe & USB_DIR_IN ? "inbound" : "outbound", | ||
1115 | cant_sleep ? "deferred" : "inline"); | ||
1116 | if (cant_sleep) { | ||
1117 | usb_get_urb(urb); | ||
1118 | spin_lock_irqsave(&wa->xfer_list_lock, my_flags); | ||
1119 | list_add_tail(&xfer->list_node, &wa->xfer_delayed_list); | ||
1120 | spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags); | ||
1121 | queue_work(wusbd, &wa->xfer_work); | ||
1122 | } else { | ||
1123 | wa_urb_enqueue_b(xfer); | ||
1124 | } | ||
1125 | d_fnend(3, dev, "(wa %p ep %p urb %p [%d] gfp 0x%x) = 0\n", | ||
1126 | wa, ep, urb, urb->transfer_buffer_length, gfp); | ||
1127 | return 0; | ||
1128 | |||
1129 | error_dequeued: | ||
1130 | kfree(xfer); | ||
1131 | error_kmalloc: | ||
1132 | d_fnend(3, dev, "(wa %p ep %p urb %p [%d] gfp 0x%x) = %d\n", | ||
1133 | wa, ep, urb, urb->transfer_buffer_length, gfp, result); | ||
1134 | return result; | ||
1135 | } | ||
1136 | EXPORT_SYMBOL_GPL(wa_urb_enqueue); | ||
1137 | |||
1138 | /* | ||
1139 | * Dequeue a URB and make sure uwb_hcd_giveback_urb() [completion | ||
1140 | * handler] is called. | ||
1141 | * | ||
1142 | * Until a transfer goes successfully through wa_urb_enqueue() it | ||
1143 | * needs to be dequeued with completion calling; when stuck in delayed | ||
1144 | * or before wa_xfer_setup() is called, we need to do completion. | ||
1145 | * | ||
1146 | * not setup If there is no hcpriv yet, that means that that enqueue | ||
1147 | * still had no time to set the xfer up. Because | ||
1148 | * urb->status should be other than -EINPROGRESS, | ||
1149 | * enqueue() will catch that and bail out. | ||
1150 | * | ||
1151 | * If the transfer has gone through setup, we just need to clean it | ||
1152 | * up. If it has gone through submit(), we have to abort it [with an | ||
1153 | * asynch request] and then make sure we cancel each segment. | ||
1154 | * | ||
1155 | */ | ||
1156 | int wa_urb_dequeue(struct wahc *wa, struct urb *urb) | ||
1157 | { | ||
1158 | struct device *dev = &wa->usb_iface->dev; | ||
1159 | unsigned long flags, flags2; | ||
1160 | struct wa_xfer *xfer; | ||
1161 | struct wa_seg *seg; | ||
1162 | struct wa_rpipe *rpipe; | ||
1163 | unsigned cnt; | ||
1164 | unsigned rpipe_ready = 0; | ||
1165 | |||
1166 | d_fnstart(3, dev, "(wa %p, urb %p)\n", wa, urb); | ||
1167 | |||
1168 | d_printf(1, dev, "xfer %p urb %p: aborting\n", urb->hcpriv, urb); | ||
1169 | xfer = urb->hcpriv; | ||
1170 | if (xfer == NULL) { | ||
1171 | /* NOthing setup yet enqueue will see urb->status != | ||
1172 | * -EINPROGRESS (by hcd layer) and bail out with | ||
1173 | * error, no need to do completion | ||
1174 | */ | ||
1175 | BUG_ON(urb->status == -EINPROGRESS); | ||
1176 | goto out; | ||
1177 | } | ||
1178 | spin_lock_irqsave(&xfer->lock, flags); | ||
1179 | rpipe = xfer->ep->hcpriv; | ||
1180 | /* Check the delayed list -> if there, release and complete */ | ||
1181 | spin_lock_irqsave(&wa->xfer_list_lock, flags2); | ||
1182 | if (!list_empty(&xfer->list_node) && xfer->seg == NULL) | ||
1183 | goto dequeue_delayed; | ||
1184 | spin_unlock_irqrestore(&wa->xfer_list_lock, flags2); | ||
1185 | if (xfer->seg == NULL) /* still hasn't reached */ | ||
1186 | goto out_unlock; /* setup(), enqueue_b() completes */ | ||
1187 | /* Ok, the xfer is in flight already, it's been setup and submitted.*/ | ||
1188 | __wa_xfer_abort(xfer); | ||
1189 | for (cnt = 0; cnt < xfer->segs; cnt++) { | ||
1190 | seg = xfer->seg[cnt]; | ||
1191 | switch (seg->status) { | ||
1192 | case WA_SEG_NOTREADY: | ||
1193 | case WA_SEG_READY: | ||
1194 | printk(KERN_ERR "xfer %p#%u: dequeue bad state %u\n", | ||
1195 | xfer, cnt, seg->status); | ||
1196 | WARN_ON(1); | ||
1197 | break; | ||
1198 | case WA_SEG_DELAYED: | ||
1199 | seg->status = WA_SEG_ABORTED; | ||
1200 | spin_lock_irqsave(&rpipe->seg_lock, flags2); | ||
1201 | list_del(&seg->list_node); | ||
1202 | xfer->segs_done++; | ||
1203 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1204 | spin_unlock_irqrestore(&rpipe->seg_lock, flags2); | ||
1205 | break; | ||
1206 | case WA_SEG_SUBMITTED: | ||
1207 | seg->status = WA_SEG_ABORTED; | ||
1208 | usb_unlink_urb(&seg->urb); | ||
1209 | if (xfer->is_inbound == 0) | ||
1210 | usb_unlink_urb(seg->dto_urb); | ||
1211 | xfer->segs_done++; | ||
1212 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1213 | break; | ||
1214 | case WA_SEG_PENDING: | ||
1215 | seg->status = WA_SEG_ABORTED; | ||
1216 | xfer->segs_done++; | ||
1217 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1218 | break; | ||
1219 | case WA_SEG_DTI_PENDING: | ||
1220 | usb_unlink_urb(wa->dti_urb); | ||
1221 | seg->status = WA_SEG_ABORTED; | ||
1222 | xfer->segs_done++; | ||
1223 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1224 | break; | ||
1225 | case WA_SEG_DONE: | ||
1226 | case WA_SEG_ERROR: | ||
1227 | case WA_SEG_ABORTED: | ||
1228 | break; | ||
1229 | } | ||
1230 | } | ||
1231 | xfer->result = urb->status; /* -ENOENT or -ECONNRESET */ | ||
1232 | __wa_xfer_is_done(xfer); | ||
1233 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1234 | wa_xfer_completion(xfer); | ||
1235 | if (rpipe_ready) | ||
1236 | wa_xfer_delayed_run(rpipe); | ||
1237 | d_fnend(3, dev, "(wa %p, urb %p) = 0\n", wa, urb); | ||
1238 | return 0; | ||
1239 | |||
1240 | out_unlock: | ||
1241 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1242 | out: | ||
1243 | d_fnend(3, dev, "(wa %p, urb %p) = 0\n", wa, urb); | ||
1244 | return 0; | ||
1245 | |||
1246 | dequeue_delayed: | ||
1247 | list_del_init(&xfer->list_node); | ||
1248 | spin_unlock_irqrestore(&wa->xfer_list_lock, flags2); | ||
1249 | xfer->result = urb->status; | ||
1250 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1251 | wa_xfer_giveback(xfer); | ||
1252 | usb_put_urb(urb); /* we got a ref in enqueue() */ | ||
1253 | d_fnend(3, dev, "(wa %p, urb %p) = 0\n", wa, urb); | ||
1254 | return 0; | ||
1255 | } | ||
1256 | EXPORT_SYMBOL_GPL(wa_urb_dequeue); | ||
1257 | |||
1258 | /* | ||
1259 | * Translation from WA status codes (WUSB1.0 Table 8.15) to errno | ||
1260 | * codes | ||
1261 | * | ||
1262 | * Positive errno values are internal inconsistencies and should be | ||
1263 | * flagged louder. Negative are to be passed up to the user in the | ||
1264 | * normal way. | ||
1265 | * | ||
1266 | * @status: USB WA status code -- high two bits are stripped. | ||
1267 | */ | ||
1268 | static int wa_xfer_status_to_errno(u8 status) | ||
1269 | { | ||
1270 | int errno; | ||
1271 | u8 real_status = status; | ||
1272 | static int xlat[] = { | ||
1273 | [WA_XFER_STATUS_SUCCESS] = 0, | ||
1274 | [WA_XFER_STATUS_HALTED] = -EPIPE, | ||
1275 | [WA_XFER_STATUS_DATA_BUFFER_ERROR] = -ENOBUFS, | ||
1276 | [WA_XFER_STATUS_BABBLE] = -EOVERFLOW, | ||
1277 | [WA_XFER_RESERVED] = EINVAL, | ||
1278 | [WA_XFER_STATUS_NOT_FOUND] = 0, | ||
1279 | [WA_XFER_STATUS_INSUFFICIENT_RESOURCE] = -ENOMEM, | ||
1280 | [WA_XFER_STATUS_TRANSACTION_ERROR] = -EILSEQ, | ||
1281 | [WA_XFER_STATUS_ABORTED] = -EINTR, | ||
1282 | [WA_XFER_STATUS_RPIPE_NOT_READY] = EINVAL, | ||
1283 | [WA_XFER_INVALID_FORMAT] = EINVAL, | ||
1284 | [WA_XFER_UNEXPECTED_SEGMENT_NUMBER] = EINVAL, | ||
1285 | [WA_XFER_STATUS_RPIPE_TYPE_MISMATCH] = EINVAL, | ||
1286 | }; | ||
1287 | status &= 0x3f; | ||
1288 | |||
1289 | if (status == 0) | ||
1290 | return 0; | ||
1291 | if (status >= ARRAY_SIZE(xlat)) { | ||
1292 | if (printk_ratelimit()) | ||
1293 | printk(KERN_ERR "%s(): BUG? " | ||
1294 | "Unknown WA transfer status 0x%02x\n", | ||
1295 | __func__, real_status); | ||
1296 | return -EINVAL; | ||
1297 | } | ||
1298 | errno = xlat[status]; | ||
1299 | if (unlikely(errno > 0)) { | ||
1300 | if (printk_ratelimit()) | ||
1301 | printk(KERN_ERR "%s(): BUG? " | ||
1302 | "Inconsistent WA status: 0x%02x\n", | ||
1303 | __func__, real_status); | ||
1304 | errno = -errno; | ||
1305 | } | ||
1306 | return errno; | ||
1307 | } | ||
1308 | |||
1309 | /* | ||
1310 | * Process a xfer result completion message | ||
1311 | * | ||
1312 | * inbound transfers: need to schedule a DTI read | ||
1313 | * | ||
1314 | * FIXME: this functio needs to be broken up in parts | ||
1315 | */ | ||
1316 | static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer) | ||
1317 | { | ||
1318 | int result; | ||
1319 | struct device *dev = &wa->usb_iface->dev; | ||
1320 | unsigned long flags; | ||
1321 | u8 seg_idx; | ||
1322 | struct wa_seg *seg; | ||
1323 | struct wa_rpipe *rpipe; | ||
1324 | struct wa_xfer_result *xfer_result = wa->xfer_result; | ||
1325 | u8 done = 0; | ||
1326 | u8 usb_status; | ||
1327 | unsigned rpipe_ready = 0; | ||
1328 | |||
1329 | d_fnstart(3, dev, "(wa %p xfer %p)\n", wa, xfer); | ||
1330 | spin_lock_irqsave(&xfer->lock, flags); | ||
1331 | seg_idx = xfer_result->bTransferSegment & 0x7f; | ||
1332 | if (unlikely(seg_idx >= xfer->segs)) | ||
1333 | goto error_bad_seg; | ||
1334 | seg = xfer->seg[seg_idx]; | ||
1335 | rpipe = xfer->ep->hcpriv; | ||
1336 | usb_status = xfer_result->bTransferStatus; | ||
1337 | d_printf(2, dev, "xfer %p#%u: bTransferStatus 0x%02x (seg %u)\n", | ||
1338 | xfer, seg_idx, usb_status, seg->status); | ||
1339 | if (seg->status == WA_SEG_ABORTED | ||
1340 | || seg->status == WA_SEG_ERROR) /* already handled */ | ||
1341 | goto segment_aborted; | ||
1342 | if (seg->status == WA_SEG_SUBMITTED) /* ops, got here */ | ||
1343 | seg->status = WA_SEG_PENDING; /* before wa_seg{_dto}_cb() */ | ||
1344 | if (seg->status != WA_SEG_PENDING) { | ||
1345 | if (printk_ratelimit()) | ||
1346 | dev_err(dev, "xfer %p#%u: Bad segment state %u\n", | ||
1347 | xfer, seg_idx, seg->status); | ||
1348 | seg->status = WA_SEG_PENDING; /* workaround/"fix" it */ | ||
1349 | } | ||
1350 | if (usb_status & 0x80) { | ||
1351 | seg->result = wa_xfer_status_to_errno(usb_status); | ||
1352 | dev_err(dev, "DTI: xfer %p#%u failed (0x%02x)\n", | ||
1353 | xfer, seg->index, usb_status); | ||
1354 | goto error_complete; | ||
1355 | } | ||
1356 | /* FIXME: we ignore warnings, tally them for stats */ | ||
1357 | if (usb_status & 0x40) /* Warning?... */ | ||
1358 | usb_status = 0; /* ... pass */ | ||
1359 | if (xfer->is_inbound) { /* IN data phase: read to buffer */ | ||
1360 | seg->status = WA_SEG_DTI_PENDING; | ||
1361 | BUG_ON(wa->buf_in_urb->status == -EINPROGRESS); | ||
1362 | if (xfer->is_dma) { | ||
1363 | wa->buf_in_urb->transfer_dma = | ||
1364 | xfer->urb->transfer_dma | ||
1365 | + seg_idx * xfer->seg_size; | ||
1366 | wa->buf_in_urb->transfer_flags | ||
1367 | |= URB_NO_TRANSFER_DMA_MAP; | ||
1368 | } else { | ||
1369 | wa->buf_in_urb->transfer_buffer = | ||
1370 | xfer->urb->transfer_buffer | ||
1371 | + seg_idx * xfer->seg_size; | ||
1372 | wa->buf_in_urb->transfer_flags | ||
1373 | &= ~URB_NO_TRANSFER_DMA_MAP; | ||
1374 | } | ||
1375 | wa->buf_in_urb->transfer_buffer_length = | ||
1376 | le32_to_cpu(xfer_result->dwTransferLength); | ||
1377 | wa->buf_in_urb->context = seg; | ||
1378 | result = usb_submit_urb(wa->buf_in_urb, GFP_ATOMIC); | ||
1379 | if (result < 0) | ||
1380 | goto error_submit_buf_in; | ||
1381 | } else { | ||
1382 | /* OUT data phase, complete it -- */ | ||
1383 | seg->status = WA_SEG_DONE; | ||
1384 | seg->result = le32_to_cpu(xfer_result->dwTransferLength); | ||
1385 | xfer->segs_done++; | ||
1386 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1387 | done = __wa_xfer_is_done(xfer); | ||
1388 | } | ||
1389 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1390 | if (done) | ||
1391 | wa_xfer_completion(xfer); | ||
1392 | if (rpipe_ready) | ||
1393 | wa_xfer_delayed_run(rpipe); | ||
1394 | d_fnend(3, dev, "(wa %p xfer %p) = void\n", wa, xfer); | ||
1395 | return; | ||
1396 | |||
1397 | |||
1398 | error_submit_buf_in: | ||
1399 | if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { | ||
1400 | dev_err(dev, "DTI: URB max acceptable errors " | ||
1401 | "exceeded, resetting device\n"); | ||
1402 | wa_reset_all(wa); | ||
1403 | } | ||
1404 | if (printk_ratelimit()) | ||
1405 | dev_err(dev, "xfer %p#%u: can't submit DTI data phase: %d\n", | ||
1406 | xfer, seg_idx, result); | ||
1407 | seg->result = result; | ||
1408 | error_complete: | ||
1409 | seg->status = WA_SEG_ERROR; | ||
1410 | xfer->segs_done++; | ||
1411 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1412 | __wa_xfer_abort(xfer); | ||
1413 | done = __wa_xfer_is_done(xfer); | ||
1414 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1415 | if (done) | ||
1416 | wa_xfer_completion(xfer); | ||
1417 | if (rpipe_ready) | ||
1418 | wa_xfer_delayed_run(rpipe); | ||
1419 | d_fnend(3, dev, "(wa %p xfer %p) = void [segment/DTI-submit error]\n", | ||
1420 | wa, xfer); | ||
1421 | return; | ||
1422 | |||
1423 | |||
1424 | error_bad_seg: | ||
1425 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1426 | wa_urb_dequeue(wa, xfer->urb); | ||
1427 | if (printk_ratelimit()) | ||
1428 | dev_err(dev, "xfer %p#%u: bad segment\n", xfer, seg_idx); | ||
1429 | if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { | ||
1430 | dev_err(dev, "DTI: URB max acceptable errors " | ||
1431 | "exceeded, resetting device\n"); | ||
1432 | wa_reset_all(wa); | ||
1433 | } | ||
1434 | d_fnend(3, dev, "(wa %p xfer %p) = void [bad seg]\n", wa, xfer); | ||
1435 | return; | ||
1436 | |||
1437 | |||
1438 | segment_aborted: | ||
1439 | /* nothing to do, as the aborter did the completion */ | ||
1440 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1441 | d_fnend(3, dev, "(wa %p xfer %p) = void [segment aborted]\n", | ||
1442 | wa, xfer); | ||
1443 | return; | ||
1444 | |||
1445 | } | ||
1446 | |||
1447 | /* | ||
1448 | * Callback for the IN data phase | ||
1449 | * | ||
1450 | * If succesful transition state; otherwise, take a note of the | ||
1451 | * error, mark this segment done and try completion. | ||
1452 | * | ||
1453 | * Note we don't access until we are sure that the transfer hasn't | ||
1454 | * been cancelled (ECONNRESET, ENOENT), which could mean that | ||
1455 | * seg->xfer could be already gone. | ||
1456 | */ | ||
1457 | static void wa_buf_in_cb(struct urb *urb) | ||
1458 | { | ||
1459 | struct wa_seg *seg = urb->context; | ||
1460 | struct wa_xfer *xfer = seg->xfer; | ||
1461 | struct wahc *wa; | ||
1462 | struct device *dev; | ||
1463 | struct wa_rpipe *rpipe; | ||
1464 | unsigned rpipe_ready; | ||
1465 | unsigned long flags; | ||
1466 | u8 done = 0; | ||
1467 | |||
1468 | d_fnstart(3, NULL, "(urb %p [%d])\n", urb, urb->status); | ||
1469 | switch (urb->status) { | ||
1470 | case 0: | ||
1471 | spin_lock_irqsave(&xfer->lock, flags); | ||
1472 | wa = xfer->wa; | ||
1473 | dev = &wa->usb_iface->dev; | ||
1474 | rpipe = xfer->ep->hcpriv; | ||
1475 | d_printf(2, dev, "xfer %p#%u: data in done (%zu bytes)\n", | ||
1476 | xfer, seg->index, (size_t)urb->actual_length); | ||
1477 | seg->status = WA_SEG_DONE; | ||
1478 | seg->result = urb->actual_length; | ||
1479 | xfer->segs_done++; | ||
1480 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1481 | done = __wa_xfer_is_done(xfer); | ||
1482 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1483 | if (done) | ||
1484 | wa_xfer_completion(xfer); | ||
1485 | if (rpipe_ready) | ||
1486 | wa_xfer_delayed_run(rpipe); | ||
1487 | break; | ||
1488 | case -ECONNRESET: /* URB unlinked; no need to do anything */ | ||
1489 | case -ENOENT: /* as it was done by the who unlinked us */ | ||
1490 | break; | ||
1491 | default: /* Other errors ... */ | ||
1492 | spin_lock_irqsave(&xfer->lock, flags); | ||
1493 | wa = xfer->wa; | ||
1494 | dev = &wa->usb_iface->dev; | ||
1495 | rpipe = xfer->ep->hcpriv; | ||
1496 | if (printk_ratelimit()) | ||
1497 | dev_err(dev, "xfer %p#%u: data in error %d\n", | ||
1498 | xfer, seg->index, urb->status); | ||
1499 | if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, | ||
1500 | EDC_ERROR_TIMEFRAME)){ | ||
1501 | dev_err(dev, "DTO: URB max acceptable errors " | ||
1502 | "exceeded, resetting device\n"); | ||
1503 | wa_reset_all(wa); | ||
1504 | } | ||
1505 | seg->status = WA_SEG_ERROR; | ||
1506 | seg->result = urb->status; | ||
1507 | xfer->segs_done++; | ||
1508 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1509 | __wa_xfer_abort(xfer); | ||
1510 | done = __wa_xfer_is_done(xfer); | ||
1511 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1512 | if (done) | ||
1513 | wa_xfer_completion(xfer); | ||
1514 | if (rpipe_ready) | ||
1515 | wa_xfer_delayed_run(rpipe); | ||
1516 | } | ||
1517 | d_fnend(3, NULL, "(urb %p [%d]) = void\n", urb, urb->status); | ||
1518 | } | ||
1519 | |||
1520 | /* | ||
1521 | * Handle an incoming transfer result buffer | ||
1522 | * | ||
1523 | * Given a transfer result buffer, it completes the transfer (possibly | ||
1524 | * scheduling and buffer in read) and then resubmits the DTI URB for a | ||
1525 | * new transfer result read. | ||
1526 | * | ||
1527 | * | ||
1528 | * The xfer_result DTI URB state machine | ||
1529 | * | ||
1530 | * States: OFF | RXR (Read-Xfer-Result) | RBI (Read-Buffer-In) | ||
1531 | * | ||
1532 | * We start in OFF mode, the first xfer_result notification [through | ||
1533 | * wa_handle_notif_xfer()] moves us to RXR by posting the DTI-URB to | ||
1534 | * read. | ||
1535 | * | ||
1536 | * We receive a buffer -- if it is not a xfer_result, we complain and | ||
1537 | * repost the DTI-URB. If it is a xfer_result then do the xfer seg | ||
1538 | * request accounting. If it is an IN segment, we move to RBI and post | ||
1539 | * a BUF-IN-URB to the right buffer. The BUF-IN-URB callback will | ||
1540 | * repost the DTI-URB and move to RXR state. if there was no IN | ||
1541 | * segment, it will repost the DTI-URB. | ||
1542 | * | ||
1543 | * We go back to OFF when we detect a ENOENT or ESHUTDOWN (or too many | ||
1544 | * errors) in the URBs. | ||
1545 | */ | ||
1546 | static void wa_xfer_result_cb(struct urb *urb) | ||
1547 | { | ||
1548 | int result; | ||
1549 | struct wahc *wa = urb->context; | ||
1550 | struct device *dev = &wa->usb_iface->dev; | ||
1551 | struct wa_xfer_result *xfer_result; | ||
1552 | u32 xfer_id; | ||
1553 | struct wa_xfer *xfer; | ||
1554 | u8 usb_status; | ||
1555 | |||
1556 | d_fnstart(3, dev, "(%p)\n", wa); | ||
1557 | BUG_ON(wa->dti_urb != urb); | ||
1558 | switch (wa->dti_urb->status) { | ||
1559 | case 0: | ||
1560 | /* We have a xfer result buffer; check it */ | ||
1561 | d_printf(2, dev, "DTI: xfer result %d bytes at %p\n", | ||
1562 | urb->actual_length, urb->transfer_buffer); | ||
1563 | d_dump(3, dev, urb->transfer_buffer, urb->actual_length); | ||
1564 | if (wa->dti_urb->actual_length != sizeof(*xfer_result)) { | ||
1565 | dev_err(dev, "DTI Error: xfer result--bad size " | ||
1566 | "xfer result (%d bytes vs %zu needed)\n", | ||
1567 | urb->actual_length, sizeof(*xfer_result)); | ||
1568 | break; | ||
1569 | } | ||
1570 | xfer_result = wa->xfer_result; | ||
1571 | if (xfer_result->hdr.bLength != sizeof(*xfer_result)) { | ||
1572 | dev_err(dev, "DTI Error: xfer result--" | ||
1573 | "bad header length %u\n", | ||
1574 | xfer_result->hdr.bLength); | ||
1575 | break; | ||
1576 | } | ||
1577 | if (xfer_result->hdr.bNotifyType != WA_XFER_RESULT) { | ||
1578 | dev_err(dev, "DTI Error: xfer result--" | ||
1579 | "bad header type 0x%02x\n", | ||
1580 | xfer_result->hdr.bNotifyType); | ||
1581 | break; | ||
1582 | } | ||
1583 | usb_status = xfer_result->bTransferStatus & 0x3f; | ||
1584 | if (usb_status == WA_XFER_STATUS_ABORTED | ||
1585 | || usb_status == WA_XFER_STATUS_NOT_FOUND) | ||
1586 | /* taken care of already */ | ||
1587 | break; | ||
1588 | xfer_id = xfer_result->dwTransferID; | ||
1589 | xfer = wa_xfer_get_by_id(wa, xfer_id); | ||
1590 | if (xfer == NULL) { | ||
1591 | /* FIXME: transaction might have been cancelled */ | ||
1592 | dev_err(dev, "DTI Error: xfer result--" | ||
1593 | "unknown xfer 0x%08x (status 0x%02x)\n", | ||
1594 | xfer_id, usb_status); | ||
1595 | break; | ||
1596 | } | ||
1597 | wa_xfer_result_chew(wa, xfer); | ||
1598 | wa_xfer_put(xfer); | ||
1599 | break; | ||
1600 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
1601 | case -ESHUTDOWN: /* going away! */ | ||
1602 | dev_dbg(dev, "DTI: going down! %d\n", urb->status); | ||
1603 | goto out; | ||
1604 | default: | ||
1605 | /* Unknown error */ | ||
1606 | if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, | ||
1607 | EDC_ERROR_TIMEFRAME)) { | ||
1608 | dev_err(dev, "DTI: URB max acceptable errors " | ||
1609 | "exceeded, resetting device\n"); | ||
1610 | wa_reset_all(wa); | ||
1611 | goto out; | ||
1612 | } | ||
1613 | if (printk_ratelimit()) | ||
1614 | dev_err(dev, "DTI: URB error %d\n", urb->status); | ||
1615 | break; | ||
1616 | } | ||
1617 | /* Resubmit the DTI URB */ | ||
1618 | result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC); | ||
1619 | if (result < 0) { | ||
1620 | dev_err(dev, "DTI Error: Could not submit DTI URB (%d), " | ||
1621 | "resetting\n", result); | ||
1622 | wa_reset_all(wa); | ||
1623 | } | ||
1624 | out: | ||
1625 | d_fnend(3, dev, "(%p) = void\n", wa); | ||
1626 | return; | ||
1627 | } | ||
1628 | |||
1629 | /* | ||
1630 | * Transfer complete notification | ||
1631 | * | ||
1632 | * Called from the notif.c code. We get a notification on EP2 saying | ||
1633 | * that some endpoint has some transfer result data available. We are | ||
1634 | * about to read it. | ||
1635 | * | ||
1636 | * To speed up things, we always have a URB reading the DTI URB; we | ||
1637 | * don't really set it up and start it until the first xfer complete | ||
1638 | * notification arrives, which is what we do here. | ||
1639 | * | ||
1640 | * Follow up in wa_xfer_result_cb(), as that's where the whole state | ||
1641 | * machine starts. | ||
1642 | * | ||
1643 | * So here we just initialize the DTI URB for reading transfer result | ||
1644 | * notifications and also the buffer-in URB, for reading buffers. Then | ||
1645 | * we just submit the DTI URB. | ||
1646 | * | ||
1647 | * @wa shall be referenced | ||
1648 | */ | ||
1649 | void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr) | ||
1650 | { | ||
1651 | int result; | ||
1652 | struct device *dev = &wa->usb_iface->dev; | ||
1653 | struct wa_notif_xfer *notif_xfer; | ||
1654 | const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd; | ||
1655 | |||
1656 | d_fnstart(4, dev, "(%p, %p)\n", wa, notif_hdr); | ||
1657 | notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr); | ||
1658 | BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER); | ||
1659 | |||
1660 | if ((0x80 | notif_xfer->bEndpoint) != dti_epd->bEndpointAddress) { | ||
1661 | /* FIXME: hardcoded limitation, adapt */ | ||
1662 | dev_err(dev, "BUG: DTI ep is %u, not %u (hack me)\n", | ||
1663 | notif_xfer->bEndpoint, dti_epd->bEndpointAddress); | ||
1664 | goto error; | ||
1665 | } | ||
1666 | if (wa->dti_urb != NULL) /* DTI URB already started */ | ||
1667 | goto out; | ||
1668 | |||
1669 | wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
1670 | if (wa->dti_urb == NULL) { | ||
1671 | dev_err(dev, "Can't allocate DTI URB\n"); | ||
1672 | goto error_dti_urb_alloc; | ||
1673 | } | ||
1674 | usb_fill_bulk_urb( | ||
1675 | wa->dti_urb, wa->usb_dev, | ||
1676 | usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint), | ||
1677 | wa->xfer_result, wa->xfer_result_size, | ||
1678 | wa_xfer_result_cb, wa); | ||
1679 | |||
1680 | wa->buf_in_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
1681 | if (wa->buf_in_urb == NULL) { | ||
1682 | dev_err(dev, "Can't allocate BUF-IN URB\n"); | ||
1683 | goto error_buf_in_urb_alloc; | ||
1684 | } | ||
1685 | usb_fill_bulk_urb( | ||
1686 | wa->buf_in_urb, wa->usb_dev, | ||
1687 | usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint), | ||
1688 | NULL, 0, wa_buf_in_cb, wa); | ||
1689 | result = usb_submit_urb(wa->dti_urb, GFP_KERNEL); | ||
1690 | if (result < 0) { | ||
1691 | dev_err(dev, "DTI Error: Could not submit DTI URB (%d), " | ||
1692 | "resetting\n", result); | ||
1693 | goto error_dti_urb_submit; | ||
1694 | } | ||
1695 | out: | ||
1696 | d_fnend(4, dev, "(%p, %p) = void\n", wa, notif_hdr); | ||
1697 | return; | ||
1698 | |||
1699 | error_dti_urb_submit: | ||
1700 | usb_put_urb(wa->buf_in_urb); | ||
1701 | error_buf_in_urb_alloc: | ||
1702 | usb_put_urb(wa->dti_urb); | ||
1703 | wa->dti_urb = NULL; | ||
1704 | error_dti_urb_alloc: | ||
1705 | error: | ||
1706 | wa_reset_all(wa); | ||
1707 | d_fnend(4, dev, "(%p, %p) = void\n", wa, notif_hdr); | ||
1708 | return; | ||
1709 | } | ||
diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c new file mode 100644 index 000000000000..07c63a31c799 --- /dev/null +++ b/drivers/usb/wusbcore/wusbhc.c | |||
@@ -0,0 +1,418 @@ | |||
1 | /* | ||
2 | * Wireless USB Host Controller | ||
3 | * sysfs glue, wusbcore module support and life cycle management | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Intel Corporation | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * Creation/destruction of wusbhc is split in two parts; that that | ||
25 | * doesn't require the HCD to be added (wusbhc_{create,destroy}) and | ||
26 | * the one that requires (phase B, wusbhc_b_{create,destroy}). | ||
27 | * | ||
28 | * This is so because usb_add_hcd() will start the HC, and thus, all | ||
29 | * the HC specific stuff has to be already initialiazed (like sysfs | ||
30 | * thingies). | ||
31 | */ | ||
32 | #include <linux/device.h> | ||
33 | #include <linux/module.h> | ||
34 | #include "wusbhc.h" | ||
35 | |||
36 | /** | ||
37 | * Extract the wusbhc that corresponds to a USB Host Controller class device | ||
38 | * | ||
39 | * WARNING! Apply only if @dev is that of a | ||
40 | * wusbhc.usb_hcd.self->class_dev; otherwise, you loose. | ||
41 | */ | ||
42 | static struct wusbhc *usbhc_dev_to_wusbhc(struct device *dev) | ||
43 | { | ||
44 | struct usb_bus *usb_bus = dev_get_drvdata(dev); | ||
45 | struct usb_hcd *usb_hcd = bus_to_hcd(usb_bus); | ||
46 | return usb_hcd_to_wusbhc(usb_hcd); | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * Show & store the current WUSB trust timeout | ||
51 | * | ||
52 | * We don't do locking--it is an 'atomic' value. | ||
53 | * | ||
54 | * The units that we store/show are always MILLISECONDS. However, the | ||
55 | * value of trust_timeout is jiffies. | ||
56 | */ | ||
57 | static ssize_t wusb_trust_timeout_show(struct device *dev, | ||
58 | struct device_attribute *attr, char *buf) | ||
59 | { | ||
60 | struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); | ||
61 | |||
62 | return scnprintf(buf, PAGE_SIZE, "%u\n", wusbhc->trust_timeout); | ||
63 | } | ||
64 | |||
65 | static ssize_t wusb_trust_timeout_store(struct device *dev, | ||
66 | struct device_attribute *attr, | ||
67 | const char *buf, size_t size) | ||
68 | { | ||
69 | struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); | ||
70 | ssize_t result = -ENOSYS; | ||
71 | unsigned trust_timeout; | ||
72 | |||
73 | result = sscanf(buf, "%u", &trust_timeout); | ||
74 | if (result != 1) { | ||
75 | result = -EINVAL; | ||
76 | goto out; | ||
77 | } | ||
78 | /* FIXME: maybe we should check for range validity? */ | ||
79 | wusbhc->trust_timeout = trust_timeout; | ||
80 | cancel_delayed_work(&wusbhc->keep_alive_timer); | ||
81 | flush_workqueue(wusbd); | ||
82 | queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, | ||
83 | (trust_timeout * CONFIG_HZ)/1000/2); | ||
84 | out: | ||
85 | return result < 0 ? result : size; | ||
86 | } | ||
87 | static DEVICE_ATTR(wusb_trust_timeout, 0644, wusb_trust_timeout_show, | ||
88 | wusb_trust_timeout_store); | ||
89 | |||
90 | /* | ||
91 | * Show & store the current WUSB CHID | ||
92 | */ | ||
93 | static ssize_t wusb_chid_show(struct device *dev, | ||
94 | struct device_attribute *attr, char *buf) | ||
95 | { | ||
96 | struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); | ||
97 | ssize_t result = 0; | ||
98 | |||
99 | if (wusbhc->wuie_host_info != NULL) | ||
100 | result += ckhdid_printf(buf, PAGE_SIZE, | ||
101 | &wusbhc->wuie_host_info->CHID); | ||
102 | return result; | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Store a new CHID | ||
107 | * | ||
108 | * This will (FIXME) trigger many changes. | ||
109 | * | ||
110 | * - Send an all zeros CHID and it will stop the controller | ||
111 | * - Send a non-zero CHID and it will start it | ||
112 | * (unless it was started, it will just change the CHID, | ||
113 | * diconnecting all devices first). | ||
114 | * | ||
115 | * So first we scan the MMC we are sent and then we act on it. We | ||
116 | * read it in the same format as we print it, an ASCII string of 16 | ||
117 | * hex bytes. | ||
118 | * | ||
119 | * See wusbhc_chid_set() for more info. | ||
120 | */ | ||
121 | static ssize_t wusb_chid_store(struct device *dev, | ||
122 | struct device_attribute *attr, | ||
123 | const char *buf, size_t size) | ||
124 | { | ||
125 | struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); | ||
126 | struct wusb_ckhdid chid; | ||
127 | ssize_t result; | ||
128 | |||
129 | result = sscanf(buf, | ||
130 | "%02hhx %02hhx %02hhx %02hhx " | ||
131 | "%02hhx %02hhx %02hhx %02hhx " | ||
132 | "%02hhx %02hhx %02hhx %02hhx " | ||
133 | "%02hhx %02hhx %02hhx %02hhx\n", | ||
134 | &chid.data[0] , &chid.data[1] , | ||
135 | &chid.data[2] , &chid.data[3] , | ||
136 | &chid.data[4] , &chid.data[5] , | ||
137 | &chid.data[6] , &chid.data[7] , | ||
138 | &chid.data[8] , &chid.data[9] , | ||
139 | &chid.data[10], &chid.data[11], | ||
140 | &chid.data[12], &chid.data[13], | ||
141 | &chid.data[14], &chid.data[15]); | ||
142 | if (result != 16) { | ||
143 | dev_err(dev, "Unrecognized CHID (need 16 8-bit hex digits): " | ||
144 | "%d\n", (int)result); | ||
145 | return -EINVAL; | ||
146 | } | ||
147 | result = wusbhc_chid_set(wusbhc, &chid); | ||
148 | return result < 0 ? result : size; | ||
149 | } | ||
150 | static DEVICE_ATTR(wusb_chid, 0644, wusb_chid_show, wusb_chid_store); | ||
151 | |||
152 | /* Group all the WUSBHC attributes */ | ||
153 | static struct attribute *wusbhc_attrs[] = { | ||
154 | &dev_attr_wusb_trust_timeout.attr, | ||
155 | &dev_attr_wusb_chid.attr, | ||
156 | NULL, | ||
157 | }; | ||
158 | |||
159 | static struct attribute_group wusbhc_attr_group = { | ||
160 | .name = NULL, /* we want them in the same directory */ | ||
161 | .attrs = wusbhc_attrs, | ||
162 | }; | ||
163 | |||
164 | /* | ||
165 | * Create a wusbhc instance | ||
166 | * | ||
167 | * NOTEs: | ||
168 | * | ||
169 | * - assumes *wusbhc has been zeroed and wusbhc->usb_hcd has been | ||
170 | * initialized but not added. | ||
171 | * | ||
172 | * - fill out ports_max, mmcies_max and mmcie_{add,rm} before calling. | ||
173 | * | ||
174 | * - fill out wusbhc->uwb_rc and refcount it before calling | ||
175 | * - fill out the wusbhc->sec_modes array | ||
176 | */ | ||
177 | int wusbhc_create(struct wusbhc *wusbhc) | ||
178 | { | ||
179 | int result = 0; | ||
180 | |||
181 | wusbhc->trust_timeout = WUSB_TRUST_TIMEOUT_MS; | ||
182 | mutex_init(&wusbhc->mutex); | ||
183 | result = wusbhc_mmcie_create(wusbhc); | ||
184 | if (result < 0) | ||
185 | goto error_mmcie_create; | ||
186 | result = wusbhc_devconnect_create(wusbhc); | ||
187 | if (result < 0) | ||
188 | goto error_devconnect_create; | ||
189 | result = wusbhc_rh_create(wusbhc); | ||
190 | if (result < 0) | ||
191 | goto error_rh_create; | ||
192 | result = wusbhc_sec_create(wusbhc); | ||
193 | if (result < 0) | ||
194 | goto error_sec_create; | ||
195 | return 0; | ||
196 | |||
197 | error_sec_create: | ||
198 | wusbhc_rh_destroy(wusbhc); | ||
199 | error_rh_create: | ||
200 | wusbhc_devconnect_destroy(wusbhc); | ||
201 | error_devconnect_create: | ||
202 | wusbhc_mmcie_destroy(wusbhc); | ||
203 | error_mmcie_create: | ||
204 | return result; | ||
205 | } | ||
206 | EXPORT_SYMBOL_GPL(wusbhc_create); | ||
207 | |||
208 | static inline struct kobject *wusbhc_kobj(struct wusbhc *wusbhc) | ||
209 | { | ||
210 | return &wusbhc->usb_hcd.self.controller->kobj; | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * Phase B of a wusbhc instance creation | ||
215 | * | ||
216 | * Creates fields that depend on wusbhc->usb_hcd having been | ||
217 | * added. This is where we create the sysfs files in | ||
218 | * /sys/class/usb_host/usb_hostX/. | ||
219 | * | ||
220 | * NOTE: Assumes wusbhc->usb_hcd has been already added by the upper | ||
221 | * layer (hwahc or whci) | ||
222 | */ | ||
223 | int wusbhc_b_create(struct wusbhc *wusbhc) | ||
224 | { | ||
225 | int result = 0; | ||
226 | struct device *dev = wusbhc->usb_hcd.self.controller; | ||
227 | |||
228 | result = sysfs_create_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group); | ||
229 | if (result < 0) { | ||
230 | dev_err(dev, "Cannot register WUSBHC attributes: %d\n", result); | ||
231 | goto error_create_attr_group; | ||
232 | } | ||
233 | |||
234 | result = wusbhc_pal_register(wusbhc); | ||
235 | if (result < 0) | ||
236 | goto error_pal_register; | ||
237 | return 0; | ||
238 | |||
239 | error_pal_register: | ||
240 | sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group); | ||
241 | error_create_attr_group: | ||
242 | return result; | ||
243 | } | ||
244 | EXPORT_SYMBOL_GPL(wusbhc_b_create); | ||
245 | |||
246 | void wusbhc_b_destroy(struct wusbhc *wusbhc) | ||
247 | { | ||
248 | wusbhc_pal_unregister(wusbhc); | ||
249 | sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group); | ||
250 | } | ||
251 | EXPORT_SYMBOL_GPL(wusbhc_b_destroy); | ||
252 | |||
253 | void wusbhc_destroy(struct wusbhc *wusbhc) | ||
254 | { | ||
255 | wusbhc_sec_destroy(wusbhc); | ||
256 | wusbhc_rh_destroy(wusbhc); | ||
257 | wusbhc_devconnect_destroy(wusbhc); | ||
258 | wusbhc_mmcie_destroy(wusbhc); | ||
259 | } | ||
260 | EXPORT_SYMBOL_GPL(wusbhc_destroy); | ||
261 | |||
262 | struct workqueue_struct *wusbd; | ||
263 | EXPORT_SYMBOL_GPL(wusbd); | ||
264 | |||
265 | /* | ||
266 | * WUSB Cluster ID allocation map | ||
267 | * | ||
268 | * Each WUSB bus in a channel is identified with a Cluster Id in the | ||
269 | * unauth address pace (WUSB1.0[4.3]). We take the range 0xe0 to 0xff | ||
270 | * (that's space for 31 WUSB controllers, as 0xff can't be taken). We | ||
271 | * start taking from 0xff, 0xfe, 0xfd... (hence the += or -= 0xff). | ||
272 | * | ||
273 | * For each one we taken, we pin it in the bitap | ||
274 | */ | ||
275 | #define CLUSTER_IDS 32 | ||
276 | static DECLARE_BITMAP(wusb_cluster_id_table, CLUSTER_IDS); | ||
277 | static DEFINE_SPINLOCK(wusb_cluster_ids_lock); | ||
278 | |||
279 | /* | ||
280 | * Get a WUSB Cluster ID | ||
281 | * | ||
282 | * Need to release with wusb_cluster_id_put() when done w/ it. | ||
283 | */ | ||
284 | /* FIXME: coordinate with the choose_addres() from the USB stack */ | ||
285 | /* we want to leave the top of the 128 range for cluster addresses and | ||
286 | * the bottom for device addresses (as we map them one on one with | ||
287 | * ports). */ | ||
288 | u8 wusb_cluster_id_get(void) | ||
289 | { | ||
290 | u8 id; | ||
291 | spin_lock(&wusb_cluster_ids_lock); | ||
292 | id = find_first_zero_bit(wusb_cluster_id_table, CLUSTER_IDS); | ||
293 | if (id > CLUSTER_IDS) { | ||
294 | id = 0; | ||
295 | goto out; | ||
296 | } | ||
297 | set_bit(id, wusb_cluster_id_table); | ||
298 | id = (u8) 0xff - id; | ||
299 | out: | ||
300 | spin_unlock(&wusb_cluster_ids_lock); | ||
301 | return id; | ||
302 | |||
303 | } | ||
304 | EXPORT_SYMBOL_GPL(wusb_cluster_id_get); | ||
305 | |||
306 | /* | ||
307 | * Release a WUSB Cluster ID | ||
308 | * | ||
309 | * Obtained it with wusb_cluster_id_get() | ||
310 | */ | ||
311 | void wusb_cluster_id_put(u8 id) | ||
312 | { | ||
313 | id = 0xff - id; | ||
314 | BUG_ON(id >= CLUSTER_IDS); | ||
315 | spin_lock(&wusb_cluster_ids_lock); | ||
316 | WARN_ON(!test_bit(id, wusb_cluster_id_table)); | ||
317 | clear_bit(id, wusb_cluster_id_table); | ||
318 | spin_unlock(&wusb_cluster_ids_lock); | ||
319 | } | ||
320 | EXPORT_SYMBOL_GPL(wusb_cluster_id_put); | ||
321 | |||
322 | /** | ||
323 | * wusbhc_giveback_urb - return an URB to the USB core | ||
324 | * @wusbhc: the host controller the URB is from. | ||
325 | * @urb: the URB. | ||
326 | * @status: the URB's status. | ||
327 | * | ||
328 | * Return an URB to the USB core doing some additional WUSB specific | ||
329 | * processing. | ||
330 | * | ||
331 | * - After a successful transfer, update the trust timeout timestamp | ||
332 | * for the WUSB device. | ||
333 | * | ||
334 | * - [WUSB] sections 4.13 and 7.5.1 specifies the stop retrasmittion | ||
335 | * condition for the WCONNECTACK_IE is that the host has observed | ||
336 | * the associated device responding to a control transfer. | ||
337 | */ | ||
338 | void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, int status) | ||
339 | { | ||
340 | struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev); | ||
341 | |||
342 | if (status == 0) { | ||
343 | wusb_dev->entry_ts = jiffies; | ||
344 | |||
345 | /* wusbhc_devconnect_acked() can't be called from from | ||
346 | atomic context so defer it to a work queue. */ | ||
347 | if (!list_empty(&wusb_dev->cack_node)) | ||
348 | queue_work(wusbd, &wusb_dev->devconnect_acked_work); | ||
349 | } | ||
350 | |||
351 | usb_hcd_giveback_urb(&wusbhc->usb_hcd, urb, status); | ||
352 | } | ||
353 | EXPORT_SYMBOL_GPL(wusbhc_giveback_urb); | ||
354 | |||
355 | /** | ||
356 | * wusbhc_reset_all - reset the HC hardware | ||
357 | * @wusbhc: the host controller to reset. | ||
358 | * | ||
359 | * Request a full hardware reset of the chip. This will also reset | ||
360 | * the radio controller and any other PALs. | ||
361 | */ | ||
362 | void wusbhc_reset_all(struct wusbhc *wusbhc) | ||
363 | { | ||
364 | uwb_rc_reset_all(wusbhc->uwb_rc); | ||
365 | } | ||
366 | EXPORT_SYMBOL_GPL(wusbhc_reset_all); | ||
367 | |||
368 | static struct notifier_block wusb_usb_notifier = { | ||
369 | .notifier_call = wusb_usb_ncb, | ||
370 | .priority = INT_MAX /* Need to be called first of all */ | ||
371 | }; | ||
372 | |||
373 | static int __init wusbcore_init(void) | ||
374 | { | ||
375 | int result; | ||
376 | result = wusb_crypto_init(); | ||
377 | if (result < 0) | ||
378 | goto error_crypto_init; | ||
379 | /* WQ is singlethread because we need to serialize notifications */ | ||
380 | wusbd = create_singlethread_workqueue("wusbd"); | ||
381 | if (wusbd == NULL) { | ||
382 | result = -ENOMEM; | ||
383 | printk(KERN_ERR "WUSB-core: Cannot create wusbd workqueue\n"); | ||
384 | goto error_wusbd_create; | ||
385 | } | ||
386 | usb_register_notify(&wusb_usb_notifier); | ||
387 | bitmap_zero(wusb_cluster_id_table, CLUSTER_IDS); | ||
388 | set_bit(0, wusb_cluster_id_table); /* reserve Cluster ID 0xff */ | ||
389 | return 0; | ||
390 | |||
391 | error_wusbd_create: | ||
392 | wusb_crypto_exit(); | ||
393 | error_crypto_init: | ||
394 | return result; | ||
395 | |||
396 | } | ||
397 | module_init(wusbcore_init); | ||
398 | |||
399 | static void __exit wusbcore_exit(void) | ||
400 | { | ||
401 | clear_bit(0, wusb_cluster_id_table); | ||
402 | if (!bitmap_empty(wusb_cluster_id_table, CLUSTER_IDS)) { | ||
403 | char buf[256]; | ||
404 | bitmap_scnprintf(buf, sizeof(buf), wusb_cluster_id_table, | ||
405 | CLUSTER_IDS); | ||
406 | printk(KERN_ERR "BUG: WUSB Cluster IDs not released " | ||
407 | "on exit: %s\n", buf); | ||
408 | WARN_ON(1); | ||
409 | } | ||
410 | usb_unregister_notify(&wusb_usb_notifier); | ||
411 | destroy_workqueue(wusbd); | ||
412 | wusb_crypto_exit(); | ||
413 | } | ||
414 | module_exit(wusbcore_exit); | ||
415 | |||
416 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
417 | MODULE_DESCRIPTION("Wireless USB core"); | ||
418 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h new file mode 100644 index 000000000000..d0c132434f1b --- /dev/null +++ b/drivers/usb/wusbcore/wusbhc.h | |||
@@ -0,0 +1,495 @@ | |||
1 | /* | ||
2 | * Wireless USB Host Controller | ||
3 | * Common infrastructure for WHCI and HWA WUSB-HC drivers | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Intel Corporation | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * This driver implements parts common to all Wireless USB Host | ||
25 | * Controllers (struct wusbhc, embedding a struct usb_hcd) and is used | ||
26 | * by: | ||
27 | * | ||
28 | * - hwahc: HWA, USB-dongle that implements a Wireless USB host | ||
29 | * controller, (Wireless USB 1.0 Host-Wire-Adapter specification). | ||
30 | * | ||
31 | * - whci: WHCI, a PCI card with a wireless host controller | ||
32 | * (Wireless Host Controller Interface 1.0 specification). | ||
33 | * | ||
34 | * Check out the Design-overview.txt file in the source documentation | ||
35 | * for other details on the implementation. | ||
36 | * | ||
37 | * Main blocks: | ||
38 | * | ||
39 | * rh Root Hub emulation (part of the HCD glue) | ||
40 | * | ||
41 | * devconnect Handle all the issues related to device connection, | ||
42 | * authentication, disconnection, timeout, reseting, | ||
43 | * keepalives, etc. | ||
44 | * | ||
45 | * mmc MMC IE broadcasting handling | ||
46 | * | ||
47 | * A host controller driver just initializes its stuff and as part of | ||
48 | * that, creates a 'struct wusbhc' instance that handles all the | ||
49 | * common WUSB mechanisms. Links in the function ops that are specific | ||
50 | * to it and then registers the host controller. Ready to run. | ||
51 | */ | ||
52 | |||
53 | #ifndef __WUSBHC_H__ | ||
54 | #define __WUSBHC_H__ | ||
55 | |||
56 | #include <linux/usb.h> | ||
57 | #include <linux/list.h> | ||
58 | #include <linux/mutex.h> | ||
59 | #include <linux/kref.h> | ||
60 | #include <linux/workqueue.h> | ||
61 | /* FIXME: Yes, I know: BAD--it's not my fault the USB HC iface is not | ||
62 | * public */ | ||
63 | #include <linux/../../drivers/usb/core/hcd.h> | ||
64 | #include <linux/uwb.h> | ||
65 | #include <linux/usb/wusb.h> | ||
66 | |||
67 | |||
68 | /** | ||
69 | * Wireless USB device | ||
70 | * | ||
71 | * Describe a WUSB device connected to the cluster. This struct | ||
72 | * belongs to the 'struct wusb_port' it is attached to and it is | ||
73 | * responsible for putting and clearing the pointer to it. | ||
74 | * | ||
75 | * Note this "complements" the 'struct usb_device' that the usb_hcd | ||
76 | * keeps for each connected USB device. However, it extends some | ||
77 | * information that is not available (there is no hcpriv ptr in it!) | ||
78 | * *and* most importantly, it's life cycle is different. It is created | ||
79 | * as soon as we get a DN_Connect (connect request notification) from | ||
80 | * the device through the WUSB host controller; the USB stack doesn't | ||
81 | * create the device until we authenticate it. FIXME: this will | ||
82 | * change. | ||
83 | * | ||
84 | * @bos: This is allocated when the BOS descriptors are read from | ||
85 | * the device and freed upon the wusb_dev struct dying. | ||
86 | * @wusb_cap_descr: points into @bos, and has been verified to be size | ||
87 | * safe. | ||
88 | */ | ||
89 | struct wusb_dev { | ||
90 | struct kref refcnt; | ||
91 | struct wusbhc *wusbhc; | ||
92 | struct list_head cack_node; /* Connect-Ack list */ | ||
93 | u8 port_idx; | ||
94 | u8 addr; | ||
95 | u8 beacon_type:4; | ||
96 | struct usb_encryption_descriptor ccm1_etd; | ||
97 | struct wusb_ckhdid cdid; | ||
98 | unsigned long entry_ts; | ||
99 | struct usb_bos_descriptor *bos; | ||
100 | struct usb_wireless_cap_descriptor *wusb_cap_descr; | ||
101 | struct uwb_mas_bm availability; | ||
102 | struct work_struct devconnect_acked_work; | ||
103 | struct urb *set_gtk_urb; | ||
104 | struct usb_ctrlrequest *set_gtk_req; | ||
105 | struct usb_device *usb_dev; | ||
106 | }; | ||
107 | |||
108 | #define WUSB_DEV_ADDR_UNAUTH 0x80 | ||
109 | |||
110 | static inline void wusb_dev_init(struct wusb_dev *wusb_dev) | ||
111 | { | ||
112 | kref_init(&wusb_dev->refcnt); | ||
113 | /* no need to init the cack_node */ | ||
114 | } | ||
115 | |||
116 | extern void wusb_dev_destroy(struct kref *_wusb_dev); | ||
117 | |||
118 | static inline struct wusb_dev *wusb_dev_get(struct wusb_dev *wusb_dev) | ||
119 | { | ||
120 | kref_get(&wusb_dev->refcnt); | ||
121 | return wusb_dev; | ||
122 | } | ||
123 | |||
124 | static inline void wusb_dev_put(struct wusb_dev *wusb_dev) | ||
125 | { | ||
126 | kref_put(&wusb_dev->refcnt, wusb_dev_destroy); | ||
127 | } | ||
128 | |||
129 | /** | ||
130 | * Wireless USB Host Controlller root hub "fake" ports | ||
131 | * (state and device information) | ||
132 | * | ||
133 | * Wireless USB is wireless, so there are no ports; but we | ||
134 | * fake'em. Each RC can connect a max of devices at the same time | ||
135 | * (given in the Wireless Adapter descriptor, bNumPorts or WHCI's | ||
136 | * caps), referred to in wusbhc->ports_max. | ||
137 | * | ||
138 | * See rh.c for more information. | ||
139 | * | ||
140 | * The @status and @change use the same bits as in USB2.0[11.24.2.7], | ||
141 | * so we don't have to do much when getting the port's status. | ||
142 | * | ||
143 | * WUSB1.0[7.1], USB2.0[11.24.2.7.1,fig 11-10], | ||
144 | * include/linux/usb_ch9.h (#define USB_PORT_STAT_*) | ||
145 | */ | ||
146 | struct wusb_port { | ||
147 | u16 status; | ||
148 | u16 change; | ||
149 | struct wusb_dev *wusb_dev; /* connected device's info */ | ||
150 | unsigned reset_count; | ||
151 | u32 ptk_tkid; | ||
152 | }; | ||
153 | |||
154 | /** | ||
155 | * WUSB Host Controller specifics | ||
156 | * | ||
157 | * All fields that are common to all Wireless USB controller types | ||
158 | * (HWA and WHCI) are grouped here. Host Controller | ||
159 | * functions/operations that only deal with general Wireless USB HC | ||
160 | * issues use this data type to refer to the host. | ||
161 | * | ||
162 | * @usb_hcd Instantiation of a USB host controller | ||
163 | * (initialized by upper layer [HWA=HC or WHCI]. | ||
164 | * | ||
165 | * @dev Device that implements this; initialized by the | ||
166 | * upper layer (HWA-HC, WHCI...); this device should | ||
167 | * have a refcount. | ||
168 | * | ||
169 | * @trust_timeout After this time without hearing for device | ||
170 | * activity, we consider the device gone and we have to | ||
171 | * re-authenticate. | ||
172 | * | ||
173 | * Can be accessed w/o locking--however, read to a | ||
174 | * local variable then use. | ||
175 | * | ||
176 | * @chid WUSB Cluster Host ID: this is supposed to be a | ||
177 | * unique value that doesn't change across reboots (so | ||
178 | * that your devices do not require re-association). | ||
179 | * | ||
180 | * Read/Write protected by @mutex | ||
181 | * | ||
182 | * @dev_info This array has ports_max elements. It is used to | ||
183 | * give the HC information about the WUSB devices (see | ||
184 | * 'struct wusb_dev_info'). | ||
185 | * | ||
186 | * For HWA we need to allocate it in heap; for WHCI it | ||
187 | * needs to be permanently mapped, so we keep it for | ||
188 | * both and make it easy. Call wusbhc->dev_info_set() | ||
189 | * to update an entry. | ||
190 | * | ||
191 | * @ports_max Number of simultaneous device connections (fake | ||
192 | * ports) this HC will take. Read-only. | ||
193 | * | ||
194 | * @port Array of port status for each fake root port. Guaranteed to | ||
195 | * always be the same lenght during device existence | ||
196 | * [this allows for some unlocked but referenced reading]. | ||
197 | * | ||
198 | * @mmcies_max Max number of Information Elements this HC can send | ||
199 | * in its MMC. Read-only. | ||
200 | * | ||
201 | * @mmcie_add HC specific operation (WHCI or HWA) for adding an | ||
202 | * MMCIE. | ||
203 | * | ||
204 | * @mmcie_rm HC specific operation (WHCI or HWA) for removing an | ||
205 | * MMCIE. | ||
206 | * | ||
207 | * @enc_types Array which describes the encryptions methods | ||
208 | * supported by the host as described in WUSB1.0 -- | ||
209 | * one entry per supported method. As of WUSB1.0 there | ||
210 | * is only four methods, we make space for eight just in | ||
211 | * case they decide to add some more (and pray they do | ||
212 | * it in sequential order). if 'enc_types[enc_method] | ||
213 | * != 0', then it is supported by the host. enc_method | ||
214 | * is USB_ENC_TYPE*. | ||
215 | * | ||
216 | * @set_ptk: Set the PTK and enable encryption for a device. Or, if | ||
217 | * the supplied key is NULL, disable encryption for that | ||
218 | * device. | ||
219 | * | ||
220 | * @set_gtk: Set the GTK to be used for all future broadcast packets | ||
221 | * (i.e., MMCs). With some hardware, setting the GTK may start | ||
222 | * MMC transmission. | ||
223 | * | ||
224 | * NOTE: | ||
225 | * | ||
226 | * - If wusb_dev->usb_dev is not NULL, then usb_dev is valid | ||
227 | * (wusb_dev has a refcount on it). Likewise, if usb_dev->wusb_dev | ||
228 | * is not NULL, usb_dev->wusb_dev is valid (usb_dev keeps a | ||
229 | * refcount on it). | ||
230 | * | ||
231 | * Most of the times when you need to use it, it will be non-NULL, | ||
232 | * so there is no real need to check for it (wusb_dev will | ||
233 | * dissapear before usb_dev). | ||
234 | * | ||
235 | * - The following fields need to be filled out before calling | ||
236 | * wusbhc_create(): ports_max, mmcies_max, mmcie_{add,rm}. | ||
237 | * | ||
238 | * - there is no wusbhc_init() method, we do everything in | ||
239 | * wusbhc_create(). | ||
240 | * | ||
241 | * - Creation is done in two phases, wusbhc_create() and | ||
242 | * wusbhc_create_b(); b are the parts that need to be called after | ||
243 | * calling usb_hcd_add(&wusbhc->usb_hcd). | ||
244 | */ | ||
245 | struct wusbhc { | ||
246 | struct usb_hcd usb_hcd; /* HAS TO BE 1st */ | ||
247 | struct device *dev; | ||
248 | struct uwb_rc *uwb_rc; | ||
249 | struct uwb_pal pal; | ||
250 | |||
251 | unsigned trust_timeout; /* in jiffies */ | ||
252 | struct wuie_host_info *wuie_host_info; /* Includes CHID */ | ||
253 | |||
254 | struct mutex mutex; /* locks everything else */ | ||
255 | u16 cluster_id; /* Wireless USB Cluster ID */ | ||
256 | struct wusb_port *port; /* Fake port status handling */ | ||
257 | struct wusb_dev_info *dev_info; /* for Set Device Info mgmt */ | ||
258 | u8 ports_max; | ||
259 | unsigned active:1; /* currently xmit'ing MMCs */ | ||
260 | struct wuie_keep_alive keep_alive_ie; /* protected by mutex */ | ||
261 | struct delayed_work keep_alive_timer; | ||
262 | struct list_head cack_list; /* Connect acknowledging */ | ||
263 | size_t cack_count; /* protected by 'mutex' */ | ||
264 | struct wuie_connect_ack cack_ie; | ||
265 | struct uwb_rsv *rsv; /* cluster bandwidth reservation */ | ||
266 | |||
267 | struct mutex mmcie_mutex; /* MMC WUIE handling */ | ||
268 | struct wuie_hdr **mmcie; /* WUIE array */ | ||
269 | u8 mmcies_max; | ||
270 | /* FIXME: make wusbhc_ops? */ | ||
271 | int (*start)(struct wusbhc *wusbhc); | ||
272 | void (*stop)(struct wusbhc *wusbhc); | ||
273 | int (*mmcie_add)(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, | ||
274 | u8 handle, struct wuie_hdr *wuie); | ||
275 | int (*mmcie_rm)(struct wusbhc *wusbhc, u8 handle); | ||
276 | int (*dev_info_set)(struct wusbhc *, struct wusb_dev *wusb_dev); | ||
277 | int (*bwa_set)(struct wusbhc *wusbhc, s8 stream_index, | ||
278 | const struct uwb_mas_bm *); | ||
279 | int (*set_ptk)(struct wusbhc *wusbhc, u8 port_idx, | ||
280 | u32 tkid, const void *key, size_t key_size); | ||
281 | int (*set_gtk)(struct wusbhc *wusbhc, | ||
282 | u32 tkid, const void *key, size_t key_size); | ||
283 | int (*set_num_dnts)(struct wusbhc *wusbhc, u8 interval, u8 slots); | ||
284 | |||
285 | struct { | ||
286 | struct usb_key_descriptor descr; | ||
287 | u8 data[16]; /* GTK key data */ | ||
288 | } __attribute__((packed)) gtk; | ||
289 | u8 gtk_index; | ||
290 | u32 gtk_tkid; | ||
291 | struct work_struct gtk_rekey_done_work; | ||
292 | int pending_set_gtks; | ||
293 | |||
294 | struct usb_encryption_descriptor *ccm1_etd; | ||
295 | }; | ||
296 | |||
297 | #define usb_hcd_to_wusbhc(u) container_of((u), struct wusbhc, usb_hcd) | ||
298 | |||
299 | |||
300 | extern int wusbhc_create(struct wusbhc *); | ||
301 | extern int wusbhc_b_create(struct wusbhc *); | ||
302 | extern void wusbhc_b_destroy(struct wusbhc *); | ||
303 | extern void wusbhc_destroy(struct wusbhc *); | ||
304 | extern int wusb_dev_sysfs_add(struct wusbhc *, struct usb_device *, | ||
305 | struct wusb_dev *); | ||
306 | extern void wusb_dev_sysfs_rm(struct wusb_dev *); | ||
307 | extern int wusbhc_sec_create(struct wusbhc *); | ||
308 | extern int wusbhc_sec_start(struct wusbhc *); | ||
309 | extern void wusbhc_sec_stop(struct wusbhc *); | ||
310 | extern void wusbhc_sec_destroy(struct wusbhc *); | ||
311 | extern void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, | ||
312 | int status); | ||
313 | void wusbhc_reset_all(struct wusbhc *wusbhc); | ||
314 | |||
315 | int wusbhc_pal_register(struct wusbhc *wusbhc); | ||
316 | void wusbhc_pal_unregister(struct wusbhc *wusbhc); | ||
317 | |||
318 | /* | ||
319 | * Return @usb_dev's @usb_hcd (properly referenced) or NULL if gone | ||
320 | * | ||
321 | * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr) | ||
322 | * | ||
323 | * This is a safe assumption as @usb_dev->bus is referenced all the | ||
324 | * time during the @usb_dev life cycle. | ||
325 | */ | ||
326 | static inline struct usb_hcd *usb_hcd_get_by_usb_dev(struct usb_device *usb_dev) | ||
327 | { | ||
328 | struct usb_hcd *usb_hcd; | ||
329 | usb_hcd = container_of(usb_dev->bus, struct usb_hcd, self); | ||
330 | return usb_get_hcd(usb_hcd); | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Increment the reference count on a wusbhc. | ||
335 | * | ||
336 | * @wusbhc's life cycle is identical to that of the underlying usb_hcd. | ||
337 | */ | ||
338 | static inline struct wusbhc *wusbhc_get(struct wusbhc *wusbhc) | ||
339 | { | ||
340 | return usb_get_hcd(&wusbhc->usb_hcd) ? wusbhc : NULL; | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * Return the wusbhc associated to a @usb_dev | ||
345 | * | ||
346 | * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr) | ||
347 | * | ||
348 | * @returns: wusbhc for @usb_dev; NULL if the @usb_dev is being torn down. | ||
349 | * WARNING: referenced at the usb_hcd level, unlocked | ||
350 | * | ||
351 | * FIXME: move offline | ||
352 | */ | ||
353 | static inline struct wusbhc *wusbhc_get_by_usb_dev(struct usb_device *usb_dev) | ||
354 | { | ||
355 | struct wusbhc *wusbhc = NULL; | ||
356 | struct usb_hcd *usb_hcd; | ||
357 | if (usb_dev->devnum > 1 && !usb_dev->wusb) { | ||
358 | /* but root hubs */ | ||
359 | dev_err(&usb_dev->dev, "devnum %d wusb %d\n", usb_dev->devnum, | ||
360 | usb_dev->wusb); | ||
361 | BUG_ON(usb_dev->devnum > 1 && !usb_dev->wusb); | ||
362 | } | ||
363 | usb_hcd = usb_hcd_get_by_usb_dev(usb_dev); | ||
364 | if (usb_hcd == NULL) | ||
365 | return NULL; | ||
366 | BUG_ON(usb_hcd->wireless == 0); | ||
367 | return wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
368 | } | ||
369 | |||
370 | |||
371 | static inline void wusbhc_put(struct wusbhc *wusbhc) | ||
372 | { | ||
373 | usb_put_hcd(&wusbhc->usb_hcd); | ||
374 | } | ||
375 | |||
376 | int wusbhc_start(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid); | ||
377 | void wusbhc_stop(struct wusbhc *wusbhc); | ||
378 | extern int wusbhc_chid_set(struct wusbhc *, const struct wusb_ckhdid *); | ||
379 | |||
380 | /* Device connect handling */ | ||
381 | extern int wusbhc_devconnect_create(struct wusbhc *); | ||
382 | extern void wusbhc_devconnect_destroy(struct wusbhc *); | ||
383 | extern int wusbhc_devconnect_start(struct wusbhc *wusbhc, | ||
384 | const struct wusb_ckhdid *chid); | ||
385 | extern void wusbhc_devconnect_stop(struct wusbhc *wusbhc); | ||
386 | extern int wusbhc_devconnect_auth(struct wusbhc *, u8); | ||
387 | extern void wusbhc_handle_dn(struct wusbhc *, u8 srcaddr, | ||
388 | struct wusb_dn_hdr *dn_hdr, size_t size); | ||
389 | extern int wusbhc_dev_reset(struct wusbhc *wusbhc, u8 port); | ||
390 | extern void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port); | ||
391 | extern int wusb_usb_ncb(struct notifier_block *nb, unsigned long val, | ||
392 | void *priv); | ||
393 | extern int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, | ||
394 | u8 addr); | ||
395 | |||
396 | /* Wireless USB fake Root Hub methods */ | ||
397 | extern int wusbhc_rh_create(struct wusbhc *); | ||
398 | extern void wusbhc_rh_destroy(struct wusbhc *); | ||
399 | |||
400 | extern int wusbhc_rh_status_data(struct usb_hcd *, char *); | ||
401 | extern int wusbhc_rh_control(struct usb_hcd *, u16, u16, u16, char *, u16); | ||
402 | extern int wusbhc_rh_suspend(struct usb_hcd *); | ||
403 | extern int wusbhc_rh_resume(struct usb_hcd *); | ||
404 | extern int wusbhc_rh_start_port_reset(struct usb_hcd *, unsigned); | ||
405 | |||
406 | /* MMC handling */ | ||
407 | extern int wusbhc_mmcie_create(struct wusbhc *); | ||
408 | extern void wusbhc_mmcie_destroy(struct wusbhc *); | ||
409 | extern int wusbhc_mmcie_set(struct wusbhc *, u8 interval, u8 repeat_cnt, | ||
410 | struct wuie_hdr *); | ||
411 | extern void wusbhc_mmcie_rm(struct wusbhc *, struct wuie_hdr *); | ||
412 | |||
413 | /* Bandwidth reservation */ | ||
414 | int wusbhc_rsv_establish(struct wusbhc *wusbhc); | ||
415 | void wusbhc_rsv_terminate(struct wusbhc *wusbhc); | ||
416 | |||
417 | /* | ||
418 | * I've always said | ||
419 | * I wanted a wedding in a church... | ||
420 | * | ||
421 | * but lately I've been thinking about | ||
422 | * the Botanical Gardens. | ||
423 | * | ||
424 | * We could do it by the tulips. | ||
425 | * It'll be beautiful | ||
426 | * | ||
427 | * --Security! | ||
428 | */ | ||
429 | extern int wusb_dev_sec_add(struct wusbhc *, struct usb_device *, | ||
430 | struct wusb_dev *); | ||
431 | extern void wusb_dev_sec_rm(struct wusb_dev *) ; | ||
432 | extern int wusb_dev_4way_handshake(struct wusbhc *, struct wusb_dev *, | ||
433 | struct wusb_ckhdid *ck); | ||
434 | void wusbhc_gtk_rekey(struct wusbhc *wusbhc); | ||
435 | |||
436 | |||
437 | /* WUSB Cluster ID handling */ | ||
438 | extern u8 wusb_cluster_id_get(void); | ||
439 | extern void wusb_cluster_id_put(u8); | ||
440 | |||
441 | /* | ||
442 | * wusb_port_by_idx - return the port associated to a zero-based port index | ||
443 | * | ||
444 | * NOTE: valid without locking as long as wusbhc is referenced (as the | ||
445 | * number of ports doesn't change). The data pointed to has to | ||
446 | * be verified though :) | ||
447 | */ | ||
448 | static inline struct wusb_port *wusb_port_by_idx(struct wusbhc *wusbhc, | ||
449 | u8 port_idx) | ||
450 | { | ||
451 | return &wusbhc->port[port_idx]; | ||
452 | } | ||
453 | |||
454 | /* | ||
455 | * wusb_port_no_to_idx - Convert port number (per usb_dev->portnum) to | ||
456 | * a port_idx. | ||
457 | * | ||
458 | * USB stack USB ports are 1 based!! | ||
459 | * | ||
460 | * NOTE: only valid for WUSB devices!!! | ||
461 | */ | ||
462 | static inline u8 wusb_port_no_to_idx(u8 port_no) | ||
463 | { | ||
464 | return port_no - 1; | ||
465 | } | ||
466 | |||
467 | extern struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *, | ||
468 | struct usb_device *); | ||
469 | |||
470 | /* | ||
471 | * Return a referenced wusb_dev given a @usb_dev | ||
472 | * | ||
473 | * Returns NULL if the usb_dev is being torn down. | ||
474 | * | ||
475 | * FIXME: move offline | ||
476 | */ | ||
477 | static inline | ||
478 | struct wusb_dev *wusb_dev_get_by_usb_dev(struct usb_device *usb_dev) | ||
479 | { | ||
480 | struct wusbhc *wusbhc; | ||
481 | struct wusb_dev *wusb_dev; | ||
482 | wusbhc = wusbhc_get_by_usb_dev(usb_dev); | ||
483 | if (wusbhc == NULL) | ||
484 | return NULL; | ||
485 | mutex_lock(&wusbhc->mutex); | ||
486 | wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev); | ||
487 | mutex_unlock(&wusbhc->mutex); | ||
488 | wusbhc_put(wusbhc); | ||
489 | return wusb_dev; | ||
490 | } | ||
491 | |||
492 | /* Misc */ | ||
493 | |||
494 | extern struct workqueue_struct *wusbd; | ||
495 | #endif /* #ifndef __WUSBHC_H__ */ | ||