2 * at91sam7s USB CDC device implementation
4 * Copyright (c) 2012, Roel Verdult
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * based on the "Basic USB Example" from ATMEL (doc6123.pdf)
38 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
39 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
40 #define AT91C_EP_IN_SIZE 0x40
41 #define AT91C_EP_OUT 1
42 #define AT91C_EP_OUT_SIZE 0x40
45 const char devDescriptor
[] = {
46 /* Device descriptor */
48 0x01, // bDescriptorType
49 0x10,0x01, // Complies with USB Spec. Release (0110h = release 1.10)
50 0x02, // bDeviceClass: CDC class code
51 0x00, // bDeviceSubclass: CDC class sub code
52 0x00, // bDeviceProtocol: CDC Device protocol
53 0x08, // bMaxPacketSize0
54 0x2d,0x2d, // Vendor ID (--)
55 0x4d,0x50, // Product ID (PM), transmitted in reverse
56 0x01,0x00, // Device release number (0001)
57 0x01, // iManufacturer // 0x01
63 const char cfgDescriptor
[] = {
64 /* ============== CONFIGURATION 1 =========== */
65 /* Configuration 1 descriptor */
67 0x02, // CbDescriptorType
68 0x43, // CwTotalLength 2 EP + Control
70 0x02, // CbNumInterfaces
71 0x01, // CbConfigurationValue
72 0x00, // CiConfiguration
73 0xC0, // CbmAttributes 0xA0
76 /* Communication Class Interface Descriptor Requirement */
78 0x04, // bDescriptorType
79 0x00, // bInterfaceNumber
80 0x00, // bAlternateSetting
81 0x01, // bNumEndpoints
82 0x02, // bInterfaceClass
83 0x02, // bInterfaceSubclass
84 0x00, // bInterfaceProtocol
87 /* Header Functional Descriptor */
88 0x05, // bFunction Length
89 0x24, // bDescriptor type: CS_INTERFACE
90 0x00, // bDescriptor subtype: Header Func Desc
94 /* ACM Functional Descriptor */
95 0x04, // bFunctionLength
96 0x24, // bDescriptor Type: CS_INTERFACE
97 0x02, // bDescriptor Subtype: ACM Func Desc
98 0x00, // bmCapabilities
100 /* Union Functional Descriptor */
101 0x05, // bFunctionLength
102 0x24, // bDescriptorType: CS_INTERFACE
103 0x06, // bDescriptor Subtype: Union Func Desc
104 0x00, // bMasterInterface: Communication Class Interface
105 0x01, // bSlaveInterface0: Data Class Interface
107 /* Call Management Functional Descriptor */
108 0x05, // bFunctionLength
109 0x24, // bDescriptor Type: CS_INTERFACE
110 0x01, // bDescriptor Subtype: Call Management Func Desc
111 0x00, // bmCapabilities: D1 + D0
112 0x01, // bDataInterface: Data Class Interface 1
114 /* Endpoint 1 descriptor */
116 0x05, // bDescriptorType
117 0x83, // bEndpointAddress, Endpoint 03 - IN
118 0x03, // bmAttributes INT
119 0x08, // wMaxPacketSize
123 /* Data Class Interface Descriptor Requirement */
125 0x04, // bDescriptorType
126 0x01, // bInterfaceNumber
127 0x00, // bAlternateSetting
128 0x02, // bNumEndpoints
129 0x0A, // bInterfaceClass
130 0x00, // bInterfaceSubclass
131 0x00, // bInterfaceProtocol
134 /* First alternate setting */
135 /* Endpoint 1 descriptor */
137 0x05, // bDescriptorType
138 0x01, // bEndpointAddress, Endpoint 01 - OUT
139 0x02, // bmAttributes BULK
140 AT91C_EP_OUT_SIZE
, // wMaxPacketSize
144 /* Endpoint 2 descriptor */
146 0x05, // bDescriptorType
147 0x82, // bEndpointAddress, Endpoint 02 - IN
148 0x02, // bmAttributes BULK
149 AT91C_EP_IN_SIZE
, // wMaxPacketSize
154 const char strDescriptor
[] = {
156 0x03, // Type is string
172 /* USB standard request code */
173 #define STD_GET_STATUS_ZERO 0x0080
174 #define STD_GET_STATUS_INTERFACE 0x0081
175 #define STD_GET_STATUS_ENDPOINT 0x0082
177 #define STD_CLEAR_FEATURE_ZERO 0x0100
178 #define STD_CLEAR_FEATURE_INTERFACE 0x0101
179 #define STD_CLEAR_FEATURE_ENDPOINT 0x0102
181 #define STD_SET_FEATURE_ZERO 0x0300
182 #define STD_SET_FEATURE_INTERFACE 0x0301
183 #define STD_SET_FEATURE_ENDPOINT 0x0302
185 #define STD_SET_ADDRESS 0x0500
186 #define STD_GET_DESCRIPTOR 0x0680
187 #define STD_SET_DESCRIPTOR 0x0700
188 #define STD_GET_CONFIGURATION 0x0880
189 #define STD_SET_CONFIGURATION 0x0900
190 #define STD_GET_INTERFACE 0x0A81
191 #define STD_SET_INTERFACE 0x0B01
192 #define STD_SYNCH_FRAME 0x0C82
194 /* CDC Class Specific Request Code */
195 #define GET_LINE_CODING 0x21A1
196 #define SET_LINE_CODING 0x2021
197 #define SET_CONTROL_LINE_STATE 0x2221
200 unsigned int dwDTERRate
;
204 } AT91S_CDC_LINE_CODING
, *AT91PS_CDC_LINE_CODING
;
206 AT91S_CDC_LINE_CODING line
= {
212 void AT91F_CDC_Enumerate();
214 AT91PS_UDP pUdp
= AT91C_BASE_UDP
;
215 byte_t btConfiguration
= 0;
216 byte_t btConnection
= 0;
217 byte_t btReceiveBank
= AT91C_UDP_RX_DATA_BK0
;
219 //*----------------------------------------------------------------------------
220 //* \fn AT91F_USB_Disable
221 //* \brief This function deactivates the USB device
222 //*----------------------------------------------------------------------------
224 // Disconnect and reconnect USB controller for 100ms
225 AT91C_BASE_PIOA
->PIO_ODR
= AT91C_PIO_PA24
;
228 // Clear all lingering interrupts
229 if(pUdp
->UDP_ISR
& AT91C_UDP_ENDBUSRES
) {
230 pUdp
->UDP_ICR
= AT91C_UDP_ENDBUSRES
;
234 //*----------------------------------------------------------------------------
235 //* \fn AT91F_USB_Enable
236 //* \brief This function Activates the USB device
237 //*----------------------------------------------------------------------------
239 // Set the PLL USB Divider
240 AT91C_BASE_CKGR
->CKGR_PLLR
|= AT91C_CKGR_USBDIV_1
;
242 // Specific Chip USB Initialisation
243 // Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock
244 AT91C_BASE_PMC
->PMC_SCER
= AT91C_PMC_UDP
;
245 AT91C_BASE_PMC
->PMC_PCER
= (1 << AT91C_ID_UDP
);
247 // Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO
248 // Set in PIO mode and Configure in Output
249 AT91C_BASE_PIOA
->PIO_PER
= AT91C_PIO_PA16
; // Set in PIO mode
250 AT91C_BASE_PIOA
->PIO_OER
= AT91C_PIO_PA16
; // Configure as Output
252 // Clear for set the Pul up resistor
253 AT91C_BASE_PIOA
->PIO_CODR
= AT91C_PIO_PA16
;
255 // Disconnect and USB device
258 // Wait for a short while
261 // Reconnect USB reconnect
262 AT91C_BASE_PIOA
->PIO_SODR
= AT91C_PIO_PA24
;
263 AT91C_BASE_PIOA
->PIO_OER
= AT91C_PIO_PA24
;
266 //*----------------------------------------------------------------------------
267 //* \fn AT91F_UDP_IsConfigured
268 //* \brief Test if the device is configured and handle enumeration
269 //*----------------------------------------------------------------------------
271 AT91_REG isr
= pUdp
->UDP_ISR
;
273 if (isr
& AT91C_UDP_ENDBUSRES
) {
274 pUdp
->UDP_ICR
= AT91C_UDP_ENDBUSRES
;
275 // reset all endpoints
276 pUdp
->UDP_RSTEP
= (unsigned int)-1;
278 // Enable the function
279 pUdp
->UDP_FADDR
= AT91C_UDP_FEN
;
280 // Configure endpoint 0
281 pUdp
->UDP_CSR
[0] = (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_CTRL
);
283 else if (isr
& AT91C_UDP_EPINT0
) {
284 pUdp
->UDP_ICR
= AT91C_UDP_EPINT0
;
285 AT91F_CDC_Enumerate();
287 return (btConfiguration
) ? true : false;
293 if (!usb_check()) return false;
294 return (pUdp
->UDP_CSR
[AT91C_EP_OUT
] & btReceiveBank
);
297 //*----------------------------------------------------------------------------
298 //* \fn AT91F_UDP_Read
299 //* \brief Read available data from Endpoint OUT
300 //*----------------------------------------------------------------------------
301 uint32_t usb_read(byte_t
* data
, size_t len
) {
302 byte_t bank
= btReceiveBank
;
303 uint32_t packetSize
, nbBytesRcv
= 0;
304 uint32_t time_out
= 0;
308 if (!usb_check()) break;
310 if ( pUdp
->UDP_CSR
[AT91C_EP_OUT
] & bank
) {
311 packetSize
= MIN(pUdp
->UDP_CSR
[AT91C_EP_OUT
] >> 16, len
);
314 data
[nbBytesRcv
++] = pUdp
->UDP_FDR
[AT91C_EP_OUT
];
315 pUdp
->UDP_CSR
[AT91C_EP_OUT
] &= ~(bank
);
316 if (bank
== AT91C_UDP_RX_DATA_BK0
)
318 bank
= AT91C_UDP_RX_DATA_BK1
;
320 bank
= AT91C_UDP_RX_DATA_BK0
;
323 if (time_out
++ == 0x1fff) break;
326 btReceiveBank
= bank
;
330 //*----------------------------------------------------------------------------
331 //* \fn AT91F_CDC_Write
332 //* \brief Send through endpoint 2
333 //*----------------------------------------------------------------------------
334 uint32_t usb_write(const byte_t
* data
, const size_t len
) {
338 if (!length
) return 0;
339 if (!usb_check()) return 0;
341 // Send the first packet
342 cpt
= MIN(length
, AT91C_EP_IN_SIZE
-1);
344 while (cpt
--) pUdp
->UDP_FDR
[AT91C_EP_IN
] = *data
++;
345 pUdp
->UDP_CSR
[AT91C_EP_IN
] |= AT91C_UDP_TXPKTRDY
;
348 // Fill the second bank
349 cpt
= MIN(length
, AT91C_EP_IN_SIZE
-1);
351 while (cpt
--) pUdp
->UDP_FDR
[AT91C_EP_IN
] = *data
++;
352 // Wait for the the first bank to be sent
353 while (!(pUdp
->UDP_CSR
[AT91C_EP_IN
] & AT91C_UDP_TXCOMP
)) {
354 if (!usb_check()) return length
;
356 pUdp
->UDP_CSR
[AT91C_EP_IN
] &= ~(AT91C_UDP_TXCOMP
);
357 while (pUdp
->UDP_CSR
[AT91C_EP_IN
] & AT91C_UDP_TXCOMP
);
358 pUdp
->UDP_CSR
[AT91C_EP_IN
] |= AT91C_UDP_TXPKTRDY
;
361 // Wait for the end of transfer
362 while (!(pUdp
->UDP_CSR
[AT91C_EP_IN
] & AT91C_UDP_TXCOMP
)) {
363 if (!usb_check()) return length
;
366 pUdp
->UDP_CSR
[AT91C_EP_IN
] &= ~(AT91C_UDP_TXCOMP
);
367 while (pUdp
->UDP_CSR
[AT91C_EP_IN
] & AT91C_UDP_TXCOMP
);
372 //*----------------------------------------------------------------------------
373 //* \fn AT91F_USB_SendData
374 //* \brief Send Data through the control endpoint
375 //*----------------------------------------------------------------------------
376 unsigned int csrTab
[100];
377 unsigned char csrIdx
= 0;
379 static void AT91F_USB_SendData(AT91PS_UDP pUdp
, const char *pData
, uint32_t length
) {
384 cpt
= MIN(length
, 8);
388 pUdp
->UDP_FDR
[0] = *pData
++;
390 if (pUdp
->UDP_CSR
[0] & AT91C_UDP_TXCOMP
) {
391 pUdp
->UDP_CSR
[0] &= ~(AT91C_UDP_TXCOMP
);
392 while (pUdp
->UDP_CSR
[0] & AT91C_UDP_TXCOMP
);
395 pUdp
->UDP_CSR
[0] |= AT91C_UDP_TXPKTRDY
;
397 csr
= pUdp
->UDP_CSR
[0];
399 // Data IN stage has been stopped by a status OUT
400 if (csr
& AT91C_UDP_RX_DATA_BK0
) {
401 pUdp
->UDP_CSR
[0] &= ~(AT91C_UDP_RX_DATA_BK0
);
404 } while ( !(csr
& AT91C_UDP_TXCOMP
) );
408 if (pUdp
->UDP_CSR
[0] & AT91C_UDP_TXCOMP
) {
409 pUdp
->UDP_CSR
[0] &= ~(AT91C_UDP_TXCOMP
);
410 while (pUdp
->UDP_CSR
[0] & AT91C_UDP_TXCOMP
);
414 //*----------------------------------------------------------------------------
415 //* \fn AT91F_USB_SendZlp
416 //* \brief Send zero length packet through the control endpoint
417 //*----------------------------------------------------------------------------
418 void AT91F_USB_SendZlp(AT91PS_UDP pUdp
) {
419 pUdp
->UDP_CSR
[0] |= AT91C_UDP_TXPKTRDY
;
420 while ( !(pUdp
->UDP_CSR
[0] & AT91C_UDP_TXCOMP
) );
421 pUdp
->UDP_CSR
[0] &= ~(AT91C_UDP_TXCOMP
);
422 while (pUdp
->UDP_CSR
[0] & AT91C_UDP_TXCOMP
);
425 //*----------------------------------------------------------------------------
426 //* \fn AT91F_USB_SendStall
427 //* \brief Stall the control endpoint
428 //*----------------------------------------------------------------------------
429 void AT91F_USB_SendStall(AT91PS_UDP pUdp
) {
430 pUdp
->UDP_CSR
[0] |= AT91C_UDP_FORCESTALL
;
431 while ( !(pUdp
->UDP_CSR
[0] & AT91C_UDP_ISOERROR
) );
432 pUdp
->UDP_CSR
[0] &= ~(AT91C_UDP_FORCESTALL
| AT91C_UDP_ISOERROR
);
433 while (pUdp
->UDP_CSR
[0] & (AT91C_UDP_FORCESTALL
| AT91C_UDP_ISOERROR
));
436 //*----------------------------------------------------------------------------
437 //* \fn AT91F_CDC_Enumerate
438 //* \brief This function is a callback invoked when a SETUP packet is received
439 //*----------------------------------------------------------------------------
440 void AT91F_CDC_Enumerate() {
441 byte_t bmRequestType
, bRequest
;
442 uint16_t wValue
, wIndex
, wLength
, wStatus
;
444 if ( !(pUdp
->UDP_CSR
[0] & AT91C_UDP_RXSETUP
) )
447 bmRequestType
= pUdp
->UDP_FDR
[0];
448 bRequest
= pUdp
->UDP_FDR
[0];
449 wValue
= (pUdp
->UDP_FDR
[0] & 0xFF);
450 wValue
|= (pUdp
->UDP_FDR
[0] << 8);
451 wIndex
= (pUdp
->UDP_FDR
[0] & 0xFF);
452 wIndex
|= (pUdp
->UDP_FDR
[0] << 8);
453 wLength
= (pUdp
->UDP_FDR
[0] & 0xFF);
454 wLength
|= (pUdp
->UDP_FDR
[0] << 8);
456 if (bmRequestType
& 0x80) {
457 pUdp
->UDP_CSR
[0] |= AT91C_UDP_DIR
;
458 while ( !(pUdp
->UDP_CSR
[0] & AT91C_UDP_DIR
) );
460 pUdp
->UDP_CSR
[0] &= ~AT91C_UDP_RXSETUP
;
461 while ( (pUdp
->UDP_CSR
[0] & AT91C_UDP_RXSETUP
) );
463 // Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1
464 switch ((bRequest
<< 8) | bmRequestType
) {
465 case STD_GET_DESCRIPTOR
:
466 if (wValue
== 0x100) // Return Device Descriptor
467 AT91F_USB_SendData(pUdp
, devDescriptor
, MIN(sizeof(devDescriptor
), wLength
));
468 else if (wValue
== 0x200) // Return Configuration Descriptor
469 AT91F_USB_SendData(pUdp
, cfgDescriptor
, MIN(sizeof(cfgDescriptor
), wLength
));
470 else if ((wValue
& 0x300) == 0x300) // Return String Descriptor
471 AT91F_USB_SendData(pUdp
, strDescriptor
, MIN(sizeof(strDescriptor
), wLength
));
473 AT91F_USB_SendStall(pUdp
);
475 case STD_SET_ADDRESS
:
476 AT91F_USB_SendZlp(pUdp
);
477 pUdp
->UDP_FADDR
= (AT91C_UDP_FEN
| wValue
);
478 pUdp
->UDP_GLBSTATE
= (wValue
) ? AT91C_UDP_FADDEN
: 0;
480 case STD_SET_CONFIGURATION
:
481 btConfiguration
= wValue
;
482 AT91F_USB_SendZlp(pUdp
);
483 pUdp
->UDP_GLBSTATE
= (wValue
) ? AT91C_UDP_CONFG
: AT91C_UDP_FADDEN
;
484 pUdp
->UDP_CSR
[1] = (wValue
) ? (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_BULK_OUT
) : 0;
485 pUdp
->UDP_CSR
[2] = (wValue
) ? (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_BULK_IN
) : 0;
486 pUdp
->UDP_CSR
[3] = (wValue
) ? (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_INT_IN
) : 0;
488 case STD_GET_CONFIGURATION
:
489 AT91F_USB_SendData(pUdp
, (char *) &(btConfiguration
), sizeof(btConfiguration
));
491 case STD_GET_STATUS_ZERO
:
493 AT91F_USB_SendData(pUdp
, (char *) &wStatus
, sizeof(wStatus
));
495 case STD_GET_STATUS_INTERFACE
:
497 AT91F_USB_SendData(pUdp
, (char *) &wStatus
, sizeof(wStatus
));
499 case STD_GET_STATUS_ENDPOINT
:
502 if ((pUdp
->UDP_GLBSTATE
& AT91C_UDP_CONFG
) && (wIndex
<= 3)) {
503 wStatus
= (pUdp
->UDP_CSR
[wIndex
] & AT91C_UDP_EPEDS
) ? 0 : 1;
504 AT91F_USB_SendData(pUdp
, (char *) &wStatus
, sizeof(wStatus
));
506 else if ((pUdp
->UDP_GLBSTATE
& AT91C_UDP_FADDEN
) && (wIndex
== 0)) {
507 wStatus
= (pUdp
->UDP_CSR
[wIndex
] & AT91C_UDP_EPEDS
) ? 0 : 1;
508 AT91F_USB_SendData(pUdp
, (char *) &wStatus
, sizeof(wStatus
));
511 AT91F_USB_SendStall(pUdp
);
513 case STD_SET_FEATURE_ZERO
:
514 AT91F_USB_SendStall(pUdp
);
516 case STD_SET_FEATURE_INTERFACE
:
517 AT91F_USB_SendZlp(pUdp
);
519 case STD_SET_FEATURE_ENDPOINT
:
521 if ((wValue
== 0) && wIndex
&& (wIndex
<= 3)) {
522 pUdp
->UDP_CSR
[wIndex
] = 0;
523 AT91F_USB_SendZlp(pUdp
);
526 AT91F_USB_SendStall(pUdp
);
528 case STD_CLEAR_FEATURE_ZERO
:
529 AT91F_USB_SendStall(pUdp
);
531 case STD_CLEAR_FEATURE_INTERFACE
:
532 AT91F_USB_SendZlp(pUdp
);
534 case STD_CLEAR_FEATURE_ENDPOINT
:
536 if ((wValue
== 0) && wIndex
&& (wIndex
<= 3)) {
538 pUdp
->UDP_CSR
[1] = (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_BULK_OUT
);
539 else if (wIndex
== 2)
540 pUdp
->UDP_CSR
[2] = (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_BULK_IN
);
541 else if (wIndex
== 3)
542 pUdp
->UDP_CSR
[3] = (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_ISO_IN
);
543 AT91F_USB_SendZlp(pUdp
);
546 AT91F_USB_SendStall(pUdp
);
549 // handle CDC class requests
550 case SET_LINE_CODING
:
551 while ( !(pUdp
->UDP_CSR
[0] & AT91C_UDP_RX_DATA_BK0
) );
552 pUdp
->UDP_CSR
[0] &= ~(AT91C_UDP_RX_DATA_BK0
);
553 AT91F_USB_SendZlp(pUdp
);
555 case GET_LINE_CODING
:
556 AT91F_USB_SendData(pUdp
, (char *) &line
, MIN(sizeof(line
), wLength
));
558 case SET_CONTROL_LINE_STATE
:
559 btConnection
= wValue
;
560 AT91F_USB_SendZlp(pUdp
);
563 AT91F_USB_SendStall(pUdp
);