ark_dwc2.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. #include "usb_os_adapter.h"
  2. #include "trace.h"
  3. #include <asm/dma-mapping.h>
  4. #include <linux/usb/ch9.h>
  5. #include <linux/usb/gadget.h>
  6. #include "core.h"
  7. #include "hcd.h"
  8. #include "ark_dwc2.h"
  9. #include "usbroothubdes.h"
  10. #include "sysctl.h"
  11. struct dwc2_host_data {
  12. struct dwc2_hsotg *host;
  13. struct usb_hcd hcd;
  14. enum usb_device_speed host_speed;
  15. int root_hub_devnum;
  16. //struct usb_host_endpoint hep;
  17. struct urb urb_in[16];
  18. struct urb urb_out[16];
  19. struct usb_host_endpoint hep_in[16];
  20. struct usb_host_endpoint hep_out[16];
  21. struct hc_driver *dw2_hc_driver;
  22. List_t free_urb_list;
  23. spinlock_t lock;
  24. };
  25. int dwc2_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
  26. int dwc2_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
  27. extern int dwc2_driver_init(struct dwc2_hsotg **dev, struct usb_hcd *hcd);
  28. extern int dwc2_driver_uninit(struct dwc2_hsotg *hsotg);
  29. extern struct hc_driver* dwc2_get_driver();
  30. static int dwc_otg_submit_rh_msg(struct usb_device *dev,
  31. unsigned long pipe, void *buffer, int txlen,
  32. struct devrequest *cmd);
  33. struct dwc2_host_data dwc2_host;
  34. static void dwc2_host_complete_urb(struct urb *urb)
  35. {
  36. urb->dev->status &= ~USB_ST_NOT_PROC;
  37. urb->dev->act_len = urb->actual_length;
  38. //printf("actual_length:%d\r\n", urb->actual_length);
  39. urb->urb_complete = 1;
  40. }
  41. static void usb_urb_release(struct urb *urb)
  42. {
  43. if (NULL == urb)
  44. return;
  45. spin_lock(&dwc2_host.lock);
  46. list_add_tail(&urb->urb_list, &dwc2_host.free_urb_list);
  47. spin_unlock(&dwc2_host.lock);
  48. }
  49. static struct urb *usb_urb_alloc(struct dwc2_host_data *ctx,
  50. int iso_desc_count,
  51. gfp_t mem_flags)
  52. {
  53. struct urb *urb = NULL;
  54. u32 size = sizeof(*urb);
  55. ListItem_t *pxListItem = NULL;
  56. int found = 0, flags;
  57. spin_lock_irqsave(&ctx->lock, flags);
  58. list_for_each_entry(pxListItem, urb, &ctx->free_urb_list) {
  59. if (urb->number_of_packets == iso_desc_count) {
  60. found = 1;
  61. break;
  62. }
  63. }
  64. if (found) {
  65. list_del_init(&urb->urb_list);
  66. spin_unlock_irqrestore(&ctx->lock, flags);
  67. memset(urb, 0, sizeof(struct urb));
  68. INIT_LIST_ITEM(&urb->urb_list);
  69. listSET_LIST_ITEM_OWNER(&urb->urb_list, urb);
  70. urb->urb_complete = 0;
  71. return urb;
  72. }
  73. spin_unlock_irqrestore(&ctx->lock, flags);
  74. urb = (struct urb *)kzalloc(size, mem_flags);
  75. if (urb) {
  76. urb->number_of_packets = iso_desc_count;
  77. INIT_LIST_ITEM(&urb->urb_list);
  78. listSET_LIST_ITEM_OWNER(&urb->urb_list, urb);
  79. urb->urb_complete = 0;
  80. }
  81. return urb;
  82. }
  83. static void construct_urb(struct urb *urb, struct usb_host_endpoint *hep,
  84. struct usb_device *dev, int endpoint_type,
  85. unsigned long pipe, void *buffer, int len,
  86. struct devrequest *setup, int interval)
  87. {
  88. int epnum = usb_pipeendpoint(pipe);
  89. int is_in = usb_pipein(pipe);
  90. INIT_LIST_HEAD(&hep->urb_list);
  91. INIT_LIST_ITEM(&urb->urb_list);
  92. urb->urb_list.pvOwner = (void *)urb;
  93. urb->ep = hep;
  94. urb->complete = dwc2_host_complete_urb;
  95. urb->status = -EINPROGRESS;
  96. urb->dev = dev;
  97. urb->pipe = pipe;
  98. urb->transfer_buffer = buffer;
  99. urb->transfer_dma = (dma_addr_t)buffer;
  100. urb->transfer_buffer_length = len;
  101. urb->setup_packet = (unsigned char *)setup;
  102. urb->setup_dma = (dma_addr_t)setup;
  103. urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
  104. URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
  105. URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
  106. URB_DMA_SG_COMBINED);
  107. urb->transfer_flags |= (is_in ? URB_DIR_IN : URB_DIR_OUT);
  108. urb->ep->desc.wMaxPacketSize =
  109. __cpu_to_le16(is_in ? dev->epmaxpacketin[epnum] :
  110. dev->epmaxpacketout[epnum]);
  111. urb->ep->desc.bmAttributes = endpoint_type;
  112. urb->ep->desc.bEndpointAddress =
  113. (is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum;
  114. urb->ep->desc.bInterval = interval;
  115. }
  116. static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
  117. {
  118. int ret;
  119. ret = dwc2_urb_enqueue(hcd, urb, 0);
  120. if (ret < 0) {
  121. PrintVariableValueHex("Failed to enqueue URB to controller ret", ret);
  122. return ret;
  123. }
  124. return ret;
  125. }
  126. static int _dwc2_submit_control_msg(struct dwc2_host_data *host,
  127. struct usb_device *dev, unsigned long pipe,
  128. void *buffer, int len, struct devrequest *setup, int timeout)
  129. {
  130. struct urb *urb = NULL;
  131. struct usb_host_endpoint *hep = NULL;
  132. int epnum = usb_pipeendpoint(pipe);
  133. int is_in = usb_pipein(pipe);
  134. int ret = 0;
  135. unsigned int start_time;
  136. if (epnum > 8 || epnum < 0)
  137. return -EINVAL;
  138. if (is_in) {
  139. hep = &host->hep_in[epnum];
  140. } else {
  141. hep = &host->hep_out[epnum];
  142. }
  143. urb = usb_urb_alloc(host, 0, IRQ_NONE);
  144. if (urb == NULL)
  145. return -ENOMEM;
  146. construct_urb(urb, hep, dev, USB_ENDPOINT_XFER_CONTROL,
  147. pipe, buffer, len, setup, 0);
  148. /* Fix speed for non hub-attached devices */
  149. if (!usb_dev_get_parent(dev))
  150. dev->speed = host->host_speed;
  151. //unsigned char *a = urb->setup_packet;
  152. //if (a)
  153. //printf("setup-->%02x %02x %02x %02x %02x %02x %02x %02x\r\n", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
  154. ret = submit_urb(&host->hcd, urb);
  155. if (ret < 0) {
  156. dwc2_urb_dequeue(&host->hcd, urb, 0);
  157. goto exit;
  158. }
  159. start_time = get_timer(0);
  160. ret = pdTRUE;
  161. do {
  162. if (get_timer(start_time) > timeout) {
  163. ret = pdFALSE;
  164. break;
  165. }
  166. } while(!urb->urb_complete);
  167. if (ret != pdTRUE || 0 != urb->status) {//timeout
  168. dwc2_urb_dequeue(&host->hcd, urb, 0);
  169. if (0 != urb->status)
  170. PrintVariableValueHex("usb control urb error", urb->status);
  171. ret = urb->status;
  172. } else {
  173. ret = urb->actual_length;
  174. }
  175. exit:
  176. usb_urb_release(urb);
  177. return ret;
  178. }
  179. int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int *actual_length, int timeout)
  180. {
  181. struct urb *urb = NULL;
  182. struct usb_host_endpoint *hep = NULL;
  183. int epnum = usb_pipeendpoint(pipe);
  184. int is_in = usb_pipein(pipe);
  185. int ret = 0;
  186. struct dwc2_host_data *host = &dwc2_host;
  187. unsigned int start_time;
  188. if (epnum > 8 || epnum < 0)
  189. return -EINVAL;
  190. if (is_in) {
  191. hep = &host->hep_in[epnum];
  192. } else {
  193. hep = &host->hep_out[epnum];
  194. }
  195. urb = usb_urb_alloc(host, 0, IRQ_NONE);
  196. if (urb == NULL)
  197. return -ENOMEM;
  198. construct_urb(urb, hep, dev, USB_ENDPOINT_XFER_BULK,
  199. pipe, buffer, transfer_len, NULL, 0);
  200. ret = submit_urb(&host->hcd, urb);
  201. if (ret < 0) {
  202. dwc2_urb_dequeue(&host->hcd, urb, 0);
  203. goto exit;
  204. }
  205. start_time = get_timer(0);
  206. ret = pdTRUE;
  207. do {
  208. if (get_timer(start_time) > timeout) {
  209. ret = pdFALSE;
  210. break;
  211. }
  212. } while(!urb->urb_complete);
  213. if (ret != pdTRUE || 0 != urb->status) {//timeout
  214. dwc2_urb_dequeue(&host->hcd, urb, 0);
  215. if (actual_length)
  216. *actual_length = 0;
  217. if (0 != urb->status)
  218. PrintVariableValueHex("usb bulk urb error", urb->status);
  219. ret = urb->status;
  220. } else {
  221. if (actual_length)
  222. *actual_length = urb->actual_length;
  223. }
  224. exit:
  225. usb_urb_release(urb);
  226. return ret;
  227. }
  228. void usb_reset_endpoint()
  229. {
  230. int i;
  231. struct dwc2_host_data *host = &dwc2_host;
  232. if ((NULL == host->dw2_hc_driver) || (NULL == host->dw2_hc_driver->endpoint_reset))
  233. return;
  234. for (i = 0; i < 16; i++) {
  235. host->dw2_hc_driver->endpoint_reset(&(host->hcd), &host->hep_in[i]);
  236. host->dw2_hc_driver->endpoint_reset(&(host->hcd), &host->hep_out[i]);
  237. }
  238. }
  239. void usb_disable_endpoint()
  240. {
  241. int i;
  242. struct dwc2_host_data *host = &dwc2_host;
  243. if ((NULL == host->dw2_hc_driver) || (NULL == host->dw2_hc_driver->endpoint_disable))
  244. return;
  245. for (i = 0; i < 16; i++) {
  246. host->dw2_hc_driver->endpoint_disable(&(host->hcd), &host->hep_in[i]);
  247. host->dw2_hc_driver->endpoint_disable(&(host->hcd), &host->hep_out[i]);
  248. }
  249. }
  250. void reset_usb_phy()
  251. {
  252. vSysctlConfigure(SYS_SOFT_RST, 30, 1, 0);//phy reset
  253. mdelay(10);
  254. vSysctlConfigure(SYS_SOFT_RST, 30, 1, 1);//phy reset
  255. }
  256. void usb_sysctrl_init()
  257. {
  258. vSysctlConfigure(SYS_ANA_CFG, 8, 0xff, 4);
  259. vSysctlConfigure(SYS_SOFT_RST, 30, 1, 0);//phy reset
  260. vSysctlConfigure(SYS_SOFT_RST, 3, 1, 0);
  261. mdelay(10);
  262. vSysctlConfigure(SYS_SOFT_RST, 30, 1, 1);//phy reset
  263. vSysctlConfigure(SYS_SOFT_RST, 3, 1, 1);
  264. vSysctlConfigure(SYS_ANA_CFG, 24, 3, 1);
  265. mdelay(10);
  266. }
  267. int hub_status_data(char buf[8])
  268. {
  269. int ret = 1;
  270. struct dwc2_host_data *host = &dwc2_host;
  271. //printf("prvUsbPortScanTimerCallback\r\n");
  272. ret = host->dw2_hc_driver->hub_status_data(&(host->hcd), buf);
  273. if (ret != 0) {
  274. //printf("state:%d usb state changed now!\r\n", buf[0]);
  275. }
  276. return ret;
  277. }
  278. void usb_dwc2_lowlevel_restart()
  279. {
  280. struct dwc2_host_data *host = &dwc2_host;
  281. if (host->dw2_hc_driver && host->dw2_hc_driver->stop) {
  282. host->dw2_hc_driver->stop(&(host->hcd));
  283. }
  284. msleep(50);
  285. if (host->dw2_hc_driver && host->dw2_hc_driver->start) {
  286. host->dw2_hc_driver->start(&(host->hcd));
  287. }
  288. }
  289. //#define mainTIMER_SCAN_FREQUENCY_MS pdMS_TO_TICKS( 1000UL )
  290. int usb_dwc2_lowlevel_init()
  291. {
  292. struct dwc2_host_data *host = &dwc2_host;
  293. int ret;
  294. INIT_LIST_HEAD(&host->free_urb_list);
  295. spin_lock_init(&host->lock);
  296. ret = dwc2_driver_init(&host->host, &(host->hcd));
  297. if (!host->host) {
  298. SendUartString("MUSB host is not registered\n");
  299. return -ENODEV;
  300. }
  301. host->dw2_hc_driver = dwc2_get_driver();
  302. return ret;
  303. }
  304. int usb_dwc2_lowlevel_uninit()
  305. {
  306. if (!dwc2_host.host) {
  307. SendUartString("MUSB host is not registered\n");
  308. return -ENODEV;
  309. }
  310. dwc2_driver_uninit(dwc2_host.host);
  311. return 0;
  312. }
  313. int submit_control_msg(struct usb_device *dev, unsigned long pipe,
  314. void *buffer, int length, struct devrequest *setup, int timeout)
  315. {
  316. if (dev->parent == NULL) {
  317. return dwc_otg_submit_rh_msg(dev, pipe, buffer, length, setup);
  318. } else {
  319. return _dwc2_submit_control_msg(&dwc2_host, dev, pipe, buffer, length, setup, timeout);
  320. }
  321. }
  322. /*
  323. * DWC2 to USB API interface
  324. */
  325. /* Direction: In ; Request: Status */
  326. static int dwc_otg_submit_rh_msg_in_status(struct usb_device *dev, void *buffer,
  327. int txlen, struct devrequest *cmd)
  328. {
  329. int len = 0;
  330. int stat = 0;
  331. switch (cmd->requesttype & ~USB_DIR_IN) {
  332. case 0:
  333. *(uint16_t *)buffer = cpu_to_le16(1);
  334. len = 2;
  335. break;
  336. case USB_RECIP_INTERFACE:
  337. case USB_RECIP_ENDPOINT:
  338. *(uint16_t *)buffer = cpu_to_le16(0);
  339. len = 2;
  340. break;
  341. case USB_TYPE_CLASS:
  342. *(uint32_t *)buffer = cpu_to_le32(0);
  343. len = 4;
  344. break;
  345. case USB_RECIP_OTHER | USB_TYPE_CLASS:
  346. len = 4;
  347. stat = dwc2_host.dw2_hc_driver->hub_control(&dwc2_host.hcd, (cmd->requesttype << 8) | (cmd->request),
  348. cmd->value, cmd->index, (char*)buffer, len);
  349. break;
  350. default:
  351. //puts("unsupported root hub command\n");
  352. stat = USB_ST_STALLED;
  353. }
  354. dev->act_len = min(len, txlen);
  355. dev->status = stat;
  356. return stat;
  357. }
  358. /* Direction: In ; Request: Descriptor */
  359. /* roothub.a masks */
  360. #define RH_A_NDP (0xff << 0) /* number of downstream ports */
  361. #define RH_A_PSM (1 << 8) /* power switching mode */
  362. #define RH_A_NPS (1 << 9) /* no power switching */
  363. #define RH_A_DT (1 << 10) /* device type (mbz) */
  364. #define RH_A_OCPM (1 << 11) /* over current protection mode */
  365. #define RH_A_NOCP (1 << 12) /* no over current protection */
  366. #define RH_A_POTPGT (0xffUL << 24) /* power on to power good time */
  367. /* roothub.b masks */
  368. #define RH_B_DR 0x0000ffff /* device removable flags */
  369. #define RH_B_PPCM 0xffff0000 /* port power control mask */
  370. static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev,
  371. void *buffer, int txlen,
  372. struct devrequest *cmd)
  373. {
  374. unsigned char data[32];
  375. uint32_t dsc;
  376. int len = 0;
  377. int stat = 0;
  378. uint16_t wValue = cpu_to_le16(cmd->value);
  379. uint16_t wLength = cpu_to_le16(cmd->length);
  380. switch (cmd->requesttype & ~USB_DIR_IN) {
  381. case 0:
  382. {
  383. switch (wValue & 0xff00) {
  384. case 0x0100: /* device descriptor */
  385. len = min3(txlen, (int)sizeof(root_hub_dev_des), (int)wLength);
  386. memcpy(buffer, root_hub_dev_des, len);
  387. break;
  388. case 0x0200: /* configuration descriptor */
  389. len = min3(txlen, (int)sizeof(root_hub_config_des), (int)wLength);
  390. memcpy(buffer, root_hub_config_des, len);
  391. break;
  392. case 0x0300: /* string descriptors */
  393. switch (wValue & 0xff) {
  394. case 0x00:
  395. len = min3(txlen, (int)sizeof(root_hub_str_index0),
  396. (int)wLength);
  397. memcpy(buffer, root_hub_str_index0, len);
  398. break;
  399. case 0x01:
  400. len = min3(txlen, (int)sizeof(root_hub_str_index1),
  401. (int)wLength);
  402. memcpy(buffer, root_hub_str_index1, len);
  403. break;
  404. }
  405. break;
  406. default:
  407. stat = USB_ST_STALLED;
  408. }
  409. break;
  410. }
  411. case USB_TYPE_CLASS:
  412. /* Root port config, set 1 port and nothing else. */
  413. dsc = 0x00000001;
  414. data[0] = 9; /* min length; */
  415. data[1] = 0x29;
  416. data[2] = dsc & RH_A_NDP;
  417. data[3] = 0;
  418. if (dsc & RH_A_PSM)
  419. data[3] |= 0x1;
  420. if (dsc & RH_A_NOCP)
  421. data[3] |= 0x10;
  422. else if (dsc & RH_A_OCPM)
  423. data[3] |= 0x8;
  424. /* corresponds to data[4-7] */
  425. data[5] = (dsc & RH_A_POTPGT) >> 24;
  426. data[7] = dsc & RH_B_DR;
  427. if (data[2] < 7) {
  428. data[8] = 0xff;
  429. } else {
  430. data[0] += 2;
  431. data[8] = (dsc & RH_B_DR) >> 8;
  432. data[9] = 0xff;
  433. data[10] = data[9];
  434. }
  435. len = min3(txlen, (int)data[0], (int)wLength);
  436. memcpy(buffer, data, len);
  437. break;
  438. default:
  439. //puts("unsupported root hub command\n");
  440. stat = USB_ST_STALLED;
  441. }
  442. dev->act_len = min(len, txlen);
  443. dev->status = stat;
  444. return stat;
  445. }
  446. /* Direction: In ; Request: Configuration */
  447. static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev,
  448. void *buffer, int txlen,
  449. struct devrequest *cmd)
  450. {
  451. int len = 0;
  452. int stat = 0;
  453. switch (cmd->requesttype & ~USB_DIR_IN) {
  454. case 0:
  455. *(uint8_t *)buffer = 0x01;
  456. len = 1;
  457. break;
  458. default:
  459. //puts("unsupported root hub command\n");
  460. stat = USB_ST_STALLED;
  461. }
  462. dev->act_len = min(len, txlen);
  463. dev->status = stat;
  464. return stat;
  465. }
  466. /* Direction: In */
  467. static int dwc_otg_submit_rh_msg_in(
  468. struct usb_device *dev, void *buffer,
  469. int txlen, struct devrequest *cmd)
  470. {
  471. switch (cmd->request) {
  472. case USB_REQ_GET_STATUS:
  473. return dwc_otg_submit_rh_msg_in_status(dev, buffer,
  474. txlen, cmd);
  475. case USB_REQ_GET_DESCRIPTOR:
  476. return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer,
  477. txlen, cmd);
  478. case USB_REQ_GET_CONFIGURATION:
  479. return dwc_otg_submit_rh_msg_in_configuration(dev, buffer,
  480. txlen, cmd);
  481. default:
  482. //puts("unsupported root hub command\n");
  483. return USB_ST_STALLED;
  484. }
  485. }
  486. /* Direction: Out */
  487. static int dwc_otg_submit_rh_msg_out(
  488. struct usb_device *dev,
  489. void *buffer, int txlen,
  490. struct devrequest *cmd)
  491. {
  492. int len = 0;
  493. int stat = 0;
  494. uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8);
  495. uint16_t wValue = cpu_to_le16(cmd->value);
  496. switch (bmrtype_breq & ~USB_DIR_IN) {
  497. case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_ENDPOINT:
  498. case (USB_REQ_CLEAR_FEATURE << 8) | USB_TYPE_CLASS:
  499. break;
  500. case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
  501. case (USB_REQ_SET_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
  502. dwc2_host.dw2_hc_driver->hub_control(&dwc2_host.hcd, (cmd->requesttype << 8) | (cmd->request),
  503. cmd->value, cmd->index, (char*)buffer, txlen);
  504. break;
  505. case (USB_REQ_SET_ADDRESS << 8):
  506. dwc2_host.root_hub_devnum = wValue;
  507. dwc2_host.dw2_hc_driver->hub_control(&dwc2_host.hcd, (cmd->requesttype << 8) | (cmd->request),
  508. cmd->value, cmd->index, (char*)buffer, txlen);
  509. break;
  510. case (USB_REQ_SET_CONFIGURATION << 8):
  511. break;
  512. default:
  513. //puts("unsupported root hub command\n");
  514. stat = USB_ST_STALLED;
  515. }
  516. len = min(len, txlen);
  517. dev->act_len = len;
  518. dev->status = stat;
  519. return stat;
  520. }
  521. static int dwc_otg_submit_rh_msg(struct usb_device *dev,
  522. unsigned long pipe, void *buffer, int txlen,
  523. struct devrequest *cmd)
  524. {
  525. int stat = 0;
  526. if (usb_pipeint(pipe)) {
  527. //puts("Root-Hub submit IRQ: NOT implemented\n");
  528. return 0;
  529. }
  530. if (cmd->requesttype & USB_DIR_IN)
  531. stat = dwc_otg_submit_rh_msg_in(dev, buffer, txlen, cmd);
  532. else
  533. stat = dwc_otg_submit_rh_msg_out(dev, buffer, txlen, cmd);
  534. stat = dev->act_len;
  535. return stat;
  536. }