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.

607 line
22KB

  1. /* USB Serial Example for Teensy USB Development Board
  2. * http://www.pjrc.com/teensy/usb_serial.html
  3. * Copyright (c) 2008 PJRC.COM, LLC
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. * THE SOFTWARE.
  22. */
  23. #include "usb_common.h"
  24. #include "usb_private.h"
  25. /**************************************************************************
  26. *
  27. * Endpoint Buffer Configuration
  28. *
  29. **************************************************************************/
  30. static const uint8_t PROGMEM endpoint_config_table[] = {
  31. 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER,
  32. 1, EP_TYPE_INTERRUPT_OUT, EP_SIZE(DEBUG_RX_SIZE) | DEBUG_RX_BUFFER,
  33. 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(FLIGHTSIM_TX_SIZE) | FLIGHTSIM_TX_BUFFER,
  34. 1, EP_TYPE_INTERRUPT_OUT, EP_SIZE(FLIGHTSIM_RX_SIZE) | FLIGHTSIM_RX_BUFFER,
  35. 0
  36. };
  37. /**************************************************************************
  38. *
  39. * Descriptor Data
  40. *
  41. **************************************************************************/
  42. // Descriptors are the data that your computer reads when it auto-detects
  43. // this USB device (called "enumeration" in USB lingo). The most commonly
  44. // changed items are editable at the top of this file. Changing things
  45. // in here should only be done by those who've read chapter 9 of the USB
  46. // spec and relevant portions of any USB class specifications!
  47. static const uint8_t PROGMEM device_descriptor[] = {
  48. 18, // bLength
  49. 1, // bDescriptorType
  50. 0x00, 0x02, // bcdUSB
  51. 0, // bDeviceClass
  52. 0, // bDeviceSubClass
  53. 0, // bDeviceProtocol
  54. ENDPOINT0_SIZE, // bMaxPacketSize0
  55. LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
  56. LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
  57. 0x02, 0x01, // bcdDevice
  58. 0, // iManufacturer
  59. 1, // iProduct
  60. 0, // iSerialNumber
  61. 1 // bNumConfigurations
  62. };
  63. static uint8_t PROGMEM rawhid_hid_report_desc[] = {
  64. 0x06, 0x1C, 0xFF, // Usage page = 0xFF1C
  65. 0x0A, 0x39, 0xA7, // Usage = 0xA739
  66. 0xA1, 0x01, // Collection 0x01
  67. 0x75, 0x08, // report size = 8 bits
  68. 0x15, 0x00, // logical minimum = 0
  69. 0x26, 0xFF, 0x00, // logical maximum = 255
  70. 0x95, FLIGHTSIM_TX_SIZE, // report count
  71. 0x09, 0x01, // usage
  72. 0x81, 0x02, // Input (array)
  73. 0x95, FLIGHTSIM_RX_SIZE, // report count
  74. 0x09, 0x02, // usage
  75. 0x91, 0x02, // Output (array)
  76. 0xC0 // end collection
  77. };
  78. static const uint8_t PROGMEM debug_hid_report_desc[] = {
  79. 0x06, 0xC9, 0xFF, // Usage Page 0xFFC9 (vendor defined)
  80. 0x09, 0x04, // Usage 0x04
  81. 0xA1, 0x5C, // Collection 0x5C
  82. 0x75, 0x08, // report size = 8 bits (global)
  83. 0x15, 0x00, // logical minimum = 0 (global)
  84. 0x26, 0xFF, 0x00, // logical maximum = 255 (global)
  85. 0x95, DEBUG_TX_SIZE, // report count (global)
  86. 0x09, 0x75, // usage (local)
  87. 0x81, 0x02, // Input
  88. 0x95, DEBUG_RX_SIZE, // report count (global)
  89. 0x09, 0x76, // usage (local)
  90. 0x91, 0x02, // Output
  91. 0x95, 0x04, // report count (global)
  92. 0x09, 0x76, // usage (local)
  93. 0xB1, 0x02, // Feature
  94. 0xC0 // end collection
  95. };
  96. #define FLIGHTSIM_HID_DESC_OFFSET ( 9 + 9 )
  97. #define DEBUG_HID_DESC_OFFSET ( 9 + 9+9+7+7 + 9 )
  98. #define CONFIG1_DESC_SIZE ( 9 + 9+9+7+7 + 9+9+7+7 )
  99. static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
  100. // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
  101. 9, // bLength;
  102. 2, // bDescriptorType;
  103. LSB(CONFIG1_DESC_SIZE), // wTotalLength
  104. MSB(CONFIG1_DESC_SIZE),
  105. NUM_INTERFACE, // bNumInterfaces
  106. 1, // bConfigurationValue
  107. 0, // iConfiguration
  108. 0xC0, // bmAttributes
  109. 50, // bMaxPower
  110. // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
  111. 9, // bLength
  112. 4, // bDescriptorType
  113. FLIGHTSIM_INTERFACE, // bInterfaceNumber
  114. 0, // bAlternateSetting
  115. 2, // bNumEndpoints
  116. 0x03, // bInterfaceClass (0x03 = HID)
  117. 0x00, // bInterfaceSubClass (0x01 = Boot)
  118. 0x00, // bInterfaceProtocol (0x01 = Keyboard)
  119. 2, // iInterface
  120. // HID interface descriptor, HID 1.11 spec, section 6.2.1
  121. 9, // bLength
  122. 0x21, // bDescriptorType
  123. 0x11, 0x01, // bcdHID
  124. 0, // bCountryCode
  125. 1, // bNumDescriptors
  126. 0x22, // bDescriptorType
  127. sizeof(rawhid_hid_report_desc), // wDescriptorLength
  128. 0,
  129. // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
  130. 7, // bLength
  131. 5, // bDescriptorType
  132. FLIGHTSIM_TX_ENDPOINT | 0x80, // bEndpointAddress
  133. 0x03, // bmAttributes (0x03=intr)
  134. FLIGHTSIM_TX_SIZE, 0, // wMaxPacketSize
  135. FLIGHTSIM_TX_INTERVAL, // bInterval
  136. // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
  137. 7, // bLength
  138. 5, // bDescriptorType
  139. FLIGHTSIM_RX_ENDPOINT, // bEndpointAddress
  140. 0x03, // bmAttributes (0x03=intr)
  141. FLIGHTSIM_RX_SIZE, 0, // wMaxPacketSize
  142. FLIGHTSIM_RX_INTERVAL, // bInterval
  143. // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
  144. 9, // bLength
  145. 4, // bDescriptorType
  146. DEBUG_INTERFACE, // bInterfaceNumber
  147. 0, // bAlternateSetting
  148. 2, // bNumEndpoints
  149. 0x03, // bInterfaceClass (0x03 = HID)
  150. 0x00, // bInterfaceSubClass
  151. 0x00, // bInterfaceProtocol
  152. 3, // iInterface
  153. // HID interface descriptor, HID 1.11 spec, section 6.2.1
  154. 9, // bLength
  155. 0x21, // bDescriptorType
  156. 0x11, 0x01, // bcdHID
  157. 0, // bCountryCode
  158. 1, // bNumDescriptors
  159. 0x22, // bDescriptorType
  160. sizeof(debug_hid_report_desc), // wDescriptorLength
  161. 0,
  162. // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
  163. 7, // bLength
  164. 5, // bDescriptorType
  165. DEBUG_TX_ENDPOINT | 0x80, // bEndpointAddress
  166. 0x03, // bmAttributes (0x03=intr)
  167. DEBUG_TX_SIZE, 0, // wMaxPacketSize
  168. DEBUG_TX_INTERVAL, // bInterval
  169. // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
  170. 7, // bLength
  171. 5, // bDescriptorType
  172. DEBUG_RX_ENDPOINT, // bEndpointAddress
  173. 0x03, // bmAttributes (0x03=intr)
  174. DEBUG_RX_SIZE, 0, // wMaxPacketSize
  175. DEBUG_RX_INTERVAL // bInterval
  176. };
  177. // If you're desperate for a little extra code memory, these strings
  178. // can be completely removed if iManufacturer, iProduct, iSerialNumber
  179. // in the device desciptor are changed to zeros.
  180. struct usb_string_descriptor_struct {
  181. uint8_t bLength;
  182. uint8_t bDescriptorType;
  183. int16_t wString[];
  184. };
  185. static const struct usb_string_descriptor_struct PROGMEM string0 = {
  186. 4,
  187. 3,
  188. {0x0409}
  189. };
  190. static const struct usb_string_descriptor_struct PROGMEM string1 = {
  191. sizeof(STR_PRODUCT),
  192. 3,
  193. STR_PRODUCT
  194. };
  195. // This table defines which descriptor data is sent for each specific
  196. // request from the host (in wValue and wIndex).
  197. static const struct descriptor_list_struct {
  198. uint16_t wValue;
  199. uint16_t wIndex;
  200. const uint8_t *addr;
  201. uint8_t length;
  202. } PROGMEM descriptor_list[] = {
  203. {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
  204. {0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
  205. {0x2200, FLIGHTSIM_INTERFACE, rawhid_hid_report_desc, sizeof(rawhid_hid_report_desc)},
  206. {0x2100, FLIGHTSIM_INTERFACE, config1_descriptor+FLIGHTSIM_HID_DESC_OFFSET, 9},
  207. {0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)},
  208. {0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9},
  209. {0x0300, 0x0000, (const uint8_t *)&string0, 4},
  210. {0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_PRODUCT)},
  211. };
  212. #define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))
  213. /**************************************************************************
  214. *
  215. * Variables - these are the only non-stack RAM usage
  216. *
  217. **************************************************************************/
  218. // zero when we are not configured, non-zero when enumerated
  219. volatile uint8_t usb_configuration USBSTATE;
  220. volatile uint8_t usb_suspended USBSTATE;
  221. // the time remaining before we transmit any partially full
  222. // packet, or send a zero length packet.
  223. volatile uint8_t debug_flush_timer USBSTATE;
  224. // these are a more reliable timeout than polling the
  225. // frame counter (UDFNUML)
  226. volatile uint16_t rawhid_rx_timeout_count USBSTATE;
  227. volatile uint16_t rawhid_tx_timeout_count USBSTATE;
  228. /**************************************************************************
  229. *
  230. * Public Functions - these are the API intended for the user
  231. *
  232. **************************************************************************/
  233. // initialize USB serial
  234. void usb_init(void)
  235. {
  236. uint8_t u;
  237. u = USBCON;
  238. if ((u & (1<<USBE)) && !(u & (1<<FRZCLK))) return;
  239. HW_CONFIG();
  240. USB_FREEZE(); // enable USB
  241. PLL_CONFIG(); // config PLL
  242. while (!(PLLCSR & (1<<PLOCK))) ; // wait for PLL lock
  243. USB_CONFIG(); // start USB clock
  244. UDCON = 0; // enable attach resistor
  245. usb_configuration = 0;
  246. usb_suspended = 0;
  247. debug_flush_timer = 0;
  248. rawhid_rx_timeout_count = 0;
  249. rawhid_tx_timeout_count = 0;
  250. UDINT = 0;
  251. UDIEN = (1<<EORSTE)|(1<<SOFE);
  252. //sei(); // init() in wiring.c does this
  253. }
  254. void usb_shutdown(void)
  255. {
  256. UDIEN = 0; // disable interrupts
  257. UDCON = 1; // disconnect attach resistor
  258. USBCON = 0; // shut off USB periperal
  259. PLLCSR = 0; // shut off PLL
  260. usb_configuration = 0;
  261. usb_suspended = 1;
  262. }
  263. // Public API functions moved to usb_api.cpp
  264. /**************************************************************************
  265. *
  266. * Private Functions - not intended for general user consumption....
  267. *
  268. **************************************************************************/
  269. // USB Device Interrupt - handle all device-level events
  270. // the transmit buffer flushing is triggered by the start of frame
  271. //
  272. ISR(USB_GEN_vect)
  273. {
  274. uint8_t intbits, t, ep;
  275. intbits = UDINT;
  276. UDINT = 0;
  277. ep = UENUM;
  278. if (intbits & (1<<EORSTI)) {
  279. UENUM = 0;
  280. UECONX = 1;
  281. UECFG0X = EP_TYPE_CONTROL;
  282. UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER;
  283. UEIENX = (1<<RXSTPE);
  284. usb_configuration = 0;
  285. }
  286. if ((intbits & (1<<SOFI)) && usb_configuration) {
  287. UENUM = FLIGHTSIM_TX_ENDPOINT;
  288. t = UEBCLX;
  289. if (t > 0) {
  290. for (; t < FLIGHTSIM_TX_SIZE; t++) {
  291. UEDATX = 0;
  292. }
  293. UEINTX = 0x3A;
  294. }
  295. t = debug_flush_timer;
  296. if (t) {
  297. debug_flush_timer = -- t;
  298. if (!t) {
  299. UENUM = DEBUG_TX_ENDPOINT;
  300. while ((UEINTX & (1<<RWAL))) {
  301. UEDATX = 0;
  302. }
  303. UEINTX = 0x3A;
  304. }
  305. }
  306. }
  307. if (intbits & (1<<SUSPI)) {
  308. // USB Suspend (inactivity for 3ms)
  309. UDIEN = (1<<WAKEUPE);
  310. usb_configuration = 0;
  311. usb_suspended = 1;
  312. #if (F_CPU >= 8000000L)
  313. // WAKEUPI does not work with USB clock freeze
  314. // when CPU is running less than 8 MHz.
  315. // Is this a hardware bug?
  316. USB_FREEZE(); // shut off USB
  317. PLLCSR = 0; // shut off PLL
  318. #endif
  319. // to properly meet the USB spec, current must
  320. // reduce to less than 2.5 mA, which means using
  321. // powerdown mode, but that breaks the Arduino
  322. // user's paradigm....
  323. }
  324. if (usb_suspended && (intbits & (1<<WAKEUPI))) {
  325. // USB Resume (pretty much any activity)
  326. #if (F_CPU >= 8000000L)
  327. PLL_CONFIG();
  328. while (!(PLLCSR & (1<<PLOCK))) ;
  329. USB_CONFIG();
  330. #endif
  331. UDIEN = (1<<EORSTE)|(1<<SOFE)|(1<<SUSPE);
  332. usb_suspended = 0;
  333. return;
  334. }
  335. UENUM = ep;
  336. }
  337. // Misc functions to wait for ready and send/receive packets
  338. static inline void usb_wait_in_ready(void)
  339. {
  340. while (!(UEINTX & (1<<TXINI))) ;
  341. }
  342. static inline void usb_send_in(void)
  343. {
  344. UEINTX = ~(1<<TXINI);
  345. }
  346. static inline void usb_wait_receive_out(void)
  347. {
  348. while (!(UEINTX & (1<<RXOUTI))) ;
  349. }
  350. static inline void usb_ack_out(void)
  351. {
  352. UEINTX = ~(1<<RXOUTI);
  353. }
  354. // USB Endpoint Interrupt - endpoint 0 is handled here. The
  355. // other endpoints are manipulated by the user-callable
  356. // functions, and the start-of-frame interrupt.
  357. //
  358. ISR(USB_COM_vect)
  359. {
  360. uint8_t intbits;
  361. const uint8_t *list;
  362. const uint8_t *cfg;
  363. uint8_t i, n, len, en;
  364. uint8_t bmRequestType;
  365. uint8_t bRequest;
  366. uint16_t wValue;
  367. uint16_t wIndex;
  368. uint16_t wLength;
  369. uint16_t desc_val;
  370. const uint8_t *desc_addr;
  371. uint8_t desc_length;
  372. UENUM = 0;
  373. intbits = UEINTX;
  374. if (intbits & (1<<RXSTPI)) {
  375. bmRequestType = UEDATX;
  376. bRequest = UEDATX;
  377. read_word_lsbfirst(wValue, UEDATX);
  378. read_word_lsbfirst(wIndex, UEDATX);
  379. read_word_lsbfirst(wLength, UEDATX);
  380. UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI));
  381. if (bRequest == GET_DESCRIPTOR) {
  382. list = (const uint8_t *)descriptor_list;
  383. for (i=0; ; i++) {
  384. if (i >= NUM_DESC_LIST) {
  385. UECONX = (1<<STALLRQ)|(1<<EPEN); //stall
  386. return;
  387. }
  388. pgm_read_word_postinc(desc_val, list);
  389. if (desc_val != wValue) {
  390. list += sizeof(struct descriptor_list_struct)-2;
  391. continue;
  392. }
  393. pgm_read_word_postinc(desc_val, list);
  394. if (desc_val != wIndex) {
  395. list += sizeof(struct descriptor_list_struct)-4;
  396. continue;
  397. }
  398. pgm_read_word_postinc(desc_addr, list);
  399. desc_length = pgm_read_byte(list);
  400. break;
  401. }
  402. len = (wLength < 256) ? wLength : 255;
  403. if (len > desc_length) len = desc_length;
  404. list = desc_addr;
  405. do {
  406. // wait for host ready for IN packet
  407. do {
  408. i = UEINTX;
  409. } while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
  410. if (i & (1<<RXOUTI)) return; // abort
  411. // send IN packet
  412. n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
  413. for (i = n; i; i--) {
  414. pgm_read_byte_postinc(UEDATX, list);
  415. }
  416. len -= n;
  417. usb_send_in();
  418. } while (len || n == ENDPOINT0_SIZE);
  419. return;
  420. }
  421. if (bRequest == SET_ADDRESS) {
  422. usb_send_in();
  423. usb_wait_in_ready();
  424. UDADDR = wValue | (1<<ADDEN);
  425. return;
  426. }
  427. if (bRequest == SET_CONFIGURATION && bmRequestType == 0) {
  428. usb_configuration = wValue;
  429. debug_flush_timer = 0;
  430. usb_send_in();
  431. cfg = endpoint_config_table;
  432. for (i=1; i<NUM_ENDPOINTS; i++) {
  433. UENUM = i;
  434. pgm_read_byte_postinc(en, cfg);
  435. UECONX = en;
  436. if (en) {
  437. pgm_read_byte_postinc(UECFG0X, cfg);
  438. pgm_read_byte_postinc(UECFG1X, cfg);
  439. }
  440. }
  441. UERST = 0x1E;
  442. UERST = 0;
  443. return;
  444. }
  445. if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) {
  446. usb_wait_in_ready();
  447. UEDATX = usb_configuration;
  448. usb_send_in();
  449. return;
  450. }
  451. if (bRequest == GET_STATUS) {
  452. usb_wait_in_ready();
  453. i = 0;
  454. if (bmRequestType == 0x82) {
  455. UENUM = wIndex;
  456. if (UECONX & (1<<STALLRQ)) i = 1;
  457. UENUM = 0;
  458. }
  459. UEDATX = i;
  460. UEDATX = 0;
  461. usb_send_in();
  462. return;
  463. }
  464. if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE)
  465. && bmRequestType == 0x02 && wValue == 0) {
  466. i = wIndex & 0x7F;
  467. if (i >= 1 && i <= NUM_ENDPOINTS) {
  468. usb_send_in();
  469. UENUM = i;
  470. if (bRequest == SET_FEATURE) {
  471. UECONX = (1<<STALLRQ)|(1<<EPEN);
  472. } else {
  473. UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN);
  474. UERST = (1 << i);
  475. UERST = 0;
  476. }
  477. return;
  478. }
  479. }
  480. if (wIndex == FLIGHTSIM_INTERFACE) {
  481. if (bmRequestType == 0xA1 && bRequest == HID_GET_REPORT) {
  482. len = FLIGHTSIM_TX_SIZE;
  483. do {
  484. // wait for host ready for IN packet
  485. do {
  486. i = UEINTX;
  487. } while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
  488. if (i & (1<<RXOUTI)) return; // abort
  489. // send IN packet
  490. n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
  491. for (i = n; i; i--) {
  492. // just send zeros
  493. UEDATX = 0;
  494. }
  495. len -= n;
  496. usb_send_in();
  497. } while (len || n == ENDPOINT0_SIZE);
  498. return;
  499. }
  500. if (bmRequestType == 0x21 && bRequest == HID_SET_REPORT) {
  501. len = FLIGHTSIM_RX_SIZE;
  502. do {
  503. n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
  504. usb_wait_receive_out();
  505. // ignore incoming bytes
  506. usb_ack_out();
  507. len -= n;
  508. } while (len);
  509. usb_wait_in_ready();
  510. usb_send_in();
  511. return;
  512. }
  513. }
  514. if (wIndex == DEBUG_INTERFACE) {
  515. if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) {
  516. len = wLength;
  517. do {
  518. // wait for host ready for IN packet
  519. do {
  520. i = UEINTX;
  521. } while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
  522. if (i & (1<<RXOUTI)) return; // abort
  523. // send IN packet
  524. n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
  525. for (i = n; i; i--) {
  526. UEDATX = 0;
  527. }
  528. len -= n;
  529. usb_send_in();
  530. } while (len || n == ENDPOINT0_SIZE);
  531. return;
  532. }
  533. if (bRequest == HID_SET_REPORT && bmRequestType == 0x21) {
  534. if (wValue == 0x0300 && wLength == 0x0004) {
  535. uint8_t b1, b2, b3, b4;
  536. usb_wait_receive_out();
  537. b1 = UEDATX;
  538. b2 = UEDATX;
  539. b3 = UEDATX;
  540. b4 = UEDATX;
  541. usb_ack_out();
  542. usb_send_in();
  543. if (b1 == 0xA9 && b2 == 0x45 && b3 == 0xC2 && b4 == 0x6B)
  544. _reboot_Teensyduino_();
  545. if (b1 == 0x8B && b2 == 0xC5 && b3 == 0x1D && b4 == 0x70)
  546. _restart_Teensyduino_();
  547. }
  548. }
  549. }
  550. if (bRequest == 0xC9 && bmRequestType == 0x40) {
  551. usb_send_in();
  552. usb_wait_in_ready();
  553. _restart_Teensyduino_();
  554. }
  555. }
  556. UECONX = (1<<STALLRQ) | (1<<EPEN); // stall
  557. }