You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

USBCore.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. /* Copyright (c) 2010, Peter Barrett
  2. **
  3. ** Permission to use, copy, modify, and/or distribute this software for
  4. ** any purpose with or without fee is hereby granted, provided that the
  5. ** above copyright notice and this permission notice appear in all copies.
  6. **
  7. ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  8. ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  9. ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
  10. ** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
  11. ** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  12. ** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  13. ** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  14. ** SOFTWARE.
  15. */
  16. #include "Platform.h"
  17. #include "USBAPI.h"
  18. #include "USBDesc.h"
  19. #if defined(USBCON)
  20. #define EP_TYPE_CONTROL 0x00
  21. #define EP_TYPE_BULK_IN 0x81
  22. #define EP_TYPE_BULK_OUT 0x80
  23. #define EP_TYPE_INTERRUPT_IN 0xC1
  24. #define EP_TYPE_INTERRUPT_OUT 0xC0
  25. #define EP_TYPE_ISOCHRONOUS_IN 0x41
  26. #define EP_TYPE_ISOCHRONOUS_OUT 0x40
  27. /** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */
  28. #define TX_RX_LED_PULSE_MS 100
  29. volatile u8 TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */
  30. volatile u8 RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */
  31. //==================================================================
  32. //==================================================================
  33. extern const u16 STRING_LANGUAGE[] PROGMEM;
  34. extern const u16 STRING_IPRODUCT[] PROGMEM;
  35. extern const u16 STRING_IMANUFACTURER[] PROGMEM;
  36. extern const DeviceDescriptor USB_DeviceDescriptor PROGMEM;
  37. extern const DeviceDescriptor USB_DeviceDescriptorA PROGMEM;
  38. const u16 STRING_LANGUAGE[2] = {
  39. (3<<8) | (2+2),
  40. 0x0409 // English
  41. };
  42. const u16 STRING_IPRODUCT[17] = {
  43. (3<<8) | (2+2*16),
  44. #if USB_PID == 0x8036
  45. 'A','r','d','u','i','n','o',' ','L','e','o','n','a','r','d','o'
  46. #else
  47. 'U','S','B',' ','I','O',' ','B','o','a','r','d',' ',' ',' ',' '
  48. #endif
  49. };
  50. const u16 STRING_IMANUFACTURER[12] = {
  51. (3<<8) | (2+2*11),
  52. #if USB_VID == 0x2341
  53. 'A','r','d','u','i','n','o',' ','L','L','C'
  54. #else
  55. 'U','n','k','n','o','w','n',' ',' ',' ',' '
  56. #endif
  57. };
  58. #ifdef CDC_ENABLED
  59. #define DEVICE_CLASS 0x02
  60. #else
  61. #define DEVICE_CLASS 0x00
  62. #endif
  63. // DEVICE DESCRIPTOR
  64. const DeviceDescriptor USB_DeviceDescriptor =
  65. D_DEVICE(0x00,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1);
  66. const DeviceDescriptor USB_DeviceDescriptorA =
  67. D_DEVICE(DEVICE_CLASS,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1);
  68. //==================================================================
  69. //==================================================================
  70. volatile u8 _usbConfiguration = 0;
  71. static inline void WaitIN(void)
  72. {
  73. while (!(UEINTX & (1<<TXINI)));
  74. }
  75. static inline void ClearIN(void)
  76. {
  77. UEINTX = ~(1<<TXINI);
  78. }
  79. static inline void WaitOUT(void)
  80. {
  81. while (!(UEINTX & (1<<RXOUTI)))
  82. ;
  83. }
  84. static inline u8 WaitForINOrOUT()
  85. {
  86. while (!(UEINTX & ((1<<TXINI)|(1<<RXOUTI))))
  87. ;
  88. return (UEINTX & (1<<RXOUTI)) == 0;
  89. }
  90. static inline void ClearOUT(void)
  91. {
  92. UEINTX = ~(1<<RXOUTI);
  93. }
  94. void Recv(volatile u8* data, u8 count)
  95. {
  96. while (count--)
  97. *data++ = UEDATX;
  98. RXLED1; // light the RX LED
  99. RxLEDPulse = TX_RX_LED_PULSE_MS;
  100. }
  101. static inline u8 Recv8()
  102. {
  103. RXLED1; // light the RX LED
  104. RxLEDPulse = TX_RX_LED_PULSE_MS;
  105. return UEDATX;
  106. }
  107. static inline void Send8(u8 d)
  108. {
  109. UEDATX = d;
  110. }
  111. static inline void SetEP(u8 ep)
  112. {
  113. UENUM = ep;
  114. }
  115. static inline u8 FifoByteCount()
  116. {
  117. return UEBCLX;
  118. }
  119. static inline u8 ReceivedSetupInt()
  120. {
  121. return UEINTX & (1<<RXSTPI);
  122. }
  123. static inline void ClearSetupInt()
  124. {
  125. UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI));
  126. }
  127. static inline void Stall()
  128. {
  129. UECONX = (1<<STALLRQ) | (1<<EPEN);
  130. }
  131. static inline u8 ReadWriteAllowed()
  132. {
  133. return UEINTX & (1<<RWAL);
  134. }
  135. static inline u8 Stalled()
  136. {
  137. return UEINTX & (1<<STALLEDI);
  138. }
  139. static inline u8 FifoFree()
  140. {
  141. return UEINTX & (1<<FIFOCON);
  142. }
  143. static inline void ReleaseRX()
  144. {
  145. UEINTX = 0x6B; // FIFOCON=0 NAKINI=1 RWAL=1 NAKOUTI=0 RXSTPI=1 RXOUTI=0 STALLEDI=1 TXINI=1
  146. }
  147. static inline void ReleaseTX()
  148. {
  149. UEINTX = 0x3A; // FIFOCON=0 NAKINI=0 RWAL=1 NAKOUTI=1 RXSTPI=1 RXOUTI=0 STALLEDI=1 TXINI=0
  150. }
  151. static inline u8 FrameNumber()
  152. {
  153. return UDFNUML;
  154. }
  155. //==================================================================
  156. //==================================================================
  157. u8 USBGetConfiguration(void)
  158. {
  159. return _usbConfiguration;
  160. }
  161. #define USB_RECV_TIMEOUT
  162. class LockEP
  163. {
  164. u8 _sreg;
  165. public:
  166. LockEP(u8 ep) : _sreg(SREG)
  167. {
  168. cli();
  169. SetEP(ep & 7);
  170. }
  171. ~LockEP()
  172. {
  173. SREG = _sreg;
  174. }
  175. };
  176. // Number of bytes, assumes a rx endpoint
  177. u8 USB_Available(u8 ep)
  178. {
  179. LockEP lock(ep);
  180. return FifoByteCount();
  181. }
  182. // Non Blocking receive
  183. // Return number of bytes read
  184. int USB_Recv(u8 ep, void* d, int len)
  185. {
  186. if (!_usbConfiguration || len < 0)
  187. return -1;
  188. LockEP lock(ep);
  189. u8 n = FifoByteCount();
  190. len = min(n,len);
  191. n = len;
  192. u8* dst = (u8*)d;
  193. while (n--)
  194. *dst++ = Recv8();
  195. if (len && !FifoByteCount()) // release empty buffer
  196. ReleaseRX();
  197. return len;
  198. }
  199. // Recv 1 byte if ready
  200. int USB_Recv(u8 ep)
  201. {
  202. u8 c;
  203. if (USB_Recv(ep,&c,1) != 1)
  204. return -1;
  205. return c;
  206. }
  207. // Space in send EP
  208. u8 USB_SendSpace(u8 ep)
  209. {
  210. LockEP lock(ep);
  211. if (!ReadWriteAllowed())
  212. return 0;
  213. return 64 - FifoByteCount();
  214. }
  215. // Blocking Send of data to an endpoint
  216. int USB_Send(u8 ep, const void* d, int len)
  217. {
  218. if (!_usbConfiguration)
  219. return -1;
  220. int r = len;
  221. const u8* data = (const u8*)d;
  222. u8 zero = ep & TRANSFER_ZERO;
  223. u8 timeout = 250; // 250ms timeout on send? TODO
  224. while (len)
  225. {
  226. u8 n = USB_SendSpace(ep);
  227. if (n == 0)
  228. {
  229. if (!(--timeout))
  230. return -1;
  231. delay(1);
  232. continue;
  233. }
  234. if (n > len)
  235. n = len;
  236. len -= n;
  237. {
  238. LockEP lock(ep);
  239. if (ep & TRANSFER_ZERO)
  240. {
  241. while (n--)
  242. Send8(0);
  243. }
  244. else if (ep & TRANSFER_PGM)
  245. {
  246. while (n--)
  247. Send8(pgm_read_byte(data++));
  248. }
  249. else
  250. {
  251. while (n--)
  252. Send8(*data++);
  253. }
  254. if (!ReadWriteAllowed() || ((len == 0) && (ep & TRANSFER_RELEASE))) // Release full buffer
  255. ReleaseTX();
  256. }
  257. }
  258. TXLED1; // light the TX LED
  259. TxLEDPulse = TX_RX_LED_PULSE_MS;
  260. return r;
  261. }
  262. extern const u8 _initEndpoints[] PROGMEM;
  263. const u8 _initEndpoints[] =
  264. {
  265. 0,
  266. #ifdef CDC_ENABLED
  267. EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM
  268. EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT
  269. EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN
  270. #endif
  271. #ifdef HID_ENABLED
  272. EP_TYPE_INTERRUPT_IN // HID_ENDPOINT_INT
  273. #endif
  274. };
  275. #define EP_SINGLE_64 0x32 // EP0
  276. #define EP_DOUBLE_64 0x36 // Other endpoints
  277. static
  278. void InitEP(u8 index, u8 type, u8 size)
  279. {
  280. UENUM = index;
  281. UECONX = 1;
  282. UECFG0X = type;
  283. UECFG1X = size;
  284. }
  285. static
  286. void InitEndpoints()
  287. {
  288. for (u8 i = 1; i < sizeof(_initEndpoints); i++)
  289. {
  290. UENUM = i;
  291. UECONX = 1;
  292. UECFG0X = pgm_read_byte(_initEndpoints+i);
  293. UECFG1X = EP_DOUBLE_64;
  294. }
  295. UERST = 0x7E; // And reset them
  296. UERST = 0;
  297. }
  298. // Handle CLASS_INTERFACE requests
  299. static
  300. bool ClassInterfaceRequest(Setup& setup)
  301. {
  302. u8 i = setup.wIndex;
  303. #ifdef CDC_ENABLED
  304. if (CDC_ACM_INTERFACE == i)
  305. return CDC_Setup(setup);
  306. #endif
  307. #ifdef HID_ENABLED
  308. if (HID_INTERFACE == i)
  309. return HID_Setup(setup);
  310. #endif
  311. return false;
  312. }
  313. int _cmark;
  314. int _cend;
  315. void InitControl(int end)
  316. {
  317. SetEP(0);
  318. _cmark = 0;
  319. _cend = end;
  320. }
  321. static
  322. bool SendControl(u8 d)
  323. {
  324. if (_cmark < _cend)
  325. {
  326. if (!WaitForINOrOUT())
  327. return false;
  328. Send8(d);
  329. if (!((_cmark + 1) & 0x3F))
  330. ClearIN(); // Fifo is full, release this packet
  331. }
  332. _cmark++;
  333. return true;
  334. };
  335. // Clipped by _cmark/_cend
  336. int USB_SendControl(u8 flags, const void* d, int len)
  337. {
  338. int sent = len;
  339. const u8* data = (const u8*)d;
  340. bool pgm = flags & TRANSFER_PGM;
  341. while (len--)
  342. {
  343. u8 c = pgm ? pgm_read_byte(data++) : *data++;
  344. if (!SendControl(c))
  345. return -1;
  346. }
  347. return sent;
  348. }
  349. // Does not timeout or cross fifo boundaries
  350. // Will only work for transfers <= 64 bytes
  351. // TODO
  352. int USB_RecvControl(void* d, int len)
  353. {
  354. WaitOUT();
  355. Recv((u8*)d,len);
  356. ClearOUT();
  357. return len;
  358. }
  359. int SendInterfaces()
  360. {
  361. int total = 0;
  362. u8 interfaces = 0;
  363. #ifdef CDC_ENABLED
  364. total = CDC_GetInterface(&interfaces);
  365. #endif
  366. #ifdef HID_ENABLED
  367. total += HID_GetInterface(&interfaces);
  368. #endif
  369. return interfaces;
  370. }
  371. // Construct a dynamic configuration descriptor
  372. // This really needs dynamic endpoint allocation etc
  373. // TODO
  374. static
  375. bool SendConfiguration(int maxlen)
  376. {
  377. // Count and measure interfaces
  378. InitControl(0);
  379. int interfaces = SendInterfaces();
  380. ConfigDescriptor config = D_CONFIG(_cmark + sizeof(ConfigDescriptor),interfaces);
  381. // Now send them
  382. InitControl(maxlen);
  383. USB_SendControl(0,&config,sizeof(ConfigDescriptor));
  384. SendInterfaces();
  385. return true;
  386. }
  387. u8 _cdcComposite = 0;
  388. static
  389. bool SendDescriptor(Setup& setup)
  390. {
  391. u8 t = setup.wValueH;
  392. if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t)
  393. return SendConfiguration(setup.wLength);
  394. InitControl(setup.wLength);
  395. #ifdef HID_ENABLED
  396. if (HID_REPORT_DESCRIPTOR_TYPE == t)
  397. return HID_GetDescriptor(t);
  398. #endif
  399. u8 desc_length = 0;
  400. const u8* desc_addr = 0;
  401. if (USB_DEVICE_DESCRIPTOR_TYPE == t)
  402. {
  403. if (setup.wLength == 8)
  404. _cdcComposite = 1;
  405. desc_addr = _cdcComposite ? (const u8*)&USB_DeviceDescriptorA : (const u8*)&USB_DeviceDescriptor;
  406. }
  407. else if (USB_STRING_DESCRIPTOR_TYPE == t)
  408. {
  409. if (setup.wValueL == 0)
  410. desc_addr = (const u8*)&STRING_LANGUAGE;
  411. else if (setup.wValueL == IPRODUCT)
  412. desc_addr = (const u8*)&STRING_IPRODUCT;
  413. else if (setup.wValueL == IMANUFACTURER)
  414. desc_addr = (const u8*)&STRING_IMANUFACTURER;
  415. else
  416. return false;
  417. }
  418. if (desc_addr == 0)
  419. return false;
  420. if (desc_length == 0)
  421. desc_length = pgm_read_byte(desc_addr);
  422. USB_SendControl(TRANSFER_PGM,desc_addr,desc_length);
  423. return true;
  424. }
  425. // Endpoint 0 interrupt
  426. ISR(USB_COM_vect)
  427. {
  428. SetEP(0);
  429. if (!ReceivedSetupInt())
  430. return;
  431. Setup setup;
  432. Recv((u8*)&setup,8);
  433. ClearSetupInt();
  434. u8 requestType = setup.bmRequestType;
  435. if (requestType & REQUEST_DEVICETOHOST)
  436. WaitIN();
  437. else
  438. ClearIN();
  439. bool ok = true;
  440. if (REQUEST_STANDARD == (requestType & REQUEST_TYPE))
  441. {
  442. // Standard Requests
  443. u8 r = setup.bRequest;
  444. if (GET_STATUS == r)
  445. {
  446. Send8(0); // TODO
  447. Send8(0);
  448. }
  449. else if (CLEAR_FEATURE == r)
  450. {
  451. }
  452. else if (SET_FEATURE == r)
  453. {
  454. }
  455. else if (SET_ADDRESS == r)
  456. {
  457. WaitIN();
  458. UDADDR = setup.wValueL | (1<<ADDEN);
  459. }
  460. else if (GET_DESCRIPTOR == r)
  461. {
  462. ok = SendDescriptor(setup);
  463. }
  464. else if (SET_DESCRIPTOR == r)
  465. {
  466. ok = false;
  467. }
  468. else if (GET_CONFIGURATION == r)
  469. {
  470. Send8(1);
  471. }
  472. else if (SET_CONFIGURATION == r)
  473. {
  474. if (REQUEST_DEVICE == (requestType & REQUEST_RECIPIENT))
  475. {
  476. InitEndpoints();
  477. _usbConfiguration = setup.wValueL;
  478. } else
  479. ok = false;
  480. }
  481. else if (GET_INTERFACE == r)
  482. {
  483. }
  484. else if (SET_INTERFACE == r)
  485. {
  486. }
  487. }
  488. else
  489. {
  490. InitControl(setup.wLength); // Max length of transfer
  491. ok = ClassInterfaceRequest(setup);
  492. }
  493. if (ok)
  494. ClearIN();
  495. else
  496. {
  497. Stall();
  498. }
  499. }
  500. void USB_Flush(u8 ep)
  501. {
  502. SetEP(ep);
  503. if (FifoByteCount())
  504. ReleaseTX();
  505. }
  506. // General interrupt
  507. ISR(USB_GEN_vect)
  508. {
  509. u8 udint = UDINT;
  510. UDINT = 0;
  511. // End of Reset
  512. if (udint & (1<<EORSTI))
  513. {
  514. InitEP(0,EP_TYPE_CONTROL,EP_SINGLE_64); // init ep0
  515. _usbConfiguration = 0; // not configured yet
  516. UEIENX = 1 << RXSTPE; // Enable interrupts for ep0
  517. }
  518. // Start of Frame - happens every millisecond so we use it for TX and RX LED one-shot timing, too
  519. if (udint & (1<<SOFI))
  520. {
  521. #ifdef CDC_ENABLED
  522. USB_Flush(CDC_TX); // Send a tx frame if found
  523. while (USB_Available(CDC_RX)) // Handle received bytes (if any)
  524. Serial.accept();
  525. #endif
  526. // check whether the one-shot period has elapsed. if so, turn off the LED
  527. if (TxLEDPulse && !(--TxLEDPulse))
  528. TXLED0;
  529. if (RxLEDPulse && !(--RxLEDPulse))
  530. RXLED0;
  531. }
  532. }
  533. // VBUS or counting frames
  534. // Any frame counting?
  535. u8 USBConnected()
  536. {
  537. u8 f = UDFNUML;
  538. delay(3);
  539. return f != UDFNUML;
  540. }
  541. //=======================================================================
  542. //=======================================================================
  543. USBDevice_ USBDevice;
  544. USBDevice_::USBDevice_()
  545. {
  546. }
  547. void USBDevice_::attach()
  548. {
  549. _usbConfiguration = 0;
  550. UHWCON = 0x01; // power internal reg
  551. USBCON = (1<<USBE)|(1<<FRZCLK); // clock frozen, usb enabled
  552. PLLCSR = 0x12; // Need 16 MHz xtal
  553. while (!(PLLCSR & (1<<PLOCK))) // wait for lock pll
  554. ;
  555. // Some tests on specific versions of macosx (10.7.3), reported some
  556. // strange behaviuors when the board is reset using the serial
  557. // port touch at 1200 bps. This delay fixes this behaviour.
  558. delay(1);
  559. USBCON = ((1<<USBE)|(1<<OTGPADE)); // start USB clock
  560. UDIEN = (1<<EORSTE)|(1<<SOFE); // Enable interrupts for EOR (End of Reset) and SOF (start of frame)
  561. UDCON = 0; // enable attach resistor
  562. TX_RX_LED_INIT;
  563. }
  564. void USBDevice_::detach()
  565. {
  566. }
  567. // Check for interrupts
  568. // TODO: VBUS detection
  569. bool USBDevice_::configured()
  570. {
  571. return _usbConfiguration;
  572. }
  573. void USBDevice_::poll()
  574. {
  575. }
  576. #endif /* if defined(USBCON) */