blob: 4e52408a924106cc1ccf826b4c07808ac0d540fe [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
Harald Welte1b89f3b2022-01-13 10:03:42 +010098static void
99_fill_irq_err(struct ice1usb_irq_err *out, const struct e1_error_count *cur_err)
100{
101 out->crc = cur_err->crc;
102 out->align = cur_err->align;
103 out->ovfl = cur_err->ovfl;
104 out->unfl = cur_err->unfl;
105 out->flags = cur_err->flags;
106}
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200107
Sylvain Munautc9c22a62022-01-12 11:47:08 +0100108static void
109_usb_e1_run(int port)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200110{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100111 struct usb_e1_state *usb_e1 = _get_state(port);
Sylvain Munautff44f142022-01-03 20:34:23 +0100112 volatile struct usb_ep *ep_regs;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200113 int bdi;
114
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100115 if (!usb_e1->running)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200116 return;
117
Sylvain Munautff44f142022-01-03 20:34:23 +0100118 /* Interrupt endpoint */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100119 ep_regs = _get_ep_regs(USB_EP_E1_INT(port));
Sylvain Munautff44f142022-01-03 20:34:23 +0100120
121 if ((ep_regs->bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA) {
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100122 const struct e1_error_count *cur_err = e1_get_error_count(port);
123 if (memcmp(cur_err, &usb_e1->last_err, sizeof(*cur_err))) {
Harald Welte1b89f3b2022-01-13 10:03:42 +0100124 struct ice1usb_irq errmsg;
125 errmsg.type = ICE1USB_IRQ_T_ERRCNT;
126 _fill_irq_err(&errmsg.u.errors, cur_err);
Harald Welte805f2cf2020-12-14 17:31:03 +0100127 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
Sylvain Munautff44f142022-01-03 20:34:23 +0100205 /* Feedback endpoint */
Sylvain Munaut2de84f82022-01-06 08:12:04 +0100206 _usb_fill_feedback_ep(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200207}
208
Sylvain Munautc9c22a62022-01-12 11:47:08 +0100209void
210usb_e1_poll(void)
211{
212 for (int i=0; i<2; i++) {
213 e1_poll(i);
214 _usb_e1_run(i);
215 }
216}
217
218
Harald Weltec8271852020-12-14 13:48:09 +0100219static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200220_e1_set_conf(const struct usb_conf_desc *conf)
221{
222 const struct usb_intf_desc *intf;
223
224 printf("e1 set_conf %08x\n", conf);
225 if (!conf)
226 return USB_FND_SUCCESS;
227
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100228 for (int port=0; port<2; port++)
229 {
230 intf = usb_desc_find_intf(conf, USB_INTF_E1(port), 0, NULL);
231 if (!intf)
232 return USB_FND_ERROR;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200233
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100234 printf("e1 set_conf[%d] %08x\n", port, intf);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200235
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100236 usb_ep_boot(intf, USB_EP_E1_IN(port), true);
237 usb_ep_boot(intf, USB_EP_E1_OUT(port), true);
238 usb_ep_boot(intf, USB_EP_E1_FB(port), false);
239 usb_ep_boot(intf, USB_EP_E1_INT(port), false);
240 }
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200241
242 return USB_FND_SUCCESS;
243}
244
Sylvain Munautace09322022-01-10 12:41:49 +0100245static uint32_t
246_tx_config_reg(const struct ice1usb_tx_config *cfg)
Harald Welte9469e042020-12-15 23:09:40 +0100247{
Sylvain Munautace09322022-01-10 12:41:49 +0100248 return ((cfg->mode & 3) << 1) |
Sylvain Munaut3da51512022-01-03 22:12:59 +0100249 ((cfg->timing & 1) << 3) |
250 ((cfg->alarm & 1) << 4) |
Sylvain Munautace09322022-01-10 12:41:49 +0100251 ((cfg->ext_loopback & 3) << 5);
Harald Welte9469e042020-12-15 23:09:40 +0100252}
253
Sylvain Munautace09322022-01-10 12:41:49 +0100254static uint32_t
255_rx_config_reg(const struct ice1usb_rx_config *cfg)
Harald Welte9469e042020-12-15 23:09:40 +0100256{
Sylvain Munautace09322022-01-10 12:41:49 +0100257 return (cfg->mode << 1);
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 Munaut0cc16132022-01-10 13:26:15 +0100298 e1_stop(port);
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 Munaut0cc16132022-01-10 13:26:15 +0100303 e1_start(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200304
Sylvain Munaut96744362022-01-03 17:03:26 +0100305 /* Reset BDI */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100306 usb_e1->in_bdi = 0;
307 usb_e1->out_bdi = 0;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100308
Sylvain Munautff44f142022-01-03 20:34:23 +0100309 /* EP OUT: Queue two buffers */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100310 ep_regs = _get_ep_regs(USB_EP_E1_OUT(port));
Sylvain Munaut1d987092022-01-05 21:04:09 +0100311 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
312 ep_regs->bd[1].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100313
Harald Weltee6b0fe82020-12-17 22:22:05 +0100314 break;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100315 }
Harald Welte805f2cf2020-12-14 17:31:03 +0100316
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200317 return USB_FND_SUCCESS;
318}
319
Harald Weltec8271852020-12-14 13:48:09 +0100320static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200321_e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
322{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100323 struct usb_e1_state *usb_e1;
324 int port;
325
326 /* Is it for E1 interface ? */
Sylvain Munautff44f142022-01-03 20:34:23 +0100327 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200328 return USB_FND_CONTINUE;
329
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100330 /* Get matching port (if any) */
331 port = _ifnum2port(base->bInterfaceNumber);
332 if (port < 0)
333 return USB_FND_ERROR;
334
335 usb_e1 = _get_state(port);
336
337 /* Return current alt-setting */
338 *alt = usb_e1->running ? 1 : 0;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200339
340 return USB_FND_SUCCESS;
341}
342
Harald Welte9469e042020-12-15 23:09:40 +0100343static bool
344_set_tx_mode_done(struct usb_xfer *xfer)
345{
346 const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config *) xfer->data;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100347 struct usb_ctrl_req *req = xfer->cb_ctx;
348 int port = _ifnum2port(req->wIndex);
349 struct usb_e1_state *usb_e1 = _get_state(port);
350 printf("set_tx_mode[%d] %02x%02x%02x%02x\r\n", port,
Harald Welte9469e042020-12-15 23:09:40 +0100351 xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100352 usb_e1->tx_cfg = *cfg;
Sylvain Munautace09322022-01-10 12:41:49 +0100353 e1_tx_config(port, _tx_config_reg(cfg));
Harald Welte9469e042020-12-15 23:09:40 +0100354 return true;
355}
356
357static bool
358_set_rx_mode_done(struct usb_xfer *xfer)
359{
360 const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config *) xfer->data;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100361 struct usb_ctrl_req *req = xfer->cb_ctx;
362 int port = _ifnum2port(req->wIndex);
363 struct usb_e1_state *usb_e1 = _get_state(port);
364 printf("set_rx_mode[%d] %02x\r\n", port, xfer->data[0]);
365 usb_e1->rx_cfg = *cfg;
Sylvain Munautace09322022-01-10 12:41:49 +0100366 e1_rx_config(port, _rx_config_reg(cfg));
Harald Welte9469e042020-12-15 23:09:40 +0100367 return true;
368}
369
Harald Welte9469e042020-12-15 23:09:40 +0100370static enum usb_fnd_resp
Sylvain Munautcaf8cf92022-01-12 13:35:12 +0100371_e1_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
Harald Welte9469e042020-12-15 23:09:40 +0100372{
Harald Welte1b89f3b2022-01-13 10:03:42 +0100373 const struct e1_error_count *cur_err;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100374 struct usb_e1_state *usb_e1;
375 int port;
Harald Welte9469e042020-12-15 23:09:40 +0100376
Sylvain Munautcaf8cf92022-01-12 13:35:12 +0100377 /* Check it's for an E1 interface */
378 if (USB_REQ_TYPE_RCPT(req) != (USB_REQ_TYPE_VENDOR | USB_REQ_RCPT_INTF))
379 return USB_FND_CONTINUE;
380
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100381 /* Get matching port (if any) */
382 port = _ifnum2port(req->wIndex);
383 if (port < 0)
384 return USB_FND_CONTINUE;
385
386 usb_e1 = _get_state(port);
387
388 /* Process request */
Harald Welte9469e042020-12-15 23:09:40 +0100389 switch (req->bRequest) {
390 case ICE1USB_INTF_GET_CAPABILITIES:
391 /* no optional capabilities yet */
392 xfer->len = 0;
393 break;
394 case ICE1USB_INTF_SET_TX_CFG:
395 if (req->wLength < sizeof(struct ice1usb_tx_config))
396 return USB_FND_ERROR;
397 xfer->cb_done = _set_tx_mode_done;
398 xfer->cb_ctx = req;
399 xfer->len = sizeof(struct ice1usb_tx_config);
400 break;
401 case ICE1USB_INTF_GET_TX_CFG:
402 if (req->wLength < sizeof(struct ice1usb_tx_config))
403 return USB_FND_ERROR;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100404 memcpy(xfer->data, &usb_e1->tx_cfg, sizeof(struct ice1usb_tx_config));
Harald Welte9469e042020-12-15 23:09:40 +0100405 xfer->len = sizeof(struct ice1usb_tx_config);
406 break;
407 case ICE1USB_INTF_SET_RX_CFG:
408 if (req->wLength < sizeof(struct ice1usb_rx_config))
409 return USB_FND_ERROR;
410 xfer->cb_done = _set_rx_mode_done;
411 xfer->cb_ctx = req;
412 xfer->len = sizeof(struct ice1usb_rx_config);
413 break;
414 case ICE1USB_INTF_GET_RX_CFG:
415 if (req->wLength < sizeof(struct ice1usb_rx_config))
416 return USB_FND_ERROR;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100417 memcpy(xfer->data, &usb_e1->rx_cfg, sizeof(struct ice1usb_rx_config));
Harald Welte9469e042020-12-15 23:09:40 +0100418 xfer->len = sizeof(struct ice1usb_rx_config);
419 break;
Harald Welte1b89f3b2022-01-13 10:03:42 +0100420 case ICE1USB_INTF_GET_ERRORS:
421 if (req->wLength < sizeof(struct ice1usb_irq_err))
422 return USB_FND_ERROR;
423 cur_err = e1_get_error_count(port);
424 _fill_irq_err((struct ice1usb_irq_err *)xfer->data, cur_err);
425 xfer->len = sizeof(struct ice1usb_irq_err);
426 break;
Harald Welte9469e042020-12-15 23:09:40 +0100427 default:
428 return USB_FND_ERROR;
429 }
430
431 return USB_FND_SUCCESS;
432}
433
Harald Welte9469e042020-12-15 23:09:40 +0100434
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200435static struct usb_fn_drv _e1_drv = {
436 .set_conf = _e1_set_conf,
437 .set_intf = _e1_set_intf,
438 .get_intf = _e1_get_intf,
Harald Welte9469e042020-12-15 23:09:40 +0100439 .ctrl_req = _e1_ctrl_req,
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200440};
441
442void
443usb_e1_init(void)
444{
Sylvain Munaut0cc16132022-01-10 13:26:15 +0100445 uint32_t rx_cr = _rx_config_reg(&rx_cfg_default);
446 uint32_t tx_cr = _tx_config_reg(&tx_cfg_default);
447
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100448 for (int i=0; i<2; i++) {
449 struct usb_e1_state *usb_e1 = _get_state(i);
450 memset(usb_e1, 0x00, sizeof(struct usb_e1_state));
451 usb_e1->tx_cfg = tx_cfg_default;
452 usb_e1->rx_cfg = rx_cfg_default;
Sylvain Munaut0cc16132022-01-10 13:26:15 +0100453 e1_init(i, rx_cr, tx_cr);
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100454 }
455
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200456 usb_register_function_driver(&_e1_drv);
457}