pdiusb.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. /*
  2. * Philips PDIUSBD12 USB 2.0 device driver
  3. *
  4. * Copyright (C) 2007-2016 Michael Buesch <m@bues.ch>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * version 2 as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include "pdiusb.h"
  16. #include "util.h"
  17. #include "main.h"
  18. #include "usb.h"
  19. #include <avr/io.h>
  20. #include <avr/interrupt.h>
  21. #include <avr/wdt.h>
  22. #include <string.h>
  23. /*************************************************************************
  24. * Microcontroller dependent pin definitions *
  25. * Adjust this to your pin configuration *
  26. *************************************************************************/
  27. #define PDIUSB_CTL_PIN PIND
  28. #define PDIUSB_CTL_PORT PORTD
  29. #define PDIUSB_CTL_DDR DDRD
  30. #define PDIUSB_CTL_IRQ (1u << 3) /* INT_N pin. Mandatory */
  31. #define PDIUSB_CTL_A0 (1u << 6) /* A0 pin. Mandatory */
  32. #define PDIUSB_CTL_WR (1u << 4) /* WD_N pin. Mandatory */
  33. #define PDIUSB_CTL_RD (1u << 5) /* RD_N pin. Mandatory */
  34. /* Optional pins. Don't define these, if the pin is not connected. */
  35. //#define PDIUSB_CTL_RST (1u << 4) /* RESET_N pin. Optional */
  36. //#define PDIUSB_CTL_SUSP (1u << 3) /* SUSPEND pin. Optional */
  37. /* The interrupt vector */
  38. #define PDIUSB_IRQ_VECTOR INT1_vect
  39. /* Define to 1, if the MCU (Microcontroller) uses the CLKOUT
  40. * pin for its input clock. Define to 0, if it doesn't. */
  41. #define MCU_USES_CLKOUT 0
  42. /* Endpoint operation mode. (see datasheet)
  43. * PDIUSB_MODE_EPNONISO => Non-ISO mode
  44. * PDIUSB_MODE_EPISOOUT => ISO-OUT mode
  45. * PDIUSB_MODE_EPISOIN => ISO-IN mode
  46. * PDIUSB_MODE_EPISOBI => ISO-I/O mode
  47. */
  48. #define PDIUSB_OPMODE PDIUSB_MODE_EPNONISO
  49. /* Prepare for data-read */
  50. static inline void raw_data_in_prepare(void)
  51. {
  52. /* Disable pullups */
  53. PORTC = 0;
  54. /* Pins = input */
  55. DDRC = 0;
  56. }
  57. /* Read the pins */
  58. static inline uint8_t raw_data_in(void)
  59. {
  60. return PINC;
  61. }
  62. /* Prepare for data-write */
  63. static inline void raw_data_out_prepare(void)
  64. {
  65. /* Pins = output */
  66. DDRC = 0xFF;
  67. }
  68. /* Write the pins */
  69. static inline void raw_data_out(uint8_t data)
  70. {
  71. PORTC = data;
  72. }
  73. /* Delay for the data-in/out routine. */
  74. static inline void raw_data_delay(void)
  75. {
  76. nop();
  77. nop();
  78. }
  79. /* Enable the PDIUSB interrupt line */
  80. static inline void pdiusb_interrupt_enable(void)
  81. {
  82. GICR = (uint8_t)(GICR | (1u << INT1));
  83. }
  84. /* Disable the PDIUSB interrupt line */
  85. static inline void pdiusb_interrupt_disable(void)
  86. {
  87. GICR = (uint8_t)(GICR & ~(1u << INT1));
  88. }
  89. /* Clear the PDIUSB interrupt line flag */
  90. static inline void pdiusb_interrupt_flag_clear(void)
  91. {
  92. GIFR = (1u << INTF1);
  93. }
  94. /*************************************************************************
  95. * END: Microcontroller dependent pin definitions *
  96. *************************************************************************/
  97. typedef uint16_t trans_stat_t;
  98. #define TRANS_STAT(status, size) ((trans_stat_t)((uint16_t)(status) |\
  99. ((uint16_t)(size) << 8)))
  100. #define GET_TRANS_STAT(trans) ((uint8_t)((uint16_t)(trans) & 0xFF))
  101. #define GET_TRANS_SIZE(trans) ((uint8_t)(((uint16_t)(trans) >> 8) & 0xFF))
  102. /* Define the optional pins to zero, if they are undefined. */
  103. #ifndef PDIUSB_CTL_RST
  104. # define PDIUSB_CTL_RST 0
  105. #endif
  106. #ifndef PDIUSB_CTL_SUSP
  107. # define PDIUSB_CTL_SUSP 0
  108. #endif
  109. #define PDIUSB_EP0_MAXSIZE 16
  110. #define PDIUSB_EP1_MAXSIZE 16
  111. #if PDIUSB_OPMODE == PDIUSB_MODE_EPNONISO
  112. # define PDIUSB_EP2_MAXSIZE 64
  113. #elif PDIUSB_OPMODE == PDIUSB_MODE_EPISOOUT
  114. # define PDIUSB_EP2_MAXSIZE 128
  115. #elif PDIUSB_OPMODE == PDIUSB_MODE_EPISOIN
  116. # define PDIUSB_EP2_MAXSIZE 128
  117. #elif PDIUSB_OPMODE == PDIUSB_MODE_EPISOBI
  118. # define PDIUSB_EP2_MAXSIZE 64
  119. #else
  120. # error "Invalid PDIUSB_OPMODE"
  121. #endif
  122. #define PDIUSB_MAXSIZE (max(PDIUSB_EP0_MAXSIZE, \
  123. max(PDIUSB_EP1_MAXSIZE, \
  124. PDIUSB_EP2_MAXSIZE)))
  125. /* Buffer for holding received data. */
  126. static uint8_t pdiusb_buffer[PDIUSB_MAXSIZE];
  127. /* Suspend status */
  128. static uint8_t pdiusb_suspended;
  129. static inline void pdiusb_command_mode(void)
  130. {
  131. PDIUSB_CTL_PORT = (uint8_t)(PDIUSB_CTL_PORT | PDIUSB_CTL_A0);
  132. }
  133. static inline void pdiusb_data_mode(void)
  134. {
  135. PDIUSB_CTL_PORT = (uint8_t)(PDIUSB_CTL_PORT & ~PDIUSB_CTL_A0);
  136. }
  137. /* Write data to the controller. */
  138. static void pdiusb_write(uint8_t data)
  139. {
  140. raw_data_out_prepare();
  141. PDIUSB_CTL_PORT = (uint8_t)(PDIUSB_CTL_PORT & ~PDIUSB_CTL_WR);
  142. raw_data_out(data);
  143. PDIUSB_CTL_PORT = (uint8_t)(PDIUSB_CTL_PORT | PDIUSB_CTL_WR);
  144. raw_data_delay();
  145. }
  146. /* Read data from the controller. */
  147. static uint8_t pdiusb_read(void)
  148. {
  149. uint8_t data;
  150. raw_data_in_prepare();
  151. PDIUSB_CTL_PORT = (uint8_t)(PDIUSB_CTL_PORT & ~PDIUSB_CTL_RD);
  152. raw_data_delay();
  153. data = raw_data_in();
  154. PDIUSB_CTL_PORT = (uint8_t)(PDIUSB_CTL_PORT | PDIUSB_CTL_RD);
  155. return data;
  156. }
  157. /* Send a command to the controller. */
  158. static void pdiusb_command(uint8_t command)
  159. {
  160. pdiusb_command_mode();
  161. pdiusb_write(command);
  162. pdiusb_data_mode();
  163. }
  164. /* Send a command and write 8-bit of command data. */
  165. static void pdiusb_command_w8(uint8_t command, uint8_t data)
  166. {
  167. pdiusb_command(command);
  168. pdiusb_write(data);
  169. }
  170. /* Send a command and write 16-bit of command data. */
  171. static void pdiusb_command_w16(uint8_t command, uint16_t data)
  172. {
  173. pdiusb_command(command);
  174. pdiusb_write((uint8_t)data);
  175. pdiusb_write((uint8_t)(data >> 8));
  176. }
  177. /* Send a command and read 8-bit of command data. */
  178. static uint8_t pdiusb_command_r8(uint8_t command)
  179. {
  180. uint8_t data;
  181. pdiusb_command(command);
  182. data = pdiusb_read();
  183. return data;
  184. }
  185. /* Send a command and read 16-bit of command data. */
  186. static uint16_t pdiusb_command_r16(uint8_t command)
  187. {
  188. uint16_t a, b;
  189. pdiusb_command(command);
  190. a = pdiusb_read();
  191. b = pdiusb_read();
  192. return (a | (b << 8));
  193. }
  194. static uint8_t pdiusb_read_buffer(uint8_t *buf, uint8_t max_size)
  195. {
  196. uint8_t i, data_size;
  197. pdiusb_command(PDIUSB_CMD_RWBUF);
  198. pdiusb_read(); /* Read the reserved byte */
  199. data_size = pdiusb_read();
  200. if (data_size > max_size) {
  201. usb_print1num("PDIUSB: RX buffer overrun", data_size);
  202. return 0;
  203. }
  204. for (i = 0; i < data_size; i++)
  205. buf[i] = pdiusb_read();
  206. DBG(usb_print1num("PDIUSB: Received", data_size));
  207. DBG(usb_dumpmem(buf, data_size));
  208. return data_size;
  209. }
  210. static void pdiusb_write_buffer(const uint8_t *buf, uint8_t size)
  211. {
  212. uint8_t i;
  213. DBG(usb_print1num("PDIUSB: Sending", size));
  214. DBG(usb_dumpmem(buf, size));
  215. pdiusb_command(PDIUSB_CMD_RWBUF);
  216. pdiusb_write(0); /* Write the reserved byte */
  217. pdiusb_write(size);
  218. for (i = 0; i < size; i++)
  219. pdiusb_write(buf[i]);
  220. }
  221. static void stall_ep(uint8_t ep_index)
  222. {
  223. DBG(usb_print1num("PDIUSB: Stalling EP index", ep_index));
  224. pdiusb_command_w8(PDIUSB_CMD_SEPSTAT(ep_index),
  225. PDIUSB_SEPSTAT_STALL);
  226. }
  227. static void unstall_ep(uint8_t ep_index)
  228. {
  229. DBG(usb_print1num("PDIUSB: Unstalling EP index", ep_index));
  230. pdiusb_command_w8(PDIUSB_CMD_SEPSTAT(ep_index), 0);
  231. }
  232. static uint8_t ep_is_stalled(uint8_t ep_index)
  233. {
  234. return (pdiusb_command_r8(PDIUSB_CMD_GEPSTAT(ep_index))
  235. & PDIUSB_GEPSTAT_STALL);
  236. }
  237. static trans_stat_t handle_irq_ep_out(uint8_t ep_index)
  238. {
  239. uint8_t status, size;
  240. DBG(usb_print1num("PDIUSB: OUT irq on EP", ep_index));
  241. status = pdiusb_command_r8(PDIUSB_CMD_TRSTAT(ep_index));
  242. if (!(status & PDIUSB_TRSTAT_TRANSOK)) {
  243. if (status != PDIUSB_TRERR_NOERR) {
  244. usb_print2num("PDIUSB: OUT trans on EP", ep_index, "failed with",
  245. status & PDIUSB_TRSTAT_ERR);
  246. return TRANS_STAT(0, 0);
  247. }
  248. }
  249. pdiusb_command(PDIUSB_CMD_SELEP(ep_index));
  250. size = pdiusb_read_buffer(pdiusb_buffer, sizeof(pdiusb_buffer));
  251. if (status & PDIUSB_TRSTAT_SETUP) {
  252. pdiusb_command(PDIUSB_CMD_SELEP(PDIUSB_EPIDX_IN(ep_index)));
  253. pdiusb_command(PDIUSB_CMD_ACKSETUP);
  254. pdiusb_command(PDIUSB_CMD_SELEP(ep_index));
  255. pdiusb_command(PDIUSB_CMD_ACKSETUP);
  256. }
  257. pdiusb_command(PDIUSB_CMD_CLRBUF);
  258. return TRANS_STAT(status | PDIUSB_TRSTAT_TRANSOK, size);
  259. }
  260. static bool handle_irq_ep_in(uint8_t ep_index)
  261. {
  262. uint8_t status;
  263. // DBG(usb_print1num("PDIUSB: IN irq on EP", ep_index));
  264. status = pdiusb_command_r8(PDIUSB_CMD_TRSTAT(ep_index));
  265. if (!(status & PDIUSB_TRSTAT_TRANSOK)) {
  266. status = status & PDIUSB_TRSTAT_ERR;
  267. if (status != PDIUSB_TRERR_NOERR && status != PDIUSB_TRERR_NAK) {
  268. usb_print2num("PDIUSB: trans on EP", ep_index, "failed with",
  269. status);
  270. return 0;
  271. }
  272. }
  273. /* For non-doublebuffered EPs, check if the buffer is ready. */
  274. if (ep_index != PDIUSB_EP_EP2IN) {
  275. status = pdiusb_command_r8(PDIUSB_CMD_SELEP(ep_index));
  276. if (status & PDIUSB_SELEPR_FULL)
  277. return 0; /* Not yet */
  278. }
  279. return 1;
  280. }
  281. static void ep_queue_data(uint8_t ep_index, void *data, uint8_t size)
  282. {
  283. pdiusb_command(PDIUSB_CMD_SELEP(ep_index));
  284. pdiusb_write_buffer(data, size);
  285. pdiusb_command(PDIUSB_CMD_VALBUF);
  286. }
  287. static void handle_ctlout_data(uint8_t trans_status, uint8_t size)
  288. {
  289. uint8_t res;
  290. if (trans_status & PDIUSB_TRSTAT_SETUP) {
  291. if (size == sizeof(struct usb_ctrl)) {
  292. res = usb_control_setup_rx((struct usb_ctrl *)pdiusb_buffer);
  293. } else {
  294. usb_printstr("PDIUSB: CTLOUT received invalid SETUP");
  295. res = USB_RX_ERROR;
  296. }
  297. } else
  298. res = usb_control_rx(pdiusb_buffer, size);
  299. if (res == USB_RX_ERROR)
  300. stall_ep(PDIUSB_EP_CTLOUT);
  301. }
  302. #if USB_WITH_EP1
  303. static void handle_ep1out_data(uint8_t trans_status, uint8_t size)
  304. {
  305. uint8_t res;
  306. res = usb_ep1_rx(pdiusb_buffer, size);
  307. if (res == USB_RX_ERROR)
  308. stall_ep(PDIUSB_EP_EP1OUT);
  309. }
  310. #endif
  311. #if USB_WITH_EP2
  312. static void handle_ep2out_data(uint8_t trans_status, uint8_t size)
  313. {
  314. uint8_t res;
  315. res = usb_ep2_rx(pdiusb_buffer, size);
  316. if (res == USB_RX_ERROR)
  317. stall_ep(PDIUSB_EP_EP2OUT);
  318. }
  319. #endif
  320. static void handle_irq_busrst(void)
  321. {
  322. usb_printstr("PDIUSB: Bus reset detected");
  323. pdiusb_suspended = 0;
  324. usb_reset();
  325. }
  326. static void handle_irq_suspchg(void)
  327. {
  328. if (PDIUSB_CTL_PIN & PDIUSB_CTL_SUSP) {
  329. if (!pdiusb_suspended)
  330. usb_printstr("PDIUSB: Suspended");
  331. pdiusb_suspended = 1;
  332. } else {
  333. if (pdiusb_suspended)
  334. usb_printstr("PDIUSB: Resumed");
  335. pdiusb_suspended = 0;
  336. }
  337. }
  338. static void handle_irq_dmaeot(void)
  339. {
  340. }
  341. ISR(PDIUSB_IRQ_VECTOR)
  342. {
  343. uint16_t status;
  344. trans_stat_t trans;
  345. bool ok;
  346. void *buf;
  347. uint8_t size;
  348. status = pdiusb_command_r16(PDIUSB_CMD_IRQSTAT);
  349. if (status & PDIUSB_IST_BUSRST)
  350. handle_irq_busrst();
  351. if (status & PDIUSB_IST_SUSPCHG)
  352. handle_irq_suspchg();
  353. if (status & PDIUSB_IST_DMAEOT)
  354. handle_irq_dmaeot();
  355. if (status & PDIUSB_IST_EP(PDIUSB_EP_CTLOUT)) {
  356. trans = handle_irq_ep_out(PDIUSB_EP_CTLOUT);
  357. if (GET_TRANS_STAT(trans) & PDIUSB_TRSTAT_TRANSOK) {
  358. handle_ctlout_data(GET_TRANS_STAT(trans),
  359. GET_TRANS_SIZE(trans));
  360. }
  361. }
  362. if (status & PDIUSB_IST_EP(PDIUSB_EP_CTLIN)) {
  363. ok = handle_irq_ep_in(PDIUSB_EP_CTLIN);
  364. if (ok) {
  365. size = usb_control_tx_poll(&buf, PDIUSB_EP0_MAXSIZE);
  366. if (size != USB_TX_POLL_NONE)
  367. ep_queue_data(PDIUSB_EP_CTLIN, buf, size);
  368. }
  369. }
  370. if (status & PDIUSB_IST_EP(PDIUSB_EP_EP1OUT)) {
  371. trans = handle_irq_ep_out(PDIUSB_EP_EP1OUT);
  372. #if USB_WITH_EP1
  373. if (GET_TRANS_STAT(trans) & PDIUSB_TRSTAT_TRANSOK) {
  374. handle_ep1out_data(GET_TRANS_STAT(trans),
  375. GET_TRANS_SIZE(trans));
  376. }
  377. #endif
  378. }
  379. if (status & PDIUSB_IST_EP(PDIUSB_EP_EP1IN)) {
  380. ok = handle_irq_ep_in(PDIUSB_EP_EP1IN);
  381. #if USB_WITH_EP1
  382. if (ok) {
  383. size = usb_ep1_tx_poll(&buf, PDIUSB_EP1_MAXSIZE);
  384. if (size != USB_TX_POLL_NONE)
  385. ep_queue_data(PDIUSB_EP_EP1IN, buf, size);
  386. }
  387. #endif
  388. }
  389. if (status & PDIUSB_IST_EP(PDIUSB_EP_EP2OUT)) {
  390. trans = handle_irq_ep_out(PDIUSB_EP_EP2OUT);
  391. #if USB_WITH_EP2
  392. if (GET_TRANS_STAT(trans) & PDIUSB_TRSTAT_TRANSOK) {
  393. handle_ep2out_data(GET_TRANS_STAT(trans),
  394. GET_TRANS_SIZE(trans));
  395. }
  396. #endif
  397. }
  398. if (status & PDIUSB_IST_EP(PDIUSB_EP_EP2IN)) {
  399. ok = handle_irq_ep_in(PDIUSB_EP_EP2IN);
  400. #if USB_WITH_EP2
  401. if (ok) {
  402. size = usb_ep2_tx_poll(&buf, PDIUSB_EP2_MAXSIZE);
  403. if (size != USB_TX_POLL_NONE)
  404. ep_queue_data(PDIUSB_EP_EP2IN, buf, size);
  405. }
  406. #endif
  407. }
  408. }
  409. #if MCU_USES_CLKOUT
  410. #ifndef F_CPU
  411. # error "F_CPU not defined. Unknown CPU frequency"
  412. #endif
  413. #if F_CPU == 48000000UL
  414. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_48MHZ
  415. #elif F_CPU == 24000000UL
  416. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_24MHZ
  417. #elif F_CPU == 16000000UL
  418. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_16MHZ
  419. #elif F_CPU == 12000000UL
  420. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_12MHZ
  421. #elif F_CPU == 9600000UL
  422. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_9p6MHZ
  423. #elif F_CPU == 8000000UL
  424. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_8MHZ
  425. #elif F_CPU == 6857142UL
  426. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_6p9MHZ
  427. #elif F_CPU == 6000000UL
  428. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_6MHZ
  429. #elif F_CPU == 5333333UL
  430. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_5p3MHZ
  431. #elif F_CPU == 4800000UL
  432. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_4p8MHZ
  433. #elif F_CPU == 4363636UL
  434. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_4p4MHZ
  435. #elif F_CPU == 4000000UL
  436. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_4MHZ
  437. #elif F_CPU == 3692307UL
  438. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_3p7MHZ
  439. #elif F_CPU == 3428571UL
  440. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_3p4MHZ
  441. #elif F_CPU == 3200000UL
  442. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_3p2MHZ
  443. #elif F_CPU == 3000000UL
  444. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_3MHZ
  445. #else
  446. # error "Impossible CLKOUT frequency. Please adjust F_CPU"
  447. #endif
  448. #endif /* MCU_USES_CLKOUT */
  449. /* Default value, if CLKOUT is unused. */
  450. #ifndef PDIUSB_CLKOUT_DIVISOR
  451. # define PDIUSB_CLKOUT_DIVISOR PDIUSB_CLKOUT_3MHZ
  452. #endif
  453. static void pdiusb_set_mode(uint16_t mode)
  454. {
  455. mode |= PDIUSB_MODE_STO; /* Always set */
  456. mode |= PDIUSB_MODE_NOLAZYCLK; /* Always keep CLKOUT at full speed */
  457. mode |= (PDIUSB_CLKOUT_DIVISOR << PDIUSB_MODE_CLKDIV_SHIFT)
  458. & PDIUSB_MODE_CLKDIV; /* CLKOUT pin divisor */
  459. mode |= PDIUSB_MODE_CLKARUN; /* Clock is always running */
  460. mode |= PDIUSB_MODE_IRQM; /* Report errors */
  461. mode |= PDIUSB_OPMODE; /* Endpoint configuration */
  462. pdiusb_command_w16(PDIUSB_CMD_SETMODE, mode);
  463. }
  464. /* Basic port setup */
  465. static uint16_t pdiusb_configure_ports(void)
  466. {
  467. PDIUSB_CTL_PORT = (uint8_t)(PDIUSB_CTL_PORT | (PDIUSB_CTL_WR |
  468. PDIUSB_CTL_RD |
  469. PDIUSB_CTL_RST));
  470. PDIUSB_CTL_PORT = (uint8_t)(PDIUSB_CTL_PORT & ~(PDIUSB_CTL_IRQ |
  471. PDIUSB_CTL_SUSP));
  472. PDIUSB_CTL_DDR = (uint8_t)(PDIUSB_CTL_DDR | (PDIUSB_CTL_A0 |
  473. PDIUSB_CTL_WR |
  474. PDIUSB_CTL_RD |
  475. PDIUSB_CTL_RST));
  476. PDIUSB_CTL_DDR = (uint8_t)(PDIUSB_CTL_DDR & ~(PDIUSB_CTL_IRQ |
  477. PDIUSB_CTL_SUSP));
  478. pdiusb_data_mode();
  479. /* Return the chipID to verify the device is working. */
  480. return pdiusb_command_r16(PDIUSB_CMD_GETCHIPID);
  481. }
  482. uint8_t pdiusb_configure_clkout(void)
  483. {
  484. uint16_t chipid;
  485. if (!MCU_USES_CLKOUT)
  486. return 0;
  487. chipid = pdiusb_configure_ports();
  488. if (chipid != PDIUSB_CHIPID)
  489. return 1;
  490. pdiusb_set_mode(0);
  491. _delay_ms(10);
  492. return 0;
  493. }
  494. uint8_t pdiusb_init(void)
  495. {
  496. uint16_t chipid;
  497. usb_reset();
  498. chipid = pdiusb_configure_ports();
  499. if (chipid != PDIUSB_CHIPID) {
  500. usb_print1num("PDIUSB unknown chip ID:", chipid);
  501. return 1;
  502. }
  503. pdiusb_set_mode(0);
  504. pdiusb_command_w8(PDIUSB_CMD_DMA, 0);
  505. _delay_ms(50);
  506. /* Enable software USB pullup */
  507. pdiusb_set_mode(PDIUSB_MODE_SOFTCONN);
  508. unstall_ep(PDIUSB_EP_CTLOUT);
  509. unstall_ep(PDIUSB_EP_CTLIN);
  510. pdiusb_interrupt_flag_clear();
  511. pdiusb_interrupt_enable();
  512. return 0;
  513. }
  514. void pdiusb_exit(void)
  515. {
  516. uint8_t ep_index;
  517. pdiusb_interrupt_disable();
  518. for (ep_index = 0; ep_index < PDIUSB_EP_COUNT; ep_index++)
  519. stall_ep(ep_index);
  520. usb_set_address(0);
  521. pdiusb_set_mode(0); /* Disconnect SOFTCONN */
  522. long_delay_ms(500); /* Wait for host to handle disconnect */
  523. }
  524. /*************************************************************************
  525. * Callbacks from the USB stack *
  526. *************************************************************************/
  527. void usb_set_address(uint8_t address)
  528. {
  529. address &= PDIUSB_ADDR;
  530. if (address)
  531. address |= PDIUSB_AEN;
  532. pdiusb_command_w8(PDIUSB_CMD_ADDREN, address);
  533. }
  534. void usb_enable_endpoints(uint8_t enable)
  535. {
  536. pdiusb_command_w8(PDIUSB_CMD_ENDPEN, 0);
  537. if (enable)
  538. pdiusb_command_w8(PDIUSB_CMD_ENDPEN, PDIUSB_GENISOEN);
  539. }
  540. static uint8_t pdiusb_ep_addr_to_ep_index(uint8_t ep)
  541. {
  542. uint8_t ep_index;
  543. switch (ep & ~0x80) {
  544. case 0:
  545. ep_index = PDIUSB_EP_CTLOUT;
  546. break;
  547. #if USB_WITH_EP1
  548. case 1:
  549. ep_index = PDIUSB_EP_EP1OUT;
  550. break;
  551. #endif
  552. #if USB_WITH_EP2
  553. case 2:
  554. ep_index = PDIUSB_EP_EP2OUT;
  555. break;
  556. #endif
  557. default:
  558. return 0xFF;
  559. }
  560. if (usb_ep_is_in(ep))
  561. ep_index = PDIUSB_EPIDX_IN(ep_index);
  562. return ep_index;
  563. }
  564. void usb_stall_endpoint(uint8_t ep)
  565. {
  566. uint8_t ep_index;
  567. DBG(usb_print1num("PDIUSB: Stalling EP", ep));
  568. ep_index = pdiusb_ep_addr_to_ep_index(ep);
  569. if (ep_index == 0xFF) {
  570. usb_print1num("PDIUSB: stall-EP unknown EP", ep);
  571. return;
  572. }
  573. stall_ep(ep_index);
  574. }
  575. void usb_unstall_endpoint(uint8_t ep)
  576. {
  577. uint8_t ep_index;
  578. DBG(usb_print1num("PDIUSB: Unstalling EP", ep));
  579. ep_index = pdiusb_ep_addr_to_ep_index(ep);
  580. if (ep_index == 0xFF) {
  581. usb_print1num("PDIUSB: unstall-EP unknown EP", ep);
  582. return;
  583. }
  584. unstall_ep(ep_index);
  585. }
  586. uint8_t usb_endpoint_is_stalled(uint8_t ep)
  587. {
  588. uint8_t ep_index;
  589. ep_index = pdiusb_ep_addr_to_ep_index(ep);
  590. if (ep_index == 0xFF) {
  591. usb_print1num("PDIUSB: EP-is-stalled unknown EP", ep);
  592. return 1;
  593. }
  594. return ep_is_stalled(ep_index);
  595. }