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