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