blob: 05f799902cc4a159063bf59740c490a86ee99fcf [file] [log] [blame]
Harald Welte7abdb512016-03-03 17:48:32 +01001//#define TRACE_LEVEL 6
2
Christina Quast2b8a18b2015-04-12 09:31:36 +02003#include "board.h"
Harald Welte2a6d3af2016-02-28 19:29:14 +01004#include "req_ctx.h"
Harald Welte54cb3d02016-02-29 14:12:40 +01005#include "linuxlist.h"
6
7static volatile uint32_t usbep_in_progress[BOARD_USB_NUMENDPOINTS];
Christina Quast2b8a18b2015-04-12 09:31:36 +02008
Harald Welte2a6d3af2016-02-28 19:29:14 +01009/* call-back after (successful?) transfer of a buffer */
10static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
11 uint32_t remaining)
Christina Quast2b8a18b2015-04-12 09:31:36 +020012{
Harald Welte2a6d3af2016-02-28 19:29:14 +010013 struct req_ctx *rctx = (struct req_ctx *) arg;
14
Harald Weltea0cf2002016-03-02 10:35:51 +010015 TRACE_DEBUG("%s (EP=%u)\r\n", __func__, rctx->ep);
16
17 __disable_irq();
18 usbep_in_progress[rctx->ep]--;
19 __enable_irq();
20 TRACE_DEBUG("%u: in_progress=%d\n", rctx->ep, usbep_in_progress[rctx->ep]);
Harald Welte54cb3d02016-02-29 14:12:40 +010021
Harald Welte2a6d3af2016-02-28 19:29:14 +010022 if (status != USBD_STATUS_SUCCESS)
23 TRACE_ERROR("%s error, status=%d\n", __func__, status);
24
25 /* release request contxt to pool */
26 req_ctx_set_state(rctx, RCTX_S_FREE);
Christina Quast2b8a18b2015-04-12 09:31:36 +020027}
28
Harald Welte54cb3d02016-02-29 14:12:40 +010029int usb_refill_to_host(struct llist_head *queue, uint32_t ep)
Christina Quast2b8a18b2015-04-12 09:31:36 +020030{
Harald Welte2a6d3af2016-02-28 19:29:14 +010031 struct req_ctx *rctx;
32 int rc;
Christina Quast2b8a18b2015-04-12 09:31:36 +020033
Harald Weltea0cf2002016-03-02 10:35:51 +010034 __disable_irq();
35 if (usbep_in_progress[ep]) {
36 __enable_irq();
Harald Welte54cb3d02016-02-29 14:12:40 +010037 return 0;
Harald Weltea0cf2002016-03-02 10:35:51 +010038 }
Harald Welte2a6d3af2016-02-28 19:29:14 +010039
Harald Weltea0cf2002016-03-02 10:35:51 +010040 if (llist_empty(queue)) {
41 __enable_irq();
Harald Welte54cb3d02016-02-29 14:12:40 +010042 return 0;
Harald Weltea0cf2002016-03-02 10:35:51 +010043 }
44
45 usbep_in_progress[ep]++;
Harald Welte54cb3d02016-02-29 14:12:40 +010046
47 rctx = llist_entry(queue->next, struct req_ctx, list);
48 llist_del(&rctx->list);
49
Harald Weltea0cf2002016-03-02 10:35:51 +010050 __enable_irq();
51
52 TRACE_DEBUG("%u: in_progress=%d\n", ep, usbep_in_progress[ep]);
53 TRACE_DEBUG("%s (EP=%u)\r\n", __func__, ep);
54
Harald Welte54cb3d02016-02-29 14:12:40 +010055 req_ctx_set_state(rctx, RCTX_S_USB_TX_BUSY);
56 rctx->ep = ep;
57
58 rc = USBD_Write(ep, rctx->data, rctx->tot_len,
Harald Welte2a6d3af2016-02-28 19:29:14 +010059 (TransferCallback) &usb_write_cb, rctx);
60 if (rc != USBD_STATUS_SUCCESS) {
Harald Welte2ad0ca12016-02-29 10:07:16 +010061 TRACE_ERROR("%s error %x\n", __func__, rc);
Harald Welte2a6d3af2016-02-28 19:29:14 +010062 req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
Harald Weltea0cf2002016-03-02 10:35:51 +010063 __disable_irq();
64 usbep_in_progress[ep]--;
65 __enable_irq();
66 TRACE_DEBUG("%u: in_progress=%d\n", ep, usbep_in_progress[ep]);
Harald Welte2a6d3af2016-02-28 19:29:14 +010067 return 0;
68 }
69
70 return 1;
Christina Quast2b8a18b2015-04-12 09:31:36 +020071}
72
Harald Welte2a6d3af2016-02-28 19:29:14 +010073static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
74 uint32_t remaining)
Christina Quast2b8a18b2015-04-12 09:31:36 +020075{
Harald Welte2a6d3af2016-02-28 19:29:14 +010076 struct req_ctx *rctx = (struct req_ctx *) arg;
Harald Welte54cb3d02016-02-29 14:12:40 +010077 struct llist_head *queue = (struct llist_head *) usbep_in_progress[rctx->ep];
78
Harald Weltea0cf2002016-03-02 10:35:51 +010079 TRACE_DEBUG("%s (EP=%u)\r\n", __func__, rctx->ep);
80
Harald Welte54cb3d02016-02-29 14:12:40 +010081 usbep_in_progress[rctx->ep] = 0;
Christina Quast2b8a18b2015-04-12 09:31:36 +020082
Harald Welte2a6d3af2016-02-28 19:29:14 +010083 if (status != USBD_STATUS_SUCCESS) {
84 TRACE_ERROR("%s error, status=%d\n", __func__, status);
85 /* release request contxt to pool */
86 req_ctx_put(rctx);
87 return;
88 }
Harald Welteebb80ed2016-03-02 13:56:59 +010089 req_ctx_set_state(rctx, RCTX_S_MAIN_PROCESSING);
Harald Welte54cb3d02016-02-29 14:12:40 +010090 llist_add_tail(&rctx->list, queue);
Harald Welte2a6d3af2016-02-28 19:29:14 +010091}
92
Harald Welte54cb3d02016-02-29 14:12:40 +010093int usb_refill_from_host(struct llist_head *queue, int ep)
Harald Welte2a6d3af2016-02-28 19:29:14 +010094{
95 struct req_ctx *rctx;
96 int rc;
97
Harald Welte54cb3d02016-02-29 14:12:40 +010098 if (usbep_in_progress[ep])
99 return 0;
100
Harald Weltea0cf2002016-03-02 10:35:51 +0100101 TRACE_DEBUG("%s (EP=%u)\r\n", __func__, ep);
102
Harald Welte2a6d3af2016-02-28 19:29:14 +0100103 rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_USB_RX_BUSY);
Harald Welte54cb3d02016-02-29 14:12:40 +0100104 rctx->ep = ep;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100105
106 rc = USBD_Read(ep, rctx->data, rctx->size,
107 (TransferCallback) &usb_read_cb, rctx);
108
109 if (rc != USBD_STATUS_SUCCESS) {
Harald Welte2ad0ca12016-02-29 10:07:16 +0100110 TRACE_ERROR("%s error %x\n", __func__, rc);
Harald Welte2a6d3af2016-02-28 19:29:14 +0100111 req_ctx_put(rctx);
Harald Welte54cb3d02016-02-29 14:12:40 +0100112 return 0;
Harald Welte2a6d3af2016-02-28 19:29:14 +0100113 }
114
Harald Welte54cb3d02016-02-29 14:12:40 +0100115 usbep_in_progress[ep] = (uint32_t) queue;
116
117 return 1;
Christina Quast2b8a18b2015-04-12 09:31:36 +0200118}