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)
42 #include "at91sam7s512.h"
43 #include "config_gpio.h"
45 #define AT91C_EP_CONTROL 0
46 #define AT91C_EP_OUT 1
48 #define AT91C_EP_NOTIFY 3
49 #define AT91C_EP_OUT_SIZE 0x40
50 #define AT91C_EP_IN_SIZE 0x40
52 // Language must always be 0.
53 #define STR_LANGUAGE_CODES 0x00
54 #define STR_MANUFACTURER 0x01
55 #define STR_PRODUCT 0x02
58 static const char devDescriptor
[] = {
59 /* Device descriptor */
61 0x01, // bDescriptorType
62 0x00,0x02, // Complies with USB Spec. Release (0200h = release 2.0)
63 0x02, // bDeviceClass: (Communication Device Class)
64 0x00, // bDeviceSubclass: (unused at this time)
65 0x00, // bDeviceProtocol: (unused at this time)
66 0x08, // bMaxPacketSize0
67 0xc4,0x9a, // Vendor ID (0x9ac4 = J. Westhues)
68 0x8f,0x4b, // Product ID (0x4b8f = Proxmark-3 RFID Instrument)
69 0x01,0x00, // Device release number (0001)
70 STR_MANUFACTURER
, // iManufacturer
71 STR_PRODUCT
, // iProduct
72 0x00, // iSerialNumber
77 static const char cfgDescriptor
[] = {
78 /* ============== CONFIGURATION 1 =========== */
79 /* Configuration 1 descriptor */
81 0x02, // CbDescriptorType
82 0x43, // CwTotalLength 2 EP + Control
84 0x02, // CbNumInterfaces
85 0x01, // CbConfigurationValue
86 0x00, // CiConfiguration
87 0x80, // CbmAttributes (Bus Powered)
88 0x4B, // CMaxPower (150mA max current drawn from bus)
90 /* Interface 0 Descriptor: Communication Class Interface */
92 0x04, // bDescriptorType
93 0x00, // bInterfaceNumber
94 0x00, // bAlternateSetting
95 0x01, // bNumEndpoints
96 0x02, // bInterfaceClass: Communication Interface Class
97 0x02, // bInterfaceSubclass: Abstract Control Model
98 0x01, // bInterfaceProtocol: Common AT Commands, V.25ter
101 /* Header Functional Descriptor */
102 0x05, // bFunction Length
103 0x24, // bDescriptor type: CS_INTERFACE
104 0x00, // bDescriptor subtype: Header Functional Descriptor
108 /* ACM Functional Descriptor */
109 0x04, // bFunctionLength
110 0x24, // bDescriptor Type: CS_INTERFACE
111 0x02, // bDescriptor Subtype: Abstract Control Management Functional Descriptor
112 0x02, // bmCapabilities: D1: Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State
114 /* Union Functional Descriptor */
115 0x05, // bFunctionLength
116 0x24, // bDescriptorType: CS_INTERFACE
117 0x06, // bDescriptor Subtype: Union Functional Descriptor
118 0x00, // bMasterInterface: Communication Class Interface
119 0x01, // bSlaveInterface0: Data Class Interface
121 /* Call Management Functional Descriptor */
122 0x05, // bFunctionLength
123 0x24, // bDescriptor Type: CS_INTERFACE
124 0x01, // bDescriptor Subtype: Call Management Functional Descriptor
125 0x00, // bmCapabilities: Device sends/receives call management information only over the Communication Class interface. Device does not handle call management itself
126 0x01, // bDataInterface: Data Class Interface 1
128 /* Endpoint 1 descriptor */
130 0x05, // bDescriptorType
131 0x83, // bEndpointAddress: Endpoint 03 - IN
132 0x03, // bmAttributes: INT
133 0x08, // wMaxPacketSize: 8
137 /* Interface 1 Descriptor: Data Class Interface */
139 0x04, // bDescriptorType
140 0x01, // bInterfaceNumber
141 0x00, // bAlternateSetting
142 0x02, // bNumEndpoints
143 0x0A, // bInterfaceClass: Data Interface Class
144 0x00, // bInterfaceSubclass: not used
145 0x00, // bInterfaceProtocol: No class specific protocol required)
148 /* Endpoint 1 descriptor */
150 0x05, // bDescriptorType
151 0x01, // bEndpointAddress: Endpoint 01 - OUT
152 0x02, // bmAttributes: BULK
153 AT91C_EP_OUT_SIZE
, // wMaxPacketSize
157 /* Endpoint 2 descriptor */
159 0x05, // bDescriptorType
160 0x82, // bEndpointAddress: Endpoint 02 - IN
161 0x02, // bmAttributes: BULK
162 AT91C_EP_IN_SIZE
, // wMaxPacketSize
168 static const char StrDescLanguageCodes
[] = {
170 0x03, // Type is string
171 0x09, 0x04 // supported language Code 0 = 0x0409 (English)
175 // Note: ModemManager (Linux) ignores Proxmark3 devices by matching the
176 // manufacturer string "proxmark.org". Don't change this.
177 static const char StrDescManufacturer
[] = {
179 0x03, // Type is string
195 static const char StrDescProduct
[] = {
197 0x03, // Type is string
210 static const char* getStringDescriptor(uint8_t idx
) {
212 case STR_LANGUAGE_CODES
:
213 return StrDescLanguageCodes
;
214 case STR_MANUFACTURER
:
215 return StrDescManufacturer
;
217 return StrDescProduct
;
224 // Bitmap for all status bits in CSR which must be written as 1 to cause no effect
225 #define REG_NO_EFFECT_1_ALL (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 | AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP | AT91C_UDP_TXCOMP)
228 // Clear flags in the UDP_CSR register
229 #define UDP_CLEAR_EP_FLAGS(endpoint, flags) { \
230 volatile unsigned int reg; \
231 reg = AT91C_BASE_UDP->UDP_CSR[(endpoint)]; \
232 reg |= REG_NO_EFFECT_1_ALL; \
234 AT91C_BASE_UDP->UDP_CSR[(endpoint)] = reg; \
238 // Set flags in the UDP_CSR register
239 #define UDP_SET_EP_FLAGS(endpoint, flags) { \
240 volatile unsigned int reg; \
241 reg = AT91C_BASE_UDP->UDP_CSR[(endpoint)]; \
242 reg |= REG_NO_EFFECT_1_ALL; \
244 AT91C_BASE_UDP->UDP_CSR[(endpoint)] = reg; \
248 /* USB standard request codes */
249 #define STD_GET_STATUS_ZERO 0x0080
250 #define STD_GET_STATUS_INTERFACE 0x0081
251 #define STD_GET_STATUS_ENDPOINT 0x0082
253 #define STD_CLEAR_FEATURE_ZERO 0x0100
254 #define STD_CLEAR_FEATURE_INTERFACE 0x0101
255 #define STD_CLEAR_FEATURE_ENDPOINT 0x0102
257 #define STD_SET_FEATURE_ZERO 0x0300
258 #define STD_SET_FEATURE_INTERFACE 0x0301
259 #define STD_SET_FEATURE_ENDPOINT 0x0302
261 #define STD_SET_ADDRESS 0x0500
262 #define STD_GET_DESCRIPTOR 0x0680
263 #define STD_SET_DESCRIPTOR 0x0700
264 #define STD_GET_CONFIGURATION 0x0880
265 #define STD_SET_CONFIGURATION 0x0900
266 #define STD_GET_INTERFACE 0x0A81
267 #define STD_SET_INTERFACE 0x0B01
268 #define STD_SYNCH_FRAME 0x0C82
270 /* CDC Class Specific Request Code */
271 #define GET_LINE_CODING 0x21A1
272 #define SET_LINE_CODING 0x2021
273 #define SET_CONTROL_LINE_STATE 0x2221
277 unsigned int dwDTERRate
;
281 } AT91S_CDC_LINE_CODING
, *AT91PS_CDC_LINE_CODING
;
284 static AT91S_CDC_LINE_CODING line
= {
291 static uint8_t btConfiguration
= 0;
292 static uint8_t btConnection
= 0;
293 static uint8_t btReceiveBank
= AT91C_UDP_RX_DATA_BK0
;
296 //*----------------------------------------------------------------------------
298 //* \brief This function deactivates the USB device
299 //*----------------------------------------------------------------------------
301 // Disconnect the USB device
302 AT91C_BASE_PIOA
->PIO_ODR
= GPIO_USB_PU
;
304 // Clear all lingering interrupts
305 if (AT91C_BASE_UDP
->UDP_ISR
& AT91C_UDP_ENDBUSRES
) {
306 AT91C_BASE_UDP
->UDP_ICR
= AT91C_UDP_ENDBUSRES
;
311 //*----------------------------------------------------------------------------
313 //* \brief This function Activates the USB device
314 //*----------------------------------------------------------------------------
316 // Set the PLL USB Divider
317 AT91C_BASE_CKGR
->CKGR_PLLR
|= AT91C_CKGR_USBDIV_1
;
319 // Specific Chip USB Initialisation
320 // Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock
321 AT91C_BASE_PMC
->PMC_SCER
= AT91C_PMC_UDP
;
322 AT91C_BASE_PMC
->PMC_PCER
= (1 << AT91C_ID_UDP
);
324 // Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO
325 // Set in PIO mode and Configure in Output
326 AT91C_BASE_PIOA
->PIO_PER
= GPIO_USB_PU
; // Set in PIO mode
327 AT91C_BASE_PIOA
->PIO_OER
= GPIO_USB_PU
; // Configure as Output
329 // Clear for set the Pullup resistor
330 AT91C_BASE_PIOA
->PIO_CODR
= GPIO_USB_PU
;
332 // Disconnect and reconnect USB controller for 100ms
335 // Wait for a short while
336 for (volatile size_t i
= 0; i
< 0x100000; i
++);
338 // Reconnect USB reconnect
339 AT91C_BASE_PIOA
->PIO_SODR
= GPIO_USB_PU
;
340 AT91C_BASE_PIOA
->PIO_OER
= GPIO_USB_PU
;
344 //*----------------------------------------------------------------------------
345 //* \fn AT91F_USB_SendZlp
346 //* \brief Send zero length packet through an endpoint
347 //*----------------------------------------------------------------------------
348 static void AT91F_USB_SendZlp(uint8_t endpoint
) {
349 UDP_SET_EP_FLAGS(endpoint
, AT91C_UDP_TXPKTRDY
);
350 while (!(AT91C_BASE_UDP
->UDP_CSR
[endpoint
] & AT91C_UDP_TXCOMP
))
352 UDP_CLEAR_EP_FLAGS(endpoint
, AT91C_UDP_TXCOMP
);
353 while (AT91C_BASE_UDP
->UDP_CSR
[endpoint
] & AT91C_UDP_TXCOMP
)
358 //*----------------------------------------------------------------------------
359 //* \fn AT91F_USB_SendData
360 //* \brief Send Data through the control endpoint
361 //*----------------------------------------------------------------------------
362 static void AT91F_USB_SendData(const char *pData
, uint32_t length
) {
367 cpt
= MIN(length
, 8);
371 AT91C_BASE_UDP
->UDP_FDR
[0] = *pData
++;
373 if (AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_CONTROL
] & AT91C_UDP_TXCOMP
) {
374 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL
, AT91C_UDP_TXCOMP
);
375 while (AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_CONTROL
] & AT91C_UDP_TXCOMP
)
379 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL
, AT91C_UDP_TXPKTRDY
);
381 csr
= AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_CONTROL
];
383 // Data IN stage has been stopped by a status OUT
384 if (csr
& AT91C_UDP_RX_DATA_BK0
) {
385 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL
, AT91C_UDP_RX_DATA_BK0
);
388 } while (!(csr
& AT91C_UDP_TXCOMP
));
392 if (AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_CONTROL
] & AT91C_UDP_TXCOMP
) {
393 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL
, AT91C_UDP_TXCOMP
);
394 while (AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_CONTROL
] & AT91C_UDP_TXCOMP
)
400 //*----------------------------------------------------------------------------
401 //* \fn AT91F_USB_SendStall
402 //* \brief Stall the control endpoint
403 //*----------------------------------------------------------------------------
404 static void AT91F_USB_SendStall(void) {
405 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL
, AT91C_UDP_FORCESTALL
);
406 while (!(AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_CONTROL
] & AT91C_UDP_ISOERROR
))
408 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL
, AT91C_UDP_FORCESTALL
| AT91C_UDP_ISOERROR
);
409 while (AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_CONTROL
] & (AT91C_UDP_FORCESTALL
| AT91C_UDP_ISOERROR
))
414 //*----------------------------------------------------------------------------
415 //* \fn AT91F_CDC_Enumerate
416 //* \brief This function is a callback invoked when a SETUP packet is received
417 //*----------------------------------------------------------------------------
418 static void AT91F_CDC_Enumerate() {
419 uint8_t bmRequestType
, bRequest
;
420 uint16_t wValue
, wIndex
, wLength
, wStatus
;
422 if (!(AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_CONTROL
] & AT91C_UDP_RXSETUP
))
425 bmRequestType
= AT91C_BASE_UDP
->UDP_FDR
[AT91C_EP_CONTROL
];
426 bRequest
= AT91C_BASE_UDP
->UDP_FDR
[AT91C_EP_CONTROL
];
427 wValue
= (AT91C_BASE_UDP
->UDP_FDR
[AT91C_EP_CONTROL
] & 0xFF);
428 wValue
|= (AT91C_BASE_UDP
->UDP_FDR
[AT91C_EP_CONTROL
] << 8);
429 wIndex
= (AT91C_BASE_UDP
->UDP_FDR
[AT91C_EP_CONTROL
] & 0xFF);
430 wIndex
|= (AT91C_BASE_UDP
->UDP_FDR
[AT91C_EP_CONTROL
] << 8);
431 wLength
= (AT91C_BASE_UDP
->UDP_FDR
[AT91C_EP_CONTROL
] & 0xFF);
432 wLength
|= (AT91C_BASE_UDP
->UDP_FDR
[AT91C_EP_CONTROL
] << 8);
434 if (bmRequestType
& 0x80) { // Data Phase Transfer Direction Device to Host
435 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL
, AT91C_UDP_DIR
);
436 while (!(AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_CONTROL
] & AT91C_UDP_DIR
))
439 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL
, AT91C_UDP_RXSETUP
);
440 while (AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_CONTROL
] & AT91C_UDP_RXSETUP
)
443 // Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1
444 switch ((bRequest
<< 8) | bmRequestType
) {
445 case STD_GET_DESCRIPTOR
:
446 if (wValue
== 0x100) // Return Device Descriptor
447 AT91F_USB_SendData(devDescriptor
, MIN(sizeof(devDescriptor
), wLength
));
448 else if (wValue
== 0x200) // Return Configuration Descriptor
449 AT91F_USB_SendData(cfgDescriptor
, MIN(sizeof(cfgDescriptor
), wLength
));
450 else if ((wValue
& 0xF00) == 0x300) { // Return String Descriptor
451 const char *strDescriptor
= getStringDescriptor(wValue
& 0xff);
452 if (strDescriptor
!= NULL
) {
453 AT91F_USB_SendData(strDescriptor
, MIN(strDescriptor
[0], wLength
));
455 AT91F_USB_SendStall();
459 AT91F_USB_SendStall();
461 case STD_SET_ADDRESS
:
462 AT91F_USB_SendZlp(AT91C_EP_CONTROL
);
463 AT91C_BASE_UDP
->UDP_FADDR
= (AT91C_UDP_FEN
| wValue
);
464 AT91C_BASE_UDP
->UDP_GLBSTATE
= (wValue
) ? AT91C_UDP_FADDEN
: 0;
466 case STD_SET_CONFIGURATION
:
467 btConfiguration
= wValue
;
468 AT91F_USB_SendZlp(AT91C_EP_CONTROL
);
469 AT91C_BASE_UDP
->UDP_GLBSTATE
= (wValue
) ? AT91C_UDP_CONFG
: AT91C_UDP_FADDEN
;
470 AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_OUT
] = (wValue
) ? (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_BULK_OUT
) : 0;
471 AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_IN
] = (wValue
) ? (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_BULK_IN
) : 0;
472 AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_NOTIFY
] = (wValue
) ? (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_INT_IN
) : 0;
474 case STD_GET_CONFIGURATION
:
475 AT91F_USB_SendData((char *) &(btConfiguration
), sizeof(btConfiguration
));
477 case STD_GET_STATUS_ZERO
:
478 wStatus
= 0; // Device is Bus powered, remote wakeup disabled
479 AT91F_USB_SendData((char *) &wStatus
, sizeof(wStatus
));
481 case STD_GET_STATUS_INTERFACE
:
482 wStatus
= 0; // reserved for future use
483 AT91F_USB_SendData((char *) &wStatus
, sizeof(wStatus
));
485 case STD_GET_STATUS_ENDPOINT
:
488 if ((AT91C_BASE_UDP
->UDP_GLBSTATE
& AT91C_UDP_CONFG
) && (wIndex
<= AT91C_EP_NOTIFY
)) {
489 wStatus
= (AT91C_BASE_UDP
->UDP_CSR
[wIndex
] & AT91C_UDP_EPEDS
) ? 0 : 1;
490 AT91F_USB_SendData((char *) &wStatus
, sizeof(wStatus
));
491 } else if ((AT91C_BASE_UDP
->UDP_GLBSTATE
& AT91C_UDP_FADDEN
) && (wIndex
== AT91C_EP_CONTROL
)) {
492 wStatus
= (AT91C_BASE_UDP
->UDP_CSR
[wIndex
] & AT91C_UDP_EPEDS
) ? 0 : 1;
493 AT91F_USB_SendData((char *) &wStatus
, sizeof(wStatus
));
495 AT91F_USB_SendStall();
497 case STD_SET_FEATURE_ZERO
:
498 AT91F_USB_SendStall();
500 case STD_SET_FEATURE_INTERFACE
:
501 AT91F_USB_SendZlp(AT91C_EP_CONTROL
);
503 case STD_SET_FEATURE_ENDPOINT
:
505 if ((wValue
== 0) && (wIndex
>= AT91C_EP_OUT
) && (wIndex
<= AT91C_EP_NOTIFY
)) {
506 AT91C_BASE_UDP
->UDP_CSR
[wIndex
] = 0;
507 AT91F_USB_SendZlp(AT91C_EP_CONTROL
);
509 AT91F_USB_SendStall();
511 case STD_CLEAR_FEATURE_ZERO
:
512 AT91F_USB_SendStall();
514 case STD_CLEAR_FEATURE_INTERFACE
:
515 AT91F_USB_SendZlp(AT91C_EP_CONTROL
);
517 case STD_CLEAR_FEATURE_ENDPOINT
:
519 if ((wValue
== 0) && (wIndex
>= AT91C_EP_OUT
) && (wIndex
<= AT91C_EP_NOTIFY
)) {
520 if (wIndex
== AT91C_EP_OUT
)
521 AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_OUT
] = (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_BULK_OUT
);
522 else if (wIndex
== AT91C_EP_IN
)
523 AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_IN
] = (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_BULK_IN
);
524 else if (wIndex
== AT91C_EP_NOTIFY
)
525 AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_NOTIFY
] = (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_INT_IN
);
526 AT91F_USB_SendZlp(AT91C_EP_CONTROL
);
529 AT91F_USB_SendStall();
532 // handle CDC class requests
533 case SET_LINE_CODING
:
534 while (!(AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_CONTROL
] & AT91C_UDP_RX_DATA_BK0
))
536 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL
, AT91C_UDP_RX_DATA_BK0
);
537 AT91F_USB_SendZlp(AT91C_EP_CONTROL
);
539 case GET_LINE_CODING
:
540 AT91F_USB_SendData((char *) &line
, MIN(sizeof(line
), wLength
));
542 case SET_CONTROL_LINE_STATE
:
543 btConnection
= wValue
;
544 AT91F_USB_SendZlp(AT91C_EP_CONTROL
);
547 AT91F_USB_SendStall();
553 //*----------------------------------------------------------------------------
555 //* \brief Test if the device is configured and handle enumeration
556 //*----------------------------------------------------------------------------
557 static bool usb_check() {
558 AT91_REG isr
= AT91C_BASE_UDP
->UDP_ISR
;
560 if (isr
& AT91C_UDP_ENDBUSRES
) {
561 AT91C_BASE_UDP
->UDP_ICR
= AT91C_UDP_ENDBUSRES
;
562 // reset all endpoints
563 AT91C_BASE_UDP
->UDP_RSTEP
= (unsigned int)-1;
564 AT91C_BASE_UDP
->UDP_RSTEP
= 0;
565 // Enable the function
566 AT91C_BASE_UDP
->UDP_FADDR
= AT91C_UDP_FEN
;
567 // Configure endpoint 0
568 AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_CONTROL
] = (AT91C_UDP_EPEDS
| AT91C_UDP_EPTYPE_CTRL
);
569 } else if (isr
& AT91C_UDP_EPINT0
) {
570 AT91C_BASE_UDP
->UDP_ICR
= AT91C_UDP_EPINT0
;
571 AT91F_CDC_Enumerate();
573 return (btConfiguration
) ? true : false;
578 if (!usb_check()) return false;
579 return (AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_OUT
] & btReceiveBank
);
584 In github PR #129, some users appears to get a false positive from
585 usb_poll, which returns true, but the usb_read operation
587 This check is basically the same as above, but also checks
588 that the length available to read is non-zero, thus hopefully fixes the
591 bool usb_poll_validate_length() {
592 if (!usb_check()) return false;
593 if (!(AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_OUT
] & btReceiveBank
)) return false;
594 return (AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_OUT
] >> 16) > 0;
598 //*----------------------------------------------------------------------------
600 //* \brief Read available data from Endpoint OUT
601 //*----------------------------------------------------------------------------
602 static uint32_t usb_read(uint8_t* data
, size_t len
) {
603 uint8_t bank
= btReceiveBank
;
604 uint32_t packetSize
, nbBytesRcv
= 0;
605 uint32_t time_out
= 0;
608 if (!usb_check()) break;
610 if ( AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_OUT
] & bank
) {
611 packetSize
= MIN(AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_OUT
] >> 16, len
);
614 data
[nbBytesRcv
++] = AT91C_BASE_UDP
->UDP_FDR
[AT91C_EP_OUT
];
615 UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT
, bank
);
616 if (bank
== AT91C_UDP_RX_DATA_BK0
) {
617 bank
= AT91C_UDP_RX_DATA_BK1
;
619 bank
= AT91C_UDP_RX_DATA_BK0
;
622 if (time_out
++ == 0x1fff) break;
625 btReceiveBank
= bank
;
630 //*----------------------------------------------------------------------------
632 //* \brief Send through endpoint 2
633 //*----------------------------------------------------------------------------
634 static uint32_t usb_write(const uint8_t* data
, const size_t len
) {
638 if (!length
) return 0;
639 if (!usb_check()) return 0;
641 // Send the first packet
642 cpt
= MIN(length
, AT91C_EP_IN_SIZE
);
645 AT91C_BASE_UDP
->UDP_FDR
[AT91C_EP_IN
] = *data
++;
647 UDP_SET_EP_FLAGS(AT91C_EP_IN
, AT91C_UDP_TXPKTRDY
);
648 while (!(AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_IN
] & AT91C_UDP_TXPKTRDY
))
652 // Fill the next bank
653 cpt
= MIN(length
, AT91C_EP_IN_SIZE
);
656 AT91C_BASE_UDP
->UDP_FDR
[AT91C_EP_IN
] = *data
++;
658 // Wait for the previous bank to be sent
659 while (!(AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_IN
] & AT91C_UDP_TXCOMP
)) {
660 if (!usb_check()) return length
;
662 UDP_SET_EP_FLAGS(AT91C_EP_IN
, AT91C_UDP_TXPKTRDY
);
663 while (!(AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_IN
] & AT91C_UDP_TXPKTRDY
))
665 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN
, AT91C_UDP_TXCOMP
);
666 while (AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_IN
] & AT91C_UDP_TXCOMP
)
670 // Wait for the end of transfer
671 while (!(AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_IN
] & AT91C_UDP_TXCOMP
)) {
672 if (!usb_check()) return length
;
674 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN
, AT91C_UDP_TXCOMP
);
675 while (AT91C_BASE_UDP
->UDP_CSR
[AT91C_EP_IN
] & AT91C_UDP_TXCOMP
)
678 if (len
% AT91C_EP_IN_SIZE
== 0) { // need to send a zero length packet to complete the transfer
679 AT91F_USB_SendZlp(AT91C_EP_IN
);
686 //***************************************************************************
687 // Interface to the main program
688 //***************************************************************************
690 // The function to receive a command from the client via USB
691 bool cmd_receive(UsbCommand
* cmd
) {
693 // Check if there is a usb packet available
697 // Try to retrieve the available command frame
698 size_t rxlen
= usb_read((uint8_t*)cmd
, sizeof(UsbCommand
));
700 // Check if the transfer was complete
701 if (rxlen
!= sizeof(UsbCommand
))
704 // Received command successfully
709 // The function to send a response to the client via USB
710 bool cmd_send(uint16_t cmd
, uint32_t arg0
, uint32_t arg1
, uint32_t arg2
, void* data
, uint16_t datalen
) {
714 // Compose the outgoing response frame
715 txcmd
.cmd
= cmd
| CMD_VARIABLE_SIZE_FLAG
;
720 // Add the (optional) content to the frame, with a maximum size of USB_CMD_DATA_SIZE
722 datalen
= MIN(datalen
, USB_CMD_DATA_SIZE
);
723 for (uint16_t i
= 0; i
< datalen
; i
++) {
724 txcmd
.d
.asBytes
[i
] = ((uint8_t*)data
)[i
];
726 txcmd
.datalen
= datalen
;
731 // Send frame and make sure all bytes are transmitted
732 size_t tx_size
= offsetof(UsbResponse
, d
) + datalen
;
733 if (usb_write((uint8_t*)&txcmd
, tx_size
) != 0) return false;
739 // For compatibility only: legacy function to send a response with fixed size to the client via USB
740 bool cmd_send_old(uint16_t cmd
, uint32_t arg0
, uint32_t arg1
, uint32_t arg2
, void* data
, uint16_t datalen
) {
744 // Compose the outgoing response frame
750 // Add the (optional) content to the frame, with a maximum size of USB_CMD_DATA_SIZE
752 datalen
= MIN(datalen
, USB_CMD_DATA_SIZE
);
753 for (uint16_t i
= 0; i
< datalen
; i
++) {
754 txcmd
.d
.asBytes
[i
] = ((uint8_t*)data
)[i
];
758 // Send frame and make sure all bytes are transmitted
759 if (usb_write((uint8_t*)&txcmd
, sizeof(UsbCommand
)) != 0) return false;