diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/target/arm/tcc77x/system-tcc77x.c | 6 | ||||
-rw-r--r-- | firmware/target/arm/tcc77x/usb-tcc77x.c | 738 | ||||
-rw-r--r-- | firmware/usb.c | 3 |
3 files changed, 742 insertions, 5 deletions
diff --git a/firmware/target/arm/tcc77x/system-tcc77x.c b/firmware/target/arm/tcc77x/system-tcc77x.c index 2c8959fded..38004851bd 100644 --- a/firmware/target/arm/tcc77x/system-tcc77x.c +++ b/firmware/target/arm/tcc77x/system-tcc77x.c | |||
@@ -26,7 +26,7 @@ | |||
26 | /* Externally defined interrupt handlers */ | 26 | /* Externally defined interrupt handlers */ |
27 | extern void TIMER(void); | 27 | extern void TIMER(void); |
28 | extern void ADC(void); | 28 | extern void ADC(void); |
29 | extern void USBD_IRQ(void); | 29 | extern void USB_DEVICE(void); |
30 | 30 | ||
31 | void irq(void) | 31 | void irq(void) |
32 | { | 32 | { |
@@ -37,9 +37,9 @@ void irq(void) | |||
37 | TIMER(); | 37 | TIMER(); |
38 | else if (irq & ADC_IRQ_MASK) | 38 | else if (irq & ADC_IRQ_MASK) |
39 | ADC(); | 39 | ADC(); |
40 | #ifdef HAVE_USBSTACK | 40 | #ifdef HAVE_USBSTACK |
41 | else if (irq & USBD_IRQ_MASK) | 41 | else if (irq & USBD_IRQ_MASK) |
42 | USBD_IRQ(); | 42 | USB_DEVICE(); |
43 | #endif | 43 | #endif |
44 | else | 44 | else |
45 | panicf("Unhandled IRQ 0x%08X", irq); | 45 | panicf("Unhandled IRQ 0x%08X", irq); |
diff --git a/firmware/target/arm/tcc77x/usb-tcc77x.c b/firmware/target/arm/tcc77x/usb-tcc77x.c index 9cfcb503e0..1092ed60a1 100644 --- a/firmware/target/arm/tcc77x/usb-tcc77x.c +++ b/firmware/target/arm/tcc77x/usb-tcc77x.c | |||
@@ -21,9 +21,744 @@ | |||
21 | 21 | ||
22 | #include "config.h" | 22 | #include "config.h" |
23 | #include "usb.h" | 23 | #include "usb.h" |
24 | #include "system.h" | 24 | |
25 | #include "usb-tcc7xx.h" | 25 | #include "usb-tcc7xx.h" |
26 | 26 | ||
27 | #include "cpu.h" | ||
28 | #include "system.h" | ||
29 | #include "kernel.h" | ||
30 | #include "panic.h" | ||
31 | |||
32 | #ifdef HAVE_USBSTACK | ||
33 | #include "usb_ch9.h" | ||
34 | #include "usb_core.h" | ||
35 | |||
36 | #define TCC7xx_USB_EPIF_IRQ_MASK 0xf | ||
37 | |||
38 | static int dbg_level = 0x02; | ||
39 | static int global_ep_irq_mask = 0x1; | ||
40 | #define DEBUG(level, fmt, args...) do { if (dbg_level & (level)) printf(fmt, ## args); } while (0) | ||
41 | |||
42 | #include <inttypes.h> | ||
43 | |||
44 | |||
45 | #include "sprintf.h" | ||
46 | #include "power.h" | ||
47 | |||
48 | #ifndef BOOTLOADER | ||
49 | #define printf(...) do {} while (0) | ||
50 | #define panicf_my panicf | ||
51 | #else | ||
52 | int printf(const char *fmt, ...); | ||
53 | #define panicf_my(fmt, args...) { \ | ||
54 | int flags = disable_irq_save(); \ | ||
55 | printf("*** PANIC ***"); \ | ||
56 | printf(fmt, ## args); \ | ||
57 | printf("*** PANIC ***"); \ | ||
58 | while (usb_detect() == USB_INSERTED) \ | ||
59 | ; \ | ||
60 | power_off(); \ | ||
61 | while(1); \ | ||
62 | restore_irq(flags); \ | ||
63 | } | ||
64 | #endif | ||
65 | |||
66 | struct tcc_ep { | ||
67 | unsigned char dir; /* endpoint direction */ | ||
68 | volatile uint16_t *ep; /* hw ep buffer */ | ||
69 | int id; /* Endpoint id */ | ||
70 | int mask; /* Endpoint bit mask */ | ||
71 | char *buf; /* user buffer to store data */ | ||
72 | int max_len; /* how match data will fit */ | ||
73 | int count; /* actual data count */ | ||
74 | bool busy; | ||
75 | } ; | ||
76 | |||
77 | static struct tcc_ep tcc_endpoints[] = { | ||
78 | /* control */ | ||
79 | { | ||
80 | .dir = -1, | ||
81 | .ep = &TCC7xx_USB_EP0_BUF, | ||
82 | }, { /* bulk */ | ||
83 | .dir = -1, | ||
84 | .ep = &TCC7xx_USB_EP1_BUF, | ||
85 | }, { /* bulk */ | ||
86 | .dir = -1, | ||
87 | .ep = &TCC7xx_USB_EP2_BUF, | ||
88 | }, { /* interrupt */ | ||
89 | .dir = -1, | ||
90 | .ep = &TCC7xx_USB_EP3_BUF, | ||
91 | }, | ||
92 | } ; | ||
93 | |||
94 | static int usb_drv_write_packet(volatile unsigned short *buf, unsigned char *data, int len, int max); | ||
95 | static void usb_set_speed(int); | ||
96 | |||
97 | int usb_drv_request_endpoint(int dir) | ||
98 | { | ||
99 | int flags = disable_irq_save(); | ||
100 | size_t ep; | ||
101 | int ret = 0; | ||
102 | |||
103 | if (dir == USB_DIR_IN) | ||
104 | ep = 1; | ||
105 | else | ||
106 | ep = 2; | ||
107 | |||
108 | if (!tcc_endpoints[ep].busy) { | ||
109 | tcc_endpoints[ep].busy = true; | ||
110 | tcc_endpoints[ep].dir = dir; | ||
111 | ret = ep | dir; | ||
112 | } else { | ||
113 | ret = -1; | ||
114 | } | ||
115 | |||
116 | restore_irq(flags); | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | void usb_drv_release_endpoint(int ep) | ||
121 | { | ||
122 | int flags; | ||
123 | ep = ep & 0x7f; | ||
124 | |||
125 | if (ep < 1 || ep > NUM_ENDPOINTS) | ||
126 | return ; | ||
127 | |||
128 | flags = disable_irq_save(); | ||
129 | |||
130 | tcc_endpoints[ep].busy = false; | ||
131 | tcc_endpoints[ep].dir = -1; | ||
132 | |||
133 | restore_irq(flags); | ||
134 | } | ||
135 | |||
136 | static void udelay(unsigned long msecs) | ||
137 | { | ||
138 | /* TODO: implement me other way */ | ||
139 | msecs*=126; | ||
140 | while (msecs--) | ||
141 | asm("nop;"); | ||
142 | } | ||
143 | |||
144 | static inline void pullup_on(void) | ||
145 | { | ||
146 | TCC7xx_USB_PHY_CFG = 0x000c; | ||
147 | } | ||
148 | |||
149 | static inline void pullup_off(void) | ||
150 | { | ||
151 | TCC7xx_USB_PHY_CFG = 0x3e4c; | ||
152 | } | ||
153 | |||
154 | #if 0 | ||
155 | static | ||
156 | char *dump_data(char *data, int count) | ||
157 | { | ||
158 | static char buf[1024]; | ||
159 | char *dump = buf; | ||
160 | int i; | ||
161 | |||
162 | for (i = 0; i < count; i++) | ||
163 | dump += snprintf(dump, sizeof(buf) - (dump - buf), "%02x", data[i]); | ||
164 | return buf; | ||
165 | } | ||
166 | #endif | ||
167 | |||
168 | static | ||
169 | void handle_control(void) | ||
170 | { | ||
171 | /* control are always 8 bytes len */ | ||
172 | static unsigned char ep_control[8]; | ||
173 | struct usb_ctrlrequest *req = | ||
174 | (struct usb_ctrlrequest *) ep_control; | ||
175 | unsigned short stat; | ||
176 | unsigned short count = 0; | ||
177 | int i; | ||
178 | int type; | ||
179 | |||
180 | /* select control endpoint */ | ||
181 | TCC7xx_USB_INDEX = 0x00; | ||
182 | stat = TCC7xx_USB_EP0_STAT; | ||
183 | |||
184 | if (stat & 0x10) { | ||
185 | DEBUG(2, "stall"); | ||
186 | TCC7xx_USB_EP0_STAT = 0x10; | ||
187 | } | ||
188 | |||
189 | if (TCC7xx_USB_EP0_STAT & 0x01) { /* RX */ | ||
190 | uint16_t *ptr = (uint16_t *) ep_control; | ||
191 | |||
192 | count = TCC7xx_USB_EP_BRCR; | ||
193 | |||
194 | if (TCC7xx_USB_EP0_STAT & 0x2) | ||
195 | TCC7xx_USB_EP0_STAT = 0x02; | ||
196 | |||
197 | if (count != 4) { /* bad control? */ | ||
198 | unsigned short dummy; | ||
199 | |||
200 | while (count--) | ||
201 | dummy = TCC7xx_USB_EP0_BUF; | ||
202 | DEBUG(1, "WTF: count = %d", count); | ||
203 | } else { | ||
204 | /* simply read control packet */ | ||
205 | for (i = 0; i < count; i++) | ||
206 | ptr[i] = TCC7xx_USB_EP0_BUF; | ||
207 | } | ||
208 | |||
209 | count *= 2; | ||
210 | TCC7xx_USB_EP0_STAT = 0x01; | ||
211 | DEBUG(1, "CTRL: len = %d %04x", count, stat); | ||
212 | } else if (TCC7xx_USB_EP0_STAT & 0x02) { /* TX */ | ||
213 | TCC7xx_USB_EP0_STAT = 0x02; | ||
214 | DEBUG(2, "TX Done\n"); | ||
215 | } else { | ||
216 | DEBUG(1, "stat: %04x", stat); | ||
217 | } | ||
218 | |||
219 | TCC7xx_USB_EPIF = 1; | ||
220 | |||
221 | if (0 == (stat & 0x1) || count != 8) | ||
222 | return ; | ||
223 | #if 1 /* TODO: remove me someday */ | ||
224 | { | ||
225 | int i; | ||
226 | uint16_t *ptr = (uint16_t *) ep_control; | ||
227 | for (i = 1; i < (count>>1); i++) { | ||
228 | if (ptr[i] != ptr[0]) | ||
229 | break; | ||
230 | } | ||
231 | if (i == (count>>1)) { | ||
232 | /*DEBUG(2, */panicf_my("sanity failed"); | ||
233 | return ; | ||
234 | } | ||
235 | } | ||
236 | #endif | ||
237 | type = req->bRequestType; | ||
238 | |||
239 | /* TODO: don't pass some kinds of requests to upper level */ | ||
240 | switch (req->bRequest) { | ||
241 | case USB_REQ_CLEAR_FEATURE: | ||
242 | DEBUG(2, "USB_REQ_CLEAR_FEATURE"); | ||
243 | DEBUG(2, "...%04x %04x", req->wValue, req->wIndex); | ||
244 | break; | ||
245 | case USB_REQ_SET_ADDRESS: | ||
246 | //DEBUG(2, "USB_REQ_SET_ADDRESS, %d %d", req->wValue, TCC7xx_USB_FUNC); | ||
247 | /* seems we don't have to set it manually | ||
248 | TCC7xx_USB_FUNC = req->wValue; */ | ||
249 | break; | ||
250 | case USB_REQ_GET_DESCRIPTOR: | ||
251 | DEBUG(2, "gd, %02x %02x", req->wValue, req->wIndex); | ||
252 | break; | ||
253 | case USB_REQ_GET_CONFIGURATION: | ||
254 | DEBUG(2, "USB_REQ_GET_CONFIGURATION"); | ||
255 | break; | ||
256 | default: | ||
257 | DEBUG(2, "req: %02x %02d", req->bRequestType, req->bRequest); | ||
258 | } | ||
259 | |||
260 | usb_core_control_request(req); | ||
261 | } | ||
262 | |||
263 | static | ||
264 | void handle_ep_in(struct tcc_ep *tcc_ep, uint16_t stat) | ||
265 | { | ||
266 | uint8_t *buf = tcc_ep->buf; | ||
267 | uint16_t *wbuf = (uint16_t *) buf; | ||
268 | int wcount; | ||
269 | int count; | ||
270 | int i; | ||
271 | |||
272 | if (tcc_ep->dir != USB_DIR_OUT) { | ||
273 | panicf_my("ep%d: is input only", tcc_ep->id); | ||
274 | } | ||
275 | |||
276 | wcount = TCC7xx_USB_EP_BRCR; | ||
277 | |||
278 | DEBUG(2, "ep%d: %04x %04x", tcc_ep->id, stat, wcount); | ||
279 | |||
280 | /* read data */ | ||
281 | count = wcount * 2; | ||
282 | if (stat & TCC7xx_USP_EP_STAT_LWO) { | ||
283 | count--; | ||
284 | wcount--; | ||
285 | } | ||
286 | |||
287 | if (buf == NULL) | ||
288 | panicf_my("ep%d: Unexpected packet! %d %x", tcc_ep->id, count, TCC7xx_USB_EP_CTRL); | ||
289 | if (tcc_ep->max_len < count) | ||
290 | panicf_my("Too big packet: %d excepted %d %x", count, tcc_ep->max_len, TCC7xx_USB_EP_CTRL); | ||
291 | |||
292 | for (i = 0; i < wcount; i++) | ||
293 | wbuf[i] = *tcc_ep->ep; | ||
294 | |||
295 | if (count & 1) { /* lwo */ | ||
296 | uint16_t tmp = *tcc_ep->ep; | ||
297 | buf[count - 1] = tmp & 0xff; | ||
298 | } | ||
299 | |||
300 | tcc_ep->buf = NULL; | ||
301 | |||
302 | TCC7xx_USB_EP_STAT = TCC7xx_USB_EP_STAT; | ||
303 | TCC7xx_USB_EPIF = tcc_ep->mask; | ||
304 | TCC7xx_USB_EPIE &= ~tcc_ep->mask; /* TODO: use INGLD? */ | ||
305 | global_ep_irq_mask &= ~tcc_ep->mask; | ||
306 | |||
307 | if (TCC7xx_USB_EP_STAT & 0x1) | ||
308 | panicf_my("One more packet?"); | ||
309 | |||
310 | TCC7xx_USB_EP_CTRL |= TCC7xx_USB_EP_CTRL_OUTHD; | ||
311 | |||
312 | usb_core_transfer_complete(tcc_ep->id, USB_DIR_OUT, 0, count); | ||
313 | } | ||
314 | |||
315 | static | ||
316 | void handle_ep_out(struct tcc_ep *tcc_ep, uint16_t stat) | ||
317 | { | ||
318 | (void) stat; | ||
319 | |||
320 | if (tcc_ep->dir != USB_DIR_IN) { | ||
321 | panicf_my("ep%d: is out only", tcc_ep->id); | ||
322 | } | ||
323 | |||
324 | if (tcc_ep->buf == NULL) { | ||
325 | panicf_my("%s:%d", __FILE__, __LINE__); | ||
326 | } | ||
327 | |||
328 | if (tcc_ep->max_len) { | ||
329 | int count = usb_drv_write_packet(tcc_ep->ep, | ||
330 | tcc_ep->buf, | ||
331 | tcc_ep->max_len, | ||
332 | 512); | ||
333 | tcc_ep->buf += count; | ||
334 | tcc_ep->max_len -= count; | ||
335 | tcc_ep->count += count; | ||
336 | } else { | ||
337 | tcc_ep->buf = NULL; | ||
338 | } | ||
339 | |||
340 | TCC7xx_USB_EP_STAT = 0x2; /* Clear TX stat */ | ||
341 | TCC7xx_USB_EPIF = tcc_ep->mask; | ||
342 | |||
343 | if (tcc_ep->buf == NULL) { | ||
344 | TCC7xx_USB_EPIE &= ~tcc_ep->mask; | ||
345 | global_ep_irq_mask &= ~tcc_ep->mask; | ||
346 | |||
347 | usb_core_transfer_complete(tcc_ep->id, USB_DIR_IN, 0, tcc_ep->count); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | static | ||
352 | void handle_ep(unsigned short ep_irq) | ||
353 | { | ||
354 | if (ep_irq & 0x1) { | ||
355 | handle_control(); | ||
356 | } | ||
357 | |||
358 | if (ep_irq & 0xe) { | ||
359 | int endpoint; | ||
360 | |||
361 | for (endpoint = 1; endpoint < 4; endpoint++) { | ||
362 | struct tcc_ep *tcc_ep = &tcc_endpoints[endpoint]; | ||
363 | uint16_t stat; | ||
364 | |||
365 | if (0 == (ep_irq & (1 << endpoint))) | ||
366 | continue; | ||
367 | if (!tcc_ep->busy) | ||
368 | panicf_my("ep%d: wasn't requested", endpoint); | ||
369 | |||
370 | TCC7xx_USB_INDEX = endpoint; | ||
371 | stat = TCC7xx_USB_EP_STAT; | ||
372 | |||
373 | DEBUG(1, "ep%d: %04x", endpoint, stat); | ||
374 | |||
375 | if (stat & 0x1) | ||
376 | handle_ep_in(tcc_ep, stat); | ||
377 | else if (stat & 0x2) | ||
378 | handle_ep_out(tcc_ep, stat); | ||
379 | else /* TODO: remove me? */ | ||
380 | panicf_my("Unhandled ep%d state: %x, %d", endpoint, TCC7xx_USB_EP_STAT, TCC7xx_USB_INDEX); | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | |||
385 | static void usb_set_speed(int high_speed) | ||
386 | { | ||
387 | TCC7xx_USB_EP_DIR = 0x0000; | ||
388 | |||
389 | /* control endpoint */ | ||
390 | TCC7xx_USB_INDEX = 0; | ||
391 | TCC7xx_USB_EP0_CTRL = 0x0000; | ||
392 | TCC7xx_USB_EP_MAXP = 64; | ||
393 | TCC7xx_USB_EP_CTRL = TCC7xx_USB_EP_CTRL_CDP | TCC7xx_USB_EP_CTRL_FLUSH; | ||
394 | |||
395 | /* ep1: bulk-in, to host */ | ||
396 | TCC7xx_USB_INDEX = 1; | ||
397 | TCC7xx_USB_EP_DIR |= (1 << 1); | ||
398 | TCC7xx_USB_EP_CTRL = TCC7xx_USB_EP_CTRL_CDP; | ||
399 | |||
400 | if (high_speed) | ||
401 | TCC7xx_USB_EP_MAXP = 512; | ||
402 | else | ||
403 | TCC7xx_USB_EP_MAXP = 64; | ||
404 | |||
405 | TCC7xx_USB_EP_DMA_CTRL = 0x0; | ||
406 | |||
407 | /* ep2: bulk-out, from host */ | ||
408 | TCC7xx_USB_INDEX = 2; | ||
409 | TCC7xx_USB_EP_DIR &= ~(1 << 2); | ||
410 | TCC7xx_USB_EP_CTRL = TCC7xx_USB_EP_CTRL_CDP; | ||
411 | |||
412 | if (high_speed) | ||
413 | TCC7xx_USB_EP_MAXP = 512; | ||
414 | else | ||
415 | TCC7xx_USB_EP_MAXP = 64; | ||
416 | |||
417 | TCC7xx_USB_EP_DMA_CTRL = 0x0; | ||
418 | |||
419 | /* ep3: interrupt in */ | ||
420 | TCC7xx_USB_INDEX = 3; | ||
421 | TCC7xx_USB_EP_DIR &= ~(1 << 3); | ||
422 | TCC7xx_USB_EP_CTRL = TCC7xx_USB_EP_CTRL_CDP; | ||
423 | TCC7xx_USB_EP_MAXP = 64; | ||
424 | |||
425 | TCC7xx_USB_EP_DMA_CTRL = 0x0; | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | Reset TCC7xx usb device | ||
430 | */ | ||
431 | static void usb_reset(void) | ||
432 | { | ||
433 | pullup_on(); | ||
434 | |||
435 | TCC7xx_USB_DELAY_CTRL |= 0x81; | ||
436 | |||
437 | TCC7xx_USB_SYS_CTRL = 0xa000 | | ||
438 | TCC7xx_USB_SYS_CTRL_RESET | | ||
439 | TCC7xx_USB_SYS_CTRL_RFRE | | ||
440 | TCC7xx_USB_SYS_CTRL_SPDEN | | ||
441 | TCC7xx_USB_SYS_CTRL_VBONE | | ||
442 | TCC7xx_USB_SYS_CTRL_VBOFE; | ||
443 | |||
444 | usb_set_speed(1); | ||
445 | pullup_on(); | ||
446 | |||
447 | TCC7xx_USB_EPIF = TCC7xx_USB_EPIF_IRQ_MASK; | ||
448 | global_ep_irq_mask = 0x1; | ||
449 | TCC7xx_USB_EPIE = global_ep_irq_mask; | ||
450 | |||
451 | usb_core_bus_reset(); | ||
452 | } | ||
453 | |||
454 | /* IRQ handler */ | ||
455 | void USB_DEVICE(void) | ||
456 | { | ||
457 | unsigned short sys_stat; | ||
458 | unsigned short ep_irq; | ||
459 | unsigned short index_save; | ||
460 | |||
461 | sys_stat = TCC7xx_USB_SYS_STAT; | ||
462 | |||
463 | if (sys_stat & TCC7xx_USB_SYS_STAT_RESET) { | ||
464 | TCC7xx_USB_SYS_STAT = TCC7xx_USB_SYS_STAT_RESET; | ||
465 | usb_reset(); | ||
466 | TCC7xx_USB_SYS_CTRL |= TCC7xx_USB_SYS_CTRL_SUSPEND; | ||
467 | DEBUG(2, "reset"); | ||
468 | } | ||
469 | |||
470 | if (sys_stat & TCC7xx_USB_SYS_STAT_RESUME) { | ||
471 | TCC7xx_USB_SYS_STAT = TCC7xx_USB_SYS_STAT_RESUME; | ||
472 | usb_reset(); | ||
473 | TCC7xx_USB_SYS_CTRL |= TCC7xx_USB_SYS_CTRL_SUSPEND; | ||
474 | DEBUG(2, "resume"); | ||
475 | } | ||
476 | |||
477 | if (sys_stat & TCC7xx_USB_SYS_STAT_SPD_END) { | ||
478 | usb_set_speed(1); | ||
479 | TCC7xx_USB_SYS_STAT = TCC7xx_USB_SYS_STAT_SPD_END; | ||
480 | DEBUG(2, "spd end"); | ||
481 | } | ||
482 | |||
483 | if (sys_stat & TCC7xx_USB_SYS_STAT_ERRORS) { | ||
484 | DEBUG(2, "errors: %4x", sys_stat & TCC7xx_USB_SYS_STAT_ERRORS); | ||
485 | TCC7xx_USB_SYS_STAT = sys_stat & TCC7xx_USB_SYS_STAT_ERRORS; | ||
486 | } | ||
487 | |||
488 | // TCC7xx_USB_SYS_STAT = sys_stat; | ||
489 | |||
490 | index_save = TCC7xx_USB_INDEX; | ||
491 | |||
492 | ep_irq = TCC7xx_USB_EPIF & global_ep_irq_mask; | ||
493 | |||
494 | while (ep_irq & TCC7xx_USB_EPIF_IRQ_MASK) { | ||
495 | handle_ep(ep_irq); | ||
496 | |||
497 | /* is that really needed, btw not a problem for rockbox */ | ||
498 | udelay(50); | ||
499 | ep_irq = TCC7xx_USB_EPIF & global_ep_irq_mask; | ||
500 | } | ||
501 | |||
502 | TCC7xx_USB_INDEX = index_save; | ||
503 | } | ||
504 | |||
505 | void usb_drv_set_address(int address) | ||
506 | { | ||
507 | DEBUG(2, "setting address %d %d", address, TCC7xx_USB_FUNC); | ||
508 | } | ||
509 | |||
510 | int usb_drv_port_speed(void) | ||
511 | { | ||
512 | return (TCC7xx_USB_SYS_STAT & 0x10) ? 1 : 0; | ||
513 | } | ||
514 | |||
515 | static int usb_drv_write_packet(volatile unsigned short *buf, unsigned char *data, int len, int max) | ||
516 | { | ||
517 | uint16_t *wbuf = (uint16_t *) data; | ||
518 | int count, i; | ||
519 | |||
520 | len = MIN(len, max); | ||
521 | count = (len + 1) / 2; | ||
522 | |||
523 | TCC7xx_USB_EP_BWCR = len; | ||
524 | |||
525 | for (i = 0; i < count; i++) | ||
526 | *buf = *wbuf++; | ||
527 | |||
528 | return len; | ||
529 | } | ||
530 | |||
531 | int usb_drv_send(int endpoint, void *ptr, int length) | ||
532 | { | ||
533 | int flags = disable_irq_save(); | ||
534 | int rc = 0; | ||
535 | char *data = (unsigned char*) ptr;; | ||
536 | |||
537 | DEBUG(2, "%s(%d,%d)" , __func__, endpoint, length); | ||
538 | |||
539 | if (endpoint != 0) | ||
540 | panicf_my("%s(%d,%d)", __func__, endpoint, length); | ||
541 | |||
542 | TCC7xx_USB_INDEX = 0; | ||
543 | while (length > 0) { | ||
544 | int ret; | ||
545 | |||
546 | ret = usb_drv_write_packet(&TCC7xx_USB_EP0_BUF, data, length, 64); | ||
547 | length -= ret; | ||
548 | data += ret; | ||
549 | |||
550 | while (0 == (TCC7xx_USB_EP0_STAT & 0x2)) | ||
551 | ; | ||
552 | TCC7xx_USB_EP0_STAT = 0x2; | ||
553 | } | ||
554 | |||
555 | restore_irq(flags); | ||
556 | return rc; | ||
557 | } | ||
558 | |||
559 | int usb_drv_send_nonblocking(int endpoint, void *ptr, int length) | ||
560 | { | ||
561 | int flags; | ||
562 | int rc = 0, count = length; | ||
563 | char *data = (unsigned char*) ptr; | ||
564 | struct tcc_ep *ep = &tcc_endpoints[endpoint & 0x7f]; | ||
565 | |||
566 | if (ep->dir != USB_DIR_IN || length == 0) | ||
567 | panicf_my("%s(%d,%d): Not supported", __func__, endpoint, length); | ||
568 | |||
569 | DEBUG(2, "%s(%d,%d):", __func__, endpoint, length); | ||
570 | |||
571 | flags = disable_irq_save(); | ||
572 | |||
573 | if(ep->buf != NULL) { | ||
574 | panicf_my("%s: ep is already busy", __func__); | ||
575 | } | ||
576 | |||
577 | TCC7xx_USB_INDEX = ep->id; | ||
578 | |||
579 | count = usb_drv_write_packet(ep->ep, data, length, 512); | ||
580 | |||
581 | data += count; | ||
582 | length -= count; | ||
583 | |||
584 | ep->buf = data; | ||
585 | ep->max_len = length; | ||
586 | ep->count = count; | ||
587 | |||
588 | TCC7xx_USB_EPIE |= ep->mask; | ||
589 | global_ep_irq_mask |= ep->mask; | ||
590 | |||
591 | restore_irq(flags); | ||
592 | |||
593 | DEBUG(2, "%s end", __func__); | ||
594 | |||
595 | return rc; | ||
596 | } | ||
597 | |||
598 | int usb_drv_recv(int endpoint, void* ptr, int length) | ||
599 | { | ||
600 | volatile struct tcc_ep *tcc_ep = &tcc_endpoints[endpoint & 0x7f]; | ||
601 | int flags; | ||
602 | |||
603 | if (length == 0) { | ||
604 | if (endpoint != 0) | ||
605 | panicf_my("%s(%d,%d) zero length?", __func__, endpoint, length); | ||
606 | return 0; | ||
607 | } | ||
608 | // TODO: check ep | ||
609 | if (tcc_ep->dir != USB_DIR_OUT) | ||
610 | panicf_my("%s(%d,%d)", __func__, endpoint, length); | ||
611 | |||
612 | DEBUG(2, "%s(%d,%d)", __func__, endpoint, length); | ||
613 | |||
614 | flags = disable_irq_save(); | ||
615 | |||
616 | if (tcc_ep->buf) { | ||
617 | panicf_my("%s: overrun: %x %x", __func__, tcc_ep->buf, tcc_ep); | ||
618 | } | ||
619 | |||
620 | tcc_ep->buf = ptr; | ||
621 | tcc_ep->max_len = length; | ||
622 | tcc_ep->count = 0; | ||
623 | |||
624 | TCC7xx_USB_INDEX = tcc_ep->id; | ||
625 | |||
626 | TCC7xx_USB_EP_CTRL &= ~TCC7xx_USB_EP_CTRL_OUTHD; | ||
627 | TCC7xx_USB_EPIE |= tcc_ep->mask; | ||
628 | global_ep_irq_mask |= tcc_ep->mask; | ||
629 | |||
630 | restore_irq(flags); | ||
631 | |||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | void usb_drv_cancel_all_transfers(void) | ||
636 | { | ||
637 | int endpoint; | ||
638 | int flags; | ||
639 | |||
640 | DEBUG(2, "%s", __func__); | ||
641 | |||
642 | flags = disable_irq_save(); | ||
643 | for (endpoint = 0; endpoint < 4; endpoint++) { | ||
644 | if (tcc_endpoints[endpoint].buf) { | ||
645 | /* usb_core_transfer_complete(tcc_endpoints[endpoint].id, | ||
646 | tcc_endpoints[endpoint].dir, -1, 0); */ | ||
647 | tcc_endpoints[endpoint].buf = NULL; | ||
648 | } | ||
649 | } | ||
650 | |||
651 | global_ep_irq_mask = 1; | ||
652 | TCC7xx_USB_EPIE = global_ep_irq_mask; | ||
653 | TCC7xx_USB_EPIF = TCC7xx_USB_EPIF_IRQ_MASK; | ||
654 | restore_irq(flags); | ||
655 | } | ||
656 | |||
657 | void usb_drv_set_test_mode(int mode) | ||
658 | { | ||
659 | panicf_my("%s(%d)", __func__, mode); | ||
660 | } | ||
661 | |||
662 | bool usb_drv_stalled(int endpoint, bool in) | ||
663 | { | ||
664 | panicf_my("%s(%d,%d)", __func__, endpoint, in); | ||
665 | } | ||
666 | |||
667 | void usb_drv_stall(int endpoint, bool stall,bool in) | ||
668 | { | ||
669 | printf("%s(%d,%d,%d)", __func__, endpoint, stall, in); | ||
670 | } | ||
671 | |||
672 | void usb_drv_init(void) | ||
673 | { | ||
674 | size_t i; | ||
675 | |||
676 | DEBUG(2, "%s", __func__); | ||
677 | |||
678 | for (i = 0; i < sizeof(tcc_endpoints)/sizeof(struct tcc_ep); i++) { | ||
679 | tcc_endpoints[i].id = i; | ||
680 | tcc_endpoints[i].mask = 1 << i; | ||
681 | tcc_endpoints[i].buf = NULL; | ||
682 | tcc_endpoints[i].busy = false; | ||
683 | tcc_endpoints[i].dir = -1; | ||
684 | } | ||
685 | |||
686 | /* Enable USB clock */ | ||
687 | BCLKCTR |= DEV_USBD; | ||
688 | |||
689 | /* switch USB to host and then reset */ | ||
690 | TCC7xx_USB_PHY_CFG = 0x3e4c; | ||
691 | SWRESET |= DEV_USBD; | ||
692 | udelay(50); | ||
693 | SWRESET &= ~DEV_USBD; | ||
694 | |||
695 | usb_reset(); | ||
696 | |||
697 | /* unmask irq */ | ||
698 | CREQ = USBD_IRQ_MASK; | ||
699 | IRQSEL |= USBD_IRQ_MASK; | ||
700 | TMODE &= ~USBD_IRQ_MASK; | ||
701 | IEN |= USBD_IRQ_MASK; | ||
702 | } | ||
703 | |||
704 | void usb_drv_exit(void) | ||
705 | { | ||
706 | TCC7xx_USB_EPIE = 0; | ||
707 | BCLKCTR &= ~DEV_USBD; | ||
708 | |||
709 | SWRESET |= DEV_USBD; | ||
710 | udelay(50); | ||
711 | SWRESET &= ~DEV_USBD; | ||
712 | |||
713 | pullup_off(); | ||
714 | } | ||
715 | |||
716 | void usb_init_device(void) | ||
717 | { | ||
718 | } | ||
719 | |||
720 | void usb_enable(bool on) | ||
721 | { | ||
722 | if (on) | ||
723 | usb_core_init(); | ||
724 | else | ||
725 | usb_core_exit(); | ||
726 | } | ||
727 | |||
728 | |||
729 | int usb_detect(void) | ||
730 | { | ||
731 | /* TODO: not correct for all targets, we should poll VBUS | ||
732 | signal on USB bus. */ | ||
733 | if (charger_inserted()) | ||
734 | return USB_INSERTED; | ||
735 | return USB_EXTRACTED; | ||
736 | } | ||
737 | |||
738 | #ifdef BOOTLOADER | ||
739 | #include "ata.h" | ||
740 | void usb_test(void) | ||
741 | { | ||
742 | int rc; | ||
743 | |||
744 | printf("ATA"); | ||
745 | rc = ata_init(); | ||
746 | |||
747 | if(rc) { | ||
748 | panicf("ata_init failed"); | ||
749 | } | ||
750 | |||
751 | usb_init(); | ||
752 | usb_start_monitoring(); | ||
753 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
754 | |||
755 | while (1) { | ||
756 | sleep(HZ); | ||
757 | // usb_serial_send("Hello\r\n", 7); | ||
758 | } | ||
759 | } | ||
760 | #endif | ||
761 | #else | ||
27 | void usb_init_device(void) | 762 | void usb_init_device(void) |
28 | { | 763 | { |
29 | /* simply switch USB off for now */ | 764 | /* simply switch USB off for now */ |
@@ -42,3 +777,4 @@ int usb_detect(void) | |||
42 | { | 777 | { |
43 | return USB_EXTRACTED; | 778 | return USB_EXTRACTED; |
44 | } | 779 | } |
780 | #endif | ||
diff --git a/firmware/usb.c b/firmware/usb.c index ab4f0403b9..e5c7565d39 100644 --- a/firmware/usb.c +++ b/firmware/usb.c | |||
@@ -50,7 +50,8 @@ | |||
50 | /* Conditions under which we want the entire driver */ | 50 | /* Conditions under which we want the entire driver */ |
51 | #if !defined(BOOTLOADER) || (CONFIG_CPU == SH7034) || \ | 51 | #if !defined(BOOTLOADER) || (CONFIG_CPU == SH7034) || \ |
52 | (defined(TOSHIBA_GIGABEAT_S) && defined(USE_ROCKBOX_USB) && defined(USB_STORAGE)) || \ | 52 | (defined(TOSHIBA_GIGABEAT_S) && defined(USE_ROCKBOX_USB) && defined(USB_STORAGE)) || \ |
53 | (defined(CREATIVE_ZVx) && defined(HAVE_USBSTACK)) | 53 | (defined(HAVE_USBSTACK) && (defined(CREATIVE_ZVx) || \ |
54 | defined(CPU_TCC77X) || defined(CPU_TCC780X))) | ||
54 | #define USB_FULL_INIT | 55 | #define USB_FULL_INIT |
55 | #endif | 56 | #endif |
56 | 57 | ||