1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /*
29 * Comm Class spec: http://www.usb.org/developers/devclass_docs/usbccs10.pdf
30 * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
31 * http://www.usb.org/developers/devclass_docs/cdc_wmc10.zip
32 */
33
34 #include <sys/param.h>
35 #include <sys/stdint.h>
36 #include <sys/stddef.h>
37 #include <sys/queue.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/bus.h>
41 #include <sys/linker_set.h>
42 #include <sys/module.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/condvar.h>
46 #include <sys/sysctl.h>
47 #include <sys/sx.h>
48 #include <sys/unistd.h>
49 #include <sys/callout.h>
50 #include <sys/malloc.h>
51 #include <sys/priv.h>
52
53 #include <dev/usb/usb.h>
54 #include <dev/usb/usb_cdc.h>
55 #include <dev/usb/usbdi.h>
56 #include <dev/usb/usbdi_util.h>
57 #include <dev/usb/usbhid.h>
58 #include "usb_if.h"
59
60 #define USB_DEBUG_VAR g_modem_debug
61 #include <dev/usb/usb_debug.h>
62
63 #include <dev/usb/gadget/g_modem.h>
64
65 enum {
66 G_MODEM_INTR_DT,
67 G_MODEM_BULK_RD,
68 G_MODEM_BULK_WR,
69 G_MODEM_N_TRANSFER,
70 };
71
72 struct g_modem_softc {
73 struct mtx sc_mtx;
74 struct usb_callout sc_callout;
75 struct usb_callout sc_watchdog;
76 struct usb_xfer *sc_xfer[G_MODEM_N_TRANSFER];
77
78 int sc_mode;
79 int sc_tx_busy;
80 int sc_pattern_len;
81 int sc_throughput;
82 int sc_tx_interval;
83
84 char sc_pattern[G_MODEM_MAX_STRLEN];
85
86 uint16_t sc_data_len;
87
88 uint8_t sc_data_buf[G_MODEM_BUFSIZE];
89 uint8_t sc_line_coding[32];
90 uint8_t sc_abstract_state[32];
91 };
92
93 static SYSCTL_NODE(_hw_usb, OID_AUTO, g_modem, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
94 "USB modem gadget");
95
96 #ifdef USB_DEBUG
97 static int g_modem_debug = 0;
98
99 SYSCTL_INT(_hw_usb_g_modem, OID_AUTO, debug, CTLFLAG_RWTUN,
100 &g_modem_debug, 0, "Debug level");
101 #endif
102
103 static int g_modem_mode = 0;
104
105 SYSCTL_INT(_hw_usb_g_modem, OID_AUTO, mode, CTLFLAG_RWTUN,
106 &g_modem_mode, 0, "Mode selection");
107
108 static int g_modem_pattern_interval = 1000;
109
110 SYSCTL_INT(_hw_usb_g_modem, OID_AUTO, pattern_interval, CTLFLAG_RWTUN,
111 &g_modem_pattern_interval, 0, "Pattern interval in milliseconds");
112
113 static char g_modem_pattern_data[G_MODEM_MAX_STRLEN];
114
115 SYSCTL_STRING(_hw_usb_g_modem, OID_AUTO, pattern, CTLFLAG_RW,
116 &g_modem_pattern_data, sizeof(g_modem_pattern_data), "Data pattern");
117
118 static int g_modem_throughput;
119
120 SYSCTL_INT(_hw_usb_g_modem, OID_AUTO, throughput, CTLFLAG_RD,
121 &g_modem_throughput, sizeof(g_modem_throughput), "Throughput in bytes per second");
122
123 static device_probe_t g_modem_probe;
124 static device_attach_t g_modem_attach;
125 static device_detach_t g_modem_detach;
126 static usb_handle_request_t g_modem_handle_request;
127 static usb_callback_t g_modem_intr_callback;
128 static usb_callback_t g_modem_bulk_read_callback;
129 static usb_callback_t g_modem_bulk_write_callback;
130
131 static void g_modem_timeout(void *arg);
132
133 static device_method_t g_modem_methods[] = {
134 /* USB interface */
135 DEVMETHOD(usb_handle_request, g_modem_handle_request),
136
137 /* Device interface */
138 DEVMETHOD(device_probe, g_modem_probe),
139 DEVMETHOD(device_attach, g_modem_attach),
140 DEVMETHOD(device_detach, g_modem_detach),
141
142 DEVMETHOD_END
143 };
144
145 static driver_t g_modem_driver = {
146 .name = "g_modem",
147 .methods = g_modem_methods,
148 .size = sizeof(struct g_modem_softc),
149 };
150
151 DRIVER_MODULE(g_modem, uhub, g_modem_driver, 0, 0);
152 MODULE_DEPEND(g_modem, usb, 1, 1, 1);
153
154 static const struct usb_config g_modem_config[G_MODEM_N_TRANSFER] = {
155 [G_MODEM_INTR_DT] = {
156 .type = UE_INTERRUPT,
157 .endpoint = UE_ADDR_ANY,
158 .direction = UE_DIR_TX,
159 .flags = {.ext_buffer = 1,.pipe_bof = 1,},
160 .bufsize = 0, /* use wMaxPacketSize */
161 .callback = &g_modem_intr_callback,
162 .frames = 1,
163 .usb_mode = USB_MODE_DEVICE,
164 .if_index = 0,
165 },
166
167 [G_MODEM_BULK_RD] = {
168 .type = UE_BULK,
169 .endpoint = UE_ADDR_ANY,
170 .direction = UE_DIR_RX,
171 .flags = {.ext_buffer = 1,.pipe_bof = 1,.short_xfer_ok = 1,},
172 .bufsize = G_MODEM_BUFSIZE,
173 .callback = &g_modem_bulk_read_callback,
174 .frames = 1,
175 .usb_mode = USB_MODE_DEVICE,
176 .if_index = 1,
177 },
178
179 [G_MODEM_BULK_WR] = {
180 .type = UE_BULK,
181 .endpoint = UE_ADDR_ANY,
182 .direction = UE_DIR_TX,
183 .flags = {.ext_buffer = 1,.pipe_bof = 1,},
184 .bufsize = G_MODEM_BUFSIZE,
185 .callback = &g_modem_bulk_write_callback,
186 .frames = 1,
187 .usb_mode = USB_MODE_DEVICE,
188 .if_index = 1,
189 },
190 };
191
192 static void
g_modem_timeout_reset(struct g_modem_softc * sc)193 g_modem_timeout_reset(struct g_modem_softc *sc)
194 {
195 int i = g_modem_pattern_interval;
196
197 sc->sc_tx_interval = i;
198
199 if (i <= 0)
200 i = 1;
201 else if (i > 1023)
202 i = 1023;
203
204 i = USB_MS_TO_TICKS(i);
205
206 usb_callout_reset(&sc->sc_callout, i, &g_modem_timeout, sc);
207 }
208
209 static void
g_modem_timeout(void * arg)210 g_modem_timeout(void *arg)
211 {
212 struct g_modem_softc *sc = arg;
213
214 sc->sc_mode = g_modem_mode;
215
216 memcpy(sc->sc_pattern, g_modem_pattern_data, sizeof(sc->sc_pattern));
217
218 sc->sc_pattern[G_MODEM_MAX_STRLEN - 1] = 0;
219
220 sc->sc_pattern_len = strlen(sc->sc_pattern);
221
222 DPRINTFN(11, "Timeout %p\n", sc->sc_xfer[G_MODEM_INTR_DT]);
223
224 usbd_transfer_start(sc->sc_xfer[G_MODEM_BULK_WR]);
225 usbd_transfer_start(sc->sc_xfer[G_MODEM_BULK_RD]);
226
227 g_modem_timeout_reset(sc);
228 }
229
230 static void g_modem_watchdog(void *arg);
231
232 static void
g_modem_watchdog_reset(struct g_modem_softc * sc)233 g_modem_watchdog_reset(struct g_modem_softc *sc)
234 {
235 usb_callout_reset(&sc->sc_watchdog, hz, &g_modem_watchdog, sc);
236 }
237
238 static void
g_modem_watchdog(void * arg)239 g_modem_watchdog(void *arg)
240 {
241 struct g_modem_softc *sc = arg;
242 int i;
243
244 i = sc->sc_throughput;
245
246 sc->sc_throughput = 0;
247
248 g_modem_throughput = i;
249
250 g_modem_watchdog_reset(sc);
251 }
252
253 static int
g_modem_probe(device_t dev)254 g_modem_probe(device_t dev)
255 {
256 struct usb_attach_arg *uaa = device_get_ivars(dev);
257
258 DPRINTFN(11, "\n");
259
260 if (uaa->usb_mode != USB_MODE_DEVICE)
261 return (ENXIO);
262
263 if ((uaa->info.bInterfaceClass == UICLASS_CDC) &&
264 (uaa->info.bInterfaceSubClass == UISUBCLASS_ABSTRACT_CONTROL_MODEL) &&
265 (uaa->info.bInterfaceProtocol == UIPROTO_CDC_AT))
266 return (0);
267
268 return (ENXIO);
269 }
270
271 static int
g_modem_attach(device_t dev)272 g_modem_attach(device_t dev)
273 {
274 struct g_modem_softc *sc = device_get_softc(dev);
275 struct usb_attach_arg *uaa = device_get_ivars(dev);
276 int error;
277 uint8_t iface_index[2];
278
279 DPRINTFN(11, "\n");
280
281 device_set_usb_desc(dev);
282
283 mtx_init(&sc->sc_mtx, "g_modem", NULL, MTX_DEF);
284
285 usb_callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0);
286 usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0);
287
288 sc->sc_mode = G_MODEM_MODE_SILENT;
289
290 iface_index[0] = uaa->info.bIfaceIndex;
291 iface_index[1] = uaa->info.bIfaceIndex + 1;
292
293 error = usbd_transfer_setup(uaa->device,
294 iface_index, sc->sc_xfer, g_modem_config,
295 G_MODEM_N_TRANSFER, sc, &sc->sc_mtx);
296
297 if (error) {
298 DPRINTF("error=%s\n", usbd_errstr(error));
299 goto detach;
300 }
301 usbd_set_parent_iface(uaa->device, iface_index[1], iface_index[0]);
302
303 mtx_lock(&sc->sc_mtx);
304 g_modem_timeout_reset(sc);
305 g_modem_watchdog_reset(sc);
306 mtx_unlock(&sc->sc_mtx);
307
308 return (0); /* success */
309
310 detach:
311 g_modem_detach(dev);
312
313 return (ENXIO); /* error */
314 }
315
316 static int
g_modem_detach(device_t dev)317 g_modem_detach(device_t dev)
318 {
319 struct g_modem_softc *sc = device_get_softc(dev);
320
321 DPRINTF("\n");
322
323 mtx_lock(&sc->sc_mtx);
324 usb_callout_stop(&sc->sc_callout);
325 usb_callout_stop(&sc->sc_watchdog);
326 mtx_unlock(&sc->sc_mtx);
327
328 usbd_transfer_unsetup(sc->sc_xfer, G_MODEM_N_TRANSFER);
329
330 usb_callout_drain(&sc->sc_callout);
331 usb_callout_drain(&sc->sc_watchdog);
332
333 mtx_destroy(&sc->sc_mtx);
334
335 return (0);
336 }
337
338 static void
g_modem_intr_callback(struct usb_xfer * xfer,usb_error_t error)339 g_modem_intr_callback(struct usb_xfer *xfer, usb_error_t error)
340 {
341 int actlen;
342 int aframes;
343
344 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
345
346 DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
347 USB_GET_STATE(xfer), aframes, actlen);
348
349 switch (USB_GET_STATE(xfer)) {
350 case USB_ST_TRANSFERRED:
351 break;
352
353 case USB_ST_SETUP:
354 tr_setup:
355 break;
356
357 default: /* Error */
358 DPRINTF("error=%s\n", usbd_errstr(error));
359
360 if (error != USB_ERR_CANCELLED) {
361 /* try to clear stall first */
362 usbd_xfer_set_stall(xfer);
363 goto tr_setup;
364 }
365 break;
366 }
367 }
368
369 static void
g_modem_bulk_write_callback(struct usb_xfer * xfer,usb_error_t error)370 g_modem_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
371 {
372 struct g_modem_softc *sc = usbd_xfer_softc(xfer);
373 int actlen;
374 int aframes;
375 int mod;
376 int x;
377 int max;
378
379 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
380
381 DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
382 USB_GET_STATE(xfer), aframes, actlen);
383
384 switch (USB_GET_STATE(xfer)) {
385 case USB_ST_TRANSFERRED:
386
387 sc->sc_tx_busy = 0;
388 sc->sc_throughput += actlen;
389
390 if (sc->sc_mode == G_MODEM_MODE_LOOP) {
391 /* start loop */
392 usbd_transfer_start(sc->sc_xfer[G_MODEM_BULK_RD]);
393 break;
394 } else if ((sc->sc_mode == G_MODEM_MODE_PATTERN) && (sc->sc_tx_interval != 0)) {
395 /* wait for next timeout */
396 break;
397 }
398 case USB_ST_SETUP:
399 tr_setup:
400 if (sc->sc_mode == G_MODEM_MODE_PATTERN) {
401 mod = sc->sc_pattern_len;
402 max = sc->sc_tx_interval ? mod : G_MODEM_BUFSIZE;
403
404 if (mod == 0) {
405 for (x = 0; x != max; x++)
406 sc->sc_data_buf[x] = x % 255;
407 } else {
408 for (x = 0; x != max; x++)
409 sc->sc_data_buf[x] = sc->sc_pattern[x % mod];
410 }
411
412 usbd_xfer_set_frame_data(xfer, 0, sc->sc_data_buf, max);
413 usbd_xfer_set_interval(xfer, 0);
414 usbd_xfer_set_frames(xfer, 1);
415 usbd_transfer_submit(xfer);
416
417 } else if (sc->sc_mode == G_MODEM_MODE_LOOP) {
418 if (sc->sc_tx_busy == 0)
419 break;
420
421 x = sc->sc_tx_interval;
422
423 if (x < 0)
424 x = 0;
425 else if (x > 256)
426 x = 256;
427
428 usbd_xfer_set_frame_data(xfer, 0, sc->sc_data_buf, sc->sc_data_len);
429 usbd_xfer_set_interval(xfer, x);
430 usbd_xfer_set_frames(xfer, 1);
431 usbd_transfer_submit(xfer);
432 } else {
433 sc->sc_tx_busy = 0;
434 }
435 break;
436
437 default: /* Error */
438 DPRINTF("error=%s\n", usbd_errstr(error));
439
440 if (error != USB_ERR_CANCELLED) {
441 /* try to clear stall first */
442 usbd_xfer_set_stall(xfer);
443 goto tr_setup;
444 }
445 break;
446 }
447 }
448
449 static void
g_modem_bulk_read_callback(struct usb_xfer * xfer,usb_error_t error)450 g_modem_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
451 {
452 struct g_modem_softc *sc = usbd_xfer_softc(xfer);
453 int actlen;
454 int aframes;
455
456 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
457
458 DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
459 USB_GET_STATE(xfer), aframes, actlen);
460
461 switch (USB_GET_STATE(xfer)) {
462 case USB_ST_TRANSFERRED:
463
464 sc->sc_throughput += actlen;
465
466 if (sc->sc_mode == G_MODEM_MODE_LOOP) {
467 sc->sc_tx_busy = 1;
468 sc->sc_data_len = actlen;
469 usbd_transfer_start(sc->sc_xfer[G_MODEM_BULK_WR]);
470 break;
471 }
472
473 case USB_ST_SETUP:
474 tr_setup:
475 if ((sc->sc_mode == G_MODEM_MODE_SILENT) ||
476 (sc->sc_tx_busy != 0))
477 break;
478
479 usbd_xfer_set_frame_data(xfer, 0, sc->sc_data_buf, G_MODEM_BUFSIZE);
480 usbd_xfer_set_frames(xfer, 1);
481 usbd_transfer_submit(xfer);
482 break;
483
484 default: /* Error */
485 DPRINTF("error=%s\n", usbd_errstr(error));
486
487 if (error != USB_ERR_CANCELLED) {
488 /* try to clear stall first */
489 usbd_xfer_set_stall(xfer);
490 goto tr_setup;
491 }
492 break;
493 }
494 }
495
496 static int
g_modem_handle_request(device_t dev,const void * preq,void ** pptr,uint16_t * plen,uint16_t offset,uint8_t * pstate)497 g_modem_handle_request(device_t dev,
498 const void *preq, void **pptr, uint16_t *plen,
499 uint16_t offset, uint8_t *pstate)
500 {
501 struct g_modem_softc *sc = device_get_softc(dev);
502 const struct usb_device_request *req = preq;
503 uint8_t is_complete = *pstate;
504
505 if (!is_complete) {
506 if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
507 (req->bRequest == UCDC_SET_LINE_CODING) &&
508 (req->wValue[0] == 0x00) &&
509 (req->wValue[1] == 0x00)) {
510 if (offset == 0) {
511 *plen = sizeof(sc->sc_line_coding);
512 *pptr = &sc->sc_line_coding;
513 } else {
514 *plen = 0;
515 }
516 return (0);
517 } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
518 (req->bRequest == UCDC_SET_COMM_FEATURE)) {
519 if (offset == 0) {
520 *plen = sizeof(sc->sc_abstract_state);
521 *pptr = &sc->sc_abstract_state;
522 } else {
523 *plen = 0;
524 }
525 return (0);
526 } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
527 (req->bRequest == UCDC_SET_CONTROL_LINE_STATE)) {
528 *plen = 0;
529 return (0);
530 } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
531 (req->bRequest == UCDC_SEND_BREAK)) {
532 *plen = 0;
533 return (0);
534 }
535 }
536 return (ENXIO); /* use builtin handler */
537 }
538