blob: 08b192bae5ee40831f702823143fc99d124112ef [file] [log] [blame]
Sylvain Munautbc9f5c42020-09-14 10:22:29 +02001/*
2 * usb_e1.c
3 *
4 * Copyright (C) 2019-2020 Sylvain Munaut <tnt@246tNt.com>
5 * SPDX-License-Identifier: GPL-3.0-or-later
6 */
7
8#include <stdint.h>
9#include <stdbool.h>
10#include <string.h>
11
12#include <no2usb/usb_hw.h>
13#include <no2usb/usb_priv.h>
14
15#include "console.h"
Harald Welte2df1f802020-12-14 17:46:53 +010016#include "e1.h"
Sylvain Munautff44f142022-01-03 20:34:23 +010017#include "misc.h"
18#include "usb_desc_ids.h"
Sylvain Munaut41c98b62022-01-05 21:11:35 +010019#include "utils.h"
Harald Welte9469e042020-12-15 23:09:40 +010020
21#include "ice1usb_proto.h"
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020022
Sylvain Munaut41c98b62022-01-05 21:11:35 +010023struct usb_e1_state {
Harald Welte30fc5602020-12-14 15:56:28 +010024 bool running; /* are we running (transceiving USB data)? */
25 int out_bdi; /* buffer descriptor index for OUT EP */
26 int in_bdi; /* buffer descriptor index for IN EP */
Harald Welte9469e042020-12-15 23:09:40 +010027 struct ice1usb_tx_config tx_cfg;
28 struct ice1usb_rx_config rx_cfg;
Harald Welte805f2cf2020-12-14 17:31:03 +010029 struct e1_error_count last_err;
Sylvain Munaut41c98b62022-01-05 21:11:35 +010030};
31
32static struct usb_e1_state g_usb_e1[2];
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020033
Harald Welte9469e042020-12-15 23:09:40 +010034/* default configuration at power-up */
35static const struct ice1usb_tx_config tx_cfg_default = {
36 .mode = ICE1USB_TX_MODE_TS0_CRC4_E,
37 .timing = ICE1USB_TX_TIME_SRC_LOCAL,
38 .ext_loopback = ICE1USB_TX_EXT_LOOPBACK_OFF,
39 .alarm = 0,
40};
41
42static const struct ice1usb_rx_config rx_cfg_default = {
43 .mode = ICE1USB_RX_MODE_MULTIFRAME,
44};
45
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020046
Sylvain Munautff44f142022-01-03 20:34:23 +010047static volatile struct usb_ep *
48_get_ep_regs(uint8_t ep)
49{
50 return (ep & 0x80) ? &usb_ep_regs[ep & 0x1f].in : &usb_ep_regs[ep & 0x1f].out;
51}
52
Sylvain Munaut41c98b62022-01-05 21:11:35 +010053static struct usb_e1_state *
54_get_state(int port)
55{
56 if ((port < 0) || (port > 1))
57 panic("_get_state invalid port %d", port);
58 return &g_usb_e1[port];
59}
60
61static int
62_ifnum2port(uint8_t bInterfaceNumber)
63{
64 switch (bInterfaceNumber) {
65 case USB_INTF_E1(0): return 0;
66 case USB_INTF_E1(1): return 1;
67 default:
68 /* Don't panic since this will be handled as USB STALL */
69 return -1;
70 }
71}
72
73
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020074static void
Sylvain Munaut41c98b62022-01-05 21:11:35 +010075_usb_fill_feedback_ep(int port)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020076{
Sylvain Munaut2de84f82022-01-06 08:12:04 +010077 volatile struct usb_ep *ep_regs = _get_ep_regs(USB_EP_E1_FB(port));
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020078
Sylvain Munaut2de84f82022-01-06 08:12:04 +010079 /* Always ensure we're ready to send */
80 if ((ep_regs->bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
81 {
82 uint32_t val = 8192;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020083
Sylvain Munaut2de84f82022-01-06 08:12:04 +010084 /* Add instant bias depending on TX fifo level */
85 unsigned int level = e1_tx_level(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020086
Sylvain Munaut2de84f82022-01-06 08:12:04 +010087 if (level < (4 * 16))
88 val += 256;
89 else if (level > (6 * 16))
90 val -= 256;
91
92 /* Fill buffer and submit it */
93 usb_data_write(ep_regs->bd[0].ptr, &val, 4);
94 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(3);
95 }
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020096}
97
98
99void
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100100usb_e1_run(int port)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200101{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100102 struct usb_e1_state *usb_e1 = _get_state(port);
Sylvain Munautff44f142022-01-03 20:34:23 +0100103 volatile struct usb_ep *ep_regs;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200104 int bdi;
105
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100106 if (!usb_e1->running)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200107 return;
108
Sylvain Munautff44f142022-01-03 20:34:23 +0100109 /* Interrupt endpoint */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100110 ep_regs = _get_ep_regs(USB_EP_E1_INT(port));
Sylvain Munautff44f142022-01-03 20:34:23 +0100111
112 if ((ep_regs->bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA) {
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100113 const struct e1_error_count *cur_err = e1_get_error_count(port);
114 if (memcmp(cur_err, &usb_e1->last_err, sizeof(*cur_err))) {
Harald Welte805f2cf2020-12-14 17:31:03 +0100115 struct ice1usb_irq errmsg = {
116 .type = ICE1USB_IRQ_T_ERRCNT,
117 .u = {
118 .errors = {
119 .crc = cur_err->crc,
120 .align = cur_err->align,
121 .ovfl = cur_err->ovfl,
122 .unfl = cur_err->unfl,
123 .flags = cur_err->flags,
124 }
125 }
126 };
127 printf("E");
Sylvain Munautff44f142022-01-03 20:34:23 +0100128 usb_data_write(ep_regs->bd[0].ptr, &errmsg, sizeof(errmsg));
129 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(sizeof(errmsg));
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100130 usb_e1->last_err = *cur_err;
Harald Welte805f2cf2020-12-14 17:31:03 +0100131 }
132 }
133
Sylvain Munautff44f142022-01-03 20:34:23 +0100134 /* Data IN endpoint */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100135 ep_regs = _get_ep_regs(USB_EP_E1_IN(port));
136 bdi = usb_e1->in_bdi;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200137
Sylvain Munautff44f142022-01-03 20:34:23 +0100138 while ((ep_regs->bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200139 {
Sylvain Munautff44f142022-01-03 20:34:23 +0100140 uint32_t ptr = ep_regs->bd[bdi].ptr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200141 uint32_t hdr;
Harald Welte2df1f802020-12-14 17:46:53 +0100142 unsigned int pos;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200143
144 /* Error check */
Sylvain Munautff44f142022-01-03 20:34:23 +0100145 if ((ep_regs->bd[bdi].csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR)
146 puts("Err EP IN\n");
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200147
148 /* Get some data from E1 */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100149 int n = e1_rx_level(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200150
Sylvain Munaut1d987092022-01-05 21:04:09 +0100151 if (n > 32)
152 n = 9;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200153 else if (n > 8)
154 n = 8;
155 else if (!n)
156 break;
157
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100158 n = e1_rx_need_data(port, (ptr >> 2) + 1, n, &pos);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200159
Harald Welte2df1f802020-12-14 17:46:53 +0100160 /* Write header: currently version and pos (mfr/fr number) */
161 hdr = (0 << 28) | (pos & 0xff);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200162 usb_data_write(ptr, &hdr, 4);
163
164 /* Resubmit */
Sylvain Munautff44f142022-01-03 20:34:23 +0100165 ep_regs->bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN((n * 32) + 4);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200166
167 /* Next BDI */
168 bdi ^= 1;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100169 usb_e1->in_bdi = bdi;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200170 }
171
Sylvain Munautff44f142022-01-03 20:34:23 +0100172 /* Data OUT endpoint */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100173 ep_regs = _get_ep_regs(USB_EP_E1_OUT(port));
174 bdi = usb_e1->out_bdi;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200175
Sylvain Munautff44f142022-01-03 20:34:23 +0100176 while ((ep_regs->bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200177 {
Sylvain Munautff44f142022-01-03 20:34:23 +0100178 uint32_t ptr = ep_regs->bd[bdi].ptr;
179 uint32_t csr = ep_regs->bd[bdi].csr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200180 uint32_t hdr;
181
182 /* Error check */
183 if ((csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR) {
Sylvain Munautff44f142022-01-03 20:34:23 +0100184 puts("Err EP OUT\n");
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200185 goto refill;
186 }
187
188 /* Grab header */
189 usb_data_read(&hdr, ptr, 4);
190
191 /* Empty data into the FIFO */
Sylvain Munautd108dfb2022-01-03 21:11:05 +0100192 int n = ((int)(csr & USB_BD_LEN_MSK) - 6) / 32;
193 if (n > 0)
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100194 e1_tx_feed_data(port, (ptr >> 2) + 1, n);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200195
196refill:
197 /* Refill it */
Sylvain Munaut1d987092022-01-05 21:04:09 +0100198 ep_regs->bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200199
200 /* Next BDI */
201 bdi ^= 1;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100202 usb_e1->out_bdi = bdi;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200203
204 static int x = 0;
205 if ((x++ & 0xff) == 0xff)
206 puts(".");
207 }
208
Sylvain Munautff44f142022-01-03 20:34:23 +0100209 /* Feedback endpoint */
Sylvain Munaut2de84f82022-01-06 08:12:04 +0100210 _usb_fill_feedback_ep(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200211}
212
Harald Weltec8271852020-12-14 13:48:09 +0100213static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200214_e1_set_conf(const struct usb_conf_desc *conf)
215{
216 const struct usb_intf_desc *intf;
217
218 printf("e1 set_conf %08x\n", conf);
219 if (!conf)
220 return USB_FND_SUCCESS;
221
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100222 for (int port=0; port<2; port++)
223 {
224 intf = usb_desc_find_intf(conf, USB_INTF_E1(port), 0, NULL);
225 if (!intf)
226 return USB_FND_ERROR;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200227
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100228 printf("e1 set_conf[%d] %08x\n", port, intf);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200229
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100230 usb_ep_boot(intf, USB_EP_E1_IN(port), true);
231 usb_ep_boot(intf, USB_EP_E1_OUT(port), true);
232 usb_ep_boot(intf, USB_EP_E1_FB(port), false);
233 usb_ep_boot(intf, USB_EP_E1_INT(port), false);
234 }
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200235
236 return USB_FND_SUCCESS;
237}
238
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100239static void _perform_tx_config(int port)
Harald Welte9469e042020-12-15 23:09:40 +0100240{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100241 struct usb_e1_state *usb_e1 = _get_state(port);
242 const struct ice1usb_tx_config *cfg = &usb_e1->tx_cfg;
243 e1_tx_config(port,
Sylvain Munaut3da51512022-01-03 22:12:59 +0100244 ((cfg->mode & 3) << 1) |
245 ((cfg->timing & 1) << 3) |
246 ((cfg->alarm & 1) << 4) |
247 ((cfg->ext_loopback & 3) << 5)
248 );
Harald Welte9469e042020-12-15 23:09:40 +0100249}
250
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100251static void _perform_rx_config(int port)
Harald Welte9469e042020-12-15 23:09:40 +0100252{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100253 struct usb_e1_state *usb_e1 = _get_state(port);
254 const struct ice1usb_rx_config *cfg = &usb_e1->rx_cfg;
255 e1_rx_config(port,
Sylvain Munaut3da51512022-01-03 22:12:59 +0100256 (cfg->mode << 1)
257 );
Harald Welte9469e042020-12-15 23:09:40 +0100258}
259
Harald Weltec8271852020-12-14 13:48:09 +0100260static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200261_e1_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
262{
Sylvain Munautff44f142022-01-03 20:34:23 +0100263 volatile struct usb_ep *ep_regs;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100264 struct usb_e1_state *usb_e1;
265 int port;
Sylvain Munautff44f142022-01-03 20:34:23 +0100266
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100267 /* Is it for E1 interface ? */
Sylvain Munautff44f142022-01-03 20:34:23 +0100268 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200269 return USB_FND_CONTINUE;
270
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100271 /* Get matching port (if any) */
272 port = _ifnum2port(base->bInterfaceNumber);
273 if (port < 0)
274 return USB_FND_ERROR;
275
276 usb_e1 = _get_state(port);
277
278 /* Valid setting ? */
Sylvain Munaut96744362022-01-03 17:03:26 +0100279 if (sel->bAlternateSetting > 1)
280 return USB_FND_ERROR;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200281
Sylvain Munaut96744362022-01-03 17:03:26 +0100282 /* Don't do anything if no change */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100283 if (usb_e1->running == (sel->bAlternateSetting != 0))
Sylvain Munaut96744362022-01-03 17:03:26 +0100284 return USB_FND_SUCCESS;
285
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100286 usb_e1->running = (sel->bAlternateSetting != 0);
Sylvain Munaut96744362022-01-03 17:03:26 +0100287
288 /* Reconfigure the endpoints */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100289 usb_ep_reconf(sel, USB_EP_E1_IN(port));
290 usb_ep_reconf(sel, USB_EP_E1_OUT(port));
291 usb_ep_reconf(sel, USB_EP_E1_FB(port));
292 usb_ep_reconf(sel, USB_EP_E1_INT(port));
Sylvain Munaut96744362022-01-03 17:03:26 +0100293
294 /* Update E1 and USB state */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100295 switch (usb_e1->running) {
Sylvain Munaut96744362022-01-03 17:03:26 +0100296 case false:
297 /* Disable E1 rx/tx */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100298 e1_init(port, 0, 0);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100299 break;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200300
Sylvain Munaut96744362022-01-03 17:03:26 +0100301 case true:
302 /* Reset and Re-Enable E1 */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100303 e1_init(port, 0, 0);
304 _perform_rx_config(port);
305 _perform_tx_config(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200306
Sylvain Munaut96744362022-01-03 17:03:26 +0100307 /* Reset BDI */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100308 usb_e1->in_bdi = 0;
309 usb_e1->out_bdi = 0;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100310
Sylvain Munautff44f142022-01-03 20:34:23 +0100311 /* EP OUT: Queue two buffers */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100312 ep_regs = _get_ep_regs(USB_EP_E1_OUT(port));
Sylvain Munaut1d987092022-01-05 21:04:09 +0100313 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
314 ep_regs->bd[1].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100315
Harald Weltee6b0fe82020-12-17 22:22:05 +0100316 break;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100317 }
Harald Welte805f2cf2020-12-14 17:31:03 +0100318
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200319 return USB_FND_SUCCESS;
320}
321
Harald Weltec8271852020-12-14 13:48:09 +0100322static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200323_e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
324{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100325 struct usb_e1_state *usb_e1;
326 int port;
327
328 /* Is it for E1 interface ? */
Sylvain Munautff44f142022-01-03 20:34:23 +0100329 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200330 return USB_FND_CONTINUE;
331
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100332 /* Get matching port (if any) */
333 port = _ifnum2port(base->bInterfaceNumber);
334 if (port < 0)
335 return USB_FND_ERROR;
336
337 usb_e1 = _get_state(port);
338
339 /* Return current alt-setting */
340 *alt = usb_e1->running ? 1 : 0;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200341
342 return USB_FND_SUCCESS;
343}
344
Harald Welte9469e042020-12-15 23:09:40 +0100345static bool
346_set_tx_mode_done(struct usb_xfer *xfer)
347{
348 const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config *) xfer->data;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100349 struct usb_ctrl_req *req = xfer->cb_ctx;
350 int port = _ifnum2port(req->wIndex);
351 struct usb_e1_state *usb_e1 = _get_state(port);
352 printf("set_tx_mode[%d] %02x%02x%02x%02x\r\n", port,
Harald Welte9469e042020-12-15 23:09:40 +0100353 xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100354 usb_e1->tx_cfg = *cfg;
355 _perform_tx_config(port);
Harald Welte9469e042020-12-15 23:09:40 +0100356 return true;
357}
358
359static bool
360_set_rx_mode_done(struct usb_xfer *xfer)
361{
362 const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config *) xfer->data;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100363 struct usb_ctrl_req *req = xfer->cb_ctx;
364 int port = _ifnum2port(req->wIndex);
365 struct usb_e1_state *usb_e1 = _get_state(port);
366 printf("set_rx_mode[%d] %02x\r\n", port, xfer->data[0]);
367 usb_e1->rx_cfg = *cfg;
368 _perform_rx_config(port);
Harald Welte9469e042020-12-15 23:09:40 +0100369 return true;
370}
371
372/* per-interface requests */
373static enum usb_fnd_resp
374_e1_ctrl_req_intf(struct usb_ctrl_req *req, struct usb_xfer *xfer)
375{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100376 struct usb_e1_state *usb_e1;
377 int port;
Harald Welte9469e042020-12-15 23:09:40 +0100378
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100379 /* Get matching port (if any) */
380 port = _ifnum2port(req->wIndex);
381 if (port < 0)
382 return USB_FND_CONTINUE;
383
384 usb_e1 = _get_state(port);
385
386 /* Process request */
Harald Welte9469e042020-12-15 23:09:40 +0100387 switch (req->bRequest) {
388 case ICE1USB_INTF_GET_CAPABILITIES:
389 /* no optional capabilities yet */
390 xfer->len = 0;
391 break;
392 case ICE1USB_INTF_SET_TX_CFG:
393 if (req->wLength < sizeof(struct ice1usb_tx_config))
394 return USB_FND_ERROR;
395 xfer->cb_done = _set_tx_mode_done;
396 xfer->cb_ctx = req;
397 xfer->len = sizeof(struct ice1usb_tx_config);
398 break;
399 case ICE1USB_INTF_GET_TX_CFG:
400 if (req->wLength < sizeof(struct ice1usb_tx_config))
401 return USB_FND_ERROR;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100402 memcpy(xfer->data, &usb_e1->tx_cfg, sizeof(struct ice1usb_tx_config));
Harald Welte9469e042020-12-15 23:09:40 +0100403 xfer->len = sizeof(struct ice1usb_tx_config);
404 break;
405 case ICE1USB_INTF_SET_RX_CFG:
406 if (req->wLength < sizeof(struct ice1usb_rx_config))
407 return USB_FND_ERROR;
408 xfer->cb_done = _set_rx_mode_done;
409 xfer->cb_ctx = req;
410 xfer->len = sizeof(struct ice1usb_rx_config);
411 break;
412 case ICE1USB_INTF_GET_RX_CFG:
413 if (req->wLength < sizeof(struct ice1usb_rx_config))
414 return USB_FND_ERROR;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100415 memcpy(xfer->data, &usb_e1->rx_cfg, sizeof(struct ice1usb_rx_config));
Harald Welte9469e042020-12-15 23:09:40 +0100416 xfer->len = sizeof(struct ice1usb_rx_config);
417 break;
418 default:
419 return USB_FND_ERROR;
420 }
421
422 return USB_FND_SUCCESS;
423}
424
425/* device-global requests */
426static enum usb_fnd_resp
427_e1_ctrl_req_dev(struct usb_ctrl_req *req, struct usb_xfer *xfer)
428{
429 switch (req->bRequest) {
430 case ICE1USB_DEV_GET_CAPABILITIES:
431 xfer->data[0] = (1 << ICE1USB_DEV_CAP_GPSDO);
432 xfer->len = 1;
433 break;
434 default:
435 return USB_FND_ERROR;
436 }
437
438 return USB_FND_SUCCESS;
439}
440
441
442/* USB host issues a control request to us */
443static enum usb_fnd_resp
444_e1_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
445{
446 if (USB_REQ_TYPE(req) != USB_REQ_TYPE_VENDOR)
447 return USB_FND_CONTINUE;
448
449 switch (USB_REQ_RCPT(req)) {
450 case USB_REQ_RCPT_DEV:
451 return _e1_ctrl_req_dev(req, xfer);
452 case USB_REQ_RCPT_INTF:
Harald Welte9469e042020-12-15 23:09:40 +0100453 return _e1_ctrl_req_intf(req, xfer);
454 case USB_REQ_RCPT_EP:
455 case USB_REQ_RCPT_OTHER:
456 default:
457 return USB_FND_ERROR;
458 }
459}
460
461
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200462static struct usb_fn_drv _e1_drv = {
463 .set_conf = _e1_set_conf,
464 .set_intf = _e1_set_intf,
465 .get_intf = _e1_get_intf,
Harald Welte9469e042020-12-15 23:09:40 +0100466 .ctrl_req = _e1_ctrl_req,
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200467};
468
469void
470usb_e1_init(void)
471{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100472 for (int i=0; i<2; i++) {
473 struct usb_e1_state *usb_e1 = _get_state(i);
474 memset(usb_e1, 0x00, sizeof(struct usb_e1_state));
475 usb_e1->tx_cfg = tx_cfg_default;
476 usb_e1->rx_cfg = rx_cfg_default;
477 }
478
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200479 usb_register_function_driver(&_e1_drv);
480}