diff options
Diffstat (limited to 'firmware/drivers/isp1583.c')
-rw-r--r-- | firmware/drivers/isp1583.c | 741 |
1 files changed, 741 insertions, 0 deletions
diff --git a/firmware/drivers/isp1583.c b/firmware/drivers/isp1583.c new file mode 100644 index 0000000000..8cc440dc4c --- /dev/null +++ b/firmware/drivers/isp1583.c | |||
@@ -0,0 +1,741 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Tomasz Malesinski | ||
11 | * Copyright (C) 2008 by Maurus Cuelenaere | ||
12 | * | ||
13 | * All files in this archive are subject to the GNU General Public License. | ||
14 | * See the file COPYING in the source tree root for full license agreement. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | #include "config.h" | ||
22 | #include "usb-target.h" | ||
23 | #include "usb_ch9.h" | ||
24 | #include "usb_drv.h" | ||
25 | #include "usb_core.h" | ||
26 | #include "isp1583.h" | ||
27 | #include "thread.h" | ||
28 | |||
29 | #define printf | ||
30 | #define logf printf | ||
31 | |||
32 | #define DIR_RX 0 | ||
33 | #define DIR_TX 1 | ||
34 | |||
35 | #define DIR_OUT 0 | ||
36 | #define DIR_IN 1 | ||
37 | |||
38 | struct usb_endpoint | ||
39 | { | ||
40 | unsigned char *out_buf; | ||
41 | short out_len; | ||
42 | short out_ptr; | ||
43 | void (*out_done)(int, unsigned char *, int); | ||
44 | unsigned char out_in_progress; | ||
45 | |||
46 | unsigned char *in_buf; | ||
47 | short in_min_len; | ||
48 | short in_max_len; | ||
49 | short in_ptr; | ||
50 | void (*in_done)(int, unsigned char *, int); | ||
51 | unsigned char in_ack; | ||
52 | |||
53 | unsigned char halt[2]; | ||
54 | unsigned char enabled[2]; | ||
55 | short max_pkt_size[2]; | ||
56 | short type; | ||
57 | }; | ||
58 | |||
59 | static unsigned char setup_pkt_buf[8]; | ||
60 | static struct usb_endpoint endpoints[NUM_ENDPOINTS]; | ||
61 | |||
62 | static bool high_speed_mode = false; | ||
63 | |||
64 | static inline void or_int_value(volatile unsigned short *a, volatile unsigned short *b, unsigned long r, unsigned long value) | ||
65 | { | ||
66 | set_int_value(*a, *b, (r | value)); | ||
67 | } | ||
68 | static inline void bc_int_value(volatile unsigned short *a, volatile unsigned short *b, unsigned long r, unsigned long value) | ||
69 | { | ||
70 | set_int_value(*a, *b, (r & ~value)); | ||
71 | } | ||
72 | |||
73 | static inline void nop_f(void) | ||
74 | { | ||
75 | yield(); | ||
76 | } | ||
77 | |||
78 | #define NOP asm volatile("nop\n"); | ||
79 | |||
80 | static inline int ep_index(int n, bool dir) | ||
81 | { | ||
82 | return (n << 1) | dir; | ||
83 | } | ||
84 | |||
85 | static inline bool epidx_dir(int idx) | ||
86 | { | ||
87 | return idx & 1; | ||
88 | } | ||
89 | |||
90 | static inline int epidx_n(int idx) | ||
91 | { | ||
92 | return idx >> 1; | ||
93 | } | ||
94 | |||
95 | static inline void usb_select_endpoint(int idx) | ||
96 | { | ||
97 | /* Select the endpoint */ | ||
98 | ISP1583_DFLOW_EPINDEX = idx; | ||
99 | /* The delay time from the Write Endpoint Index register to the Read Data Port register must be at least 190 ns. | ||
100 | * The delay time from the Write Endpoint Index register to the Write Data Port register must be at least 100 ns. | ||
101 | */ | ||
102 | NOP; | ||
103 | } | ||
104 | |||
105 | static inline void usb_select_setup_endpoint(void) | ||
106 | { | ||
107 | /* Select the endpoint */ | ||
108 | ISP1583_DFLOW_EPINDEX = DFLOW_EPINDEX_EP0SETUP; | ||
109 | /* The delay time from the Write Endpoint Index register to the Read Data Port register must be at least 190 ns. | ||
110 | * The delay time from the Write Endpoint Index register to the Write Data Port register must be at least 100 ns. | ||
111 | */ | ||
112 | NOP; | ||
113 | } | ||
114 | |||
115 | static void usb_setup_endpoint(int idx, int max_pkt_size, int type) | ||
116 | { | ||
117 | if(epidx_n(idx)!=0) | ||
118 | { | ||
119 | usb_select_endpoint(idx); | ||
120 | ISP1583_DFLOW_MAXPKSZ = max_pkt_size & 0x7FF; | ||
121 | ISP1583_DFLOW_EPTYPE = (DFLOW_EPTYPE_NOEMPKT | DFLOW_EPTYPE_DBLBUF | (type & 0x3)); | ||
122 | |||
123 | /* clear buffer ... */ | ||
124 | ISP1583_DFLOW_CTRLFUN |= DFLOW_CTRLFUN_CLBUF; | ||
125 | /* ... twice because of double buffering */ | ||
126 | usb_select_endpoint(idx); | ||
127 | ISP1583_DFLOW_CTRLFUN |= DFLOW_CTRLFUN_CLBUF; | ||
128 | } | ||
129 | |||
130 | struct usb_endpoint *ep; | ||
131 | ep = &(endpoints[epidx_n(idx)]); | ||
132 | ep->halt[epidx_dir(idx)] = 0; | ||
133 | ep->enabled[epidx_dir(idx)] = 0; | ||
134 | ep->out_in_progress = 0; | ||
135 | ep->in_min_len = -1; | ||
136 | ep->in_ack = 0; | ||
137 | ep->type = type; | ||
138 | ep->max_pkt_size[epidx_dir(idx)] = max_pkt_size; | ||
139 | } | ||
140 | |||
141 | static void usb_enable_endpoint(int idx) | ||
142 | { | ||
143 | if(epidx_n(idx)!=0) | ||
144 | { | ||
145 | usb_select_endpoint(idx); | ||
146 | /* Enable interrupt */ | ||
147 | or_int_value(&ISP1583_INIT_INTEN_A, &ISP1583_INIT_INTEN_B, ISP1583_INIT_INTEN_READ, 1 << (10 + idx)); | ||
148 | /* Enable endpoint */ | ||
149 | ISP1583_DFLOW_EPTYPE |= DFLOW_EPTYPE_ENABLE; | ||
150 | } | ||
151 | |||
152 | endpoints[epidx_n(idx)].enabled[epidx_dir(idx)] = 1; | ||
153 | } | ||
154 | |||
155 | static void usb_disable_endpoint(int idx, bool set_struct) | ||
156 | { | ||
157 | usb_select_endpoint(idx); | ||
158 | ISP1583_DFLOW_EPTYPE &= ~DFLOW_EPTYPE_ENABLE; | ||
159 | bc_int_value(&ISP1583_INIT_INTEN_A, &ISP1583_INIT_INTEN_B, ISP1583_INIT_INTEN_READ, 1 << (10 + idx)); | ||
160 | |||
161 | if(set_struct) | ||
162 | endpoints[epidx_n(idx)].enabled[epidx_dir(idx)] = 0; | ||
163 | } | ||
164 | |||
165 | static int usb_get_packet(unsigned char *buf, int max_len) | ||
166 | { | ||
167 | int len, i; | ||
168 | len = ISP1583_DFLOW_BUFLEN; | ||
169 | |||
170 | if (max_len < 0 || max_len > len) | ||
171 | max_len = len; | ||
172 | |||
173 | i = 0; | ||
174 | while (i < len) | ||
175 | { | ||
176 | unsigned short d = ISP1583_DFLOW_DATA; | ||
177 | if (i < max_len) | ||
178 | buf[i] = d & 0xff; | ||
179 | i++; | ||
180 | if (i < max_len) | ||
181 | buf[i] = (d >> 8) & 0xff; | ||
182 | i++; | ||
183 | } | ||
184 | return max_len; | ||
185 | } | ||
186 | |||
187 | static int usb_receive(int n) | ||
188 | { | ||
189 | logf("usb_receive(%d)", n); | ||
190 | int len; | ||
191 | |||
192 | if (endpoints[n].halt[DIR_RX] | ||
193 | || !endpoints[n].enabled[DIR_RX] | ||
194 | || endpoints[n].in_min_len < 0 | ||
195 | || !endpoints[n].in_ack) | ||
196 | return -1; | ||
197 | |||
198 | endpoints[n].in_ack = 0; | ||
199 | |||
200 | usb_select_endpoint(ep_index(n, DIR_RX)); | ||
201 | |||
202 | len = usb_get_packet(endpoints[n].in_buf + endpoints[n].in_ptr, | ||
203 | endpoints[n].in_max_len - endpoints[n].in_ptr); | ||
204 | endpoints[n].in_ptr += len; | ||
205 | if (endpoints[n].in_ptr >= endpoints[n].in_min_len) { | ||
206 | endpoints[n].in_min_len = -1; | ||
207 | if (endpoints[n].in_done) | ||
208 | (*(endpoints[n].in_done))(n, endpoints[n].in_buf, | ||
209 | endpoints[n].in_ptr); | ||
210 | } | ||
211 | logf("receive_end"); | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static bool usb_out_buffer_full(int ep) | ||
216 | { | ||
217 | usb_select_endpoint(ep_index(ep, DIR_TX)); | ||
218 | if (ISP1583_DFLOW_EPTYPE & 4) /* Check if type=bulk and double buffering is set */ | ||
219 | return (ISP1583_DFLOW_BUFSTAT & 3) == 3; /* Return true if both buffers are filled */ | ||
220 | else | ||
221 | return (ISP1583_DFLOW_BUFSTAT & 3) != 0; /* Return true if one of the buffers are filled */ | ||
222 | } | ||
223 | |||
224 | static int usb_send(int n) | ||
225 | { | ||
226 | logf("usb_send(%d)", n); | ||
227 | int max_pkt_size, len; | ||
228 | int i; | ||
229 | unsigned char *p; | ||
230 | |||
231 | if (endpoints[n].halt[DIR_TX] | ||
232 | || !endpoints[n].enabled[DIR_TX] | ||
233 | || !endpoints[n].out_in_progress) | ||
234 | { | ||
235 | logf("NOT SEND TO EP!"); | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | if (endpoints[n].out_ptr < 0) | ||
240 | { | ||
241 | endpoints[n].out_in_progress = 0; | ||
242 | if (endpoints[n].out_done) | ||
243 | (*(endpoints[n].out_done))(n, endpoints[n].out_buf, | ||
244 | endpoints[n].out_len); | ||
245 | logf("ALREADY SENT TO EP!"); | ||
246 | return -1; | ||
247 | } | ||
248 | |||
249 | if (usb_out_buffer_full(n)) | ||
250 | { | ||
251 | logf("BUFFER FULL!"); | ||
252 | return -1; | ||
253 | } | ||
254 | |||
255 | usb_select_endpoint(ep_index(n, DIR_TX)); | ||
256 | max_pkt_size = endpoints[n].max_pkt_size[DIR_TX]; | ||
257 | len = endpoints[n].out_len - endpoints[n].out_ptr; | ||
258 | if (len > max_pkt_size) | ||
259 | len = max_pkt_size; | ||
260 | |||
261 | if(len < max_pkt_size) | ||
262 | ISP1583_DFLOW_BUFLEN = len; | ||
263 | |||
264 | p = endpoints[n].out_buf + endpoints[n].out_ptr; | ||
265 | i = 0; | ||
266 | while (len - i >= 2) { | ||
267 | ISP1583_DFLOW_DATA = p[i] | (p[i + 1] << 8); | ||
268 | i += 2; | ||
269 | } | ||
270 | if (i < len) | ||
271 | ISP1583_DFLOW_DATA = p[i]; | ||
272 | |||
273 | endpoints[n].out_ptr += len; | ||
274 | |||
275 | /* | ||
276 | if (endpoints[n].out_ptr == endpoints[n].out_len | ||
277 | && len < max_pkt_size) | ||
278 | */ | ||
279 | if (endpoints[n].out_ptr == endpoints[n].out_len) | ||
280 | endpoints[n].out_ptr = -1; | ||
281 | |||
282 | logf("send_end"); | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static void usb_stall_endpoint(int idx) | ||
287 | { | ||
288 | usb_select_endpoint(idx); | ||
289 | ISP1583_DFLOW_CTRLFUN |= DFLOW_CTRLFUN_STALL; | ||
290 | endpoints[epidx_n(idx)].halt[epidx_dir(idx)] = 1; | ||
291 | } | ||
292 | |||
293 | static void usb_unstall_endpoint(int idx) | ||
294 | { | ||
295 | usb_select_endpoint(idx); | ||
296 | ISP1583_DFLOW_CTRLFUN &= ~DFLOW_CTRLFUN_STALL; | ||
297 | ISP1583_DFLOW_EPTYPE &= ~DFLOW_EPTYPE_ENABLE; | ||
298 | ISP1583_DFLOW_EPTYPE |= DFLOW_EPTYPE_ENABLE; | ||
299 | ISP1583_DFLOW_CTRLFUN |= DFLOW_CTRLFUN_CLBUF; | ||
300 | if (epidx_dir(idx) == DIR_TX) | ||
301 | endpoints[epidx_n(idx)].out_in_progress = 0; | ||
302 | else | ||
303 | { | ||
304 | endpoints[epidx_n(idx)].in_min_len = -1; | ||
305 | endpoints[epidx_n(idx)].in_ack = 0; | ||
306 | } | ||
307 | endpoints[epidx_n(idx)].halt[epidx_dir(idx)] = 0; | ||
308 | } | ||
309 | |||
310 | static void usb_status_ack(int ep, int dir) | ||
311 | { | ||
312 | logf("usb_status_ack(%d)", dir); | ||
313 | usb_select_endpoint(ep_index(ep, dir)); | ||
314 | ISP1583_DFLOW_CTRLFUN |= DFLOW_CTRLFUN_STATUS; | ||
315 | } | ||
316 | |||
317 | static void usb_data_stage_enable(int ep, int dir) | ||
318 | { | ||
319 | logf("usb_data_stage_enable(%d)", dir); | ||
320 | usb_select_endpoint(ep_index(ep, dir)); | ||
321 | ISP1583_DFLOW_CTRLFUN |= DFLOW_CTRLFUN_DSEN; | ||
322 | } | ||
323 | |||
324 | static void usb_handle_setup_rx(void) | ||
325 | { | ||
326 | int len; | ||
327 | usb_select_setup_endpoint(); | ||
328 | len = usb_get_packet(setup_pkt_buf, 8); | ||
329 | |||
330 | if (len == 8) | ||
331 | usb_core_control_request((struct usb_ctrlrequest*)setup_pkt_buf); | ||
332 | else | ||
333 | { | ||
334 | usb_drv_stall(0, true, false); | ||
335 | usb_drv_stall(0, true, true); | ||
336 | logf("usb_handle_setup_rx() failed"); | ||
337 | return; | ||
338 | } | ||
339 | |||
340 | logf("usb_handle_setup_rx(): %02x %02x %02x %02x %02x %02x %02x %02x", setup_pkt_buf[0], setup_pkt_buf[1], setup_pkt_buf[2], setup_pkt_buf[3], setup_pkt_buf[4], setup_pkt_buf[5], setup_pkt_buf[6], setup_pkt_buf[7]); | ||
341 | } | ||
342 | |||
343 | static void usb_handle_data_int(int ep, int dir) | ||
344 | { | ||
345 | int len; | ||
346 | if (dir == DIR_TX) | ||
347 | len = usb_send(ep); | ||
348 | else | ||
349 | { | ||
350 | len = usb_receive(ep); | ||
351 | endpoints[ep].in_ack = 1; | ||
352 | } | ||
353 | logf("usb_handle_data_int(%d, %d) finished", ep, dir); | ||
354 | } | ||
355 | |||
356 | bool usb_drv_powered(void) | ||
357 | { | ||
358 | #if 0 | ||
359 | return (ISP1583_INIT_OTG & INIT_OTG_BSESS_VALID) ? true : false; | ||
360 | #else | ||
361 | return (ISP1583_INIT_MODE & INIT_MODE_VBUSSTAT) ? true : false; | ||
362 | #endif | ||
363 | } | ||
364 | |||
365 | static void setup_endpoints(void) | ||
366 | { | ||
367 | usb_setup_endpoint(ep_index(0, DIR_RX), 64, 0); | ||
368 | usb_setup_endpoint(ep_index(0, DIR_TX), 64, 0); | ||
369 | |||
370 | int i; | ||
371 | for(i = 1; i < NUM_ENDPOINTS-1; i++) | ||
372 | { | ||
373 | usb_setup_endpoint(ep_index(i, DIR_RX), (high_speed_mode ? 512 : 64), 2); /* 2 = TYPE_BULK */ | ||
374 | usb_setup_endpoint(ep_index(i, DIR_TX), (high_speed_mode ? 512 : 64), 2); | ||
375 | } | ||
376 | |||
377 | usb_enable_endpoint(ep_index(0, DIR_RX)); | ||
378 | usb_enable_endpoint(ep_index(0, DIR_TX)); | ||
379 | |||
380 | for (i = 1; i < NUM_ENDPOINTS-1; i++) | ||
381 | { | ||
382 | usb_enable_endpoint(ep_index(i, DIR_RX)); | ||
383 | usb_enable_endpoint(ep_index(i, DIR_TX)); | ||
384 | } | ||
385 | |||
386 | ZVM_SPECIFIC; | ||
387 | } | ||
388 | |||
389 | void usb_helper(void) | ||
390 | { | ||
391 | if(ISP1583_GEN_INT_READ & ISP1583_INIT_INTEN_READ) | ||
392 | { | ||
393 | #ifdef DEBUG | ||
394 | //logf("Helper detected interrupt... [%d]", current_tick); | ||
395 | #endif | ||
396 | usb_drv_int(); | ||
397 | } | ||
398 | return; | ||
399 | } | ||
400 | |||
401 | void usb_drv_init(void) | ||
402 | { | ||
403 | /* Disable interrupt at CPU level */ | ||
404 | DIS_INT_CPU_TARGET; | ||
405 | |||
406 | /* Unlock the device's registers */ | ||
407 | ISP1583_GEN_UNLCKDEV = ISP1583_UNLOCK_CODE; | ||
408 | |||
409 | /* Soft reset the device */ | ||
410 | ISP1583_INIT_MODE = INIT_MODE_SFRESET; | ||
411 | sleep(10); | ||
412 | /* Enable CLKAON & GLINTENA */ | ||
413 | ISP1583_INIT_MODE = STANDARD_INIT_MODE; | ||
414 | |||
415 | /* Disable all OTG functions */ | ||
416 | ISP1583_INIT_OTG = 0; | ||
417 | |||
418 | #if 0 | ||
419 | #ifdef USE_HIGH_SPEED | ||
420 | /* Force device to high speed */ | ||
421 | ISP1583_GEN_TSTMOD = GEN_TSTMOD_FORCEHS; | ||
422 | high_speed_mode = true; | ||
423 | #endif | ||
424 | #endif | ||
425 | |||
426 | #ifdef DEBUG | ||
427 | logf("BUS_CONF/DA0:%d MODE0/DA1: %d MODE1: %d", (bool)(ISP1583_INIT_MODE & INIT_MODE_TEST0), (bool)(ISP1583_INIT_MODE & INIT_MODE_TEST1), (bool)(ISP1583_INIT_MODE & INIT_MODE_TEST2)); | ||
428 | logf("Chip ID: 0x%x", ISP1583_GEN_CHIPID); | ||
429 | //logf("INV0: 0x% IRQEDGE: 0x%x IRQPORT: 0x%x", IO_GIO_INV0, IO_GIO_IRQEDGE, IO_GIO_IRQPORT); | ||
430 | #endif | ||
431 | |||
432 | /*Set interrupt generation to target-specific mode + | ||
433 | * Set the control pipe to ACK only interrupt + | ||
434 | * Set the IN pipe to ACK only interrupt + | ||
435 | * Set OUT pipe to ACK and NYET interrupt | ||
436 | */ | ||
437 | |||
438 | ISP1583_INIT_INTCONF = 0x54 | INT_CONF_TARGET; | ||
439 | /* Clear all interrupts */ | ||
440 | set_int_value(ISP1583_GEN_INT_A, ISP1583_GEN_INT_B, 0xFFFFFFFF); | ||
441 | /* Enable USB interrupts */ | ||
442 | set_int_value(ISP1583_INIT_INTEN_A, ISP1583_INIT_INTEN_B, STANDARD_INTEN); | ||
443 | |||
444 | ZVM_SPECIFIC; | ||
445 | |||
446 | /* Enable interrupt at CPU level */ | ||
447 | EN_INT_CPU_TARGET; | ||
448 | |||
449 | setup_endpoints(); | ||
450 | |||
451 | /* Clear device address and disable it */ | ||
452 | ISP1583_INIT_ADDRESS = 0; | ||
453 | |||
454 | /* Turn SoftConnect on */ | ||
455 | ISP1583_INIT_MODE |= INIT_MODE_SOFTCT; | ||
456 | |||
457 | ZVM_SPECIFIC; | ||
458 | |||
459 | tick_add_task(usb_helper); | ||
460 | |||
461 | logf("usb_init_device() finished"); | ||
462 | } | ||
463 | |||
464 | int usb_drv_port_speed(void) | ||
465 | { | ||
466 | return (int)high_speed_mode; | ||
467 | } | ||
468 | |||
469 | void usb_drv_exit(void) | ||
470 | { | ||
471 | logf("usb_drv_exit()"); | ||
472 | |||
473 | /* Disable device */ | ||
474 | ISP1583_INIT_MODE &= ~INIT_MODE_SOFTCT; | ||
475 | ISP1583_INIT_ADDRESS = 0; | ||
476 | |||
477 | /* Disable interrupts */ | ||
478 | set_int_value(ISP1583_INIT_INTEN_A, ISP1583_INIT_INTEN_B, 0); | ||
479 | /* and the CPU's one... */ | ||
480 | DIS_INT_CPU_TARGET; | ||
481 | |||
482 | |||
483 | /* Send usb controller to suspend mode */ | ||
484 | ISP1583_INIT_MODE = INIT_MODE_GOSUSP; | ||
485 | ISP1583_INIT_MODE = 0; | ||
486 | |||
487 | tick_remove_task(usb_helper); | ||
488 | |||
489 | ZVM_SPECIFIC; | ||
490 | } | ||
491 | |||
492 | void usb_drv_stall(int endpoint, bool stall, bool in) | ||
493 | { | ||
494 | logf("%sstall EP%d %s", (stall ? "" : "un"), endpoint, (in ? "RX" : "TX" )); | ||
495 | if (stall) | ||
496 | usb_stall_endpoint(ep_index(endpoint, (int)in)); | ||
497 | else | ||
498 | usb_unstall_endpoint(ep_index(endpoint, (int)in)); | ||
499 | } | ||
500 | |||
501 | bool usb_drv_stalled(int endpoint, bool in) | ||
502 | { | ||
503 | return (endpoints[endpoint].halt[(int)in] == 1); | ||
504 | } | ||
505 | |||
506 | static void out_callback(int ep, unsigned char *buf, int len) | ||
507 | { | ||
508 | (void)buf; | ||
509 | logf("out_callback(%d, 0x%x, %d)", ep, &buf, len); | ||
510 | usb_status_ack(ep, DIR_RX); | ||
511 | usb_core_transfer_complete(ep, true, 0, len); /* 0=>status succeeded, haven't worked out status failed yet... */ | ||
512 | } | ||
513 | |||
514 | static void in_callback(int ep, unsigned char *buf, int len) | ||
515 | { | ||
516 | (void)buf; | ||
517 | logf("in_callback(%d, 0x%x, %d)", ep, &buf, len); | ||
518 | usb_status_ack(ep, DIR_TX); | ||
519 | usb_core_transfer_complete(ep, false, 0, len); | ||
520 | } | ||
521 | |||
522 | int usb_drv_recv(int ep, void* ptr, int length) | ||
523 | { | ||
524 | logf("usb_drv_recv(%d, 0x%x, %d)", ep, &ptr, length); | ||
525 | if(ep == 0 && length == 0 && ptr == NULL) | ||
526 | { | ||
527 | usb_status_ack(ep, DIR_TX); | ||
528 | return 0; | ||
529 | } | ||
530 | endpoints[ep].in_done = in_callback; | ||
531 | endpoints[ep].in_buf = ptr; | ||
532 | endpoints[ep].in_max_len = length; | ||
533 | endpoints[ep].in_min_len = length; | ||
534 | endpoints[ep].in_ptr = 0; | ||
535 | if(ep == 0) | ||
536 | { | ||
537 | usb_data_stage_enable(ep, DIR_RX); | ||
538 | return usb_receive(ep); | ||
539 | } | ||
540 | else | ||
541 | return usb_receive(ep); | ||
542 | } | ||
543 | |||
544 | int usb_drv_send_nonblocking(int ep, void* ptr, int length) | ||
545 | { | ||
546 | /* First implement DMA... */ | ||
547 | return usb_drv_send(ep, ptr, length); | ||
548 | } | ||
549 | |||
550 | int usb_drv_send(int ep, void* ptr, int length) | ||
551 | { | ||
552 | logf("usb_drv_send_nb(%d, 0x%x, %d)", ep, &ptr, length); | ||
553 | if(ep == 0 && length == 0 && ptr == NULL) | ||
554 | { | ||
555 | usb_status_ack(ep, DIR_RX); | ||
556 | return 0; | ||
557 | } | ||
558 | if(endpoints[ep].out_in_progress == 1) | ||
559 | return -1; | ||
560 | endpoints[ep].out_done = out_callback; | ||
561 | endpoints[ep].out_buf = ptr; | ||
562 | endpoints[ep].out_len = length; | ||
563 | endpoints[ep].out_ptr = 0; | ||
564 | endpoints[ep].out_in_progress = 1; | ||
565 | if(ep == 0) | ||
566 | { | ||
567 | int rc = usb_send(ep); | ||
568 | usb_data_stage_enable(ep, DIR_TX); | ||
569 | usb_drv_wait(ep, DIR_TX); | ||
570 | return rc; | ||
571 | } | ||
572 | else | ||
573 | return usb_send(ep); | ||
574 | } | ||
575 | |||
576 | void usb_drv_reset_endpoint(int ep, bool send) | ||
577 | { | ||
578 | logf("reset endpoint(%d, %d)", ep, send); | ||
579 | usb_setup_endpoint(ep_index(ep, (int)send), endpoints[ep].max_pkt_size[(int)send], endpoints[ep].type); | ||
580 | usb_enable_endpoint(ep_index(ep, (int)send)); | ||
581 | } | ||
582 | |||
583 | void usb_drv_wait(int ep, bool send) | ||
584 | { | ||
585 | logf("usb_drv_wait(%d, %d)", ep, send); | ||
586 | if(send) | ||
587 | { | ||
588 | while (endpoints[ep].out_in_progress) | ||
589 | nop_f(); | ||
590 | } | ||
591 | else | ||
592 | { | ||
593 | while (endpoints[ep].in_ack) | ||
594 | nop_f(); | ||
595 | } | ||
596 | } | ||
597 | |||
598 | void usb_drv_cancel_all_transfers(void) | ||
599 | { | ||
600 | logf("usb_drv_cancel_all_tranfers()"); | ||
601 | int i; | ||
602 | |||
603 | for(i=0;i<NUM_ENDPOINTS-1;i++) | ||
604 | endpoints[i].halt[0] = endpoints[i].halt[1] = 1; | ||
605 | } | ||
606 | |||
607 | static void bus_reset(void) | ||
608 | { | ||
609 | /* Enable CLKAON & GLINTENA */ | ||
610 | ISP1583_INIT_MODE = STANDARD_INIT_MODE; | ||
611 | /* Enable USB interrupts */ | ||
612 | ISP1583_INIT_INTCONF = 0x54 | INT_CONF_TARGET; | ||
613 | set_int_value(ISP1583_INIT_INTEN_A, ISP1583_INIT_INTEN_B, STANDARD_INTEN); | ||
614 | |||
615 | /* Disable all OTG functions */ | ||
616 | ISP1583_INIT_OTG = 0; | ||
617 | |||
618 | /* Clear device address and enable it */ | ||
619 | ISP1583_INIT_ADDRESS = INIT_ADDRESS_DEVEN; | ||
620 | |||
621 | ZVM_SPECIFIC; | ||
622 | |||
623 | /* Reset endpoints to default */ | ||
624 | setup_endpoints(); | ||
625 | |||
626 | logf("bus reset->done"); | ||
627 | } | ||
628 | |||
629 | /* Method for handling interrupts, must be called from usb-<target>.c */ | ||
630 | void usb_drv_int(void) | ||
631 | { | ||
632 | unsigned long ints; | ||
633 | ints = ISP1583_GEN_INT_READ & ISP1583_INIT_INTEN_READ; | ||
634 | |||
635 | if(!ints) | ||
636 | return; | ||
637 | |||
638 | /* Unlock the device's registers */ | ||
639 | ISP1583_GEN_UNLCKDEV = ISP1583_UNLOCK_CODE; | ||
640 | |||
641 | #if 0 | ||
642 | logf(" handling int [0x%x & 0x%x = 0x%x]", ISP1583_GEN_INT_READ, ISP1583_INIT_INTEN_READ, ints); | ||
643 | #endif | ||
644 | |||
645 | if(ints & INT_IEBRST) /* Bus reset */ | ||
646 | { | ||
647 | logf("BRESET"); | ||
648 | high_speed_mode = false; | ||
649 | bus_reset(); | ||
650 | usb_core_bus_reset(); | ||
651 | /* Mask bus reset interrupt */ | ||
652 | set_int_value(ISP1583_GEN_INT_A, ISP1583_GEN_INT_B, INT_IEBRST); | ||
653 | return; | ||
654 | } | ||
655 | if(ints & INT_IEP0SETUP) /* EP0SETUP interrupt */ | ||
656 | { | ||
657 | logf("EP0SETUP"); | ||
658 | usb_handle_setup_rx(); | ||
659 | } | ||
660 | if(ints & INT_IEHS_STA) /* change from full-speed to high-speed mode -> endpoints need to get reconfigured!! */ | ||
661 | { | ||
662 | logf("HS_STA"); | ||
663 | high_speed_mode = true; | ||
664 | setup_endpoints(); | ||
665 | } | ||
666 | if(ints & INT_EP_MASK) /* Endpoints interrupt */ | ||
667 | { | ||
668 | unsigned long ep_event; | ||
669 | unsigned short i = 10; | ||
670 | ep_event = ints & INT_EP_MASK; | ||
671 | while(ep_event) | ||
672 | { | ||
673 | if(i>25) | ||
674 | break; | ||
675 | |||
676 | if(ep_event & (1 << i)) | ||
677 | { | ||
678 | logf("EP%d %s interrupt", (i - 10) / 2, i % 2 ? "RX" : "TX"); | ||
679 | usb_handle_data_int((i - 10) / 2, i % 2); | ||
680 | ep_event &= ~(1 << i); | ||
681 | } | ||
682 | i++; | ||
683 | } | ||
684 | } | ||
685 | if(ints & INT_IERESM && !(ints & INT_IESUSP)) /* Resume status: status change from suspend to resume (active) */ | ||
686 | { | ||
687 | logf("RESM"); | ||
688 | } | ||
689 | if(ints & INT_IESUSP && !(ints & INT_IERESM)) /* Suspend status: status change from active to suspend */ | ||
690 | { | ||
691 | logf("SUSP"); | ||
692 | } | ||
693 | if(ints & INT_IEDMA) /* change in the DMA Interrupt Reason register */ | ||
694 | { | ||
695 | logf("DMA"); | ||
696 | } | ||
697 | if(ints & INT_IEVBUS) /* transition from LOW to HIGH on VBUS */ | ||
698 | { | ||
699 | logf("VBUS"); | ||
700 | } | ||
701 | /* Mask all (enabled) interrupts */ | ||
702 | set_int_value(ISP1583_GEN_INT_A, ISP1583_GEN_INT_B, ints); | ||
703 | |||
704 | ZVM_SPECIFIC; | ||
705 | } | ||
706 | |||
707 | void usb_drv_set_address(int address) | ||
708 | { | ||
709 | logf("usb_drv_set_address(0x%x)", address); | ||
710 | ISP1583_INIT_ADDRESS = (address & 0x7F) | INIT_ADDRESS_DEVEN; | ||
711 | |||
712 | ZVM_SPECIFIC; | ||
713 | |||
714 | usb_status_ack(0, DIR_TX); | ||
715 | } | ||
716 | |||
717 | void usb_drv_set_test_mode(int mode) | ||
718 | { | ||
719 | logf("usb_drv_set_test_mode(%d)", mode); | ||
720 | switch(mode){ | ||
721 | case 0: | ||
722 | ISP1583_GEN_TSTMOD = 0; | ||
723 | /* Power cycle... */ | ||
724 | break; | ||
725 | case 1: | ||
726 | ISP1583_GEN_TSTMOD = GEN_TSTMOD_JSTATE; | ||
727 | break; | ||
728 | case 2: | ||
729 | ISP1583_GEN_TSTMOD = GEN_TSTMOD_KSTATE; | ||
730 | break; | ||
731 | case 3: | ||
732 | ISP1583_GEN_TSTMOD = GEN_TSTMOD_SE0_NAK; | ||
733 | break; | ||
734 | case 4: | ||
735 | //REG_PORTSC1 |= PORTSCX_PTC_PACKET; | ||
736 | break; | ||
737 | case 5: | ||
738 | //REG_PORTSC1 |= PORTSCX_PTC_FORCE_EN; | ||
739 | break; | ||
740 | } | ||
741 | } | ||