]> the.earth.li Git - riso-kagaku-clone.git/blob - usbdrv/usbdrv.c
Initial import of V-USB as base
[riso-kagaku-clone.git] / usbdrv / usbdrv.c
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) | USBATTR_REMOTEWAKE,      /* 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 schar   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 /* ------------------------------------------------------------------------- */