|
1 /* Name: usbdrv.c |
|
2 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers |
|
3 * Author: Christian Starkjohann |
|
4 * Creation Date: 2004-12-29 |
|
5 * Tabsize: 4 |
|
6 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH |
|
7 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) |
|
8 */ |
|
9 |
|
10 #include "usbdrv.h" |
|
11 #include "oddebug.h" |
|
12 |
|
13 /* |
|
14 General Description: |
|
15 This module implements the C-part of the USB driver. See usbdrv.h for a |
|
16 documentation of the entire driver. |
|
17 */ |
|
18 |
|
19 /* ------------------------------------------------------------------------- */ |
|
20 |
|
21 /* raw USB registers / interface to assembler code: */ |
|
22 uchar usbRxBuf[2*USB_BUFSIZE]; /* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */ |
|
23 uchar usbInputBufOffset; /* offset in usbRxBuf used for low level receiving */ |
|
24 uchar usbDeviceAddr; /* assigned during enumeration, defaults to 0 */ |
|
25 uchar usbNewDeviceAddr; /* device ID which should be set after status phase */ |
|
26 uchar usbConfiguration; /* currently selected configuration. Administered by driver, but not used */ |
|
27 volatile schar usbRxLen; /* = 0; number of bytes in usbRxBuf; 0 means free, -1 for flow control */ |
|
28 uchar usbCurrentTok; /* last token received or endpoint number for last OUT token if != 0 */ |
|
29 uchar usbRxToken; /* token for data we received; or endpont number for last OUT */ |
|
30 volatile uchar usbTxLen = USBPID_NAK; /* number of bytes to transmit with next IN token or handshake token */ |
|
31 uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen contains handshake token */ |
|
32 #if USB_COUNT_SOF |
|
33 volatile uchar usbSofCount; /* incremented by assembler module every SOF */ |
|
34 #endif |
|
35 #if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE |
|
36 usbTxStatus_t usbTxStatus1; |
|
37 # if USB_CFG_HAVE_INTRIN_ENDPOINT3 |
|
38 usbTxStatus_t usbTxStatus3; |
|
39 # endif |
|
40 #endif |
|
41 #if USB_CFG_CHECK_DATA_TOGGLING |
|
42 uchar usbCurrentDataToken;/* when we check data toggling to ignore duplicate packets */ |
|
43 #endif |
|
44 |
|
45 /* USB status registers / not shared with asm code */ |
|
46 usbMsgPtr_t usbMsgPtr; /* data to transmit next -- ROM or RAM address */ |
|
47 static usbMsgLen_t usbMsgLen = USB_NO_MSG; /* remaining number of bytes */ |
|
48 static uchar usbMsgFlags; /* flag values see below */ |
|
49 |
|
50 #define USB_FLG_MSGPTR_IS_ROM (1<<6) |
|
51 #define USB_FLG_USE_USER_RW (1<<7) |
|
52 |
|
53 /* |
|
54 optimizing hints: |
|
55 - do not post/pre inc/dec integer values in operations |
|
56 - assign value of USB_READ_FLASH() to register variables and don't use side effects in arg |
|
57 - use narrow scope for variables which should be in X/Y/Z register |
|
58 - assign char sized expressions to variables to force 8 bit arithmetics |
|
59 */ |
|
60 |
|
61 /* -------------------------- String Descriptors --------------------------- */ |
|
62 |
|
63 #if USB_CFG_DESCR_PROPS_STRINGS == 0 |
|
64 |
|
65 #if USB_CFG_DESCR_PROPS_STRING_0 == 0 |
|
66 #undef USB_CFG_DESCR_PROPS_STRING_0 |
|
67 #define USB_CFG_DESCR_PROPS_STRING_0 sizeof(usbDescriptorString0) |
|
68 PROGMEM const char usbDescriptorString0[] = { /* language descriptor */ |
|
69 4, /* sizeof(usbDescriptorString0): length of descriptor in bytes */ |
|
70 3, /* descriptor type */ |
|
71 0x09, 0x04, /* language index (0x0409 = US-English) */ |
|
72 }; |
|
73 #endif |
|
74 |
|
75 #if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USB_CFG_VENDOR_NAME_LEN |
|
76 #undef USB_CFG_DESCR_PROPS_STRING_VENDOR |
|
77 #define USB_CFG_DESCR_PROPS_STRING_VENDOR sizeof(usbDescriptorStringVendor) |
|
78 PROGMEM const int usbDescriptorStringVendor[] = { |
|
79 USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN), |
|
80 USB_CFG_VENDOR_NAME |
|
81 }; |
|
82 #endif |
|
83 |
|
84 #if USB_CFG_DESCR_PROPS_STRING_PRODUCT == 0 && USB_CFG_DEVICE_NAME_LEN |
|
85 #undef USB_CFG_DESCR_PROPS_STRING_PRODUCT |
|
86 #define USB_CFG_DESCR_PROPS_STRING_PRODUCT sizeof(usbDescriptorStringDevice) |
|
87 PROGMEM const int usbDescriptorStringDevice[] = { |
|
88 USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN), |
|
89 USB_CFG_DEVICE_NAME |
|
90 }; |
|
91 #endif |
|
92 |
|
93 #if USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER == 0 && USB_CFG_SERIAL_NUMBER_LEN |
|
94 #undef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER |
|
95 #define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER sizeof(usbDescriptorStringSerialNumber) |
|
96 PROGMEM const int usbDescriptorStringSerialNumber[] = { |
|
97 USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN), |
|
98 USB_CFG_SERIAL_NUMBER |
|
99 }; |
|
100 #endif |
|
101 |
|
102 #endif /* USB_CFG_DESCR_PROPS_STRINGS == 0 */ |
|
103 |
|
104 /* --------------------------- Device Descriptor --------------------------- */ |
|
105 |
|
106 #if USB_CFG_DESCR_PROPS_DEVICE == 0 |
|
107 #undef USB_CFG_DESCR_PROPS_DEVICE |
|
108 #define USB_CFG_DESCR_PROPS_DEVICE sizeof(usbDescriptorDevice) |
|
109 PROGMEM const char usbDescriptorDevice[] = { /* USB device descriptor */ |
|
110 18, /* sizeof(usbDescriptorDevice): length of descriptor in bytes */ |
|
111 USBDESCR_DEVICE, /* descriptor type */ |
|
112 0x10, 0x01, /* USB version supported */ |
|
113 USB_CFG_DEVICE_CLASS, |
|
114 USB_CFG_DEVICE_SUBCLASS, |
|
115 0, /* protocol */ |
|
116 8, /* max packet size */ |
|
117 /* the following two casts affect the first byte of the constant only, but |
|
118 * that's sufficient to avoid a warning with the default values. |
|
119 */ |
|
120 (char)USB_CFG_VENDOR_ID,/* 2 bytes */ |
|
121 (char)USB_CFG_DEVICE_ID,/* 2 bytes */ |
|
122 USB_CFG_DEVICE_VERSION, /* 2 bytes */ |
|
123 USB_CFG_DESCR_PROPS_STRING_VENDOR != 0 ? 1 : 0, /* manufacturer string index */ |
|
124 USB_CFG_DESCR_PROPS_STRING_PRODUCT != 0 ? 2 : 0, /* product string index */ |
|
125 USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER != 0 ? 3 : 0, /* serial number string index */ |
|
126 1, /* number of configurations */ |
|
127 }; |
|
128 #endif |
|
129 |
|
130 /* ----------------------- Configuration Descriptor ------------------------ */ |
|
131 |
|
132 #if USB_CFG_DESCR_PROPS_HID_REPORT != 0 && USB_CFG_DESCR_PROPS_HID == 0 |
|
133 #undef USB_CFG_DESCR_PROPS_HID |
|
134 #define USB_CFG_DESCR_PROPS_HID 9 /* length of HID descriptor in config descriptor below */ |
|
135 #endif |
|
136 |
|
137 #if USB_CFG_DESCR_PROPS_CONFIGURATION == 0 |
|
138 #undef USB_CFG_DESCR_PROPS_CONFIGURATION |
|
139 #define USB_CFG_DESCR_PROPS_CONFIGURATION sizeof(usbDescriptorConfiguration) |
|
140 PROGMEM const char usbDescriptorConfiguration[] = { /* USB configuration descriptor */ |
|
141 9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */ |
|
142 USBDESCR_CONFIG, /* descriptor type */ |
|
143 18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT3 + |
|
144 (USB_CFG_DESCR_PROPS_HID & 0xff), 0, |
|
145 /* total length of data returned (including inlined descriptors) */ |
|
146 1, /* number of interfaces in this configuration */ |
|
147 1, /* index of this configuration */ |
|
148 0, /* configuration name string index */ |
|
149 #if USB_CFG_IS_SELF_POWERED |
|
150 (1 << 7) | USBATTR_SELFPOWER, /* attributes */ |
|
151 #else |
|
152 (1 << 7), /* attributes */ |
|
153 #endif |
|
154 USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */ |
|
155 /* interface descriptor follows inline: */ |
|
156 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */ |
|
157 USBDESCR_INTERFACE, /* descriptor type */ |
|
158 0, /* index of this interface */ |
|
159 0, /* alternate setting for this interface */ |
|
160 USB_CFG_HAVE_INTRIN_ENDPOINT + USB_CFG_HAVE_INTRIN_ENDPOINT3, /* endpoints excl 0: number of endpoint descriptors to follow */ |
|
161 USB_CFG_INTERFACE_CLASS, |
|
162 USB_CFG_INTERFACE_SUBCLASS, |
|
163 USB_CFG_INTERFACE_PROTOCOL, |
|
164 0, /* string index for interface */ |
|
165 #if (USB_CFG_DESCR_PROPS_HID & 0xff) /* HID descriptor */ |
|
166 9, /* sizeof(usbDescrHID): length of descriptor in bytes */ |
|
167 USBDESCR_HID, /* descriptor type: HID */ |
|
168 0x01, 0x01, /* BCD representation of HID version */ |
|
169 0x00, /* target country code */ |
|
170 0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */ |
|
171 0x22, /* descriptor type: report */ |
|
172 USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0, /* total length of report descriptor */ |
|
173 #endif |
|
174 #if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */ |
|
175 7, /* sizeof(usbDescrEndpoint) */ |
|
176 USBDESCR_ENDPOINT, /* descriptor type = endpoint */ |
|
177 (char)0x81, /* IN endpoint number 1 */ |
|
178 0x03, /* attrib: Interrupt endpoint */ |
|
179 8, 0, /* maximum packet size */ |
|
180 USB_CFG_INTR_POLL_INTERVAL, /* in ms */ |
|
181 #endif |
|
182 #if USB_CFG_HAVE_INTRIN_ENDPOINT3 /* endpoint descriptor for endpoint 3 */ |
|
183 7, /* sizeof(usbDescrEndpoint) */ |
|
184 USBDESCR_ENDPOINT, /* descriptor type = endpoint */ |
|
185 (char)(0x80 | USB_CFG_EP3_NUMBER), /* IN endpoint number 3 */ |
|
186 0x03, /* attrib: Interrupt endpoint */ |
|
187 8, 0, /* maximum packet size */ |
|
188 USB_CFG_INTR_POLL_INTERVAL, /* in ms */ |
|
189 #endif |
|
190 }; |
|
191 #endif |
|
192 |
|
193 /* ------------------------------------------------------------------------- */ |
|
194 |
|
195 static inline void usbResetDataToggling(void) |
|
196 { |
|
197 #if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE |
|
198 USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */ |
|
199 # if USB_CFG_HAVE_INTRIN_ENDPOINT3 |
|
200 USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */ |
|
201 # endif |
|
202 #endif |
|
203 } |
|
204 |
|
205 static inline void usbResetStall(void) |
|
206 { |
|
207 #if USB_CFG_IMPLEMENT_HALT && USB_CFG_HAVE_INTRIN_ENDPOINT |
|
208 usbTxLen1 = USBPID_NAK; |
|
209 #if USB_CFG_HAVE_INTRIN_ENDPOINT3 |
|
210 usbTxLen3 = USBPID_NAK; |
|
211 #endif |
|
212 #endif |
|
213 } |
|
214 |
|
215 /* ------------------------------------------------------------------------- */ |
|
216 |
|
217 #if !USB_CFG_SUPPRESS_INTR_CODE |
|
218 #if USB_CFG_HAVE_INTRIN_ENDPOINT |
|
219 static void usbGenericSetInterrupt(uchar *data, uchar len, usbTxStatus_t *txStatus) |
|
220 { |
|
221 uchar *p; |
|
222 char i; |
|
223 |
|
224 #if USB_CFG_IMPLEMENT_HALT |
|
225 if(usbTxLen1 == USBPID_STALL) |
|
226 return; |
|
227 #endif |
|
228 if(txStatus->len & 0x10){ /* packet buffer was empty */ |
|
229 txStatus->buffer[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */ |
|
230 }else{ |
|
231 txStatus->len = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ |
|
232 } |
|
233 p = txStatus->buffer + 1; |
|
234 i = len; |
|
235 do{ /* if len == 0, we still copy 1 byte, but that's no problem */ |
|
236 *p++ = *data++; |
|
237 }while(--i > 0); /* loop control at the end is 2 bytes shorter than at beginning */ |
|
238 usbCrc16Append(&txStatus->buffer[1], len); |
|
239 txStatus->len = len + 4; /* len must be given including sync byte */ |
|
240 DBG2(0x21 + (((int)txStatus >> 3) & 3), txStatus->buffer, len + 3); |
|
241 } |
|
242 |
|
243 USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len) |
|
244 { |
|
245 usbGenericSetInterrupt(data, len, &usbTxStatus1); |
|
246 } |
|
247 #endif |
|
248 |
|
249 #if USB_CFG_HAVE_INTRIN_ENDPOINT3 |
|
250 USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len) |
|
251 { |
|
252 usbGenericSetInterrupt(data, len, &usbTxStatus3); |
|
253 } |
|
254 #endif |
|
255 #endif /* USB_CFG_SUPPRESS_INTR_CODE */ |
|
256 |
|
257 /* ------------------ utilities for code following below ------------------- */ |
|
258 |
|
259 /* Use defines for the switch statement so that we can choose between an |
|
260 * if()else if() and a switch/case based implementation. switch() is more |
|
261 * efficient for a LARGE set of sequential choices, if() is better in all other |
|
262 * cases. |
|
263 */ |
|
264 #if USB_CFG_USE_SWITCH_STATEMENT |
|
265 # define SWITCH_START(cmd) switch(cmd){{ |
|
266 # define SWITCH_CASE(value) }break; case (value):{ |
|
267 # define SWITCH_CASE2(v1,v2) }break; case (v1): case(v2):{ |
|
268 # define SWITCH_CASE3(v1,v2,v3) }break; case (v1): case(v2): case(v3):{ |
|
269 # define SWITCH_DEFAULT }break; default:{ |
|
270 # define SWITCH_END }} |
|
271 #else |
|
272 # define SWITCH_START(cmd) {uchar _cmd = cmd; if(0){ |
|
273 # define SWITCH_CASE(value) }else if(_cmd == (value)){ |
|
274 # define SWITCH_CASE2(v1,v2) }else if(_cmd == (v1) || _cmd == (v2)){ |
|
275 # define SWITCH_CASE3(v1,v2,v3) }else if(_cmd == (v1) || _cmd == (v2) || (_cmd == v3)){ |
|
276 # define SWITCH_DEFAULT }else{ |
|
277 # define SWITCH_END }} |
|
278 #endif |
|
279 |
|
280 #ifndef USB_RX_USER_HOOK |
|
281 #define USB_RX_USER_HOOK(data, len) |
|
282 #endif |
|
283 #ifndef USB_SET_ADDRESS_HOOK |
|
284 #define USB_SET_ADDRESS_HOOK() |
|
285 #endif |
|
286 |
|
287 /* ------------------------------------------------------------------------- */ |
|
288 |
|
289 /* We use if() instead of #if in the macro below because #if can't be used |
|
290 * in macros and the compiler optimizes constant conditions anyway. |
|
291 * This may cause problems with undefined symbols if compiled without |
|
292 * optimizing! |
|
293 */ |
|
294 #define GET_DESCRIPTOR(cfgProp, staticName) \ |
|
295 if(cfgProp){ \ |
|
296 if((cfgProp) & USB_PROP_IS_RAM) \ |
|
297 flags = 0; \ |
|
298 if((cfgProp) & USB_PROP_IS_DYNAMIC){ \ |
|
299 len = usbFunctionDescriptor(rq); \ |
|
300 }else{ \ |
|
301 len = USB_PROP_LENGTH(cfgProp); \ |
|
302 usbMsgPtr = (usbMsgPtr_t)(staticName); \ |
|
303 } \ |
|
304 } |
|
305 |
|
306 /* usbDriverDescriptor() is similar to usbFunctionDescriptor(), but used |
|
307 * internally for all types of descriptors. |
|
308 */ |
|
309 static inline usbMsgLen_t usbDriverDescriptor(usbRequest_t *rq) |
|
310 { |
|
311 usbMsgLen_t len = 0; |
|
312 uchar flags = USB_FLG_MSGPTR_IS_ROM; |
|
313 |
|
314 SWITCH_START(rq->wValue.bytes[1]) |
|
315 SWITCH_CASE(USBDESCR_DEVICE) /* 1 */ |
|
316 GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice) |
|
317 SWITCH_CASE(USBDESCR_CONFIG) /* 2 */ |
|
318 GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration) |
|
319 SWITCH_CASE(USBDESCR_STRING) /* 3 */ |
|
320 #if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC |
|
321 if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM) |
|
322 flags = 0; |
|
323 len = usbFunctionDescriptor(rq); |
|
324 #else /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ |
|
325 SWITCH_START(rq->wValue.bytes[0]) |
|
326 SWITCH_CASE(0) |
|
327 GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0) |
|
328 SWITCH_CASE(1) |
|
329 GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor) |
|
330 SWITCH_CASE(2) |
|
331 GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_PRODUCT, usbDescriptorStringDevice) |
|
332 SWITCH_CASE(3) |
|
333 GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber) |
|
334 SWITCH_DEFAULT |
|
335 if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ |
|
336 len = usbFunctionDescriptor(rq); |
|
337 } |
|
338 SWITCH_END |
|
339 #endif /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ |
|
340 #if USB_CFG_DESCR_PROPS_HID_REPORT /* only support HID descriptors if enabled */ |
|
341 SWITCH_CASE(USBDESCR_HID) /* 0x21 */ |
|
342 GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18) |
|
343 SWITCH_CASE(USBDESCR_HID_REPORT)/* 0x22 */ |
|
344 GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport) |
|
345 #endif |
|
346 SWITCH_DEFAULT |
|
347 if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ |
|
348 len = usbFunctionDescriptor(rq); |
|
349 } |
|
350 SWITCH_END |
|
351 usbMsgFlags = flags; |
|
352 return len; |
|
353 } |
|
354 |
|
355 /* ------------------------------------------------------------------------- */ |
|
356 |
|
357 /* usbDriverSetup() is similar to usbFunctionSetup(), but it's used for |
|
358 * standard requests instead of class and custom requests. |
|
359 */ |
|
360 static inline usbMsgLen_t usbDriverSetup(usbRequest_t *rq) |
|
361 { |
|
362 usbMsgLen_t len = 0; |
|
363 uchar *dataPtr = usbTxBuf + 9; /* there are 2 bytes free space at the end of the buffer */ |
|
364 uchar value = rq->wValue.bytes[0]; |
|
365 #if USB_CFG_IMPLEMENT_HALT |
|
366 uchar index = rq->wIndex.bytes[0]; |
|
367 #endif |
|
368 |
|
369 dataPtr[0] = 0; /* default reply common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */ |
|
370 SWITCH_START(rq->bRequest) |
|
371 SWITCH_CASE(USBRQ_GET_STATUS) /* 0 */ |
|
372 uchar recipient = rq->bmRequestType & USBRQ_RCPT_MASK; /* assign arith ops to variables to enforce byte size */ |
|
373 if(USB_CFG_IS_SELF_POWERED && recipient == USBRQ_RCPT_DEVICE) |
|
374 dataPtr[0] = USB_CFG_IS_SELF_POWERED; |
|
375 #if USB_CFG_IMPLEMENT_HALT |
|
376 if(recipient == USBRQ_RCPT_ENDPOINT && index == 0x81) /* request status for endpoint 1 */ |
|
377 dataPtr[0] = usbTxLen1 == USBPID_STALL; |
|
378 #endif |
|
379 dataPtr[1] = 0; |
|
380 len = 2; |
|
381 #if USB_CFG_IMPLEMENT_HALT |
|
382 SWITCH_CASE2(USBRQ_CLEAR_FEATURE, USBRQ_SET_FEATURE) /* 1, 3 */ |
|
383 if(value == 0 && index == 0x81){ /* feature 0 == HALT for endpoint == 1 */ |
|
384 usbTxLen1 = rq->bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL; |
|
385 usbResetDataToggling(); |
|
386 } |
|
387 #endif |
|
388 SWITCH_CASE(USBRQ_SET_ADDRESS) /* 5 */ |
|
389 usbNewDeviceAddr = value; |
|
390 USB_SET_ADDRESS_HOOK(); |
|
391 SWITCH_CASE(USBRQ_GET_DESCRIPTOR) /* 6 */ |
|
392 len = usbDriverDescriptor(rq); |
|
393 goto skipMsgPtrAssignment; |
|
394 SWITCH_CASE(USBRQ_GET_CONFIGURATION) /* 8 */ |
|
395 dataPtr = &usbConfiguration; /* send current configuration value */ |
|
396 len = 1; |
|
397 SWITCH_CASE(USBRQ_SET_CONFIGURATION) /* 9 */ |
|
398 usbConfiguration = value; |
|
399 usbResetStall(); |
|
400 SWITCH_CASE(USBRQ_GET_INTERFACE) /* 10 */ |
|
401 len = 1; |
|
402 #if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE |
|
403 SWITCH_CASE(USBRQ_SET_INTERFACE) /* 11 */ |
|
404 usbResetDataToggling(); |
|
405 usbResetStall(); |
|
406 #endif |
|
407 SWITCH_DEFAULT /* 7=SET_DESCRIPTOR, 12=SYNC_FRAME */ |
|
408 /* Should we add an optional hook here? */ |
|
409 SWITCH_END |
|
410 usbMsgPtr = (usbMsgPtr_t)dataPtr; |
|
411 skipMsgPtrAssignment: |
|
412 return len; |
|
413 } |
|
414 |
|
415 /* ------------------------------------------------------------------------- */ |
|
416 |
|
417 /* usbProcessRx() is called for every message received by the interrupt |
|
418 * routine. It distinguishes between SETUP and DATA packets and processes |
|
419 * them accordingly. |
|
420 */ |
|
421 static inline void usbProcessRx(uchar *data, uchar len) |
|
422 { |
|
423 usbRequest_t *rq = (void *)data; |
|
424 |
|
425 /* usbRxToken can be: |
|
426 * 0x2d 00101101 (USBPID_SETUP for setup data) |
|
427 * 0xe1 11100001 (USBPID_OUT: data phase of setup transfer) |
|
428 * 0...0x0f for OUT on endpoint X |
|
429 */ |
|
430 DBG2(0x10 + (usbRxToken & 0xf), data, len + 2); /* SETUP=1d, SETUP-DATA=11, OUTx=1x */ |
|
431 USB_RX_USER_HOOK(data, len) |
|
432 #if USB_CFG_IMPLEMENT_FN_WRITEOUT |
|
433 if(usbRxToken < 0x10){ /* OUT to endpoint != 0: endpoint number in usbRxToken */ |
|
434 usbFunctionWriteOut(data, len); |
|
435 return; |
|
436 } |
|
437 #endif |
|
438 if(usbRxToken == (uchar)USBPID_SETUP){ |
|
439 if(len != 8) /* Setup size must be always 8 bytes. Ignore otherwise. */ |
|
440 return; |
|
441 usbMsgLen_t replyLen; |
|
442 usbTxBuf[0] = USBPID_DATA0; /* initialize data toggling */ |
|
443 usbTxLen = USBPID_NAK; /* abort pending transmit */ |
|
444 usbMsgFlags = 0; |
|
445 uchar type = rq->bmRequestType & USBRQ_TYPE_MASK; |
|
446 if(type != USBRQ_TYPE_STANDARD){ /* standard requests are handled by driver */ |
|
447 replyLen = usbFunctionSetup(data); |
|
448 }else{ |
|
449 replyLen = usbDriverSetup(rq); |
|
450 } |
|
451 #if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE |
|
452 if(replyLen == USB_NO_MSG){ /* use user-supplied read/write function */ |
|
453 /* do some conditioning on replyLen, but on IN transfers only */ |
|
454 if((rq->bmRequestType & USBRQ_DIR_MASK) != USBRQ_DIR_HOST_TO_DEVICE){ |
|
455 if(sizeof(replyLen) < sizeof(rq->wLength.word)){ /* help compiler with optimizing */ |
|
456 replyLen = rq->wLength.bytes[0]; |
|
457 }else{ |
|
458 replyLen = rq->wLength.word; |
|
459 } |
|
460 } |
|
461 usbMsgFlags = USB_FLG_USE_USER_RW; |
|
462 }else /* The 'else' prevents that we limit a replyLen of USB_NO_MSG to the maximum transfer len. */ |
|
463 #endif |
|
464 if(sizeof(replyLen) < sizeof(rq->wLength.word)){ /* help compiler with optimizing */ |
|
465 if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0]) /* limit length to max */ |
|
466 replyLen = rq->wLength.bytes[0]; |
|
467 }else{ |
|
468 if(replyLen > rq->wLength.word) /* limit length to max */ |
|
469 replyLen = rq->wLength.word; |
|
470 } |
|
471 usbMsgLen = replyLen; |
|
472 }else{ /* usbRxToken must be USBPID_OUT, which means data phase of setup (control-out) */ |
|
473 #if USB_CFG_IMPLEMENT_FN_WRITE |
|
474 if(usbMsgFlags & USB_FLG_USE_USER_RW){ |
|
475 uchar rval = usbFunctionWrite(data, len); |
|
476 if(rval == 0xff){ /* an error occurred */ |
|
477 usbTxLen = USBPID_STALL; |
|
478 }else if(rval != 0){ /* This was the final package */ |
|
479 usbMsgLen = 0; /* answer with a zero-sized data packet */ |
|
480 } |
|
481 } |
|
482 #endif |
|
483 } |
|
484 } |
|
485 |
|
486 /* ------------------------------------------------------------------------- */ |
|
487 |
|
488 /* This function is similar to usbFunctionRead(), but it's also called for |
|
489 * data handled automatically by the driver (e.g. descriptor reads). |
|
490 */ |
|
491 static uchar usbDeviceRead(uchar *data, uchar len) |
|
492 { |
|
493 if(len > 0){ /* don't bother app with 0 sized reads */ |
|
494 #if USB_CFG_IMPLEMENT_FN_READ |
|
495 if(usbMsgFlags & USB_FLG_USE_USER_RW){ |
|
496 len = usbFunctionRead(data, len); |
|
497 }else |
|
498 #endif |
|
499 { |
|
500 uchar i = len; |
|
501 usbMsgPtr_t r = usbMsgPtr; |
|
502 if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){ /* ROM data */ |
|
503 do{ |
|
504 uchar c = USB_READ_FLASH(r); /* assign to char size variable to enforce byte ops */ |
|
505 *data++ = c; |
|
506 r++; |
|
507 }while(--i); |
|
508 }else{ /* RAM data */ |
|
509 do{ |
|
510 *data++ = *((uchar *)r); |
|
511 r++; |
|
512 }while(--i); |
|
513 } |
|
514 usbMsgPtr = r; |
|
515 } |
|
516 } |
|
517 return len; |
|
518 } |
|
519 |
|
520 /* ------------------------------------------------------------------------- */ |
|
521 |
|
522 /* usbBuildTxBlock() is called when we have data to transmit and the |
|
523 * interrupt routine's transmit buffer is empty. |
|
524 */ |
|
525 static inline void usbBuildTxBlock(void) |
|
526 { |
|
527 usbMsgLen_t wantLen; |
|
528 uchar len; |
|
529 |
|
530 wantLen = usbMsgLen; |
|
531 if(wantLen > 8) |
|
532 wantLen = 8; |
|
533 usbMsgLen -= wantLen; |
|
534 usbTxBuf[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* DATA toggling */ |
|
535 len = usbDeviceRead(usbTxBuf + 1, wantLen); |
|
536 if(len <= 8){ /* valid data packet */ |
|
537 usbCrc16Append(&usbTxBuf[1], len); |
|
538 len += 4; /* length including sync byte */ |
|
539 if(len < 12) /* a partial package identifies end of message */ |
|
540 usbMsgLen = USB_NO_MSG; |
|
541 }else{ |
|
542 len = USBPID_STALL; /* stall the endpoint */ |
|
543 usbMsgLen = USB_NO_MSG; |
|
544 } |
|
545 usbTxLen = len; |
|
546 DBG2(0x20, usbTxBuf, len-1); |
|
547 } |
|
548 |
|
549 /* ------------------------------------------------------------------------- */ |
|
550 |
|
551 static inline void usbHandleResetHook(uchar notResetState) |
|
552 { |
|
553 #ifdef USB_RESET_HOOK |
|
554 static uchar wasReset; |
|
555 uchar isReset = !notResetState; |
|
556 |
|
557 if(wasReset != isReset){ |
|
558 USB_RESET_HOOK(isReset); |
|
559 wasReset = isReset; |
|
560 } |
|
561 #else |
|
562 notResetState = notResetState; // avoid compiler warning |
|
563 #endif |
|
564 } |
|
565 |
|
566 /* ------------------------------------------------------------------------- */ |
|
567 |
|
568 USB_PUBLIC void usbPoll(void) |
|
569 { |
|
570 schar len; |
|
571 uchar i; |
|
572 |
|
573 len = usbRxLen - 3; |
|
574 if(len >= 0){ |
|
575 /* We could check CRC16 here -- but ACK has already been sent anyway. If you |
|
576 * need data integrity checks with this driver, check the CRC in your app |
|
577 * code and report errors back to the host. Since the ACK was already sent, |
|
578 * retries must be handled on application level. |
|
579 * unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3); |
|
580 */ |
|
581 usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len); |
|
582 #if USB_CFG_HAVE_FLOWCONTROL |
|
583 if(usbRxLen > 0) /* only mark as available if not inactivated */ |
|
584 usbRxLen = 0; |
|
585 #else |
|
586 usbRxLen = 0; /* mark rx buffer as available */ |
|
587 #endif |
|
588 } |
|
589 if(usbTxLen & 0x10){ /* transmit system idle */ |
|
590 if(usbMsgLen != USB_NO_MSG){ /* transmit data pending? */ |
|
591 usbBuildTxBlock(); |
|
592 } |
|
593 } |
|
594 for(i = 20; i > 0; i--){ |
|
595 uchar usbLineStatus = USBIN & USBMASK; |
|
596 if(usbLineStatus != 0) /* SE0 has ended */ |
|
597 goto isNotReset; |
|
598 } |
|
599 /* RESET condition, called multiple times during reset */ |
|
600 usbNewDeviceAddr = 0; |
|
601 usbDeviceAddr = 0; |
|
602 usbResetStall(); |
|
603 DBG1(0xff, 0, 0); |
|
604 isNotReset: |
|
605 usbHandleResetHook(i); |
|
606 } |
|
607 |
|
608 /* ------------------------------------------------------------------------- */ |
|
609 |
|
610 USB_PUBLIC void usbInit(void) |
|
611 { |
|
612 #if USB_INTR_CFG_SET != 0 |
|
613 USB_INTR_CFG |= USB_INTR_CFG_SET; |
|
614 #endif |
|
615 #if USB_INTR_CFG_CLR != 0 |
|
616 USB_INTR_CFG &= ~(USB_INTR_CFG_CLR); |
|
617 #endif |
|
618 USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT); |
|
619 usbResetDataToggling(); |
|
620 #if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE |
|
621 usbTxLen1 = USBPID_NAK; |
|
622 #if USB_CFG_HAVE_INTRIN_ENDPOINT3 |
|
623 usbTxLen3 = USBPID_NAK; |
|
624 #endif |
|
625 #endif |
|
626 } |
|
627 |
|
628 /* ------------------------------------------------------------------------- */ |