USBCore.cpp 13 KB

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