diff options
author | David Lopo <dlopo@chipidea.mips.com> | 2008-11-17 17:14:51 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-07 12:59:58 -0500 |
commit | aa69a8093ff985873cb44fe1157bd6db29a20fe4 (patch) | |
tree | c3cf9484e9f9a607e3076fd538f57246b482c1ed /drivers/usb/gadget | |
parent | bb9496c6f7e853e5d4edd5397c9d45f1968d623c (diff) |
USB: gadget: MIPS ci13xxx_udc
MIPS USB IP core family device controller
Currently it only supports IP part number CI13412.
[dbrownell@users.sourceforge.net: minor comment tweaks]
Signed-off-by: David Lopo <dlopo@chipidea.mips.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 18 | ||||
-rw-r--r-- | drivers/usb/gadget/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/ci13xxx_udc.c | 2830 | ||||
-rw-r--r-- | drivers/usb/gadget/ci13xxx_udc.h | 195 | ||||
-rw-r--r-- | drivers/usb/gadget/gadget_chips.h | 7 |
5 files changed, 3051 insertions, 0 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index dd4cd5a51370..cf3a662c3335 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig | |||
@@ -377,6 +377,24 @@ config USB_FSL_QE | |||
377 | default USB_GADGET | 377 | default USB_GADGET |
378 | select USB_GADGET_SELECTED | 378 | select USB_GADGET_SELECTED |
379 | 379 | ||
380 | config USB_GADGET_CI13XXX | ||
381 | boolean "MIPS USB CI13xxx" | ||
382 | depends on PCI | ||
383 | select USB_GADGET_DUALSPEED | ||
384 | help | ||
385 | MIPS USB IP core family device controller | ||
386 | Currently it only supports IP part number CI13412 | ||
387 | |||
388 | Say "y" to link the driver statically, or "m" to build a | ||
389 | dynamically linked module called "ci13xxx_udc" and force all | ||
390 | gadget drivers to also be dynamically linked. | ||
391 | |||
392 | config USB_CI13XXX | ||
393 | tristate | ||
394 | depends on USB_GADGET_CI13XXX | ||
395 | default USB_GADGET | ||
396 | select USB_GADGET_SELECTED | ||
397 | |||
380 | config USB_GADGET_NET2280 | 398 | config USB_GADGET_NET2280 |
381 | boolean "NetChip 228x" | 399 | boolean "NetChip 228x" |
382 | depends on PCI | 400 | depends on PCI |
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index bd4041b47dce..5d64a2ab1889 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o | |||
19 | obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o | 19 | obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o |
20 | obj-$(CONFIG_USB_M66592) += m66592-udc.o | 20 | obj-$(CONFIG_USB_M66592) += m66592-udc.o |
21 | obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o | 21 | obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o |
22 | obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o | ||
22 | 23 | ||
23 | # | 24 | # |
24 | # USB gadget drivers | 25 | # USB gadget drivers |
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c new file mode 100644 index 000000000000..bebf911c7e5f --- /dev/null +++ b/drivers/usb/gadget/ci13xxx_udc.c | |||
@@ -0,0 +1,2830 @@ | |||
1 | /* | ||
2 | * ci13xxx_udc.c - MIPS USB IP core family device controller | ||
3 | * | ||
4 | * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. | ||
5 | * | ||
6 | * Author: David Lopo | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * Description: MIPS USB IP core family device controller | ||
15 | * Currently it only supports IP part number CI13412 | ||
16 | * | ||
17 | * This driver is composed of several blocks: | ||
18 | * - HW: hardware interface | ||
19 | * - DBG: debug facilities (optional) | ||
20 | * - UTIL: utilities | ||
21 | * - ISR: interrupts handling | ||
22 | * - ENDPT: endpoint operations (Gadget API) | ||
23 | * - GADGET: gadget operations (Gadget API) | ||
24 | * - BUS: bus glue code, bus abstraction layer | ||
25 | * - PCI: PCI core interface and PCI resources (interrupts, memory...) | ||
26 | * | ||
27 | * Compile Options | ||
28 | * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities | ||
29 | * - STALL_IN: non-empty bulk-in pipes cannot be halted | ||
30 | * if defined mass storage compliance succeeds but with warnings | ||
31 | * => case 4: Hi > Dn | ||
32 | * => case 5: Hi > Di | ||
33 | * => case 8: Hi <> Do | ||
34 | * if undefined usbtest 13 fails | ||
35 | * - TRACE: enable function tracing (depends on DEBUG) | ||
36 | * | ||
37 | * Main Features | ||
38 | * - Chapter 9 & Mass Storage Compliance with Gadget File Storage | ||
39 | * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined) | ||
40 | * - Normal & LPM support | ||
41 | * | ||
42 | * USBTEST Report | ||
43 | * - OK: 0-12, 13 (STALL_IN defined) & 14 | ||
44 | * - Not Supported: 15 & 16 (ISO) | ||
45 | * | ||
46 | * TODO List | ||
47 | * - OTG | ||
48 | * - Isochronous & Interrupt Traffic | ||
49 | * - Handle requests which spawns into several TDs | ||
50 | * - GET_STATUS(device) - always reports 0 | ||
51 | * - Gadget API (majority of optional features) | ||
52 | * - Suspend & Remote Wakeup | ||
53 | */ | ||
54 | #include <linux/device.h> | ||
55 | #include <linux/dmapool.h> | ||
56 | #include <linux/dma-mapping.h> | ||
57 | #include <linux/init.h> | ||
58 | #include <linux/interrupt.h> | ||
59 | #include <linux/interrupt.h> | ||
60 | #include <linux/io.h> | ||
61 | #include <linux/irq.h> | ||
62 | #include <linux/kernel.h> | ||
63 | #include <linux/module.h> | ||
64 | #include <linux/pci.h> | ||
65 | #include <linux/usb/ch9.h> | ||
66 | #include <linux/usb/gadget.h> | ||
67 | |||
68 | #include "ci13xxx_udc.h" | ||
69 | |||
70 | |||
71 | /****************************************************************************** | ||
72 | * DEFINE | ||
73 | *****************************************************************************/ | ||
74 | /* ctrl register bank access */ | ||
75 | static DEFINE_SPINLOCK(udc_lock); | ||
76 | |||
77 | /* driver name */ | ||
78 | #define UDC_DRIVER_NAME "ci13xxx_udc" | ||
79 | |||
80 | /* control endpoint description */ | ||
81 | static const struct usb_endpoint_descriptor | ||
82 | ctrl_endpt_desc = { | ||
83 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
84 | .bDescriptorType = USB_DT_ENDPOINT, | ||
85 | |||
86 | .bmAttributes = USB_ENDPOINT_XFER_CONTROL, | ||
87 | .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), | ||
88 | }; | ||
89 | |||
90 | /* UDC descriptor */ | ||
91 | static struct ci13xxx *_udc; | ||
92 | |||
93 | /* Interrupt statistics */ | ||
94 | #define ISR_MASK 0x1F | ||
95 | static struct { | ||
96 | u32 test; | ||
97 | u32 ui; | ||
98 | u32 uei; | ||
99 | u32 pci; | ||
100 | u32 uri; | ||
101 | u32 sli; | ||
102 | u32 none; | ||
103 | struct { | ||
104 | u32 cnt; | ||
105 | u32 buf[ISR_MASK+1]; | ||
106 | u32 idx; | ||
107 | } hndl; | ||
108 | } isr_statistics; | ||
109 | |||
110 | /** | ||
111 | * ffs_nr: find first (least significant) bit set | ||
112 | * @x: the word to search | ||
113 | * | ||
114 | * This function returns bit number (instead of position) | ||
115 | */ | ||
116 | static int ffs_nr(u32 x) | ||
117 | { | ||
118 | int n = ffs(x); | ||
119 | |||
120 | return n ? n-1 : 32; | ||
121 | } | ||
122 | |||
123 | /****************************************************************************** | ||
124 | * HW block | ||
125 | *****************************************************************************/ | ||
126 | /* register bank descriptor */ | ||
127 | static struct { | ||
128 | unsigned lpm; /* is LPM? */ | ||
129 | void __iomem *abs; /* bus map offset */ | ||
130 | void __iomem *cap; /* bus map offset + CAP offset + CAP data */ | ||
131 | size_t size; /* bank size */ | ||
132 | } hw_bank; | ||
133 | |||
134 | /* UDC register map */ | ||
135 | #define ABS_CAPLENGTH (0x100UL) | ||
136 | #define ABS_HCCPARAMS (0x108UL) | ||
137 | #define ABS_DCCPARAMS (0x124UL) | ||
138 | #define ABS_TESTMODE (hw_bank.lpm ? 0x0FCUL : 0x138UL) | ||
139 | /* offset to CAPLENTGH (addr + data) */ | ||
140 | #define CAP_USBCMD (0x000UL) | ||
141 | #define CAP_USBSTS (0x004UL) | ||
142 | #define CAP_USBINTR (0x008UL) | ||
143 | #define CAP_DEVICEADDR (0x014UL) | ||
144 | #define CAP_ENDPTLISTADDR (0x018UL) | ||
145 | #define CAP_PORTSC (0x044UL) | ||
146 | #define CAP_DEVLC (0x0B4UL) | ||
147 | #define CAP_USBMODE (hw_bank.lpm ? 0x0C8UL : 0x068UL) | ||
148 | #define CAP_ENDPTSETUPSTAT (hw_bank.lpm ? 0x0D8UL : 0x06CUL) | ||
149 | #define CAP_ENDPTPRIME (hw_bank.lpm ? 0x0DCUL : 0x070UL) | ||
150 | #define CAP_ENDPTFLUSH (hw_bank.lpm ? 0x0E0UL : 0x074UL) | ||
151 | #define CAP_ENDPTSTAT (hw_bank.lpm ? 0x0E4UL : 0x078UL) | ||
152 | #define CAP_ENDPTCOMPLETE (hw_bank.lpm ? 0x0E8UL : 0x07CUL) | ||
153 | #define CAP_ENDPTCTRL (hw_bank.lpm ? 0x0ECUL : 0x080UL) | ||
154 | #define CAP_LAST (hw_bank.lpm ? 0x12CUL : 0x0C0UL) | ||
155 | |||
156 | /* maximum number of enpoints: valid only after hw_device_reset() */ | ||
157 | static unsigned hw_ep_max; | ||
158 | |||
159 | /** | ||
160 | * hw_ep_bit: calculates the bit number | ||
161 | * @num: endpoint number | ||
162 | * @dir: endpoint direction | ||
163 | * | ||
164 | * This function returns bit number | ||
165 | */ | ||
166 | static inline int hw_ep_bit(int num, int dir) | ||
167 | { | ||
168 | return num + (dir ? 16 : 0); | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * hw_aread: reads from register bitfield | ||
173 | * @addr: address relative to bus map | ||
174 | * @mask: bitfield mask | ||
175 | * | ||
176 | * This function returns register bitfield data | ||
177 | */ | ||
178 | static u32 hw_aread(u32 addr, u32 mask) | ||
179 | { | ||
180 | return ioread32(addr + hw_bank.abs) & mask; | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * hw_awrite: writes to register bitfield | ||
185 | * @addr: address relative to bus map | ||
186 | * @mask: bitfield mask | ||
187 | * @data: new data | ||
188 | */ | ||
189 | static void hw_awrite(u32 addr, u32 mask, u32 data) | ||
190 | { | ||
191 | iowrite32(hw_aread(addr, ~mask) | (data & mask), | ||
192 | addr + hw_bank.abs); | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * hw_cread: reads from register bitfield | ||
197 | * @addr: address relative to CAP offset plus content | ||
198 | * @mask: bitfield mask | ||
199 | * | ||
200 | * This function returns register bitfield data | ||
201 | */ | ||
202 | static u32 hw_cread(u32 addr, u32 mask) | ||
203 | { | ||
204 | return ioread32(addr + hw_bank.cap) & mask; | ||
205 | } | ||
206 | |||
207 | /** | ||
208 | * hw_cwrite: writes to register bitfield | ||
209 | * @addr: address relative to CAP offset plus content | ||
210 | * @mask: bitfield mask | ||
211 | * @data: new data | ||
212 | */ | ||
213 | static void hw_cwrite(u32 addr, u32 mask, u32 data) | ||
214 | { | ||
215 | iowrite32(hw_cread(addr, ~mask) | (data & mask), | ||
216 | addr + hw_bank.cap); | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * hw_ctest_and_clear: tests & clears register bitfield | ||
221 | * @addr: address relative to CAP offset plus content | ||
222 | * @mask: bitfield mask | ||
223 | * | ||
224 | * This function returns register bitfield data | ||
225 | */ | ||
226 | static u32 hw_ctest_and_clear(u32 addr, u32 mask) | ||
227 | { | ||
228 | u32 reg = hw_cread(addr, mask); | ||
229 | |||
230 | iowrite32(reg, addr + hw_bank.cap); | ||
231 | return reg; | ||
232 | } | ||
233 | |||
234 | /** | ||
235 | * hw_ctest_and_write: tests & writes register bitfield | ||
236 | * @addr: address relative to CAP offset plus content | ||
237 | * @mask: bitfield mask | ||
238 | * @data: new data | ||
239 | * | ||
240 | * This function returns register bitfield data | ||
241 | */ | ||
242 | static u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data) | ||
243 | { | ||
244 | u32 reg = hw_cread(addr, ~0); | ||
245 | |||
246 | iowrite32((reg & ~mask) | (data & mask), addr + hw_bank.cap); | ||
247 | return (reg & mask) >> ffs_nr(mask); | ||
248 | } | ||
249 | |||
250 | /** | ||
251 | * hw_device_reset: resets chip (execute without interruption) | ||
252 | * @base: register base address | ||
253 | * | ||
254 | * This function returns an error code | ||
255 | */ | ||
256 | static int hw_device_reset(void __iomem *base) | ||
257 | { | ||
258 | u32 reg; | ||
259 | |||
260 | /* bank is a module variable */ | ||
261 | hw_bank.abs = base; | ||
262 | |||
263 | hw_bank.cap = hw_bank.abs; | ||
264 | hw_bank.cap += ABS_CAPLENGTH; | ||
265 | hw_bank.cap += ioread8(hw_bank.cap); | ||
266 | |||
267 | reg = hw_aread(ABS_HCCPARAMS, HCCPARAMS_LEN) >> ffs_nr(HCCPARAMS_LEN); | ||
268 | hw_bank.lpm = reg; | ||
269 | hw_bank.size = hw_bank.cap - hw_bank.abs; | ||
270 | hw_bank.size += CAP_LAST; | ||
271 | hw_bank.size /= sizeof(u32); | ||
272 | |||
273 | /* should flush & stop before reset */ | ||
274 | hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); | ||
275 | hw_cwrite(CAP_USBCMD, USBCMD_RS, 0); | ||
276 | |||
277 | hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST); | ||
278 | while (hw_cread(CAP_USBCMD, USBCMD_RST)) | ||
279 | udelay(10); /* not RTOS friendly */ | ||
280 | |||
281 | /* USBMODE should be configured step by step */ | ||
282 | hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); | ||
283 | hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE); | ||
284 | hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); /* HW >= 2.3 */ | ||
285 | |||
286 | if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) { | ||
287 | pr_err("cannot enter in device mode"); | ||
288 | pr_err("lpm = %i", hw_bank.lpm); | ||
289 | return -ENODEV; | ||
290 | } | ||
291 | |||
292 | reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN); | ||
293 | if (reg == 0 || reg > ENDPT_MAX) | ||
294 | return -ENODEV; | ||
295 | |||
296 | hw_ep_max = reg; /* cache hw ENDPT_MAX */ | ||
297 | |||
298 | /* setup lock mode ? */ | ||
299 | |||
300 | /* ENDPTSETUPSTAT is '0' by default */ | ||
301 | |||
302 | /* HCSPARAMS.bf.ppc SHOULD BE zero for device */ | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | /** | ||
308 | * hw_device_state: enables/disables interrupts & starts/stops device (execute | ||
309 | * without interruption) | ||
310 | * @dma: 0 => disable, !0 => enable and set dma engine | ||
311 | * | ||
312 | * This function returns an error code | ||
313 | */ | ||
314 | static int hw_device_state(u32 dma) | ||
315 | { | ||
316 | if (dma) { | ||
317 | hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma); | ||
318 | /* interrupt, error, port change, reset, sleep/suspend */ | ||
319 | hw_cwrite(CAP_USBINTR, ~0, | ||
320 | USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI); | ||
321 | hw_cwrite(CAP_USBCMD, USBCMD_RS, USBCMD_RS); | ||
322 | } else { | ||
323 | hw_cwrite(CAP_USBCMD, USBCMD_RS, 0); | ||
324 | hw_cwrite(CAP_USBINTR, ~0, 0); | ||
325 | } | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | /** | ||
330 | * hw_ep_flush: flush endpoint fifo (execute without interruption) | ||
331 | * @num: endpoint number | ||
332 | * @dir: endpoint direction | ||
333 | * | ||
334 | * This function returns an error code | ||
335 | */ | ||
336 | static int hw_ep_flush(int num, int dir) | ||
337 | { | ||
338 | int n = hw_ep_bit(num, dir); | ||
339 | |||
340 | do { | ||
341 | /* flush any pending transfer */ | ||
342 | hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n)); | ||
343 | while (hw_cread(CAP_ENDPTFLUSH, BIT(n))) | ||
344 | cpu_relax(); | ||
345 | } while (hw_cread(CAP_ENDPTSTAT, BIT(n))); | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * hw_ep_disable: disables endpoint (execute without interruption) | ||
352 | * @num: endpoint number | ||
353 | * @dir: endpoint direction | ||
354 | * | ||
355 | * This function returns an error code | ||
356 | */ | ||
357 | static int hw_ep_disable(int num, int dir) | ||
358 | { | ||
359 | hw_ep_flush(num, dir); | ||
360 | hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), | ||
361 | dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0); | ||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | /** | ||
366 | * hw_ep_enable: enables endpoint (execute without interruption) | ||
367 | * @num: endpoint number | ||
368 | * @dir: endpoint direction | ||
369 | * @type: endpoint type | ||
370 | * | ||
371 | * This function returns an error code | ||
372 | */ | ||
373 | static int hw_ep_enable(int num, int dir, int type) | ||
374 | { | ||
375 | u32 mask, data; | ||
376 | |||
377 | if (dir) { | ||
378 | mask = ENDPTCTRL_TXT; /* type */ | ||
379 | data = type << ffs_nr(mask); | ||
380 | |||
381 | mask |= ENDPTCTRL_TXS; /* unstall */ | ||
382 | mask |= ENDPTCTRL_TXR; /* reset data toggle */ | ||
383 | data |= ENDPTCTRL_TXR; | ||
384 | mask |= ENDPTCTRL_TXE; /* enable */ | ||
385 | data |= ENDPTCTRL_TXE; | ||
386 | } else { | ||
387 | mask = ENDPTCTRL_RXT; /* type */ | ||
388 | data = type << ffs_nr(mask); | ||
389 | |||
390 | mask |= ENDPTCTRL_RXS; /* unstall */ | ||
391 | mask |= ENDPTCTRL_RXR; /* reset data toggle */ | ||
392 | data |= ENDPTCTRL_RXR; | ||
393 | mask |= ENDPTCTRL_RXE; /* enable */ | ||
394 | data |= ENDPTCTRL_RXE; | ||
395 | } | ||
396 | hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), mask, data); | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | /** | ||
401 | * hw_ep_get_halt: return endpoint halt status | ||
402 | * @num: endpoint number | ||
403 | * @dir: endpoint direction | ||
404 | * | ||
405 | * This function returns 1 if endpoint halted | ||
406 | */ | ||
407 | static int hw_ep_get_halt(int num, int dir) | ||
408 | { | ||
409 | u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; | ||
410 | |||
411 | return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0; | ||
412 | } | ||
413 | |||
414 | /** | ||
415 | * hw_ep_is_primed: test if endpoint is primed (execute without interruption) | ||
416 | * @num: endpoint number | ||
417 | * @dir: endpoint direction | ||
418 | * | ||
419 | * This function returns true if endpoint primed | ||
420 | */ | ||
421 | static int hw_ep_is_primed(int num, int dir) | ||
422 | { | ||
423 | u32 reg = hw_cread(CAP_ENDPTPRIME, ~0) | hw_cread(CAP_ENDPTSTAT, ~0); | ||
424 | |||
425 | return test_bit(hw_ep_bit(num, dir), (void *)®); | ||
426 | } | ||
427 | |||
428 | /** | ||
429 | * hw_test_and_clear_setup_status: test & clear setup status (execute without | ||
430 | * interruption) | ||
431 | * @n: bit number (endpoint) | ||
432 | * | ||
433 | * This function returns setup status | ||
434 | */ | ||
435 | static int hw_test_and_clear_setup_status(int n) | ||
436 | { | ||
437 | return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n)); | ||
438 | } | ||
439 | |||
440 | /** | ||
441 | * hw_ep_prime: primes endpoint (execute without interruption) | ||
442 | * @num: endpoint number | ||
443 | * @dir: endpoint direction | ||
444 | * @is_ctrl: true if control endpoint | ||
445 | * | ||
446 | * This function returns an error code | ||
447 | */ | ||
448 | static int hw_ep_prime(int num, int dir, int is_ctrl) | ||
449 | { | ||
450 | int n = hw_ep_bit(num, dir); | ||
451 | |||
452 | /* the caller should flush first */ | ||
453 | if (hw_ep_is_primed(num, dir)) | ||
454 | return -EBUSY; | ||
455 | |||
456 | if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) | ||
457 | return -EAGAIN; | ||
458 | |||
459 | hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n)); | ||
460 | |||
461 | while (hw_cread(CAP_ENDPTPRIME, BIT(n))) | ||
462 | cpu_relax(); | ||
463 | if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) | ||
464 | return -EAGAIN; | ||
465 | |||
466 | /* status shoult be tested according with manual but it doesn't work */ | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | /** | ||
471 | * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute | ||
472 | * without interruption) | ||
473 | * @num: endpoint number | ||
474 | * @dir: endpoint direction | ||
475 | * @value: true => stall, false => unstall | ||
476 | * | ||
477 | * This function returns an error code | ||
478 | */ | ||
479 | static int hw_ep_set_halt(int num, int dir, int value) | ||
480 | { | ||
481 | if (value != 0 && value != 1) | ||
482 | return -EINVAL; | ||
483 | |||
484 | do { | ||
485 | u32 addr = CAP_ENDPTCTRL + num * sizeof(u32); | ||
486 | u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; | ||
487 | u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR; | ||
488 | |||
489 | /* data toggle - reserved for EP0 but it's in ESS */ | ||
490 | hw_cwrite(addr, mask_xs|mask_xr, value ? mask_xs : mask_xr); | ||
491 | |||
492 | } while (value != hw_ep_get_halt(num, dir)); | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | /** | ||
498 | * hw_intr_clear: disables interrupt & clears interrupt status (execute without | ||
499 | * interruption) | ||
500 | * @n: interrupt bit | ||
501 | * | ||
502 | * This function returns an error code | ||
503 | */ | ||
504 | static int hw_intr_clear(int n) | ||
505 | { | ||
506 | if (n >= REG_BITS) | ||
507 | return -EINVAL; | ||
508 | |||
509 | hw_cwrite(CAP_USBINTR, BIT(n), 0); | ||
510 | hw_cwrite(CAP_USBSTS, BIT(n), BIT(n)); | ||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | /** | ||
515 | * hw_intr_force: enables interrupt & forces interrupt status (execute without | ||
516 | * interruption) | ||
517 | * @n: interrupt bit | ||
518 | * | ||
519 | * This function returns an error code | ||
520 | */ | ||
521 | static int hw_intr_force(int n) | ||
522 | { | ||
523 | if (n >= REG_BITS) | ||
524 | return -EINVAL; | ||
525 | |||
526 | hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE); | ||
527 | hw_cwrite(CAP_USBINTR, BIT(n), BIT(n)); | ||
528 | hw_cwrite(CAP_USBSTS, BIT(n), BIT(n)); | ||
529 | hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, 0); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | /** | ||
534 | * hw_is_port_high_speed: test if port is high speed | ||
535 | * | ||
536 | * This function returns true if high speed port | ||
537 | */ | ||
538 | static int hw_port_is_high_speed(void) | ||
539 | { | ||
540 | return hw_bank.lpm ? hw_cread(CAP_DEVLC, DEVLC_PSPD) : | ||
541 | hw_cread(CAP_PORTSC, PORTSC_HSP); | ||
542 | } | ||
543 | |||
544 | /** | ||
545 | * hw_port_test_get: reads port test mode value | ||
546 | * | ||
547 | * This function returns port test mode value | ||
548 | */ | ||
549 | static u8 hw_port_test_get(void) | ||
550 | { | ||
551 | return hw_cread(CAP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC); | ||
552 | } | ||
553 | |||
554 | /** | ||
555 | * hw_port_test_set: writes port test mode (execute without interruption) | ||
556 | * @mode: new value | ||
557 | * | ||
558 | * This function returns an error code | ||
559 | */ | ||
560 | static int hw_port_test_set(u8 mode) | ||
561 | { | ||
562 | const u8 TEST_MODE_MAX = 7; | ||
563 | |||
564 | if (mode > TEST_MODE_MAX) | ||
565 | return -EINVAL; | ||
566 | |||
567 | hw_cwrite(CAP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC)); | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | /** | ||
572 | * hw_read_intr_enable: returns interrupt enable register | ||
573 | * | ||
574 | * This function returns register data | ||
575 | */ | ||
576 | static u32 hw_read_intr_enable(void) | ||
577 | { | ||
578 | return hw_cread(CAP_USBINTR, ~0); | ||
579 | } | ||
580 | |||
581 | /** | ||
582 | * hw_read_intr_status: returns interrupt status register | ||
583 | * | ||
584 | * This function returns register data | ||
585 | */ | ||
586 | static u32 hw_read_intr_status(void) | ||
587 | { | ||
588 | return hw_cread(CAP_USBSTS, ~0); | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * hw_register_read: reads all device registers (execute without interruption) | ||
593 | * @buf: destination buffer | ||
594 | * @size: buffer size | ||
595 | * | ||
596 | * This function returns number of registers read | ||
597 | */ | ||
598 | static size_t hw_register_read(u32 *buf, size_t size) | ||
599 | { | ||
600 | unsigned i; | ||
601 | |||
602 | if (size > hw_bank.size) | ||
603 | size = hw_bank.size; | ||
604 | |||
605 | for (i = 0; i < size; i++) | ||
606 | buf[i] = hw_aread(i * sizeof(u32), ~0); | ||
607 | |||
608 | return size; | ||
609 | } | ||
610 | |||
611 | /** | ||
612 | * hw_register_write: writes to register | ||
613 | * @addr: register address | ||
614 | * @data: register value | ||
615 | * | ||
616 | * This function returns an error code | ||
617 | */ | ||
618 | static int hw_register_write(u16 addr, u32 data) | ||
619 | { | ||
620 | /* align */ | ||
621 | addr /= sizeof(u32); | ||
622 | |||
623 | if (addr >= hw_bank.size) | ||
624 | return -EINVAL; | ||
625 | |||
626 | /* align */ | ||
627 | addr *= sizeof(u32); | ||
628 | |||
629 | hw_awrite(addr, ~0, data); | ||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | /** | ||
634 | * hw_test_and_clear_complete: test & clear complete status (execute without | ||
635 | * interruption) | ||
636 | * @n: bit number (endpoint) | ||
637 | * | ||
638 | * This function returns complete status | ||
639 | */ | ||
640 | static int hw_test_and_clear_complete(int n) | ||
641 | { | ||
642 | return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n)); | ||
643 | } | ||
644 | |||
645 | /** | ||
646 | * hw_test_and_clear_intr_active: test & clear active interrupts (execute | ||
647 | * without interruption) | ||
648 | * | ||
649 | * This function returns active interrutps | ||
650 | */ | ||
651 | static u32 hw_test_and_clear_intr_active(void) | ||
652 | { | ||
653 | u32 reg = hw_read_intr_status() & hw_read_intr_enable(); | ||
654 | |||
655 | hw_cwrite(CAP_USBSTS, ~0, reg); | ||
656 | return reg; | ||
657 | } | ||
658 | |||
659 | /** | ||
660 | * hw_test_and_clear_setup_guard: test & clear setup guard (execute without | ||
661 | * interruption) | ||
662 | * | ||
663 | * This function returns guard value | ||
664 | */ | ||
665 | static int hw_test_and_clear_setup_guard(void) | ||
666 | { | ||
667 | return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, 0); | ||
668 | } | ||
669 | |||
670 | /** | ||
671 | * hw_test_and_set_setup_guard: test & set setup guard (execute without | ||
672 | * interruption) | ||
673 | * | ||
674 | * This function returns guard value | ||
675 | */ | ||
676 | static int hw_test_and_set_setup_guard(void) | ||
677 | { | ||
678 | return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, USBCMD_SUTW); | ||
679 | } | ||
680 | |||
681 | /** | ||
682 | * hw_usb_set_address: configures USB address (execute without interruption) | ||
683 | * @value: new USB address | ||
684 | * | ||
685 | * This function returns an error code | ||
686 | */ | ||
687 | static int hw_usb_set_address(u8 value) | ||
688 | { | ||
689 | /* advance */ | ||
690 | hw_cwrite(CAP_DEVICEADDR, DEVICEADDR_USBADR | DEVICEADDR_USBADRA, | ||
691 | value << ffs_nr(DEVICEADDR_USBADR) | DEVICEADDR_USBADRA); | ||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | /** | ||
696 | * hw_usb_reset: restart device after a bus reset (execute without | ||
697 | * interruption) | ||
698 | * | ||
699 | * This function returns an error code | ||
700 | */ | ||
701 | static int hw_usb_reset(void) | ||
702 | { | ||
703 | hw_usb_set_address(0); | ||
704 | |||
705 | /* ESS flushes only at end?!? */ | ||
706 | hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); /* flush all EPs */ | ||
707 | |||
708 | /* clear setup token semaphores */ | ||
709 | hw_cwrite(CAP_ENDPTSETUPSTAT, 0, 0); /* writes its content */ | ||
710 | |||
711 | /* clear complete status */ | ||
712 | hw_cwrite(CAP_ENDPTCOMPLETE, 0, 0); /* writes its content */ | ||
713 | |||
714 | /* wait until all bits cleared */ | ||
715 | while (hw_cread(CAP_ENDPTPRIME, ~0)) | ||
716 | udelay(10); /* not RTOS friendly */ | ||
717 | |||
718 | /* reset all endpoints ? */ | ||
719 | |||
720 | /* reset internal status and wait for further instructions | ||
721 | no need to verify the port reset status (ESS does it) */ | ||
722 | |||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | /****************************************************************************** | ||
727 | * DBG block | ||
728 | *****************************************************************************/ | ||
729 | /** | ||
730 | * show_device: prints information about device capabilities and status | ||
731 | * | ||
732 | * Check "device.h" for details | ||
733 | */ | ||
734 | static ssize_t show_device(struct device *dev, struct device_attribute *attr, | ||
735 | char *buf) | ||
736 | { | ||
737 | struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); | ||
738 | struct usb_gadget *gadget = &udc->gadget; | ||
739 | int n = 0; | ||
740 | |||
741 | dbg_trace("[%s] %p\n", __func__, buf); | ||
742 | if (attr == NULL || buf == NULL) { | ||
743 | dev_err(dev, "[%s] EINVAL\n", __func__); | ||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n", | ||
748 | gadget->speed); | ||
749 | n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n", | ||
750 | gadget->is_dualspeed); | ||
751 | n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n", | ||
752 | gadget->is_otg); | ||
753 | n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n", | ||
754 | gadget->is_a_peripheral); | ||
755 | n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n", | ||
756 | gadget->b_hnp_enable); | ||
757 | n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n", | ||
758 | gadget->a_hnp_support); | ||
759 | n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n", | ||
760 | gadget->a_alt_hnp_support); | ||
761 | n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n", | ||
762 | (gadget->name ? gadget->name : "")); | ||
763 | |||
764 | return n; | ||
765 | } | ||
766 | static DEVICE_ATTR(device, S_IRUSR, show_device, NULL); | ||
767 | |||
768 | /** | ||
769 | * show_driver: prints information about attached gadget (if any) | ||
770 | * | ||
771 | * Check "device.h" for details | ||
772 | */ | ||
773 | static ssize_t show_driver(struct device *dev, struct device_attribute *attr, | ||
774 | char *buf) | ||
775 | { | ||
776 | struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); | ||
777 | struct usb_gadget_driver *driver = udc->driver; | ||
778 | int n = 0; | ||
779 | |||
780 | dbg_trace("[%s] %p\n", __func__, buf); | ||
781 | if (attr == NULL || buf == NULL) { | ||
782 | dev_err(dev, "[%s] EINVAL\n", __func__); | ||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | if (driver == NULL) | ||
787 | return scnprintf(buf, PAGE_SIZE, | ||
788 | "There is no gadget attached!\n"); | ||
789 | |||
790 | n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n", | ||
791 | (driver->function ? driver->function : "")); | ||
792 | n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n", | ||
793 | driver->speed); | ||
794 | |||
795 | return n; | ||
796 | } | ||
797 | static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL); | ||
798 | |||
799 | /* Maximum event message length */ | ||
800 | #define DBG_DATA_MSG 64UL | ||
801 | |||
802 | /* Maximum event messages */ | ||
803 | #define DBG_DATA_MAX 128UL | ||
804 | |||
805 | /* Event buffer descriptor */ | ||
806 | static struct { | ||
807 | char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */ | ||
808 | unsigned idx; /* index */ | ||
809 | unsigned tty; /* print to console? */ | ||
810 | rwlock_t lck; /* lock */ | ||
811 | } dbg_data = { | ||
812 | .idx = 0, | ||
813 | .tty = 0, | ||
814 | .lck = __RW_LOCK_UNLOCKED(lck) | ||
815 | }; | ||
816 | |||
817 | /** | ||
818 | * dbg_dec: decrements debug event index | ||
819 | * @idx: buffer index | ||
820 | */ | ||
821 | static void dbg_dec(unsigned *idx) | ||
822 | { | ||
823 | *idx = (*idx - 1) & (DBG_DATA_MAX-1); | ||
824 | } | ||
825 | |||
826 | /** | ||
827 | * dbg_inc: increments debug event index | ||
828 | * @idx: buffer index | ||
829 | */ | ||
830 | static void dbg_inc(unsigned *idx) | ||
831 | { | ||
832 | *idx = (*idx + 1) & (DBG_DATA_MAX-1); | ||
833 | } | ||
834 | |||
835 | /** | ||
836 | * dbg_print: prints the common part of the event | ||
837 | * @addr: endpoint address | ||
838 | * @name: event name | ||
839 | * @status: status | ||
840 | * @extra: extra information | ||
841 | */ | ||
842 | static void dbg_print(u8 addr, const char *name, int status, const char *extra) | ||
843 | { | ||
844 | struct timeval tval; | ||
845 | unsigned int stamp; | ||
846 | unsigned long flags; | ||
847 | |||
848 | write_lock_irqsave(&dbg_data.lck, flags); | ||
849 | |||
850 | do_gettimeofday(&tval); | ||
851 | stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */ | ||
852 | stamp = stamp * 1000000 + tval.tv_usec; | ||
853 | |||
854 | scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG, | ||
855 | "%04X\t» %02X %-7.7s %4i «\t%s\n", | ||
856 | stamp, addr, name, status, extra); | ||
857 | |||
858 | dbg_inc(&dbg_data.idx); | ||
859 | |||
860 | write_unlock_irqrestore(&dbg_data.lck, flags); | ||
861 | |||
862 | if (dbg_data.tty != 0) | ||
863 | pr_notice("%04X\t» %02X %-7.7s %4i «\t%s\n", | ||
864 | stamp, addr, name, status, extra); | ||
865 | } | ||
866 | |||
867 | /** | ||
868 | * dbg_done: prints a DONE event | ||
869 | * @addr: endpoint address | ||
870 | * @td: transfer descriptor | ||
871 | * @status: status | ||
872 | */ | ||
873 | static void dbg_done(u8 addr, const u32 token, int status) | ||
874 | { | ||
875 | char msg[DBG_DATA_MSG]; | ||
876 | |||
877 | scnprintf(msg, sizeof(msg), "%d %02X", | ||
878 | (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES), | ||
879 | (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS)); | ||
880 | dbg_print(addr, "DONE", status, msg); | ||
881 | } | ||
882 | |||
883 | /** | ||
884 | * dbg_event: prints a generic event | ||
885 | * @addr: endpoint address | ||
886 | * @name: event name | ||
887 | * @status: status | ||
888 | */ | ||
889 | static void dbg_event(u8 addr, const char *name, int status) | ||
890 | { | ||
891 | if (name != NULL) | ||
892 | dbg_print(addr, name, status, ""); | ||
893 | } | ||
894 | |||
895 | /* | ||
896 | * dbg_queue: prints a QUEUE event | ||
897 | * @addr: endpoint address | ||
898 | * @req: USB request | ||
899 | * @status: status | ||
900 | */ | ||
901 | static void dbg_queue(u8 addr, const struct usb_request *req, int status) | ||
902 | { | ||
903 | char msg[DBG_DATA_MSG]; | ||
904 | |||
905 | if (req != NULL) { | ||
906 | scnprintf(msg, sizeof(msg), | ||
907 | "%d %d", !req->no_interrupt, req->length); | ||
908 | dbg_print(addr, "QUEUE", status, msg); | ||
909 | } | ||
910 | } | ||
911 | |||
912 | /** | ||
913 | * dbg_setup: prints a SETUP event | ||
914 | * @addr: endpoint address | ||
915 | * @req: setup request | ||
916 | */ | ||
917 | static void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) | ||
918 | { | ||
919 | char msg[DBG_DATA_MSG]; | ||
920 | |||
921 | if (req != NULL) { | ||
922 | scnprintf(msg, sizeof(msg), | ||
923 | "%02X %02X %04X %04X %d", req->bRequestType, | ||
924 | req->bRequest, le16_to_cpu(req->wValue), | ||
925 | le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength)); | ||
926 | dbg_print(addr, "SETUP", 0, msg); | ||
927 | } | ||
928 | } | ||
929 | |||
930 | /** | ||
931 | * show_events: displays the event buffer | ||
932 | * | ||
933 | * Check "device.h" for details | ||
934 | */ | ||
935 | static ssize_t show_events(struct device *dev, struct device_attribute *attr, | ||
936 | char *buf) | ||
937 | { | ||
938 | unsigned long flags; | ||
939 | unsigned i, j, n = 0; | ||
940 | |||
941 | dbg_trace("[%s] %p\n", __func__, buf); | ||
942 | if (attr == NULL || buf == NULL) { | ||
943 | dev_err(dev, "[%s] EINVAL\n", __func__); | ||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | read_lock_irqsave(&dbg_data.lck, flags); | ||
948 | |||
949 | i = dbg_data.idx; | ||
950 | for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) { | ||
951 | n += strlen(dbg_data.buf[i]); | ||
952 | if (n >= PAGE_SIZE) { | ||
953 | n -= strlen(dbg_data.buf[i]); | ||
954 | break; | ||
955 | } | ||
956 | } | ||
957 | for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i)) | ||
958 | j += scnprintf(buf + j, PAGE_SIZE - j, | ||
959 | "%s", dbg_data.buf[i]); | ||
960 | |||
961 | read_unlock_irqrestore(&dbg_data.lck, flags); | ||
962 | |||
963 | return n; | ||
964 | } | ||
965 | |||
966 | /** | ||
967 | * store_events: configure if events are going to be also printed to console | ||
968 | * | ||
969 | * Check "device.h" for details | ||
970 | */ | ||
971 | static ssize_t store_events(struct device *dev, struct device_attribute *attr, | ||
972 | const char *buf, size_t count) | ||
973 | { | ||
974 | unsigned tty; | ||
975 | |||
976 | dbg_trace("[%s] %p, %d\n", __func__, buf, count); | ||
977 | if (attr == NULL || buf == NULL) { | ||
978 | dev_err(dev, "[%s] EINVAL\n", __func__); | ||
979 | goto done; | ||
980 | } | ||
981 | |||
982 | if (sscanf(buf, "%u", &tty) != 1 || tty > 1) { | ||
983 | dev_err(dev, "<1|0>: enable|disable console log\n"); | ||
984 | goto done; | ||
985 | } | ||
986 | |||
987 | dbg_data.tty = tty; | ||
988 | dev_info(dev, "tty = %u", dbg_data.tty); | ||
989 | |||
990 | done: | ||
991 | return count; | ||
992 | } | ||
993 | static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events); | ||
994 | |||
995 | /** | ||
996 | * show_inters: interrupt status, enable status and historic | ||
997 | * | ||
998 | * Check "device.h" for details | ||
999 | */ | ||
1000 | static ssize_t show_inters(struct device *dev, struct device_attribute *attr, | ||
1001 | char *buf) | ||
1002 | { | ||
1003 | struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); | ||
1004 | unsigned long flags; | ||
1005 | u32 intr; | ||
1006 | unsigned i, j, n = 0; | ||
1007 | |||
1008 | dbg_trace("[%s] %p\n", __func__, buf); | ||
1009 | if (attr == NULL || buf == NULL) { | ||
1010 | dev_err(dev, "[%s] EINVAL\n", __func__); | ||
1011 | return 0; | ||
1012 | } | ||
1013 | |||
1014 | spin_lock_irqsave(udc->lock, flags); | ||
1015 | |||
1016 | n += scnprintf(buf + n, PAGE_SIZE - n, | ||
1017 | "status = %08x\n", hw_read_intr_status()); | ||
1018 | n += scnprintf(buf + n, PAGE_SIZE - n, | ||
1019 | "enable = %08x\n", hw_read_intr_enable()); | ||
1020 | |||
1021 | n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n", | ||
1022 | isr_statistics.test); | ||
1023 | n += scnprintf(buf + n, PAGE_SIZE - n, "» ui = %d\n", | ||
1024 | isr_statistics.ui); | ||
1025 | n += scnprintf(buf + n, PAGE_SIZE - n, "» uei = %d\n", | ||
1026 | isr_statistics.uei); | ||
1027 | n += scnprintf(buf + n, PAGE_SIZE - n, "» pci = %d\n", | ||
1028 | isr_statistics.pci); | ||
1029 | n += scnprintf(buf + n, PAGE_SIZE - n, "» uri = %d\n", | ||
1030 | isr_statistics.uri); | ||
1031 | n += scnprintf(buf + n, PAGE_SIZE - n, "» sli = %d\n", | ||
1032 | isr_statistics.sli); | ||
1033 | n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n", | ||
1034 | isr_statistics.none); | ||
1035 | n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n", | ||
1036 | isr_statistics.hndl.cnt); | ||
1037 | |||
1038 | for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) { | ||
1039 | i &= ISR_MASK; | ||
1040 | intr = isr_statistics.hndl.buf[i]; | ||
1041 | |||
1042 | if (USBi_UI & intr) | ||
1043 | n += scnprintf(buf + n, PAGE_SIZE - n, "ui "); | ||
1044 | intr &= ~USBi_UI; | ||
1045 | if (USBi_UEI & intr) | ||
1046 | n += scnprintf(buf + n, PAGE_SIZE - n, "uei "); | ||
1047 | intr &= ~USBi_UEI; | ||
1048 | if (USBi_PCI & intr) | ||
1049 | n += scnprintf(buf + n, PAGE_SIZE - n, "pci "); | ||
1050 | intr &= ~USBi_PCI; | ||
1051 | if (USBi_URI & intr) | ||
1052 | n += scnprintf(buf + n, PAGE_SIZE - n, "uri "); | ||
1053 | intr &= ~USBi_URI; | ||
1054 | if (USBi_SLI & intr) | ||
1055 | n += scnprintf(buf + n, PAGE_SIZE - n, "sli "); | ||
1056 | intr &= ~USBi_SLI; | ||
1057 | if (intr) | ||
1058 | n += scnprintf(buf + n, PAGE_SIZE - n, "??? "); | ||
1059 | if (isr_statistics.hndl.buf[i]) | ||
1060 | n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); | ||
1061 | } | ||
1062 | |||
1063 | spin_unlock_irqrestore(udc->lock, flags); | ||
1064 | |||
1065 | return n; | ||
1066 | } | ||
1067 | |||
1068 | /** | ||
1069 | * store_inters: enable & force or disable an individual interrutps | ||
1070 | * (to be used for test purposes only) | ||
1071 | * | ||
1072 | * Check "device.h" for details | ||
1073 | */ | ||
1074 | static ssize_t store_inters(struct device *dev, struct device_attribute *attr, | ||
1075 | const char *buf, size_t count) | ||
1076 | { | ||
1077 | struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); | ||
1078 | unsigned long flags; | ||
1079 | unsigned en, bit; | ||
1080 | |||
1081 | dbg_trace("[%s] %p, %d\n", __func__, buf, count); | ||
1082 | if (attr == NULL || buf == NULL) { | ||
1083 | dev_err(dev, "[%s] EINVAL\n", __func__); | ||
1084 | goto done; | ||
1085 | } | ||
1086 | |||
1087 | if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) { | ||
1088 | dev_err(dev, "<1|0> <bit>: enable|disable interrupt"); | ||
1089 | goto done; | ||
1090 | } | ||
1091 | |||
1092 | spin_lock_irqsave(udc->lock, flags); | ||
1093 | if (en) { | ||
1094 | if (hw_intr_force(bit)) | ||
1095 | dev_err(dev, "invalid bit number\n"); | ||
1096 | else | ||
1097 | isr_statistics.test++; | ||
1098 | } else { | ||
1099 | if (hw_intr_clear(bit)) | ||
1100 | dev_err(dev, "invalid bit number\n"); | ||
1101 | } | ||
1102 | spin_unlock_irqrestore(udc->lock, flags); | ||
1103 | |||
1104 | done: | ||
1105 | return count; | ||
1106 | } | ||
1107 | static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters); | ||
1108 | |||
1109 | /** | ||
1110 | * show_port_test: reads port test mode | ||
1111 | * | ||
1112 | * Check "device.h" for details | ||
1113 | */ | ||
1114 | static ssize_t show_port_test(struct device *dev, | ||
1115 | struct device_attribute *attr, char *buf) | ||
1116 | { | ||
1117 | struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); | ||
1118 | unsigned long flags; | ||
1119 | unsigned mode; | ||
1120 | |||
1121 | dbg_trace("[%s] %p\n", __func__, buf); | ||
1122 | if (attr == NULL || buf == NULL) { | ||
1123 | dev_err(dev, "[%s] EINVAL\n", __func__); | ||
1124 | return 0; | ||
1125 | } | ||
1126 | |||
1127 | spin_lock_irqsave(udc->lock, flags); | ||
1128 | mode = hw_port_test_get(); | ||
1129 | spin_unlock_irqrestore(udc->lock, flags); | ||
1130 | |||
1131 | return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode); | ||
1132 | } | ||
1133 | |||
1134 | /** | ||
1135 | * store_port_test: writes port test mode | ||
1136 | * | ||
1137 | * Check "device.h" for details | ||
1138 | */ | ||
1139 | static ssize_t store_port_test(struct device *dev, | ||
1140 | struct device_attribute *attr, | ||
1141 | const char *buf, size_t count) | ||
1142 | { | ||
1143 | struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); | ||
1144 | unsigned long flags; | ||
1145 | unsigned mode; | ||
1146 | |||
1147 | dbg_trace("[%s] %p, %d\n", __func__, buf, count); | ||
1148 | if (attr == NULL || buf == NULL) { | ||
1149 | dev_err(dev, "[%s] EINVAL\n", __func__); | ||
1150 | goto done; | ||
1151 | } | ||
1152 | |||
1153 | if (sscanf(buf, "%u", &mode) != 1) { | ||
1154 | dev_err(dev, "<mode>: set port test mode"); | ||
1155 | goto done; | ||
1156 | } | ||
1157 | |||
1158 | spin_lock_irqsave(udc->lock, flags); | ||
1159 | if (hw_port_test_set(mode)) | ||
1160 | dev_err(dev, "invalid mode\n"); | ||
1161 | spin_unlock_irqrestore(udc->lock, flags); | ||
1162 | |||
1163 | done: | ||
1164 | return count; | ||
1165 | } | ||
1166 | static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR, | ||
1167 | show_port_test, store_port_test); | ||
1168 | |||
1169 | /** | ||
1170 | * show_qheads: DMA contents of all queue heads | ||
1171 | * | ||
1172 | * Check "device.h" for details | ||
1173 | */ | ||
1174 | static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, | ||
1175 | char *buf) | ||
1176 | { | ||
1177 | struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); | ||
1178 | unsigned long flags; | ||
1179 | unsigned i, j, n = 0; | ||
1180 | |||
1181 | dbg_trace("[%s] %p\n", __func__, buf); | ||
1182 | if (attr == NULL || buf == NULL) { | ||
1183 | dev_err(dev, "[%s] EINVAL\n", __func__); | ||
1184 | return 0; | ||
1185 | } | ||
1186 | |||
1187 | spin_lock_irqsave(udc->lock, flags); | ||
1188 | for (i = 0; i < hw_ep_max; i++) { | ||
1189 | struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; | ||
1190 | n += scnprintf(buf + n, PAGE_SIZE - n, | ||
1191 | "EP=%02i: RX=%08X TX=%08X\n", | ||
1192 | i, (u32)mEp->qh[RX].dma, (u32)mEp->qh[TX].dma); | ||
1193 | for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) { | ||
1194 | n += scnprintf(buf + n, PAGE_SIZE - n, | ||
1195 | " %04X: %08X %08X\n", j, | ||
1196 | *((u32 *)mEp->qh[RX].ptr + j), | ||
1197 | *((u32 *)mEp->qh[TX].ptr + j)); | ||
1198 | } | ||
1199 | } | ||
1200 | spin_unlock_irqrestore(udc->lock, flags); | ||
1201 | |||
1202 | return n; | ||
1203 | } | ||
1204 | static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL); | ||
1205 | |||
1206 | /** | ||
1207 | * show_registers: dumps all registers | ||
1208 | * | ||
1209 | * Check "device.h" for details | ||
1210 | */ | ||
1211 | static ssize_t show_registers(struct device *dev, | ||
1212 | struct device_attribute *attr, char *buf) | ||
1213 | { | ||
1214 | struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); | ||
1215 | unsigned long flags; | ||
1216 | u32 dump[512]; | ||
1217 | unsigned i, k, n = 0; | ||
1218 | |||
1219 | dbg_trace("[%s] %p\n", __func__, buf); | ||
1220 | if (attr == NULL || buf == NULL) { | ||
1221 | dev_err(dev, "[%s] EINVAL\n", __func__); | ||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | spin_lock_irqsave(udc->lock, flags); | ||
1226 | k = hw_register_read(dump, sizeof(dump)/sizeof(u32)); | ||
1227 | spin_unlock_irqrestore(udc->lock, flags); | ||
1228 | |||
1229 | for (i = 0; i < k; i++) { | ||
1230 | n += scnprintf(buf + n, PAGE_SIZE - n, | ||
1231 | "reg[0x%04X] = 0x%08X\n", | ||
1232 | i * (unsigned)sizeof(u32), dump[i]); | ||
1233 | } | ||
1234 | |||
1235 | return n; | ||
1236 | } | ||
1237 | |||
1238 | /** | ||
1239 | * store_registers: writes value to register address | ||
1240 | * | ||
1241 | * Check "device.h" for details | ||
1242 | */ | ||
1243 | static ssize_t store_registers(struct device *dev, | ||
1244 | struct device_attribute *attr, | ||
1245 | const char *buf, size_t count) | ||
1246 | { | ||
1247 | struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); | ||
1248 | unsigned long addr, data, flags; | ||
1249 | |||
1250 | dbg_trace("[%s] %p, %d\n", __func__, buf, count); | ||
1251 | if (attr == NULL || buf == NULL) { | ||
1252 | dev_err(dev, "[%s] EINVAL\n", __func__); | ||
1253 | goto done; | ||
1254 | } | ||
1255 | |||
1256 | if (sscanf(buf, "%li %li", &addr, &data) != 2) { | ||
1257 | dev_err(dev, "<addr> <data>: write data to register address"); | ||
1258 | goto done; | ||
1259 | } | ||
1260 | |||
1261 | spin_lock_irqsave(udc->lock, flags); | ||
1262 | if (hw_register_write(addr, data)) | ||
1263 | dev_err(dev, "invalid address range\n"); | ||
1264 | spin_unlock_irqrestore(udc->lock, flags); | ||
1265 | |||
1266 | done: | ||
1267 | return count; | ||
1268 | } | ||
1269 | static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR, | ||
1270 | show_registers, store_registers); | ||
1271 | |||
1272 | /** | ||
1273 | * show_requests: DMA contents of all requests currently queued (all endpts) | ||
1274 | * | ||
1275 | * Check "device.h" for details | ||
1276 | */ | ||
1277 | static ssize_t show_requests(struct device *dev, struct device_attribute *attr, | ||
1278 | char *buf) | ||
1279 | { | ||
1280 | struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); | ||
1281 | unsigned long flags; | ||
1282 | struct list_head *ptr = NULL; | ||
1283 | struct ci13xxx_req *req = NULL; | ||
1284 | unsigned i, j, k, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); | ||
1285 | |||
1286 | dbg_trace("[%s] %p\n", __func__, buf); | ||
1287 | if (attr == NULL || buf == NULL) { | ||
1288 | dev_err(dev, "[%s] EINVAL\n", __func__); | ||
1289 | return 0; | ||
1290 | } | ||
1291 | |||
1292 | spin_lock_irqsave(udc->lock, flags); | ||
1293 | for (i = 0; i < hw_ep_max; i++) | ||
1294 | for (k = RX; k <= TX; k++) | ||
1295 | list_for_each(ptr, &udc->ci13xxx_ep[i].qh[k].queue) | ||
1296 | { | ||
1297 | req = list_entry(ptr, | ||
1298 | struct ci13xxx_req, queue); | ||
1299 | |||
1300 | n += scnprintf(buf + n, PAGE_SIZE - n, | ||
1301 | "EP=%02i: TD=%08X %s\n", | ||
1302 | i, (u32)req->dma, | ||
1303 | ((k == RX) ? "RX" : "TX")); | ||
1304 | |||
1305 | for (j = 0; j < qSize; j++) | ||
1306 | n += scnprintf(buf + n, PAGE_SIZE - n, | ||
1307 | " %04X: %08X\n", j, | ||
1308 | *((u32 *)req->ptr + j)); | ||
1309 | } | ||
1310 | spin_unlock_irqrestore(udc->lock, flags); | ||
1311 | |||
1312 | return n; | ||
1313 | } | ||
1314 | static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL); | ||
1315 | |||
1316 | /** | ||
1317 | * dbg_create_files: initializes the attribute interface | ||
1318 | * @dev: device | ||
1319 | * | ||
1320 | * This function returns an error code | ||
1321 | */ | ||
1322 | __maybe_unused static int dbg_create_files(struct device *dev) | ||
1323 | { | ||
1324 | int retval = 0; | ||
1325 | |||
1326 | if (dev == NULL) | ||
1327 | return -EINVAL; | ||
1328 | retval = device_create_file(dev, &dev_attr_device); | ||
1329 | if (retval) | ||
1330 | goto done; | ||
1331 | retval = device_create_file(dev, &dev_attr_driver); | ||
1332 | if (retval) | ||
1333 | goto rm_device; | ||
1334 | retval = device_create_file(dev, &dev_attr_events); | ||
1335 | if (retval) | ||
1336 | goto rm_driver; | ||
1337 | retval = device_create_file(dev, &dev_attr_inters); | ||
1338 | if (retval) | ||
1339 | goto rm_events; | ||
1340 | retval = device_create_file(dev, &dev_attr_port_test); | ||
1341 | if (retval) | ||
1342 | goto rm_inters; | ||
1343 | retval = device_create_file(dev, &dev_attr_qheads); | ||
1344 | if (retval) | ||
1345 | goto rm_port_test; | ||
1346 | retval = device_create_file(dev, &dev_attr_registers); | ||
1347 | if (retval) | ||
1348 | goto rm_qheads; | ||
1349 | retval = device_create_file(dev, &dev_attr_requests); | ||
1350 | if (retval) | ||
1351 | goto rm_registers; | ||
1352 | return 0; | ||
1353 | |||
1354 | rm_registers: | ||
1355 | device_remove_file(dev, &dev_attr_registers); | ||
1356 | rm_qheads: | ||
1357 | device_remove_file(dev, &dev_attr_qheads); | ||
1358 | rm_port_test: | ||
1359 | device_remove_file(dev, &dev_attr_port_test); | ||
1360 | rm_inters: | ||
1361 | device_remove_file(dev, &dev_attr_inters); | ||
1362 | rm_events: | ||
1363 | device_remove_file(dev, &dev_attr_events); | ||
1364 | rm_driver: | ||
1365 | device_remove_file(dev, &dev_attr_driver); | ||
1366 | rm_device: | ||
1367 | device_remove_file(dev, &dev_attr_device); | ||
1368 | done: | ||
1369 | return retval; | ||
1370 | } | ||
1371 | |||
1372 | /** | ||
1373 | * dbg_remove_files: destroys the attribute interface | ||
1374 | * @dev: device | ||
1375 | * | ||
1376 | * This function returns an error code | ||
1377 | */ | ||
1378 | __maybe_unused static int dbg_remove_files(struct device *dev) | ||
1379 | { | ||
1380 | if (dev == NULL) | ||
1381 | return -EINVAL; | ||
1382 | device_remove_file(dev, &dev_attr_requests); | ||
1383 | device_remove_file(dev, &dev_attr_registers); | ||
1384 | device_remove_file(dev, &dev_attr_qheads); | ||
1385 | device_remove_file(dev, &dev_attr_port_test); | ||
1386 | device_remove_file(dev, &dev_attr_inters); | ||
1387 | device_remove_file(dev, &dev_attr_events); | ||
1388 | device_remove_file(dev, &dev_attr_driver); | ||
1389 | device_remove_file(dev, &dev_attr_device); | ||
1390 | return 0; | ||
1391 | } | ||
1392 | |||
1393 | /****************************************************************************** | ||
1394 | * UTIL block | ||
1395 | *****************************************************************************/ | ||
1396 | /** | ||
1397 | * _usb_addr: calculates endpoint address from direction & number | ||
1398 | * @ep: endpoint | ||
1399 | */ | ||
1400 | static inline u8 _usb_addr(struct ci13xxx_ep *ep) | ||
1401 | { | ||
1402 | return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num; | ||
1403 | } | ||
1404 | |||
1405 | /** | ||
1406 | * _hardware_queue: configures a request at hardware level | ||
1407 | * @gadget: gadget | ||
1408 | * @mEp: endpoint | ||
1409 | * | ||
1410 | * This function returns an error code | ||
1411 | */ | ||
1412 | static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) | ||
1413 | { | ||
1414 | unsigned i; | ||
1415 | |||
1416 | trace("%p, %p", mEp, mReq); | ||
1417 | |||
1418 | /* don't queue twice */ | ||
1419 | if (mReq->req.status == -EALREADY) | ||
1420 | return -EALREADY; | ||
1421 | |||
1422 | if (hw_ep_is_primed(mEp->num, mEp->dir)) | ||
1423 | return -EBUSY; | ||
1424 | |||
1425 | mReq->req.status = -EALREADY; | ||
1426 | |||
1427 | if (mReq->req.length && !mReq->req.dma) { | ||
1428 | mReq->req.dma = \ | ||
1429 | dma_map_single(mEp->device, mReq->req.buf, | ||
1430 | mReq->req.length, mEp->dir ? | ||
1431 | DMA_TO_DEVICE : DMA_FROM_DEVICE); | ||
1432 | if (mReq->req.dma == 0) | ||
1433 | return -ENOMEM; | ||
1434 | |||
1435 | mReq->map = 1; | ||
1436 | } | ||
1437 | |||
1438 | /* | ||
1439 | * TD configuration | ||
1440 | * TODO - handle requests which spawns into several TDs | ||
1441 | */ | ||
1442 | memset(mReq->ptr, 0, sizeof(*mReq->ptr)); | ||
1443 | mReq->ptr->next |= TD_TERMINATE; | ||
1444 | mReq->ptr->token = mReq->req.length << ffs_nr(TD_TOTAL_BYTES); | ||
1445 | mReq->ptr->token &= TD_TOTAL_BYTES; | ||
1446 | mReq->ptr->token |= TD_IOC; | ||
1447 | mReq->ptr->token |= TD_STATUS_ACTIVE; | ||
1448 | mReq->ptr->page[0] = mReq->req.dma; | ||
1449 | for (i = 1; i < 5; i++) | ||
1450 | mReq->ptr->page[i] = | ||
1451 | (mReq->req.dma + i * PAGE_SIZE) & ~TD_RESERVED_MASK; | ||
1452 | |||
1453 | /* | ||
1454 | * QH configuration | ||
1455 | * At this point it's guaranteed exclusive access to qhead | ||
1456 | * (endpt is not primed) so it's no need to use tripwire | ||
1457 | */ | ||
1458 | mEp->qh[mEp->dir].ptr->td.next = mReq->dma; /* TERMINATE = 0 */ | ||
1459 | mEp->qh[mEp->dir].ptr->td.token &= ~TD_STATUS; /* clear status */ | ||
1460 | if (mReq->req.zero == 0) | ||
1461 | mEp->qh[mEp->dir].ptr->cap |= QH_ZLT; | ||
1462 | else | ||
1463 | mEp->qh[mEp->dir].ptr->cap &= ~QH_ZLT; | ||
1464 | |||
1465 | wmb(); /* synchronize before ep prime */ | ||
1466 | |||
1467 | return hw_ep_prime(mEp->num, mEp->dir, | ||
1468 | mEp->type == USB_ENDPOINT_XFER_CONTROL); | ||
1469 | } | ||
1470 | |||
1471 | /** | ||
1472 | * _hardware_dequeue: handles a request at hardware level | ||
1473 | * @gadget: gadget | ||
1474 | * @mEp: endpoint | ||
1475 | * | ||
1476 | * This function returns an error code | ||
1477 | */ | ||
1478 | static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) | ||
1479 | { | ||
1480 | trace("%p, %p", mEp, mReq); | ||
1481 | |||
1482 | if (mReq->req.status != -EALREADY) | ||
1483 | return -EINVAL; | ||
1484 | |||
1485 | if (hw_ep_is_primed(mEp->num, mEp->dir)) | ||
1486 | hw_ep_flush(mEp->num, mEp->dir); | ||
1487 | |||
1488 | mReq->req.status = 0; | ||
1489 | |||
1490 | if (mReq->map) { | ||
1491 | dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, | ||
1492 | mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); | ||
1493 | mReq->req.dma = 0; | ||
1494 | mReq->map = 0; | ||
1495 | } | ||
1496 | |||
1497 | mReq->req.status = mReq->ptr->token & TD_STATUS; | ||
1498 | if ((TD_STATUS_ACTIVE & mReq->req.status) != 0) | ||
1499 | mReq->req.status = -ECONNRESET; | ||
1500 | else if ((TD_STATUS_HALTED & mReq->req.status) != 0) | ||
1501 | mReq->req.status = -1; | ||
1502 | else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0) | ||
1503 | mReq->req.status = -1; | ||
1504 | else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0) | ||
1505 | mReq->req.status = -1; | ||
1506 | |||
1507 | mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES; | ||
1508 | mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES); | ||
1509 | mReq->req.actual = mReq->req.length - mReq->req.actual; | ||
1510 | mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual; | ||
1511 | |||
1512 | return mReq->req.actual; | ||
1513 | } | ||
1514 | |||
1515 | /** | ||
1516 | * _ep_nuke: dequeues all endpoint requests | ||
1517 | * @mEp: endpoint | ||
1518 | * | ||
1519 | * This function returns an error code | ||
1520 | * Caller must hold lock | ||
1521 | */ | ||
1522 | static int _ep_nuke(struct ci13xxx_ep *mEp) | ||
1523 | __releases(mEp->lock) | ||
1524 | __acquires(mEp->lock) | ||
1525 | { | ||
1526 | trace("%p", mEp); | ||
1527 | |||
1528 | if (mEp == NULL) | ||
1529 | return -EINVAL; | ||
1530 | |||
1531 | hw_ep_flush(mEp->num, mEp->dir); | ||
1532 | |||
1533 | while (!list_empty(&mEp->qh[mEp->dir].queue)) { | ||
1534 | |||
1535 | /* pop oldest request */ | ||
1536 | struct ci13xxx_req *mReq = \ | ||
1537 | list_entry(mEp->qh[mEp->dir].queue.next, | ||
1538 | struct ci13xxx_req, queue); | ||
1539 | list_del_init(&mReq->queue); | ||
1540 | mReq->req.status = -ESHUTDOWN; | ||
1541 | |||
1542 | if (!mReq->req.no_interrupt && mReq->req.complete != NULL) { | ||
1543 | spin_unlock(mEp->lock); | ||
1544 | mReq->req.complete(&mEp->ep, &mReq->req); | ||
1545 | spin_lock(mEp->lock); | ||
1546 | } | ||
1547 | } | ||
1548 | return 0; | ||
1549 | } | ||
1550 | |||
1551 | /** | ||
1552 | * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts | ||
1553 | * @gadget: gadget | ||
1554 | * | ||
1555 | * This function returns an error code | ||
1556 | * Caller must hold lock | ||
1557 | */ | ||
1558 | static int _gadget_stop_activity(struct usb_gadget *gadget) | ||
1559 | __releases(udc->lock) | ||
1560 | __acquires(udc->lock) | ||
1561 | { | ||
1562 | struct usb_ep *ep; | ||
1563 | struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); | ||
1564 | struct ci13xxx_ep *mEp = container_of(gadget->ep0, | ||
1565 | struct ci13xxx_ep, ep); | ||
1566 | |||
1567 | trace("%p", gadget); | ||
1568 | |||
1569 | if (gadget == NULL) | ||
1570 | return -EINVAL; | ||
1571 | |||
1572 | spin_unlock(udc->lock); | ||
1573 | |||
1574 | /* flush all endpoints */ | ||
1575 | gadget_for_each_ep(ep, gadget) { | ||
1576 | usb_ep_fifo_flush(ep); | ||
1577 | } | ||
1578 | usb_ep_fifo_flush(gadget->ep0); | ||
1579 | |||
1580 | udc->driver->disconnect(gadget); | ||
1581 | |||
1582 | /* make sure to disable all endpoints */ | ||
1583 | gadget_for_each_ep(ep, gadget) { | ||
1584 | usb_ep_disable(ep); | ||
1585 | } | ||
1586 | usb_ep_disable(gadget->ep0); | ||
1587 | |||
1588 | if (mEp->status != NULL) { | ||
1589 | usb_ep_free_request(gadget->ep0, mEp->status); | ||
1590 | mEp->status = NULL; | ||
1591 | } | ||
1592 | |||
1593 | spin_lock(udc->lock); | ||
1594 | |||
1595 | return 0; | ||
1596 | } | ||
1597 | |||
1598 | /****************************************************************************** | ||
1599 | * ISR block | ||
1600 | *****************************************************************************/ | ||
1601 | /** | ||
1602 | * isr_reset_handler: USB reset interrupt handler | ||
1603 | * @udc: UDC device | ||
1604 | * | ||
1605 | * This function resets USB engine after a bus reset occurred | ||
1606 | */ | ||
1607 | static void isr_reset_handler(struct ci13xxx *udc) | ||
1608 | __releases(udc->lock) | ||
1609 | __acquires(udc->lock) | ||
1610 | { | ||
1611 | struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[0]; | ||
1612 | int retval; | ||
1613 | |||
1614 | trace("%p", udc); | ||
1615 | |||
1616 | if (udc == NULL) { | ||
1617 | err("EINVAL"); | ||
1618 | return; | ||
1619 | } | ||
1620 | |||
1621 | dbg_event(0xFF, "BUS RST", 0); | ||
1622 | |||
1623 | retval = _gadget_stop_activity(&udc->gadget); | ||
1624 | if (retval) | ||
1625 | goto done; | ||
1626 | |||
1627 | retval = hw_usb_reset(); | ||
1628 | if (retval) | ||
1629 | goto done; | ||
1630 | |||
1631 | spin_unlock(udc->lock); | ||
1632 | retval = usb_ep_enable(&mEp->ep, &ctrl_endpt_desc); | ||
1633 | if (!retval) { | ||
1634 | mEp->status = usb_ep_alloc_request(&mEp->ep, GFP_KERNEL); | ||
1635 | if (mEp->status == NULL) { | ||
1636 | usb_ep_disable(&mEp->ep); | ||
1637 | retval = -ENOMEM; | ||
1638 | } | ||
1639 | } | ||
1640 | spin_lock(udc->lock); | ||
1641 | |||
1642 | done: | ||
1643 | if (retval) | ||
1644 | err("error: %i", retval); | ||
1645 | } | ||
1646 | |||
1647 | /** | ||
1648 | * isr_get_status_complete: get_status request complete function | ||
1649 | * @ep: endpoint | ||
1650 | * @req: request handled | ||
1651 | * | ||
1652 | * Caller must release lock | ||
1653 | */ | ||
1654 | static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req) | ||
1655 | { | ||
1656 | trace("%p, %p", ep, req); | ||
1657 | |||
1658 | if (ep == NULL || req == NULL) { | ||
1659 | err("EINVAL"); | ||
1660 | return; | ||
1661 | } | ||
1662 | |||
1663 | kfree(req->buf); | ||
1664 | usb_ep_free_request(ep, req); | ||
1665 | } | ||
1666 | |||
1667 | /** | ||
1668 | * isr_get_status_response: get_status request response | ||
1669 | * @ep: endpoint | ||
1670 | * @setup: setup request packet | ||
1671 | * | ||
1672 | * This function returns an error code | ||
1673 | */ | ||
1674 | static int isr_get_status_response(struct ci13xxx_ep *mEp, | ||
1675 | struct usb_ctrlrequest *setup) | ||
1676 | __releases(mEp->lock) | ||
1677 | __acquires(mEp->lock) | ||
1678 | { | ||
1679 | struct usb_request *req = NULL; | ||
1680 | gfp_t gfp_flags = GFP_ATOMIC; | ||
1681 | int dir, num, retval; | ||
1682 | |||
1683 | trace("%p, %p", mEp, setup); | ||
1684 | |||
1685 | if (mEp == NULL || setup == NULL) | ||
1686 | return -EINVAL; | ||
1687 | |||
1688 | spin_unlock(mEp->lock); | ||
1689 | req = usb_ep_alloc_request(&mEp->ep, gfp_flags); | ||
1690 | spin_lock(mEp->lock); | ||
1691 | if (req == NULL) | ||
1692 | return -ENOMEM; | ||
1693 | |||
1694 | req->complete = isr_get_status_complete; | ||
1695 | req->length = 2; | ||
1696 | req->buf = kzalloc(req->length, gfp_flags); | ||
1697 | if (req->buf == NULL) { | ||
1698 | retval = -ENOMEM; | ||
1699 | goto err_free_req; | ||
1700 | } | ||
1701 | |||
1702 | if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { | ||
1703 | /* TODO: D1 - Remote Wakeup; D0 - Self Powered */ | ||
1704 | retval = 0; | ||
1705 | } else if ((setup->bRequestType & USB_RECIP_MASK) \ | ||
1706 | == USB_RECIP_ENDPOINT) { | ||
1707 | dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ? | ||
1708 | TX : RX; | ||
1709 | num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK; | ||
1710 | *((u16 *)req->buf) = hw_ep_get_halt(num, dir); | ||
1711 | } | ||
1712 | /* else do nothing; reserved for future use */ | ||
1713 | |||
1714 | spin_unlock(mEp->lock); | ||
1715 | retval = usb_ep_queue(&mEp->ep, req, gfp_flags); | ||
1716 | spin_lock(mEp->lock); | ||
1717 | if (retval) | ||
1718 | goto err_free_buf; | ||
1719 | |||
1720 | return 0; | ||
1721 | |||
1722 | err_free_buf: | ||
1723 | kfree(req->buf); | ||
1724 | err_free_req: | ||
1725 | spin_unlock(mEp->lock); | ||
1726 | usb_ep_free_request(&mEp->ep, req); | ||
1727 | spin_lock(mEp->lock); | ||
1728 | return retval; | ||
1729 | } | ||
1730 | |||
1731 | /** | ||
1732 | * isr_setup_status_phase: queues the status phase of a setup transation | ||
1733 | * @mEp: endpoint | ||
1734 | * | ||
1735 | * This function returns an error code | ||
1736 | */ | ||
1737 | static int isr_setup_status_phase(struct ci13xxx_ep *mEp) | ||
1738 | __releases(mEp->lock) | ||
1739 | __acquires(mEp->lock) | ||
1740 | { | ||
1741 | int retval; | ||
1742 | |||
1743 | trace("%p", mEp); | ||
1744 | |||
1745 | /* mEp is always valid & configured */ | ||
1746 | |||
1747 | if (mEp->type == USB_ENDPOINT_XFER_CONTROL) | ||
1748 | mEp->dir = (mEp->dir == TX) ? RX : TX; | ||
1749 | |||
1750 | mEp->status->no_interrupt = 1; | ||
1751 | |||
1752 | spin_unlock(mEp->lock); | ||
1753 | retval = usb_ep_queue(&mEp->ep, mEp->status, GFP_ATOMIC); | ||
1754 | spin_lock(mEp->lock); | ||
1755 | |||
1756 | return retval; | ||
1757 | } | ||
1758 | |||
1759 | /** | ||
1760 | * isr_tr_complete_low: transaction complete low level handler | ||
1761 | * @mEp: endpoint | ||
1762 | * | ||
1763 | * This function returns an error code | ||
1764 | * Caller must hold lock | ||
1765 | */ | ||
1766 | static int isr_tr_complete_low(struct ci13xxx_ep *mEp) | ||
1767 | __releases(mEp->lock) | ||
1768 | __acquires(mEp->lock) | ||
1769 | { | ||
1770 | struct ci13xxx_req *mReq; | ||
1771 | int retval; | ||
1772 | |||
1773 | trace("%p", mEp); | ||
1774 | |||
1775 | if (list_empty(&mEp->qh[mEp->dir].queue)) | ||
1776 | return -EINVAL; | ||
1777 | |||
1778 | /* pop oldest request */ | ||
1779 | mReq = list_entry(mEp->qh[mEp->dir].queue.next, | ||
1780 | struct ci13xxx_req, queue); | ||
1781 | list_del_init(&mReq->queue); | ||
1782 | |||
1783 | retval = _hardware_dequeue(mEp, mReq); | ||
1784 | if (retval < 0) { | ||
1785 | dbg_event(_usb_addr(mEp), "DONE", retval); | ||
1786 | goto done; | ||
1787 | } | ||
1788 | |||
1789 | dbg_done(_usb_addr(mEp), mReq->ptr->token, retval); | ||
1790 | |||
1791 | if (!mReq->req.no_interrupt && mReq->req.complete != NULL) { | ||
1792 | spin_unlock(mEp->lock); | ||
1793 | mReq->req.complete(&mEp->ep, &mReq->req); | ||
1794 | spin_lock(mEp->lock); | ||
1795 | } | ||
1796 | |||
1797 | if (!list_empty(&mEp->qh[mEp->dir].queue)) { | ||
1798 | mReq = list_entry(mEp->qh[mEp->dir].queue.next, | ||
1799 | struct ci13xxx_req, queue); | ||
1800 | _hardware_enqueue(mEp, mReq); | ||
1801 | } | ||
1802 | |||
1803 | done: | ||
1804 | return retval; | ||
1805 | } | ||
1806 | |||
1807 | /** | ||
1808 | * isr_tr_complete_handler: transaction complete interrupt handler | ||
1809 | * @udc: UDC descriptor | ||
1810 | * | ||
1811 | * This function handles traffic events | ||
1812 | */ | ||
1813 | static void isr_tr_complete_handler(struct ci13xxx *udc) | ||
1814 | __releases(udc->lock) | ||
1815 | __acquires(udc->lock) | ||
1816 | { | ||
1817 | unsigned i; | ||
1818 | |||
1819 | trace("%p", udc); | ||
1820 | |||
1821 | if (udc == NULL) { | ||
1822 | err("EINVAL"); | ||
1823 | return; | ||
1824 | } | ||
1825 | |||
1826 | for (i = 0; i < hw_ep_max; i++) { | ||
1827 | struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; | ||
1828 | int type, num, err = -EINVAL; | ||
1829 | struct usb_ctrlrequest req; | ||
1830 | |||
1831 | |||
1832 | if (mEp->desc == NULL) | ||
1833 | continue; /* not configured */ | ||
1834 | |||
1835 | if ((mEp->dir == RX && hw_test_and_clear_complete(i)) || | ||
1836 | (mEp->dir == TX && hw_test_and_clear_complete(i + 16))) { | ||
1837 | err = isr_tr_complete_low(mEp); | ||
1838 | if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { | ||
1839 | if (err > 0) /* needs status phase */ | ||
1840 | err = isr_setup_status_phase(mEp); | ||
1841 | if (err < 0) { | ||
1842 | dbg_event(_usb_addr(mEp), | ||
1843 | "ERROR", err); | ||
1844 | spin_unlock(udc->lock); | ||
1845 | if (usb_ep_set_halt(&mEp->ep)) | ||
1846 | err("error: ep_set_halt"); | ||
1847 | spin_lock(udc->lock); | ||
1848 | } | ||
1849 | } | ||
1850 | } | ||
1851 | |||
1852 | if (mEp->type != USB_ENDPOINT_XFER_CONTROL || | ||
1853 | !hw_test_and_clear_setup_status(i)) | ||
1854 | continue; | ||
1855 | |||
1856 | if (i != 0) { | ||
1857 | warn("ctrl traffic received at endpoint"); | ||
1858 | continue; | ||
1859 | } | ||
1860 | |||
1861 | /* read_setup_packet */ | ||
1862 | do { | ||
1863 | hw_test_and_set_setup_guard(); | ||
1864 | memcpy(&req, &mEp->qh[RX].ptr->setup, sizeof(req)); | ||
1865 | } while (!hw_test_and_clear_setup_guard()); | ||
1866 | |||
1867 | type = req.bRequestType; | ||
1868 | |||
1869 | mEp->dir = (type & USB_DIR_IN) ? TX : RX; | ||
1870 | |||
1871 | dbg_setup(_usb_addr(mEp), &req); | ||
1872 | |||
1873 | switch (req.bRequest) { | ||
1874 | case USB_REQ_CLEAR_FEATURE: | ||
1875 | if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) && | ||
1876 | le16_to_cpu(req.wValue) != USB_ENDPOINT_HALT) | ||
1877 | goto delegate; | ||
1878 | if (req.wLength != 0) | ||
1879 | break; | ||
1880 | num = le16_to_cpu(req.wIndex); | ||
1881 | num &= USB_ENDPOINT_NUMBER_MASK; | ||
1882 | if (!udc->ci13xxx_ep[num].wedge) { | ||
1883 | spin_unlock(udc->lock); | ||
1884 | err = usb_ep_clear_halt( | ||
1885 | &udc->ci13xxx_ep[num].ep); | ||
1886 | spin_lock(udc->lock); | ||
1887 | if (err) | ||
1888 | break; | ||
1889 | } | ||
1890 | err = isr_setup_status_phase(mEp); | ||
1891 | break; | ||
1892 | case USB_REQ_GET_STATUS: | ||
1893 | if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && | ||
1894 | type != (USB_DIR_IN|USB_RECIP_ENDPOINT) && | ||
1895 | type != (USB_DIR_IN|USB_RECIP_INTERFACE)) | ||
1896 | goto delegate; | ||
1897 | if (le16_to_cpu(req.wLength) != 2 || | ||
1898 | le16_to_cpu(req.wValue) != 0) | ||
1899 | break; | ||
1900 | err = isr_get_status_response(mEp, &req); | ||
1901 | break; | ||
1902 | case USB_REQ_SET_ADDRESS: | ||
1903 | if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) | ||
1904 | goto delegate; | ||
1905 | if (le16_to_cpu(req.wLength) != 0 || | ||
1906 | le16_to_cpu(req.wIndex) != 0) | ||
1907 | break; | ||
1908 | err = hw_usb_set_address((u8)le16_to_cpu(req.wValue)); | ||
1909 | if (err) | ||
1910 | break; | ||
1911 | err = isr_setup_status_phase(mEp); | ||
1912 | break; | ||
1913 | case USB_REQ_SET_FEATURE: | ||
1914 | if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) && | ||
1915 | le16_to_cpu(req.wValue) != USB_ENDPOINT_HALT) | ||
1916 | goto delegate; | ||
1917 | if (req.wLength != 0) | ||
1918 | break; | ||
1919 | num = le16_to_cpu(req.wIndex); | ||
1920 | num &= USB_ENDPOINT_NUMBER_MASK; | ||
1921 | |||
1922 | spin_unlock(udc->lock); | ||
1923 | err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep); | ||
1924 | spin_lock(udc->lock); | ||
1925 | if (err) | ||
1926 | break; | ||
1927 | err = isr_setup_status_phase(mEp); | ||
1928 | break; | ||
1929 | default: | ||
1930 | delegate: | ||
1931 | if (req.wLength == 0) /* no data phase */ | ||
1932 | mEp->dir = TX; | ||
1933 | |||
1934 | spin_unlock(udc->lock); | ||
1935 | err = udc->driver->setup(&udc->gadget, &req); | ||
1936 | spin_lock(udc->lock); | ||
1937 | break; | ||
1938 | } | ||
1939 | |||
1940 | if (err < 0) { | ||
1941 | dbg_event(_usb_addr(mEp), "ERROR", err); | ||
1942 | |||
1943 | spin_unlock(udc->lock); | ||
1944 | if (usb_ep_set_halt(&mEp->ep)) | ||
1945 | err("error: ep_set_halt"); | ||
1946 | spin_lock(udc->lock); | ||
1947 | } | ||
1948 | } | ||
1949 | } | ||
1950 | |||
1951 | /****************************************************************************** | ||
1952 | * ENDPT block | ||
1953 | *****************************************************************************/ | ||
1954 | /** | ||
1955 | * ep_enable: configure endpoint, making it usable | ||
1956 | * | ||
1957 | * Check usb_ep_enable() at "usb_gadget.h" for details | ||
1958 | */ | ||
1959 | static int ep_enable(struct usb_ep *ep, | ||
1960 | const struct usb_endpoint_descriptor *desc) | ||
1961 | { | ||
1962 | struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); | ||
1963 | int direction, retval = 0; | ||
1964 | unsigned long flags; | ||
1965 | |||
1966 | trace("%p, %p", ep, desc); | ||
1967 | |||
1968 | if (ep == NULL || desc == NULL) | ||
1969 | return -EINVAL; | ||
1970 | |||
1971 | spin_lock_irqsave(mEp->lock, flags); | ||
1972 | |||
1973 | /* only internal SW should enable ctrl endpts */ | ||
1974 | |||
1975 | mEp->desc = desc; | ||
1976 | |||
1977 | if (!list_empty(&mEp->qh[mEp->dir].queue)) | ||
1978 | warn("enabling a non-empty endpoint!"); | ||
1979 | |||
1980 | mEp->dir = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? TX : RX; | ||
1981 | mEp->num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; | ||
1982 | mEp->type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; | ||
1983 | |||
1984 | mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize); | ||
1985 | |||
1986 | direction = mEp->dir; | ||
1987 | do { | ||
1988 | dbg_event(_usb_addr(mEp), "ENABLE", 0); | ||
1989 | |||
1990 | if (mEp->type == USB_ENDPOINT_XFER_CONTROL) | ||
1991 | mEp->qh[mEp->dir].ptr->cap |= QH_IOS; | ||
1992 | else if (mEp->type == USB_ENDPOINT_XFER_ISOC) | ||
1993 | mEp->qh[mEp->dir].ptr->cap &= ~QH_MULT; | ||
1994 | else | ||
1995 | mEp->qh[mEp->dir].ptr->cap &= ~QH_ZLT; | ||
1996 | |||
1997 | mEp->qh[mEp->dir].ptr->cap |= | ||
1998 | (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT; | ||
1999 | mEp->qh[mEp->dir].ptr->td.next |= TD_TERMINATE; /* needed? */ | ||
2000 | |||
2001 | retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type); | ||
2002 | |||
2003 | if (mEp->type == USB_ENDPOINT_XFER_CONTROL) | ||
2004 | mEp->dir = (mEp->dir == TX) ? RX : TX; | ||
2005 | |||
2006 | } while (mEp->dir != direction); | ||
2007 | |||
2008 | spin_unlock_irqrestore(mEp->lock, flags); | ||
2009 | return retval; | ||
2010 | } | ||
2011 | |||
2012 | /** | ||
2013 | * ep_disable: endpoint is no longer usable | ||
2014 | * | ||
2015 | * Check usb_ep_disable() at "usb_gadget.h" for details | ||
2016 | */ | ||
2017 | static int ep_disable(struct usb_ep *ep) | ||
2018 | { | ||
2019 | struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); | ||
2020 | int direction, retval = 0; | ||
2021 | unsigned long flags; | ||
2022 | |||
2023 | trace("%p", ep); | ||
2024 | |||
2025 | if (ep == NULL) | ||
2026 | return -EINVAL; | ||
2027 | else if (mEp->desc == NULL) | ||
2028 | return -EBUSY; | ||
2029 | |||
2030 | spin_lock_irqsave(mEp->lock, flags); | ||
2031 | |||
2032 | /* only internal SW should disable ctrl endpts */ | ||
2033 | |||
2034 | direction = mEp->dir; | ||
2035 | do { | ||
2036 | dbg_event(_usb_addr(mEp), "DISABLE", 0); | ||
2037 | |||
2038 | retval |= _ep_nuke(mEp); | ||
2039 | retval |= hw_ep_disable(mEp->num, mEp->dir); | ||
2040 | |||
2041 | if (mEp->type == USB_ENDPOINT_XFER_CONTROL) | ||
2042 | mEp->dir = (mEp->dir == TX) ? RX : TX; | ||
2043 | |||
2044 | } while (mEp->dir != direction); | ||
2045 | |||
2046 | mEp->desc = NULL; | ||
2047 | |||
2048 | spin_unlock_irqrestore(mEp->lock, flags); | ||
2049 | return retval; | ||
2050 | } | ||
2051 | |||
2052 | /** | ||
2053 | * ep_alloc_request: allocate a request object to use with this endpoint | ||
2054 | * | ||
2055 | * Check usb_ep_alloc_request() at "usb_gadget.h" for details | ||
2056 | */ | ||
2057 | static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) | ||
2058 | { | ||
2059 | struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); | ||
2060 | struct ci13xxx_req *mReq = NULL; | ||
2061 | unsigned long flags; | ||
2062 | |||
2063 | trace("%p, %i", ep, gfp_flags); | ||
2064 | |||
2065 | if (ep == NULL) { | ||
2066 | err("EINVAL"); | ||
2067 | return NULL; | ||
2068 | } | ||
2069 | |||
2070 | spin_lock_irqsave(mEp->lock, flags); | ||
2071 | |||
2072 | mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags); | ||
2073 | if (mReq != NULL) { | ||
2074 | INIT_LIST_HEAD(&mReq->queue); | ||
2075 | |||
2076 | mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags, | ||
2077 | &mReq->dma); | ||
2078 | if (mReq->ptr == NULL) { | ||
2079 | kfree(mReq); | ||
2080 | mReq = NULL; | ||
2081 | } | ||
2082 | } | ||
2083 | |||
2084 | dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL); | ||
2085 | |||
2086 | spin_unlock_irqrestore(mEp->lock, flags); | ||
2087 | |||
2088 | return (mReq == NULL) ? NULL : &mReq->req; | ||
2089 | } | ||
2090 | |||
2091 | /** | ||
2092 | * ep_free_request: frees a request object | ||
2093 | * | ||
2094 | * Check usb_ep_free_request() at "usb_gadget.h" for details | ||
2095 | */ | ||
2096 | static void ep_free_request(struct usb_ep *ep, struct usb_request *req) | ||
2097 | { | ||
2098 | struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); | ||
2099 | struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); | ||
2100 | unsigned long flags; | ||
2101 | |||
2102 | trace("%p, %p", ep, req); | ||
2103 | |||
2104 | if (ep == NULL || req == NULL) { | ||
2105 | err("EINVAL"); | ||
2106 | return; | ||
2107 | } else if (!list_empty(&mReq->queue)) { | ||
2108 | err("EBUSY"); | ||
2109 | return; | ||
2110 | } | ||
2111 | |||
2112 | spin_lock_irqsave(mEp->lock, flags); | ||
2113 | |||
2114 | if (mReq->ptr) | ||
2115 | dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma); | ||
2116 | kfree(mReq); | ||
2117 | |||
2118 | dbg_event(_usb_addr(mEp), "FREE", 0); | ||
2119 | |||
2120 | spin_unlock_irqrestore(mEp->lock, flags); | ||
2121 | } | ||
2122 | |||
2123 | /** | ||
2124 | * ep_queue: queues (submits) an I/O request to an endpoint | ||
2125 | * | ||
2126 | * Check usb_ep_queue()* at usb_gadget.h" for details | ||
2127 | */ | ||
2128 | static int ep_queue(struct usb_ep *ep, struct usb_request *req, | ||
2129 | gfp_t __maybe_unused gfp_flags) | ||
2130 | { | ||
2131 | struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); | ||
2132 | struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); | ||
2133 | int retval = 0; | ||
2134 | unsigned long flags; | ||
2135 | |||
2136 | trace("%p, %p, %X", ep, req, gfp_flags); | ||
2137 | |||
2138 | if (ep == NULL || req == NULL || mEp->desc == NULL) | ||
2139 | return -EINVAL; | ||
2140 | |||
2141 | spin_lock_irqsave(mEp->lock, flags); | ||
2142 | |||
2143 | if (mEp->type == USB_ENDPOINT_XFER_CONTROL && | ||
2144 | !list_empty(&mEp->qh[mEp->dir].queue)) { | ||
2145 | _ep_nuke(mEp); | ||
2146 | retval = -EOVERFLOW; | ||
2147 | warn("endpoint ctrl %X nuked", _usb_addr(mEp)); | ||
2148 | } | ||
2149 | |||
2150 | /* first nuke then test link, e.g. previous status has not sent */ | ||
2151 | if (!list_empty(&mReq->queue)) { | ||
2152 | retval = -EBUSY; | ||
2153 | err("request already in queue"); | ||
2154 | goto done; | ||
2155 | } | ||
2156 | |||
2157 | if (req->length > (4 * PAGE_SIZE)) { | ||
2158 | req->length = (4 * PAGE_SIZE); | ||
2159 | retval = -EMSGSIZE; | ||
2160 | warn("request length truncated"); | ||
2161 | } | ||
2162 | |||
2163 | dbg_queue(_usb_addr(mEp), req, retval); | ||
2164 | |||
2165 | /* push request */ | ||
2166 | mReq->req.status = -EINPROGRESS; | ||
2167 | mReq->req.actual = 0; | ||
2168 | list_add_tail(&mReq->queue, &mEp->qh[mEp->dir].queue); | ||
2169 | |||
2170 | retval = _hardware_enqueue(mEp, mReq); | ||
2171 | if (retval == -EALREADY || retval == -EBUSY) { | ||
2172 | dbg_event(_usb_addr(mEp), "QUEUE", retval); | ||
2173 | retval = 0; | ||
2174 | } | ||
2175 | |||
2176 | done: | ||
2177 | spin_unlock_irqrestore(mEp->lock, flags); | ||
2178 | return retval; | ||
2179 | } | ||
2180 | |||
2181 | /** | ||
2182 | * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint | ||
2183 | * | ||
2184 | * Check usb_ep_dequeue() at "usb_gadget.h" for details | ||
2185 | */ | ||
2186 | static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) | ||
2187 | { | ||
2188 | struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); | ||
2189 | struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); | ||
2190 | unsigned long flags; | ||
2191 | |||
2192 | trace("%p, %p", ep, req); | ||
2193 | |||
2194 | if (ep == NULL || req == NULL || mEp->desc == NULL || | ||
2195 | list_empty(&mReq->queue) || list_empty(&mEp->qh[mEp->dir].queue)) | ||
2196 | return -EINVAL; | ||
2197 | |||
2198 | spin_lock_irqsave(mEp->lock, flags); | ||
2199 | |||
2200 | dbg_event(_usb_addr(mEp), "DEQUEUE", 0); | ||
2201 | |||
2202 | if (mReq->req.status == -EALREADY) | ||
2203 | _hardware_dequeue(mEp, mReq); | ||
2204 | |||
2205 | /* pop request */ | ||
2206 | list_del_init(&mReq->queue); | ||
2207 | req->status = -ECONNRESET; | ||
2208 | |||
2209 | if (!mReq->req.no_interrupt && mReq->req.complete != NULL) { | ||
2210 | spin_unlock(mEp->lock); | ||
2211 | mReq->req.complete(&mEp->ep, &mReq->req); | ||
2212 | spin_lock(mEp->lock); | ||
2213 | } | ||
2214 | |||
2215 | spin_unlock_irqrestore(mEp->lock, flags); | ||
2216 | return 0; | ||
2217 | } | ||
2218 | |||
2219 | /** | ||
2220 | * ep_set_halt: sets the endpoint halt feature | ||
2221 | * | ||
2222 | * Check usb_ep_set_halt() at "usb_gadget.h" for details | ||
2223 | */ | ||
2224 | static int ep_set_halt(struct usb_ep *ep, int value) | ||
2225 | { | ||
2226 | struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); | ||
2227 | int direction, retval = 0; | ||
2228 | unsigned long flags; | ||
2229 | |||
2230 | trace("%p, %i", ep, value); | ||
2231 | |||
2232 | if (ep == NULL || mEp->desc == NULL) | ||
2233 | return -EINVAL; | ||
2234 | |||
2235 | spin_lock_irqsave(mEp->lock, flags); | ||
2236 | |||
2237 | #ifndef STALL_IN | ||
2238 | /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */ | ||
2239 | if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX && | ||
2240 | !list_empty(&mEp->qh[mEp->dir].queue)) { | ||
2241 | spin_unlock_irqrestore(mEp->lock, flags); | ||
2242 | return -EAGAIN; | ||
2243 | } | ||
2244 | #endif | ||
2245 | |||
2246 | direction = mEp->dir; | ||
2247 | do { | ||
2248 | dbg_event(_usb_addr(mEp), "HALT", value); | ||
2249 | retval |= hw_ep_set_halt(mEp->num, mEp->dir, value); | ||
2250 | |||
2251 | if (!value) | ||
2252 | mEp->wedge = 0; | ||
2253 | |||
2254 | if (mEp->type == USB_ENDPOINT_XFER_CONTROL) | ||
2255 | mEp->dir = (mEp->dir == TX) ? RX : TX; | ||
2256 | |||
2257 | } while (mEp->dir != direction); | ||
2258 | |||
2259 | spin_unlock_irqrestore(mEp->lock, flags); | ||
2260 | return retval; | ||
2261 | } | ||
2262 | |||
2263 | /** | ||
2264 | * ep_set_wedge: sets the halt feature and ignores clear requests | ||
2265 | * | ||
2266 | * Check usb_ep_set_wedge() at "usb_gadget.h" for details | ||
2267 | */ | ||
2268 | static int ep_set_wedge(struct usb_ep *ep) | ||
2269 | { | ||
2270 | struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); | ||
2271 | unsigned long flags; | ||
2272 | |||
2273 | trace("%p", ep); | ||
2274 | |||
2275 | if (ep == NULL || mEp->desc == NULL) | ||
2276 | return -EINVAL; | ||
2277 | |||
2278 | spin_lock_irqsave(mEp->lock, flags); | ||
2279 | |||
2280 | dbg_event(_usb_addr(mEp), "WEDGE", 0); | ||
2281 | mEp->wedge = 1; | ||
2282 | |||
2283 | spin_unlock_irqrestore(mEp->lock, flags); | ||
2284 | |||
2285 | return usb_ep_set_halt(ep); | ||
2286 | } | ||
2287 | |||
2288 | /** | ||
2289 | * ep_fifo_flush: flushes contents of a fifo | ||
2290 | * | ||
2291 | * Check usb_ep_fifo_flush() at "usb_gadget.h" for details | ||
2292 | */ | ||
2293 | static void ep_fifo_flush(struct usb_ep *ep) | ||
2294 | { | ||
2295 | struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); | ||
2296 | unsigned long flags; | ||
2297 | |||
2298 | trace("%p", ep); | ||
2299 | |||
2300 | if (ep == NULL) { | ||
2301 | err("%02X: -EINVAL", _usb_addr(mEp)); | ||
2302 | return; | ||
2303 | } | ||
2304 | |||
2305 | spin_lock_irqsave(mEp->lock, flags); | ||
2306 | |||
2307 | dbg_event(_usb_addr(mEp), "FFLUSH", 0); | ||
2308 | hw_ep_flush(mEp->num, mEp->dir); | ||
2309 | |||
2310 | spin_unlock_irqrestore(mEp->lock, flags); | ||
2311 | } | ||
2312 | |||
2313 | /** | ||
2314 | * Endpoint-specific part of the API to the USB controller hardware | ||
2315 | * Check "usb_gadget.h" for details | ||
2316 | */ | ||
2317 | static const struct usb_ep_ops usb_ep_ops = { | ||
2318 | .enable = ep_enable, | ||
2319 | .disable = ep_disable, | ||
2320 | .alloc_request = ep_alloc_request, | ||
2321 | .free_request = ep_free_request, | ||
2322 | .queue = ep_queue, | ||
2323 | .dequeue = ep_dequeue, | ||
2324 | .set_halt = ep_set_halt, | ||
2325 | .set_wedge = ep_set_wedge, | ||
2326 | .fifo_flush = ep_fifo_flush, | ||
2327 | }; | ||
2328 | |||
2329 | /****************************************************************************** | ||
2330 | * GADGET block | ||
2331 | *****************************************************************************/ | ||
2332 | /** | ||
2333 | * Device operations part of the API to the USB controller hardware, | ||
2334 | * which don't involve endpoints (or i/o) | ||
2335 | * Check "usb_gadget.h" for details | ||
2336 | */ | ||
2337 | static const struct usb_gadget_ops usb_gadget_ops; | ||
2338 | |||
2339 | /** | ||
2340 | * usb_gadget_register_driver: register a gadget driver | ||
2341 | * | ||
2342 | * Check usb_gadget_register_driver() at "usb_gadget.h" for details | ||
2343 | * Interrupts are enabled here | ||
2344 | */ | ||
2345 | int usb_gadget_register_driver(struct usb_gadget_driver *driver) | ||
2346 | { | ||
2347 | struct ci13xxx *udc = _udc; | ||
2348 | unsigned long i, k, flags; | ||
2349 | int retval = -ENOMEM; | ||
2350 | |||
2351 | trace("%p", driver); | ||
2352 | |||
2353 | if (driver == NULL || | ||
2354 | driver->bind == NULL || | ||
2355 | driver->unbind == NULL || | ||
2356 | driver->setup == NULL || | ||
2357 | driver->disconnect == NULL || | ||
2358 | driver->suspend == NULL || | ||
2359 | driver->resume == NULL) | ||
2360 | return -EINVAL; | ||
2361 | else if (udc == NULL) | ||
2362 | return -ENODEV; | ||
2363 | else if (udc->driver != NULL) | ||
2364 | return -EBUSY; | ||
2365 | |||
2366 | /* alloc resources */ | ||
2367 | udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev, | ||
2368 | sizeof(struct ci13xxx_qh), | ||
2369 | 64, PAGE_SIZE); | ||
2370 | if (udc->qh_pool == NULL) | ||
2371 | return -ENOMEM; | ||
2372 | |||
2373 | udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev, | ||
2374 | sizeof(struct ci13xxx_td), | ||
2375 | 64, PAGE_SIZE); | ||
2376 | if (udc->td_pool == NULL) { | ||
2377 | dma_pool_destroy(udc->qh_pool); | ||
2378 | udc->qh_pool = NULL; | ||
2379 | return -ENOMEM; | ||
2380 | } | ||
2381 | |||
2382 | spin_lock_irqsave(udc->lock, flags); | ||
2383 | |||
2384 | info("hw_ep_max = %d", hw_ep_max); | ||
2385 | |||
2386 | udc->driver = driver; | ||
2387 | udc->gadget.ops = NULL; | ||
2388 | udc->gadget.dev.driver = NULL; | ||
2389 | |||
2390 | retval = 0; | ||
2391 | for (i = 0; i < hw_ep_max; i++) { | ||
2392 | struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; | ||
2393 | |||
2394 | scnprintf(mEp->name, sizeof(mEp->name), "ep%i", (int)i); | ||
2395 | |||
2396 | mEp->lock = udc->lock; | ||
2397 | mEp->device = &udc->gadget.dev; | ||
2398 | mEp->td_pool = udc->td_pool; | ||
2399 | |||
2400 | mEp->ep.name = mEp->name; | ||
2401 | mEp->ep.ops = &usb_ep_ops; | ||
2402 | mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; | ||
2403 | |||
2404 | /* this allocation cannot be random */ | ||
2405 | for (k = RX; k <= TX; k++) { | ||
2406 | INIT_LIST_HEAD(&mEp->qh[k].queue); | ||
2407 | mEp->qh[k].ptr = dma_pool_alloc(udc->qh_pool, | ||
2408 | GFP_KERNEL, | ||
2409 | &mEp->qh[k].dma); | ||
2410 | if (mEp->qh[k].ptr == NULL) | ||
2411 | retval = -ENOMEM; | ||
2412 | else | ||
2413 | memset(mEp->qh[k].ptr, 0, | ||
2414 | sizeof(*mEp->qh[k].ptr)); | ||
2415 | } | ||
2416 | if (i == 0) | ||
2417 | udc->gadget.ep0 = &mEp->ep; | ||
2418 | else | ||
2419 | list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list); | ||
2420 | } | ||
2421 | if (retval) | ||
2422 | goto done; | ||
2423 | |||
2424 | /* bind gadget */ | ||
2425 | driver->driver.bus = NULL; | ||
2426 | udc->gadget.ops = &usb_gadget_ops; | ||
2427 | udc->gadget.dev.driver = &driver->driver; | ||
2428 | |||
2429 | spin_unlock_irqrestore(udc->lock, flags); | ||
2430 | retval = driver->bind(&udc->gadget); /* MAY SLEEP */ | ||
2431 | spin_lock_irqsave(udc->lock, flags); | ||
2432 | |||
2433 | if (retval) { | ||
2434 | udc->gadget.ops = NULL; | ||
2435 | udc->gadget.dev.driver = NULL; | ||
2436 | goto done; | ||
2437 | } | ||
2438 | |||
2439 | retval = hw_device_state(udc->ci13xxx_ep[0].qh[RX].dma); | ||
2440 | |||
2441 | done: | ||
2442 | spin_unlock_irqrestore(udc->lock, flags); | ||
2443 | if (retval) | ||
2444 | usb_gadget_unregister_driver(driver); | ||
2445 | return retval; | ||
2446 | } | ||
2447 | EXPORT_SYMBOL(usb_gadget_register_driver); | ||
2448 | |||
2449 | /** | ||
2450 | * usb_gadget_unregister_driver: unregister a gadget driver | ||
2451 | * | ||
2452 | * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details | ||
2453 | */ | ||
2454 | int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) | ||
2455 | { | ||
2456 | struct ci13xxx *udc = _udc; | ||
2457 | unsigned long i, k, flags; | ||
2458 | |||
2459 | trace("%p", driver); | ||
2460 | |||
2461 | if (driver == NULL || | ||
2462 | driver->bind == NULL || | ||
2463 | driver->unbind == NULL || | ||
2464 | driver->setup == NULL || | ||
2465 | driver->disconnect == NULL || | ||
2466 | driver->suspend == NULL || | ||
2467 | driver->resume == NULL || | ||
2468 | driver != udc->driver) | ||
2469 | return -EINVAL; | ||
2470 | |||
2471 | spin_lock_irqsave(udc->lock, flags); | ||
2472 | |||
2473 | hw_device_state(0); | ||
2474 | |||
2475 | /* unbind gadget */ | ||
2476 | if (udc->gadget.ops != NULL) { | ||
2477 | _gadget_stop_activity(&udc->gadget); | ||
2478 | |||
2479 | spin_unlock_irqrestore(udc->lock, flags); | ||
2480 | driver->unbind(&udc->gadget); /* MAY SLEEP */ | ||
2481 | spin_lock_irqsave(udc->lock, flags); | ||
2482 | |||
2483 | udc->gadget.ops = NULL; | ||
2484 | udc->gadget.dev.driver = NULL; | ||
2485 | } | ||
2486 | |||
2487 | /* free resources */ | ||
2488 | for (i = 0; i < hw_ep_max; i++) { | ||
2489 | struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; | ||
2490 | |||
2491 | if (i == 0) | ||
2492 | udc->gadget.ep0 = NULL; | ||
2493 | else if (!list_empty(&mEp->ep.ep_list)) | ||
2494 | list_del_init(&mEp->ep.ep_list); | ||
2495 | |||
2496 | for (k = RX; k <= TX; k++) | ||
2497 | if (mEp->qh[k].ptr != NULL) | ||
2498 | dma_pool_free(udc->qh_pool, | ||
2499 | mEp->qh[k].ptr, mEp->qh[k].dma); | ||
2500 | } | ||
2501 | |||
2502 | udc->driver = NULL; | ||
2503 | |||
2504 | spin_unlock_irqrestore(udc->lock, flags); | ||
2505 | |||
2506 | if (udc->td_pool != NULL) { | ||
2507 | dma_pool_destroy(udc->td_pool); | ||
2508 | udc->td_pool = NULL; | ||
2509 | } | ||
2510 | if (udc->qh_pool != NULL) { | ||
2511 | dma_pool_destroy(udc->qh_pool); | ||
2512 | udc->qh_pool = NULL; | ||
2513 | } | ||
2514 | |||
2515 | return 0; | ||
2516 | } | ||
2517 | EXPORT_SYMBOL(usb_gadget_unregister_driver); | ||
2518 | |||
2519 | /****************************************************************************** | ||
2520 | * BUS block | ||
2521 | *****************************************************************************/ | ||
2522 | /** | ||
2523 | * udc_irq: global interrupt handler | ||
2524 | * | ||
2525 | * This function returns IRQ_HANDLED if the IRQ has been handled | ||
2526 | * It locks access to registers | ||
2527 | */ | ||
2528 | static irqreturn_t udc_irq(void) | ||
2529 | { | ||
2530 | struct ci13xxx *udc = _udc; | ||
2531 | irqreturn_t retval; | ||
2532 | u32 intr; | ||
2533 | |||
2534 | trace(); | ||
2535 | |||
2536 | if (udc == NULL) { | ||
2537 | err("ENODEV"); | ||
2538 | return IRQ_HANDLED; | ||
2539 | } | ||
2540 | |||
2541 | spin_lock(udc->lock); | ||
2542 | intr = hw_test_and_clear_intr_active(); | ||
2543 | if (intr) { | ||
2544 | isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr; | ||
2545 | isr_statistics.hndl.idx &= ISR_MASK; | ||
2546 | isr_statistics.hndl.cnt++; | ||
2547 | |||
2548 | /* order defines priority - do NOT change it */ | ||
2549 | if (USBi_URI & intr) { | ||
2550 | isr_statistics.uri++; | ||
2551 | isr_reset_handler(udc); | ||
2552 | } | ||
2553 | if (USBi_PCI & intr) { | ||
2554 | isr_statistics.pci++; | ||
2555 | udc->gadget.speed = hw_port_is_high_speed() ? | ||
2556 | USB_SPEED_HIGH : USB_SPEED_FULL; | ||
2557 | } | ||
2558 | if (USBi_UEI & intr) | ||
2559 | isr_statistics.uei++; | ||
2560 | if (USBi_UI & intr) { | ||
2561 | isr_statistics.ui++; | ||
2562 | isr_tr_complete_handler(udc); | ||
2563 | } | ||
2564 | if (USBi_SLI & intr) | ||
2565 | isr_statistics.sli++; | ||
2566 | retval = IRQ_HANDLED; | ||
2567 | } else { | ||
2568 | isr_statistics.none++; | ||
2569 | retval = IRQ_NONE; | ||
2570 | } | ||
2571 | spin_unlock(udc->lock); | ||
2572 | |||
2573 | return retval; | ||
2574 | } | ||
2575 | |||
2576 | /** | ||
2577 | * udc_release: driver release function | ||
2578 | * @dev: device | ||
2579 | * | ||
2580 | * Currently does nothing | ||
2581 | */ | ||
2582 | static void udc_release(struct device *dev) | ||
2583 | { | ||
2584 | trace("%p", dev); | ||
2585 | |||
2586 | if (dev == NULL) | ||
2587 | err("EINVAL"); | ||
2588 | } | ||
2589 | |||
2590 | /** | ||
2591 | * udc_probe: parent probe must call this to initialize UDC | ||
2592 | * @dev: parent device | ||
2593 | * @regs: registers base address | ||
2594 | * @name: driver name | ||
2595 | * | ||
2596 | * This function returns an error code | ||
2597 | * No interrupts active, the IRQ has not been requested yet | ||
2598 | * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask | ||
2599 | */ | ||
2600 | static int udc_probe(struct device *dev, void __iomem *regs, const char *name) | ||
2601 | { | ||
2602 | struct ci13xxx *udc; | ||
2603 | int retval = 0; | ||
2604 | |||
2605 | trace("%p, %p, %p", dev, regs, name); | ||
2606 | |||
2607 | if (dev == NULL || regs == NULL || name == NULL) | ||
2608 | return -EINVAL; | ||
2609 | |||
2610 | udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL); | ||
2611 | if (udc == NULL) | ||
2612 | return -ENOMEM; | ||
2613 | |||
2614 | udc->lock = &udc_lock; | ||
2615 | |||
2616 | retval = hw_device_reset(regs); | ||
2617 | if (retval) | ||
2618 | goto done; | ||
2619 | |||
2620 | udc->gadget.ops = NULL; | ||
2621 | udc->gadget.speed = USB_SPEED_UNKNOWN; | ||
2622 | udc->gadget.is_dualspeed = 1; | ||
2623 | udc->gadget.is_otg = 0; | ||
2624 | udc->gadget.name = name; | ||
2625 | |||
2626 | INIT_LIST_HEAD(&udc->gadget.ep_list); | ||
2627 | udc->gadget.ep0 = NULL; | ||
2628 | |||
2629 | strcpy(udc->gadget.dev.bus_id, "gadget"); | ||
2630 | udc->gadget.dev.dma_mask = dev->dma_mask; | ||
2631 | udc->gadget.dev.parent = dev; | ||
2632 | udc->gadget.dev.release = udc_release; | ||
2633 | |||
2634 | retval = device_register(&udc->gadget.dev); | ||
2635 | if (retval) | ||
2636 | goto done; | ||
2637 | |||
2638 | #ifdef CONFIG_USB_GADGET_DEBUG_FILES | ||
2639 | retval = dbg_create_files(&udc->gadget.dev); | ||
2640 | #endif | ||
2641 | if (retval) { | ||
2642 | device_unregister(&udc->gadget.dev); | ||
2643 | goto done; | ||
2644 | } | ||
2645 | |||
2646 | _udc = udc; | ||
2647 | return retval; | ||
2648 | |||
2649 | done: | ||
2650 | err("error = %i", retval); | ||
2651 | kfree(udc); | ||
2652 | _udc = NULL; | ||
2653 | return retval; | ||
2654 | } | ||
2655 | |||
2656 | /** | ||
2657 | * udc_remove: parent remove must call this to remove UDC | ||
2658 | * | ||
2659 | * No interrupts active, the IRQ has been released | ||
2660 | */ | ||
2661 | static void udc_remove(void) | ||
2662 | { | ||
2663 | struct ci13xxx *udc = _udc; | ||
2664 | |||
2665 | if (udc == NULL) { | ||
2666 | err("EINVAL"); | ||
2667 | return; | ||
2668 | } | ||
2669 | |||
2670 | #ifdef CONFIG_USB_GADGET_DEBUG_FILES | ||
2671 | dbg_remove_files(&udc->gadget.dev); | ||
2672 | #endif | ||
2673 | device_unregister(&udc->gadget.dev); | ||
2674 | |||
2675 | kfree(udc); | ||
2676 | _udc = NULL; | ||
2677 | } | ||
2678 | |||
2679 | /****************************************************************************** | ||
2680 | * PCI block | ||
2681 | *****************************************************************************/ | ||
2682 | /** | ||
2683 | * ci13xxx_pci_irq: interrut handler | ||
2684 | * @irq: irq number | ||
2685 | * @pdev: USB Device Controller interrupt source | ||
2686 | * | ||
2687 | * This function returns IRQ_HANDLED if the IRQ has been handled | ||
2688 | * This is an ISR don't trace, use attribute interface instead | ||
2689 | */ | ||
2690 | static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev) | ||
2691 | { | ||
2692 | if (irq == 0) { | ||
2693 | dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!"); | ||
2694 | return IRQ_HANDLED; | ||
2695 | } | ||
2696 | return udc_irq(); | ||
2697 | } | ||
2698 | |||
2699 | /** | ||
2700 | * ci13xxx_pci_probe: PCI probe | ||
2701 | * @pdev: USB device controller being probed | ||
2702 | * @id: PCI hotplug ID connecting controller to UDC framework | ||
2703 | * | ||
2704 | * This function returns an error code | ||
2705 | * Allocates basic PCI resources for this USB device controller, and then | ||
2706 | * invokes the udc_probe() method to start the UDC associated with it | ||
2707 | */ | ||
2708 | static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev, | ||
2709 | const struct pci_device_id *id) | ||
2710 | { | ||
2711 | void __iomem *regs = NULL; | ||
2712 | int retval = 0; | ||
2713 | |||
2714 | if (id == NULL) | ||
2715 | return -EINVAL; | ||
2716 | |||
2717 | retval = pci_enable_device(pdev); | ||
2718 | if (retval) | ||
2719 | goto done; | ||
2720 | |||
2721 | if (!pdev->irq) { | ||
2722 | dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!"); | ||
2723 | retval = -ENODEV; | ||
2724 | goto disable_device; | ||
2725 | } | ||
2726 | |||
2727 | retval = pci_request_regions(pdev, UDC_DRIVER_NAME); | ||
2728 | if (retval) | ||
2729 | goto disable_device; | ||
2730 | |||
2731 | /* BAR 0 holds all the registers */ | ||
2732 | regs = pci_iomap(pdev, 0, 0); | ||
2733 | if (!regs) { | ||
2734 | dev_err(&pdev->dev, "Error mapping memory!"); | ||
2735 | retval = -EFAULT; | ||
2736 | goto release_regions; | ||
2737 | } | ||
2738 | pci_set_drvdata(pdev, (__force void *)regs); | ||
2739 | |||
2740 | pci_set_master(pdev); | ||
2741 | pci_try_set_mwi(pdev); | ||
2742 | |||
2743 | retval = udc_probe(&pdev->dev, regs, UDC_DRIVER_NAME); | ||
2744 | if (retval) | ||
2745 | goto iounmap; | ||
2746 | |||
2747 | /* our device does not have MSI capability */ | ||
2748 | |||
2749 | retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED, | ||
2750 | UDC_DRIVER_NAME, pdev); | ||
2751 | if (retval) | ||
2752 | goto gadget_remove; | ||
2753 | |||
2754 | return 0; | ||
2755 | |||
2756 | gadget_remove: | ||
2757 | udc_remove(); | ||
2758 | iounmap: | ||
2759 | pci_iounmap(pdev, regs); | ||
2760 | release_regions: | ||
2761 | pci_release_regions(pdev); | ||
2762 | disable_device: | ||
2763 | pci_disable_device(pdev); | ||
2764 | done: | ||
2765 | return retval; | ||
2766 | } | ||
2767 | |||
2768 | /** | ||
2769 | * ci13xxx_pci_remove: PCI remove | ||
2770 | * @pdev: USB Device Controller being removed | ||
2771 | * | ||
2772 | * Reverses the effect of ci13xxx_pci_probe(), | ||
2773 | * first invoking the udc_remove() and then releases | ||
2774 | * all PCI resources allocated for this USB device controller | ||
2775 | */ | ||
2776 | static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev) | ||
2777 | { | ||
2778 | free_irq(pdev->irq, pdev); | ||
2779 | udc_remove(); | ||
2780 | pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev)); | ||
2781 | pci_release_regions(pdev); | ||
2782 | pci_disable_device(pdev); | ||
2783 | } | ||
2784 | |||
2785 | /** | ||
2786 | * PCI device table | ||
2787 | * PCI device structure | ||
2788 | * | ||
2789 | * Check "pci.h" for details | ||
2790 | */ | ||
2791 | static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = { | ||
2792 | { PCI_DEVICE(0x153F, 0x1004) }, | ||
2793 | { PCI_DEVICE(0x153F, 0x1006) }, | ||
2794 | { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ } | ||
2795 | }; | ||
2796 | MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table); | ||
2797 | |||
2798 | static struct pci_driver ci13xxx_pci_driver = { | ||
2799 | .name = UDC_DRIVER_NAME, | ||
2800 | .id_table = ci13xxx_pci_id_table, | ||
2801 | .probe = ci13xxx_pci_probe, | ||
2802 | .remove = __devexit_p(ci13xxx_pci_remove), | ||
2803 | }; | ||
2804 | |||
2805 | /** | ||
2806 | * ci13xxx_pci_init: module init | ||
2807 | * | ||
2808 | * Driver load | ||
2809 | */ | ||
2810 | static int __init ci13xxx_pci_init(void) | ||
2811 | { | ||
2812 | return pci_register_driver(&ci13xxx_pci_driver); | ||
2813 | } | ||
2814 | module_init(ci13xxx_pci_init); | ||
2815 | |||
2816 | /** | ||
2817 | * ci13xxx_pci_exit: module exit | ||
2818 | * | ||
2819 | * Driver unload | ||
2820 | */ | ||
2821 | static void __exit ci13xxx_pci_exit(void) | ||
2822 | { | ||
2823 | pci_unregister_driver(&ci13xxx_pci_driver); | ||
2824 | } | ||
2825 | module_exit(ci13xxx_pci_exit); | ||
2826 | |||
2827 | MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>"); | ||
2828 | MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller"); | ||
2829 | MODULE_LICENSE("GPL"); | ||
2830 | MODULE_VERSION("June 2008"); | ||
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h new file mode 100644 index 000000000000..4026e9cede34 --- /dev/null +++ b/drivers/usb/gadget/ci13xxx_udc.h | |||
@@ -0,0 +1,195 @@ | |||
1 | /* | ||
2 | * ci13xxx_udc.h - structures, registers, and macros MIPS USB IP core | ||
3 | * | ||
4 | * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. | ||
5 | * | ||
6 | * Author: David Lopo | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * Description: MIPS USB IP core family device controller | ||
13 | * Structures, registers and logging macros | ||
14 | */ | ||
15 | |||
16 | #ifndef _CI13XXX_h_ | ||
17 | #define _CI13XXX_h_ | ||
18 | |||
19 | /****************************************************************************** | ||
20 | * DEFINE | ||
21 | *****************************************************************************/ | ||
22 | #define ENDPT_MAX (16) | ||
23 | #define CTRL_PAYLOAD_MAX (64) | ||
24 | #define RX (0) /* similar to USB_DIR_OUT but can be used as an index */ | ||
25 | #define TX (1) /* similar to USB_DIR_IN but can be used as an index */ | ||
26 | |||
27 | /****************************************************************************** | ||
28 | * STRUCTURES | ||
29 | *****************************************************************************/ | ||
30 | /* DMA layout of transfer descriptors */ | ||
31 | struct ci13xxx_td { | ||
32 | /* 0 */ | ||
33 | u32 next; | ||
34 | #define TD_TERMINATE BIT(0) | ||
35 | /* 1 */ | ||
36 | u32 token; | ||
37 | #define TD_STATUS (0x00FFUL << 0) | ||
38 | #define TD_STATUS_TR_ERR BIT(3) | ||
39 | #define TD_STATUS_DT_ERR BIT(5) | ||
40 | #define TD_STATUS_HALTED BIT(6) | ||
41 | #define TD_STATUS_ACTIVE BIT(7) | ||
42 | #define TD_MULTO (0x0003UL << 10) | ||
43 | #define TD_IOC BIT(15) | ||
44 | #define TD_TOTAL_BYTES (0x7FFFUL << 16) | ||
45 | /* 2 */ | ||
46 | u32 page[5]; | ||
47 | #define TD_CURR_OFFSET (0x0FFFUL << 0) | ||
48 | #define TD_FRAME_NUM (0x07FFUL << 0) | ||
49 | #define TD_RESERVED_MASK (0x0FFFUL << 0) | ||
50 | } __attribute__ ((packed)); | ||
51 | |||
52 | /* DMA layout of queue heads */ | ||
53 | struct ci13xxx_qh { | ||
54 | /* 0 */ | ||
55 | u32 cap; | ||
56 | #define QH_IOS BIT(15) | ||
57 | #define QH_MAX_PKT (0x07FFUL << 16) | ||
58 | #define QH_ZLT BIT(29) | ||
59 | #define QH_MULT (0x0003UL << 30) | ||
60 | /* 1 */ | ||
61 | u32 curr; | ||
62 | /* 2 - 8 */ | ||
63 | struct ci13xxx_td td; | ||
64 | /* 9 */ | ||
65 | u32 RESERVED; | ||
66 | struct usb_ctrlrequest setup; | ||
67 | } __attribute__ ((packed)); | ||
68 | |||
69 | /* Extension of usb_request */ | ||
70 | struct ci13xxx_req { | ||
71 | struct usb_request req; | ||
72 | unsigned map; | ||
73 | struct list_head queue; | ||
74 | struct ci13xxx_td *ptr; | ||
75 | dma_addr_t dma; | ||
76 | }; | ||
77 | |||
78 | /* Extension of usb_ep */ | ||
79 | struct ci13xxx_ep { | ||
80 | struct usb_ep ep; | ||
81 | const struct usb_endpoint_descriptor *desc; | ||
82 | u8 dir; | ||
83 | u8 num; | ||
84 | u8 type; | ||
85 | char name[16]; | ||
86 | struct { | ||
87 | struct list_head queue; | ||
88 | struct ci13xxx_qh *ptr; | ||
89 | dma_addr_t dma; | ||
90 | } qh[2]; | ||
91 | struct usb_request *status; | ||
92 | int wedge; | ||
93 | |||
94 | /* global resources */ | ||
95 | spinlock_t *lock; | ||
96 | struct device *device; | ||
97 | struct dma_pool *td_pool; | ||
98 | }; | ||
99 | |||
100 | /* CI13XXX UDC descriptor & global resources */ | ||
101 | struct ci13xxx { | ||
102 | spinlock_t *lock; /* ctrl register bank access */ | ||
103 | |||
104 | struct dma_pool *qh_pool; /* DMA pool for queue heads */ | ||
105 | struct dma_pool *td_pool; /* DMA pool for transfer descs */ | ||
106 | |||
107 | struct usb_gadget gadget; /* USB slave device */ | ||
108 | struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */ | ||
109 | |||
110 | struct usb_gadget_driver *driver; /* 3rd party gadget driver */ | ||
111 | }; | ||
112 | |||
113 | /****************************************************************************** | ||
114 | * REGISTERS | ||
115 | *****************************************************************************/ | ||
116 | /* register size */ | ||
117 | #define REG_BITS (32) | ||
118 | |||
119 | /* HCCPARAMS */ | ||
120 | #define HCCPARAMS_LEN BIT(17) | ||
121 | |||
122 | /* DCCPARAMS */ | ||
123 | #define DCCPARAMS_DEN (0x1F << 0) | ||
124 | #define DCCPARAMS_DC BIT(7) | ||
125 | |||
126 | /* TESTMODE */ | ||
127 | #define TESTMODE_FORCE BIT(0) | ||
128 | |||
129 | /* USBCMD */ | ||
130 | #define USBCMD_RS BIT(0) | ||
131 | #define USBCMD_RST BIT(1) | ||
132 | #define USBCMD_SUTW BIT(13) | ||
133 | |||
134 | /* USBSTS & USBINTR */ | ||
135 | #define USBi_UI BIT(0) | ||
136 | #define USBi_UEI BIT(1) | ||
137 | #define USBi_PCI BIT(2) | ||
138 | #define USBi_URI BIT(6) | ||
139 | #define USBi_SLI BIT(8) | ||
140 | |||
141 | /* DEVICEADDR */ | ||
142 | #define DEVICEADDR_USBADRA BIT(24) | ||
143 | #define DEVICEADDR_USBADR (0x7FUL << 25) | ||
144 | |||
145 | /* PORTSC */ | ||
146 | #define PORTSC_SUSP BIT(7) | ||
147 | #define PORTSC_HSP BIT(9) | ||
148 | #define PORTSC_PTC (0x0FUL << 16) | ||
149 | |||
150 | /* DEVLC */ | ||
151 | #define DEVLC_PSPD (0x03UL << 25) | ||
152 | #define DEVLC_PSPD_HS (0x02UL << 25) | ||
153 | |||
154 | /* USBMODE */ | ||
155 | #define USBMODE_CM (0x03UL << 0) | ||
156 | #define USBMODE_CM_IDLE (0x00UL << 0) | ||
157 | #define USBMODE_CM_DEVICE (0x02UL << 0) | ||
158 | #define USBMODE_CM_HOST (0x03UL << 0) | ||
159 | #define USBMODE_SLOM BIT(3) | ||
160 | |||
161 | /* ENDPTCTRL */ | ||
162 | #define ENDPTCTRL_RXS BIT(0) | ||
163 | #define ENDPTCTRL_RXT (0x03UL << 2) | ||
164 | #define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */ | ||
165 | #define ENDPTCTRL_RXE BIT(7) | ||
166 | #define ENDPTCTRL_TXS BIT(16) | ||
167 | #define ENDPTCTRL_TXT (0x03UL << 18) | ||
168 | #define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */ | ||
169 | #define ENDPTCTRL_TXE BIT(23) | ||
170 | |||
171 | /****************************************************************************** | ||
172 | * LOGGING | ||
173 | *****************************************************************************/ | ||
174 | #define ci13xxx_printk(level, format, args...) \ | ||
175 | do { \ | ||
176 | if (_udc == NULL) \ | ||
177 | printk(level "[%s] " format "\n", __func__, ## args); \ | ||
178 | else \ | ||
179 | dev_printk(level, _udc->gadget.dev.parent, \ | ||
180 | "[%s] " format "\n", __func__, ## args); \ | ||
181 | } while (0) | ||
182 | |||
183 | #define err(format, args...) ci13xxx_printk(KERN_ERR, format, ## args) | ||
184 | #define warn(format, args...) ci13xxx_printk(KERN_WARNING, format, ## args) | ||
185 | #define info(format, args...) ci13xxx_printk(KERN_INFO, format, ## args) | ||
186 | |||
187 | #ifdef TRACE | ||
188 | #define trace(format, args...) ci13xxx_printk(KERN_DEBUG, format, ## args) | ||
189 | #define dbg_trace(format, args...) dev_dbg(dev, format, ##args) | ||
190 | #else | ||
191 | #define trace(format, args...) do {} while (0) | ||
192 | #define dbg_trace(format, args...) do {} while (0) | ||
193 | #endif | ||
194 | |||
195 | #endif /* _CI13XXX_h_ */ | ||
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index 4e3107dd2f34..c0679b176027 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h | |||
@@ -158,6 +158,11 @@ | |||
158 | #define gadget_is_fsl_qe(g) 0 | 158 | #define gadget_is_fsl_qe(g) 0 |
159 | #endif | 159 | #endif |
160 | 160 | ||
161 | #ifdef CONFIG_USB_GADGET_CI13XXX | ||
162 | #define gadget_is_ci13xxx(g) (!strcmp("ci13xxx_udc", (g)->name)) | ||
163 | #else | ||
164 | #define gadget_is_ci13xxx(g) 0 | ||
165 | #endif | ||
161 | 166 | ||
162 | // CONFIG_USB_GADGET_SX2 | 167 | // CONFIG_USB_GADGET_SX2 |
163 | // CONFIG_USB_GADGET_AU1X00 | 168 | // CONFIG_USB_GADGET_AU1X00 |
@@ -225,6 +230,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) | |||
225 | return 0x21; | 230 | return 0x21; |
226 | else if (gadget_is_fsl_qe(gadget)) | 231 | else if (gadget_is_fsl_qe(gadget)) |
227 | return 0x22; | 232 | return 0x22; |
233 | else if (gadget_is_ci13xxx(gadget)) | ||
234 | return 0x23; | ||
228 | return -ENOENT; | 235 | return -ENOENT; |
229 | } | 236 | } |
230 | 237 | ||