2 * Project: AVR USB driver
3 * Author: Christian Starkjohann
4 * Creation Date: 2004-12-29
6 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
7 * License: Proprietary, free under certain conditions. See Documentation.
8 * This Revision: $Id: usbdrv.c 53 2005-04-12 17:11:29Z cs $
12 #include <avr/pgmspace.h>
18 This module implements the C-part of the USB driver. See usbdrv.h for a
19 documentation of the entire driver.
22 /* ------------------------------------------------------------------------- */
24 /* raw USB registers / interface to assembler code: */
25 /* usbRxBuf MUST be in 1 byte addressable range (because usbInputBuf is only 1 byte) */
26 static char usbRxBuf
[2][USB_BUFSIZE
];/* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */
27 uchar usbDeviceId
; /* assigned during enumeration, defaults to 0 */
28 uchar usbInputBuf
; /* ptr to raw buffer used for receiving */
29 uchar usbAppBuf
; /* ptr to raw buffer passed to app for processing */
30 volatile char usbRxLen
; /* = 0; number of bytes in usbAppBuf; 0 means free */
31 uchar usbCurrentTok
; /* last token received */
32 uchar usbRxToken
; /* token for data we received */
33 uchar usbMsgLen
= 0xff; /* remaining number of bytes, no msg to send if -1 (see usbMsgPtr) */
34 volatile char usbTxLen
= -1; /* number of bytes to transmit with next IN token */
35 uchar usbTxBuf
[USB_BUFSIZE
];/* data to transmit with next IN, free if usbTxLen == -1 */
36 #if USB_CFG_HAVE_INTRIN_ENDPOINT
37 /* uchar usbRxEndp; endpoint which was addressed (1 bit in MSB) [not impl] */
38 volatile char usbTxLen1
= -1; /* TX count for endpoint 1 */
39 uchar usbTxBuf1
[USB_BUFSIZE
];/* TX data for endpoint 1 */
41 uchar usbAckBuf
[1] = {USBPID_ACK
}; /* transmit buffer for ack tokens */
42 uchar usbNakBuf
[1] = {USBPID_NAK
}; /* transmit buffer for nak tokens */
44 /* USB status registers / not shared with asm code */
45 uchar
*usbMsgPtr
; /* data to transmit next -- ROM or RAM address */
46 static uchar usbMsgFlags
; /* flag values see below */
47 static uchar usbNewDeviceId
; /* = 0; device ID which should be set after status phase */
48 static uchar usbIsReset
; /* = 0; USB bus is in reset phase */
50 #define USB_FLG_TX_PACKET (1<<0)
51 /* Leave free 6 bits after TX_PACKET. This way we can increment usbMsgFlags to toggle TX_PACKET */
52 #define USB_FLG_MSGPTR_IS_ROM (1<<6)
53 #define USB_FLG_USE_DEFAULT_RW (1<<7)
57 - do not post/pre inc/dec integer values in operations
58 - assign value of PRG_RDB() to register variables and don't use side effects in arg
59 - use narrow scope for variables which should be in X/Y/Z register
60 - assign char sized expressions to variables to force 8 bit arithmetics
63 /* ------------------------------------------------------------------------- */
65 static char usbDescrDevice
[] PROGMEM
= { /* USB device descriptor */
66 18, /* sizeof(usbDescrDevice): length of descriptor in bytes */
67 1, /* descriptor type */
68 0x01, 0x01, /* USB version supported */
70 USB_CFG_DEVICE_SUBCLASS
,
72 8, /* max packet size */
73 USB_CFG_VENDOR_ID
, /* 2 bytes */
74 USB_CFG_DEVICE_ID
, /* 2 bytes */
75 USB_CFG_DEVICE_VERSION
, /* 2 bytes */
76 #if USB_CFG_VENDOR_NAME_LEN
77 1, /* manufacturer string index */
79 0, /* manufacturer string index */
81 #if USB_CFG_DEVICE_NAME_LEN
82 2, /* product string index */
84 0, /* product string index */
86 0, /* serial number string index */
87 1, /* number of configurations */
90 static char usbDescrConfig
[] PROGMEM
= { /* USB configuration descriptor */
91 9, /* sizeof(usbDescrConfig): length of descriptor in bytes */
92 2, /* descriptor type */
93 (18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT
), 0, /* total length of data returned (including inlined descriptors) */
94 1, /* number of interfaces in this configuration */
95 1, /* index of this configuration */
96 0, /* configuration name string index */
97 #if USB_CFG_IS_SELF_POWERED
98 USBATTR_SELFPOWER
, /* attributes */
100 USBATTR_BUSPOWER
, /* attributes */
102 USB_CFG_MAX_BUS_POWER
/2, /* max USB current in 2mA units */
103 /* interface descriptor follows inline: */
104 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */
105 4, /* descriptor type */
106 0, /* index of this interface */
107 0, /* alternate setting for this interface */
108 USB_CFG_HAVE_INTRIN_ENDPOINT
, /* endpoints excl 0: number of endpoint descriptors to follow */
109 USB_CFG_INTERFACE_CLASS
,
110 USB_CFG_INTERFACE_SUBCLASS
,
111 USB_CFG_INTERFACE_PROTOCOL
,
112 0, /* string index for interface */
113 #if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */
114 7, /* sizeof(usbDescrEndpoint) */
115 5, /* descriptor type = endpoint */
116 0x81, /* IN endpoint number 1 */
117 0x03, /* attrib: Interrupt endpoint */
118 8, 0, /* maximum packet size */
119 USB_CFG_INTR_POLL_INTERVAL
, /* in ms */
123 static char usbDescrString0
[] PROGMEM
= { /* language descriptor */
124 4, /* sizeof(usbDescrString0): length of descriptor in bytes */
125 3, /* descriptor type */
126 0x09, 0x04, /* language index (0x0409 = US-English) */
129 #if USB_CFG_VENDOR_NAME_LEN
130 static int usbDescrString1
[] PROGMEM
= {
131 (2 * USB_CFG_VENDOR_NAME_LEN
+ 2) | (3<<8), /* length of descriptor in bytes | descriptor type */
135 #if USB_CFG_DEVICE_NAME_LEN
136 static int usbDescrString2
[] PROGMEM
= {
137 (2 * USB_CFG_DEVICE_NAME_LEN
+ 2) | (3<<8), /* length of descriptor in bytes | descriptor type */
142 /* We don't use prog_int or prog_int16_t for compatibility with various libc
143 * versions. Here's an other compatibility hack:
146 #define PRG_RDB(addr) pgm_read_byte(addr)
154 /* We use this union to do type conversions. This is better optimized than
155 * type casts in gcc 3.4.3 and much better than using bit shifts to build
156 * ints from chars. Byte ordering is not a problem on an 8 bit platform.
159 /* ------------------------------------------------------------------------- */
161 #if USB_CFG_HAVE_INTRIN_ENDPOINT
162 static uchar usbTxPacketCnt1
;
164 void usbSetInterrupt(uchar
*data
, uchar len
)
172 if(usbTxPacketCnt1
& 1)
174 if(usbTxLen1
< 0){ /* packet buffer was empty */
177 usbTxLen1
= -1; /* avoid sending incomplete interrupt data */
183 crc
.word
= usbCrc16(&usbTxBuf1
[1], len
);
184 usbTxBuf1
[len
+ 1] = crc
.bytes
[0];
185 usbTxBuf1
[len
+ 2] = crc
.bytes
[1];
186 usbTxLen1
= len
+ 4; /* len must be given including sync byte */
190 static void usbWrite(uchar
*data
, uchar len
)
192 #if USB_CFG_IMPLEMENT_FN_WRITE
193 if(!(usbMsgFlags
& USB_FLG_USE_DEFAULT_RW
)){
194 if(usbFunctionWrite(data
, len
) == 0xff){ /* an error occurred */
195 /* usbMsgLen = 0xff; cancel potentially pending ACK [has been done by ASM module when OUT token arrived] */
196 usbTxBuf
[0] = USBPID_STALL
;
197 usbTxLen
= 2; /* length including sync byte */
202 usbMsgLen
= 0; /* send zero-sized block as ACK */
203 usbMsgFlags
= 0; /* start with a DATA1 package */
206 static uchar
usbRead(uchar
*data
, uchar len
)
208 #if USB_CFG_IMPLEMENT_FN_READ
209 if(usbMsgFlags
& USB_FLG_USE_DEFAULT_RW
){
211 uchar i
= len
, *r
= usbMsgPtr
;
212 if(usbMsgFlags
& USB_FLG_MSGPTR_IS_ROM
){ /* ROM data */
214 char c
= PRG_RDB(r
); /* assign to char size variable to enforce byte ops */
218 }else{ /* RAM data */
224 #if USB_CFG_IMPLEMENT_FN_READ
226 if(len
!= 0) /* don't bother app with 0 sized reads */
227 return usbFunctionRead(data
, len
);
233 /* Don't make this function static to avoid inlining.
234 * The entire function would become too large and exceed the range of
237 void usbProcessRx(uchar
*data
, uchar len
)
239 /* We use if() cascades because the compare is done byte-wise while switch()
240 * is int-based. The if() cascades are therefore more efficient.
242 DBG2(0x10 + (usbRxToken
== (uchar
)USBPID_SETUP
), data
, len
);
243 if(usbRxToken
== (uchar
)USBPID_SETUP
){
244 uchar replyLen
= 0, flags
= USB_FLG_USE_DEFAULT_RW
;
245 if(len
== 8){ /* Setup size must be always 8 bytes. Ignore otherwise. */
246 uchar type
= data
[0] & (3 << 5);
247 if(type
== USBRQ_TYPE_STANDARD
<< 5){
248 uchar
*replyData
= usbTxBuf
+ 9; /* there is 3 bytes free space at the end of the buffer */
250 if(data
[1] == 0){/* GET_STATUS */
251 #if USB_CFG_IS_SELF_POWERED
252 uchar recipient
= data
[0] & 0x1f; /* assign arith ops to variables to enforce byte size */
253 if(recipient
== USBRQ_RCPT_DEVICE
)
254 replyData
[0] = USB_CFG_IS_SELF_POWERED
;
258 }else if(data
[1] == 5){ /* SET_ADDRESS */
259 usbNewDeviceId
= data
[2];
260 }else if(data
[1] == 6){ /* GET_DESCRIPTOR */
261 flags
= USB_FLG_MSGPTR_IS_ROM
| USB_FLG_USE_DEFAULT_RW
;
262 if(data
[3] == 1){ /* descriptor type requested */
263 replyLen
= sizeof(usbDescrDevice
);
264 replyData
= (uchar
*)usbDescrDevice
;
265 }else if(data
[3] == 2){
266 replyLen
= sizeof(usbDescrConfig
);
267 replyData
= (uchar
*)usbDescrConfig
;
268 }else if(data
[3] == 3){ /* string descriptor */
269 if(data
[2] == 0){ /* descriptor index */
270 replyLen
= sizeof(usbDescrString0
);
271 replyData
= (uchar
*)usbDescrString0
;
272 #if USB_CFG_VENDOR_NAME_LEN
273 }else if(data
[2] == 1){
274 replyLen
= sizeof(usbDescrString1
);
275 replyData
= (uchar
*)usbDescrString1
;
277 #if USB_CFG_DEVICE_NAME_LEN
278 }else if(data
[2] == 2){
279 replyLen
= sizeof(usbDescrString2
);
280 replyData
= (uchar
*)usbDescrString2
;
284 }else if(data
[1] == 8){ /* GET_CONFIGURATION */
286 replyData
[0] = 1; /* config is always 1, no setConfig required */
287 }else if(data
[1] == 10){ /* GET_INTERFACE */
289 #if USB_CFG_HAVE_INTRIN_ENDPOINT
290 }else if(data
[1] == 11){ /* SET_INTERFACE */
291 usbTxPacketCnt1
= 0; /* reset data toggling for interrupt socket */
294 /* the following requests can be ignored, send default reply */
295 /* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */
296 /* 9: SET_CONFIGURATION, 11: SET_INTERFACE, 12: SYNCH_FRAME */
298 usbMsgPtr
= replyData
;
299 if(!data
[7] && replyLen
> data
[6]) /* max length is in data[7]:data[6] */
301 }else{ /* not a standard request -- must be vendor or class request */
302 #if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE
304 replyLen
= data
[6]; /* if this is an OUT operation, the next token will reset usbMsgLen */
305 if((len
= usbFunctionSetup(data
)) != 0xff){
308 flags
= 0; /* we have no valid msg, use read/write functions */
311 replyLen
= usbFunctionSetup(data
);
315 usbMsgLen
= replyLen
;
317 }else{ /* out request */
322 /* ------------------------------------------------------------------------- */
324 static void usbBuildTxBlock(void)
326 uchar wantLen
, len
, txLen
, x
;
330 if(usbMsgFlags
& USB_FLG_TX_PACKET
)
337 usbMsgLen
-= wantLen
;
338 len
= usbRead(usbTxBuf
+ 1, wantLen
);
339 if(len
<= 8){ /* valid data packet */
340 crc
.word
= usbCrc16(&usbTxBuf
[1], len
);
341 usbTxBuf
[len
+ 1] = crc
.bytes
[0];
342 usbTxBuf
[len
+ 2] = crc
.bytes
[1];
343 txLen
= len
+ 4; /* length including sync byte */
344 if(len
< 8) /* a partial package identifies end of message */
347 usbTxBuf
[0] = USBPID_STALL
;
348 txLen
= 2; /* length including sync byte */
352 DBG2(0x20, usbTxBuf
, txLen
-1);
355 static inline uchar
isNotSE0(void)
359 * return (USBIN & USBMASK);
360 * here, but the compiler does int-expansion acrobatics.
361 * We can avoid this by assigning to a char-sized variable.
363 rval
= USBIN
& USBMASK
;
367 /* ------------------------------------------------------------------------- */
373 if((len
= usbRxLen
) > 0){
374 /* We could check CRC16 here -- but ACK has already been sent anyway. If you
375 * need data integrity checks with this driver, check the CRC in your app
376 * code and report errors back to the host. Since the ACK was already sent,
377 * retries must be handled on application level.
378 * unsigned crc = usbCrc16((uchar *)(unsigned)(usbAppBuf + 1), usbRxLen - 3);
380 len
-= 3; /* remove PID and CRC */
382 usbProcessRx((uchar
*)(unsigned)(usbAppBuf
+ 1), len
);
384 usbRxLen
= 0; /* mark rx buffer as available */
386 if(usbTxLen
< 0){ /* TX system is idle */
387 if(usbMsgLen
!= 0xff){
389 }else if(usbNewDeviceId
){
390 usbDeviceId
= usbNewDeviceId
;
391 DBG1(1, &usbNewDeviceId
, 1);
395 if(isNotSE0()){ /* SE0 state */
398 /* check whether SE0 lasts for more than 2.5us (3.75 bit times) */
414 /* ------------------------------------------------------------------------- */
418 usbInputBuf
= (uchar
)usbRxBuf
[0];
419 usbAppBuf
= (uchar
)usbRxBuf
[1];
420 #if USB_INTR_CFG_SET != 0
421 USB_INTR_CFG
|= USB_INTR_CFG_SET
;
423 #if USB_INTR_CFG_CLR != 0
424 USB_INTR_CFG
&= ~(USB_INTR_CFG_CLR
);
426 USB_INTR_ENABLE
|= (1 << USB_INTR_ENABLE_BIT
);
429 /* ------------------------------------------------------------------------- */