Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 1 | #include "board.h" |
| 2 | #include "llist_irqsafe.h" |
| 3 | #include "usb_buf.h" |
Harald Welte | 7abdb51 | 2016-03-03 17:48:32 +0100 | [diff] [blame] | 4 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 5 | #include "osmocom/core/linuxlist.h" |
| 6 | #include "osmocom/core/msgb.h" |
Harald Welte | 3d27c84 | 2016-03-17 20:07:45 +0100 | [diff] [blame] | 7 | #include <errno.h> |
| 8 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 9 | /*********************************************************************** |
| 10 | * USBD Integration API |
| 11 | ***********************************************************************/ |
Christina Quast | 2b8a18b | 2015-04-12 09:31:36 +0200 | [diff] [blame] | 12 | |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 13 | /* call-back after (successful?) transfer of a buffer */ |
| 14 | static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred, |
| 15 | uint32_t remaining) |
Christina Quast | 2b8a18b | 2015-04-12 09:31:36 +0200 | [diff] [blame] | 16 | { |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 17 | struct msgb *msg = (struct msgb *) arg; |
| 18 | struct usb_buffered_ep *bep = msg->dst; |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 19 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 20 | TRACE_DEBUG("%s (EP=0x%02x)\r\n", __func__, bep->ep); |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 21 | |
| 22 | __disable_irq(); |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 23 | bep->in_progress--; |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 24 | __enable_irq(); |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 25 | TRACE_DEBUG("%u: in_progress=%d\n", bep->ep, bep->in_progress); |
Harald Welte | 54cb3d0 | 2016-02-29 14:12:40 +0100 | [diff] [blame] | 26 | |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 27 | if (status != USBD_STATUS_SUCCESS) |
| 28 | TRACE_ERROR("%s error, status=%d\n", __func__, status); |
| 29 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 30 | usb_buf_free(msg); |
Christina Quast | 2b8a18b | 2015-04-12 09:31:36 +0200 | [diff] [blame] | 31 | } |
| 32 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 33 | int usb_refill_to_host(uint8_t ep) |
Christina Quast | 2b8a18b | 2015-04-12 09:31:36 +0200 | [diff] [blame] | 34 | { |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 35 | struct usb_buffered_ep *bep = usb_get_buf_ep(ep); |
| 36 | struct msgb *msg; |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 37 | int rc; |
Christina Quast | 2b8a18b | 2015-04-12 09:31:36 +0200 | [diff] [blame] | 38 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 39 | #if 0 |
| 40 | if (bep->out_from_host) { |
| 41 | TRACE_ERROR("EP 0x%02x is not IN\r\n", bep->ep); |
| 42 | return -EINVAL; |
| 43 | } |
| 44 | #endif |
| 45 | |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 46 | __disable_irq(); |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 47 | if (bep->in_progress) { |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 48 | __enable_irq(); |
Harald Welte | 54cb3d0 | 2016-02-29 14:12:40 +0100 | [diff] [blame] | 49 | return 0; |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 50 | } |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 51 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 52 | if (llist_empty(&bep->queue)) { |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 53 | __enable_irq(); |
Harald Welte | 54cb3d0 | 2016-02-29 14:12:40 +0100 | [diff] [blame] | 54 | return 0; |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 55 | } |
| 56 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 57 | bep->in_progress++; |
Harald Welte | 54cb3d0 | 2016-02-29 14:12:40 +0100 | [diff] [blame] | 58 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 59 | msg = msgb_dequeue(&bep->queue); |
Harald Welte | 54cb3d0 | 2016-02-29 14:12:40 +0100 | [diff] [blame] | 60 | |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 61 | __enable_irq(); |
| 62 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 63 | TRACE_DEBUG("%s (EP=0x%02x), in_progress=%d\r\n", __func__, ep, bep->in_progress); |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 64 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 65 | msg->dst = bep; |
Harald Welte | 54cb3d0 | 2016-02-29 14:12:40 +0100 | [diff] [blame] | 66 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 67 | rc = USBD_Write(ep, msgb_data(msg), msgb_length(msg), |
| 68 | (TransferCallback) &usb_write_cb, msg); |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 69 | if (rc != USBD_STATUS_SUCCESS) { |
Harald Welte | 2ad0ca1 | 2016-02-29 10:07:16 +0100 | [diff] [blame] | 70 | TRACE_ERROR("%s error %x\n", __func__, rc); |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 71 | /* re-insert to head of queue */ |
| 72 | llist_add_irqsafe(&msg->list, &bep->queue); |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 73 | __disable_irq(); |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 74 | bep->in_progress--; |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 75 | __enable_irq(); |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 76 | TRACE_DEBUG("%02x: in_progress=%d\n", bep->ep, bep->in_progress); |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 77 | return 0; |
| 78 | } |
| 79 | |
| 80 | return 1; |
Christina Quast | 2b8a18b | 2015-04-12 09:31:36 +0200 | [diff] [blame] | 81 | } |
| 82 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 83 | /* call-back after (successful?) transfer of a buffer */ |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 84 | static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred, |
| 85 | uint32_t remaining) |
Christina Quast | 2b8a18b | 2015-04-12 09:31:36 +0200 | [diff] [blame] | 86 | { |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 87 | struct msgb *msg = (struct msgb *) arg; |
| 88 | struct usb_buffered_ep *bep = msg->dst; |
Harald Welte | 54cb3d0 | 2016-02-29 14:12:40 +0100 | [diff] [blame] | 89 | |
Harald Welte | 53079bb | 2016-03-20 14:58:35 +0100 | [diff] [blame] | 90 | TRACE_DEBUG("%s (EP=%u, len=%u, q=%p)\r\n", __func__, |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 91 | bep->ep, transferred, &bep->queue); |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 92 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 93 | bep->in_progress = 0; |
Christina Quast | 2b8a18b | 2015-04-12 09:31:36 +0200 | [diff] [blame] | 94 | |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 95 | if (status != USBD_STATUS_SUCCESS) { |
| 96 | TRACE_ERROR("%s error, status=%d\n", __func__, status); |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 97 | usb_buf_free(msg); |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 98 | return; |
| 99 | } |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 100 | msgb_put(msg, transferred); |
| 101 | llist_add_tail_irqsafe(&msg->list, &bep->queue); |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 102 | } |
| 103 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 104 | int usb_refill_from_host(uint8_t ep) |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 105 | { |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 106 | struct usb_buffered_ep *bep = usb_get_buf_ep(ep); |
| 107 | struct msgb *msg; |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 108 | int rc; |
| 109 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 110 | #if 0 |
| 111 | if (!bep->out_from_host) { |
| 112 | TRACE_ERROR("EP 0x%02x is not OUT\r\n", bep->ep); |
| 113 | return -EINVAL; |
| 114 | } |
| 115 | #endif |
| 116 | |
| 117 | if (bep->in_progress) |
Harald Welte | 54cb3d0 | 2016-02-29 14:12:40 +0100 | [diff] [blame] | 118 | return 0; |
| 119 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 120 | TRACE_DEBUG("%s (EP=0x%02x)\r\n", __func__, bep->ep); |
Harald Welte | a0cf200 | 2016-03-02 10:35:51 +0100 | [diff] [blame] | 121 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 122 | msg = usb_buf_alloc(bep->ep); |
| 123 | if (!msg) |
Harald Welte | 3d27c84 | 2016-03-17 20:07:45 +0100 | [diff] [blame] | 124 | return -ENOMEM; |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 125 | msg->dst = bep; |
| 126 | msg->l1h = msg->head; |
Harald Welte | 3d27c84 | 2016-03-17 20:07:45 +0100 | [diff] [blame] | 127 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 128 | bep->in_progress = 1; |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 129 | |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 130 | rc = USBD_Read(ep, msg->head, msgb_tailroom(msg), |
| 131 | (TransferCallback) &usb_read_cb, msg); |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 132 | if (rc != USBD_STATUS_SUCCESS) { |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 133 | TRACE_ERROR("%s error %s\n", __func__, rc); |
| 134 | usb_buf_free(msg); |
| 135 | bep->in_progress = 0; |
Harald Welte | 2a6d3af | 2016-02-28 19:29:14 +0100 | [diff] [blame] | 136 | } |
| 137 | |
Harald Welte | 54cb3d0 | 2016-02-29 14:12:40 +0100 | [diff] [blame] | 138 | return 1; |
Christina Quast | 2b8a18b | 2015-04-12 09:31:36 +0200 | [diff] [blame] | 139 | } |
Harald Welte | 8e7fca3 | 2017-05-07 16:14:33 +0200 | [diff] [blame^] | 140 | |
| 141 | int usb_drain_queue(uint8_t ep) |
| 142 | { |
| 143 | struct usb_buffered_ep *bep = usb_get_buf_ep(ep); |
| 144 | struct msgb *msg; |
| 145 | int ret = 0; |
| 146 | |
| 147 | /* wait until no transfers are in progress anymore and block |
| 148 | * further interrupts */ |
| 149 | while (1) { |
| 150 | __disable_irq(); |
| 151 | if (!bep->in_progress) { |
| 152 | break; |
| 153 | } |
| 154 | __enable_irq(); |
| 155 | /* retry */ |
| 156 | } |
| 157 | |
| 158 | /* free all queued msgbs */ |
| 159 | while ((msg = msgb_dequeue(&bep->queue))) { |
| 160 | usb_buf_free(msg); |
| 161 | ret++; |
| 162 | } |
| 163 | |
| 164 | /* re-enable interrupts and return number of free'd msgbs */ |
| 165 | __enable_irq(); |
| 166 | |
| 167 | return ret; |
| 168 | } |