blob: a18ebe439f08b86bfa42103c63f70f4224e85802 [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{
77 static uint16_t ticks_prev = 0;
78 uint16_t ticks;
79 uint32_t val = 8192;
80 unsigned int level;
Sylvain Munautff44f142022-01-03 20:34:23 +010081 volatile struct usb_ep *ep_regs;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020082
Harald Welte2b7dadf2020-12-14 15:56:15 +010083 /* Compute real E1 tick count (with safety against bad values) */
Sylvain Munaut41c98b62022-01-05 21:11:35 +010084 ticks = e1_tick_read(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020085 val = (ticks - ticks_prev) & 0xffff;
86 ticks_prev = ticks;
87 if ((val < 7168) | (val > 9216))
88 val = 8192;
89
90 /* Bias depending on TX fifo level */
Sylvain Munaut41c98b62022-01-05 21:11:35 +010091 level = e1_tx_level(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020092 if (level < (3 * 16))
93 val += 256;
94 else if (level > (8 * 16))
95 val -= 256;
96
97 /* Prepare buffer */
Sylvain Munaut41c98b62022-01-05 21:11:35 +010098 ep_regs = _get_ep_regs(USB_EP_E1_FB(port));
Sylvain Munautff44f142022-01-03 20:34:23 +010099 usb_data_write(ep_regs->bd[0].ptr, &val, 4);
100 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(3);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200101}
102
103
104void
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100105usb_e1_run(int port)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200106{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100107 struct usb_e1_state *usb_e1 = _get_state(port);
Sylvain Munautff44f142022-01-03 20:34:23 +0100108 volatile struct usb_ep *ep_regs;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200109 int bdi;
110
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100111 if (!usb_e1->running)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200112 return;
113
Sylvain Munautff44f142022-01-03 20:34:23 +0100114 /* Interrupt endpoint */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100115 ep_regs = _get_ep_regs(USB_EP_E1_INT(port));
Sylvain Munautff44f142022-01-03 20:34:23 +0100116
117 if ((ep_regs->bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA) {
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100118 const struct e1_error_count *cur_err = e1_get_error_count(port);
119 if (memcmp(cur_err, &usb_e1->last_err, sizeof(*cur_err))) {
Harald Welte805f2cf2020-12-14 17:31:03 +0100120 struct ice1usb_irq errmsg = {
121 .type = ICE1USB_IRQ_T_ERRCNT,
122 .u = {
123 .errors = {
124 .crc = cur_err->crc,
125 .align = cur_err->align,
126 .ovfl = cur_err->ovfl,
127 .unfl = cur_err->unfl,
128 .flags = cur_err->flags,
129 }
130 }
131 };
132 printf("E");
Sylvain Munautff44f142022-01-03 20:34:23 +0100133 usb_data_write(ep_regs->bd[0].ptr, &errmsg, sizeof(errmsg));
134 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(sizeof(errmsg));
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100135 usb_e1->last_err = *cur_err;
Harald Welte805f2cf2020-12-14 17:31:03 +0100136 }
137 }
138
Sylvain Munautff44f142022-01-03 20:34:23 +0100139 /* Data IN endpoint */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100140 ep_regs = _get_ep_regs(USB_EP_E1_IN(port));
141 bdi = usb_e1->in_bdi;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200142
Sylvain Munautff44f142022-01-03 20:34:23 +0100143 while ((ep_regs->bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200144 {
Sylvain Munautff44f142022-01-03 20:34:23 +0100145 uint32_t ptr = ep_regs->bd[bdi].ptr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200146 uint32_t hdr;
Harald Welte2df1f802020-12-14 17:46:53 +0100147 unsigned int pos;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200148
149 /* Error check */
Sylvain Munautff44f142022-01-03 20:34:23 +0100150 if ((ep_regs->bd[bdi].csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR)
151 puts("Err EP IN\n");
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200152
153 /* Get some data from E1 */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100154 int n = e1_rx_level(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200155
Sylvain Munaut1d987092022-01-05 21:04:09 +0100156 if (n > 32)
157 n = 9;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200158 else if (n > 8)
159 n = 8;
160 else if (!n)
161 break;
162
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100163 n = e1_rx_need_data(port, (ptr >> 2) + 1, n, &pos);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200164
Harald Welte2df1f802020-12-14 17:46:53 +0100165 /* Write header: currently version and pos (mfr/fr number) */
166 hdr = (0 << 28) | (pos & 0xff);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200167 usb_data_write(ptr, &hdr, 4);
168
169 /* Resubmit */
Sylvain Munautff44f142022-01-03 20:34:23 +0100170 ep_regs->bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN((n * 32) + 4);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200171
172 /* Next BDI */
173 bdi ^= 1;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100174 usb_e1->in_bdi = bdi;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200175 }
176
Sylvain Munautff44f142022-01-03 20:34:23 +0100177 /* Data OUT endpoint */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100178 ep_regs = _get_ep_regs(USB_EP_E1_OUT(port));
179 bdi = usb_e1->out_bdi;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200180
Sylvain Munautff44f142022-01-03 20:34:23 +0100181 while ((ep_regs->bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200182 {
Sylvain Munautff44f142022-01-03 20:34:23 +0100183 uint32_t ptr = ep_regs->bd[bdi].ptr;
184 uint32_t csr = ep_regs->bd[bdi].csr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200185 uint32_t hdr;
186
187 /* Error check */
188 if ((csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR) {
Sylvain Munautff44f142022-01-03 20:34:23 +0100189 puts("Err EP OUT\n");
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200190 goto refill;
191 }
192
193 /* Grab header */
194 usb_data_read(&hdr, ptr, 4);
195
196 /* Empty data into the FIFO */
Sylvain Munautd108dfb2022-01-03 21:11:05 +0100197 int n = ((int)(csr & USB_BD_LEN_MSK) - 6) / 32;
198 if (n > 0)
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100199 e1_tx_feed_data(port, (ptr >> 2) + 1, n);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200200
201refill:
202 /* Refill it */
Sylvain Munaut1d987092022-01-05 21:04:09 +0100203 ep_regs->bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200204
205 /* Next BDI */
206 bdi ^= 1;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100207 usb_e1->out_bdi = bdi;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200208
209 static int x = 0;
210 if ((x++ & 0xff) == 0xff)
211 puts(".");
212 }
213
Sylvain Munautff44f142022-01-03 20:34:23 +0100214 /* Feedback endpoint */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100215 ep_regs = _get_ep_regs(USB_EP_E1_FB(port));
Sylvain Munautff44f142022-01-03 20:34:23 +0100216
217 if ((ep_regs->bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200218 {
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100219 _usb_fill_feedback_ep(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200220 }
221}
222
Harald Weltec8271852020-12-14 13:48:09 +0100223static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200224_e1_set_conf(const struct usb_conf_desc *conf)
225{
226 const struct usb_intf_desc *intf;
227
228 printf("e1 set_conf %08x\n", conf);
229 if (!conf)
230 return USB_FND_SUCCESS;
231
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100232 for (int port=0; port<2; port++)
233 {
234 intf = usb_desc_find_intf(conf, USB_INTF_E1(port), 0, NULL);
235 if (!intf)
236 return USB_FND_ERROR;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200237
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100238 printf("e1 set_conf[%d] %08x\n", port, intf);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200239
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100240 usb_ep_boot(intf, USB_EP_E1_IN(port), true);
241 usb_ep_boot(intf, USB_EP_E1_OUT(port), true);
242 usb_ep_boot(intf, USB_EP_E1_FB(port), false);
243 usb_ep_boot(intf, USB_EP_E1_INT(port), false);
244 }
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200245
246 return USB_FND_SUCCESS;
247}
248
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100249static void _perform_tx_config(int port)
Harald Welte9469e042020-12-15 23:09:40 +0100250{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100251 struct usb_e1_state *usb_e1 = _get_state(port);
252 const struct ice1usb_tx_config *cfg = &usb_e1->tx_cfg;
253 e1_tx_config(port,
Sylvain Munaut3da51512022-01-03 22:12:59 +0100254 ((cfg->mode & 3) << 1) |
255 ((cfg->timing & 1) << 3) |
256 ((cfg->alarm & 1) << 4) |
257 ((cfg->ext_loopback & 3) << 5)
258 );
Harald Welte9469e042020-12-15 23:09:40 +0100259}
260
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100261static void _perform_rx_config(int port)
Harald Welte9469e042020-12-15 23:09:40 +0100262{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100263 struct usb_e1_state *usb_e1 = _get_state(port);
264 const struct ice1usb_rx_config *cfg = &usb_e1->rx_cfg;
265 e1_rx_config(port,
Sylvain Munaut3da51512022-01-03 22:12:59 +0100266 (cfg->mode << 1)
267 );
Harald Welte9469e042020-12-15 23:09:40 +0100268}
269
Harald Weltec8271852020-12-14 13:48:09 +0100270static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200271_e1_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
272{
Sylvain Munautff44f142022-01-03 20:34:23 +0100273 volatile struct usb_ep *ep_regs;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100274 struct usb_e1_state *usb_e1;
275 int port;
Sylvain Munautff44f142022-01-03 20:34:23 +0100276
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100277 /* Is it for E1 interface ? */
Sylvain Munautff44f142022-01-03 20:34:23 +0100278 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200279 return USB_FND_CONTINUE;
280
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100281 /* Get matching port (if any) */
282 port = _ifnum2port(base->bInterfaceNumber);
283 if (port < 0)
284 return USB_FND_ERROR;
285
286 usb_e1 = _get_state(port);
287
288 /* Valid setting ? */
Sylvain Munaut96744362022-01-03 17:03:26 +0100289 if (sel->bAlternateSetting > 1)
290 return USB_FND_ERROR;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200291
Sylvain Munaut96744362022-01-03 17:03:26 +0100292 /* Don't do anything if no change */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100293 if (usb_e1->running == (sel->bAlternateSetting != 0))
Sylvain Munaut96744362022-01-03 17:03:26 +0100294 return USB_FND_SUCCESS;
295
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100296 usb_e1->running = (sel->bAlternateSetting != 0);
Sylvain Munaut96744362022-01-03 17:03:26 +0100297
298 /* Reconfigure the endpoints */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100299 usb_ep_reconf(sel, USB_EP_E1_IN(port));
300 usb_ep_reconf(sel, USB_EP_E1_OUT(port));
301 usb_ep_reconf(sel, USB_EP_E1_FB(port));
302 usb_ep_reconf(sel, USB_EP_E1_INT(port));
Sylvain Munaut96744362022-01-03 17:03:26 +0100303
304 /* Update E1 and USB state */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100305 switch (usb_e1->running) {
Sylvain Munaut96744362022-01-03 17:03:26 +0100306 case false:
307 /* Disable E1 rx/tx */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100308 e1_init(port, 0, 0);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100309 break;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200310
Sylvain Munaut96744362022-01-03 17:03:26 +0100311 case true:
312 /* Reset and Re-Enable E1 */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100313 e1_init(port, 0, 0);
314 _perform_rx_config(port);
315 _perform_tx_config(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200316
Sylvain Munaut96744362022-01-03 17:03:26 +0100317 /* Reset BDI */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100318 usb_e1->in_bdi = 0;
319 usb_e1->out_bdi = 0;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100320
Sylvain Munautff44f142022-01-03 20:34:23 +0100321 /* EP OUT: Queue two buffers */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100322 ep_regs = _get_ep_regs(USB_EP_E1_OUT(port));
Sylvain Munaut1d987092022-01-05 21:04:09 +0100323 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
324 ep_regs->bd[1].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100325
Sylvain Munautff44f142022-01-03 20:34:23 +0100326 /* EP Feedback: Pre-fill */
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100327 _usb_fill_feedback_ep(port);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100328
Harald Weltee6b0fe82020-12-17 22:22:05 +0100329 break;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100330 }
Harald Welte805f2cf2020-12-14 17:31:03 +0100331
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200332 return USB_FND_SUCCESS;
333}
334
Harald Weltec8271852020-12-14 13:48:09 +0100335static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200336_e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
337{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100338 struct usb_e1_state *usb_e1;
339 int port;
340
341 /* Is it for E1 interface ? */
Sylvain Munautff44f142022-01-03 20:34:23 +0100342 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200343 return USB_FND_CONTINUE;
344
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100345 /* Get matching port (if any) */
346 port = _ifnum2port(base->bInterfaceNumber);
347 if (port < 0)
348 return USB_FND_ERROR;
349
350 usb_e1 = _get_state(port);
351
352 /* Return current alt-setting */
353 *alt = usb_e1->running ? 1 : 0;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200354
355 return USB_FND_SUCCESS;
356}
357
Harald Welte9469e042020-12-15 23:09:40 +0100358static bool
359_set_tx_mode_done(struct usb_xfer *xfer)
360{
361 const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config *) xfer->data;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100362 struct usb_ctrl_req *req = xfer->cb_ctx;
363 int port = _ifnum2port(req->wIndex);
364 struct usb_e1_state *usb_e1 = _get_state(port);
365 printf("set_tx_mode[%d] %02x%02x%02x%02x\r\n", port,
Harald Welte9469e042020-12-15 23:09:40 +0100366 xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100367 usb_e1->tx_cfg = *cfg;
368 _perform_tx_config(port);
Harald Welte9469e042020-12-15 23:09:40 +0100369 return true;
370}
371
372static bool
373_set_rx_mode_done(struct usb_xfer *xfer)
374{
375 const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config *) xfer->data;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100376 struct usb_ctrl_req *req = xfer->cb_ctx;
377 int port = _ifnum2port(req->wIndex);
378 struct usb_e1_state *usb_e1 = _get_state(port);
379 printf("set_rx_mode[%d] %02x\r\n", port, xfer->data[0]);
380 usb_e1->rx_cfg = *cfg;
381 _perform_rx_config(port);
Harald Welte9469e042020-12-15 23:09:40 +0100382 return true;
383}
384
385/* per-interface requests */
386static enum usb_fnd_resp
387_e1_ctrl_req_intf(struct usb_ctrl_req *req, struct usb_xfer *xfer)
388{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100389 struct usb_e1_state *usb_e1;
390 int port;
Harald Welte9469e042020-12-15 23:09:40 +0100391
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100392 /* Get matching port (if any) */
393 port = _ifnum2port(req->wIndex);
394 if (port < 0)
395 return USB_FND_CONTINUE;
396
397 usb_e1 = _get_state(port);
398
399 /* Process request */
Harald Welte9469e042020-12-15 23:09:40 +0100400 switch (req->bRequest) {
401 case ICE1USB_INTF_GET_CAPABILITIES:
402 /* no optional capabilities yet */
403 xfer->len = 0;
404 break;
405 case ICE1USB_INTF_SET_TX_CFG:
406 if (req->wLength < sizeof(struct ice1usb_tx_config))
407 return USB_FND_ERROR;
408 xfer->cb_done = _set_tx_mode_done;
409 xfer->cb_ctx = req;
410 xfer->len = sizeof(struct ice1usb_tx_config);
411 break;
412 case ICE1USB_INTF_GET_TX_CFG:
413 if (req->wLength < sizeof(struct ice1usb_tx_config))
414 return USB_FND_ERROR;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100415 memcpy(xfer->data, &usb_e1->tx_cfg, sizeof(struct ice1usb_tx_config));
Harald Welte9469e042020-12-15 23:09:40 +0100416 xfer->len = sizeof(struct ice1usb_tx_config);
417 break;
418 case ICE1USB_INTF_SET_RX_CFG:
419 if (req->wLength < sizeof(struct ice1usb_rx_config))
420 return USB_FND_ERROR;
421 xfer->cb_done = _set_rx_mode_done;
422 xfer->cb_ctx = req;
423 xfer->len = sizeof(struct ice1usb_rx_config);
424 break;
425 case ICE1USB_INTF_GET_RX_CFG:
426 if (req->wLength < sizeof(struct ice1usb_rx_config))
427 return USB_FND_ERROR;
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100428 memcpy(xfer->data, &usb_e1->rx_cfg, sizeof(struct ice1usb_rx_config));
Harald Welte9469e042020-12-15 23:09:40 +0100429 xfer->len = sizeof(struct ice1usb_rx_config);
430 break;
431 default:
432 return USB_FND_ERROR;
433 }
434
435 return USB_FND_SUCCESS;
436}
437
438/* device-global requests */
439static enum usb_fnd_resp
440_e1_ctrl_req_dev(struct usb_ctrl_req *req, struct usb_xfer *xfer)
441{
442 switch (req->bRequest) {
443 case ICE1USB_DEV_GET_CAPABILITIES:
444 xfer->data[0] = (1 << ICE1USB_DEV_CAP_GPSDO);
445 xfer->len = 1;
446 break;
447 default:
448 return USB_FND_ERROR;
449 }
450
451 return USB_FND_SUCCESS;
452}
453
454
455/* USB host issues a control request to us */
456static enum usb_fnd_resp
457_e1_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
458{
459 if (USB_REQ_TYPE(req) != USB_REQ_TYPE_VENDOR)
460 return USB_FND_CONTINUE;
461
462 switch (USB_REQ_RCPT(req)) {
463 case USB_REQ_RCPT_DEV:
464 return _e1_ctrl_req_dev(req, xfer);
465 case USB_REQ_RCPT_INTF:
Harald Welte9469e042020-12-15 23:09:40 +0100466 return _e1_ctrl_req_intf(req, xfer);
467 case USB_REQ_RCPT_EP:
468 case USB_REQ_RCPT_OTHER:
469 default:
470 return USB_FND_ERROR;
471 }
472}
473
474
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200475static struct usb_fn_drv _e1_drv = {
476 .set_conf = _e1_set_conf,
477 .set_intf = _e1_set_intf,
478 .get_intf = _e1_get_intf,
Harald Welte9469e042020-12-15 23:09:40 +0100479 .ctrl_req = _e1_ctrl_req,
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200480};
481
482void
483usb_e1_init(void)
484{
Sylvain Munaut41c98b62022-01-05 21:11:35 +0100485 for (int i=0; i<2; i++) {
486 struct usb_e1_state *usb_e1 = _get_state(i);
487 memset(usb_e1, 0x00, sizeof(struct usb_e1_state));
488 usb_e1->tx_cfg = tx_cfg_default;
489 usb_e1->rx_cfg = rx_cfg_default;
490 }
491
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200492 usb_register_function_driver(&_e1_drv);
493}