1 /* $NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $ */
2
3 #include <sys/cdefs.h>
4 __FBSDID("$FreeBSD$");
5 #define UFOMA_HANDSFREE
6 /*-
7 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD
8 *
9 * Copyright (c) 2005, Takanori Watanabe All rights reserved.
10 * Copyright (c) 2003 M. Warner Losh <imp@FreeBSD.org>
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*-
35 * Copyright (c) 1998 The NetBSD Foundation, Inc.
36 * All rights reserved.
37 *
38 * This code is derived from software contributed to The NetBSD Foundation
39 * by Lennart Augustsson (lennart@augustsson.net) at
40 * Carlstedt Research & Technology.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
52 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
53 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
54 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
55 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
56 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
57 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
58 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
59 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61 * POSSIBILITY OF SUCH DAMAGE.
62 */
63
64 /*
65 * Comm Class spec: http://www.usb.org/developers/devclass_docs/usbccs10.pdf
66 * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
67 */
68
69 /*
70 * TODO:
71 * - Implement a Call Device for modems without multiplexed commands.
72 */
73
74 /*
75 * NOTE: all function names beginning like "ufoma_cfg_" can only
76 * be called from within the config thread function !
77 */
78
79 #include <sys/stdint.h>
80 #include <sys/stddef.h>
81 #include <sys/param.h>
82 #include <sys/queue.h>
83 #include <sys/types.h>
84 #include <sys/systm.h>
85 #include <sys/kernel.h>
86 #include <sys/bus.h>
87 #include <sys/module.h>
88 #include <sys/lock.h>
89 #include <sys/mutex.h>
90 #include <sys/condvar.h>
91 #include <sys/sysctl.h>
92 #include <sys/sx.h>
93 #include <sys/unistd.h>
94 #include <sys/callout.h>
95 #include <sys/malloc.h>
96 #include <sys/priv.h>
97 #include <sys/sbuf.h>
98
99 #include <dev/usb/usb.h>
100 #include <dev/usb/usbdi.h>
101 #include <dev/usb/usbdi_util.h>
102 #include <dev/usb/usb_cdc.h>
103 #include "usbdevs.h"
104
105 #define USB_DEBUG_VAR usb_debug
106 #include <dev/usb/usb_debug.h>
107 #include <dev/usb/usb_process.h>
108
109 #include <dev/usb/serial/usb_serial.h>
110
111 typedef struct ufoma_mobile_acm_descriptor {
112 uint8_t bFunctionLength;
113 uint8_t bDescriptorType;
114 uint8_t bDescriptorSubtype;
115 uint8_t bType;
116 uint8_t bMode[1];
117 } __packed usb_mcpc_acm_descriptor;
118
119 #define UISUBCLASS_MCPC 0x88
120
121 #define UDESC_VS_INTERFACE 0x44
122 #define UDESCSUB_MCPC_ACM 0x11
123
124 #define UMCPC_ACM_TYPE_AB1 0x1
125 #define UMCPC_ACM_TYPE_AB2 0x2
126 #define UMCPC_ACM_TYPE_AB5 0x5
127 #define UMCPC_ACM_TYPE_AB6 0x6
128
129 #define UMCPC_ACM_MODE_DEACTIVATED 0x0
130 #define UMCPC_ACM_MODE_MODEM 0x1
131 #define UMCPC_ACM_MODE_ATCOMMAND 0x2
132 #define UMCPC_ACM_MODE_OBEX 0x60
133 #define UMCPC_ACM_MODE_VENDOR1 0xc0
134 #define UMCPC_ACM_MODE_VENDOR2 0xfe
135 #define UMCPC_ACM_MODE_UNLINKED 0xff
136
137 #define UMCPC_CM_MOBILE_ACM 0x0
138
139 #define UMCPC_ACTIVATE_MODE 0x60
140 #define UMCPC_GET_MODETABLE 0x61
141 #define UMCPC_SET_LINK 0x62
142 #define UMCPC_CLEAR_LINK 0x63
143
144 #define UMCPC_REQUEST_ACKNOWLEDGE 0x31
145
146 #define UFOMA_MAX_TIMEOUT 15 /* standard says 10 seconds */
147 #define UFOMA_CMD_BUF_SIZE 64 /* bytes */
148
149 #define UFOMA_BULK_BUF_SIZE 1024 /* bytes */
150
151 enum {
152 UFOMA_CTRL_ENDPT_INTR,
153 UFOMA_CTRL_ENDPT_READ,
154 UFOMA_CTRL_ENDPT_WRITE,
155 UFOMA_CTRL_ENDPT_MAX,
156 };
157
158 enum {
159 UFOMA_BULK_ENDPT_WRITE,
160 UFOMA_BULK_ENDPT_READ,
161 UFOMA_BULK_ENDPT_MAX,
162 };
163
164 struct ufoma_softc {
165 struct ucom_super_softc sc_super_ucom;
166 struct ucom_softc sc_ucom;
167 struct cv sc_cv;
168 struct mtx sc_mtx;
169
170 struct usb_xfer *sc_ctrl_xfer[UFOMA_CTRL_ENDPT_MAX];
171 struct usb_xfer *sc_bulk_xfer[UFOMA_BULK_ENDPT_MAX];
172 uint8_t *sc_modetable;
173 device_t sc_dev;
174 struct usb_device *sc_udev;
175
176 uint32_t sc_unit;
177
178 uint16_t sc_line;
179
180 uint8_t sc_num_msg;
181 uint8_t sc_nobulk;
182 uint8_t sc_ctrl_iface_no;
183 uint8_t sc_ctrl_iface_index;
184 uint8_t sc_data_iface_no;
185 uint8_t sc_data_iface_index;
186 uint8_t sc_cm_cap;
187 uint8_t sc_acm_cap;
188 uint8_t sc_lsr;
189 uint8_t sc_msr;
190 uint8_t sc_modetoactivate;
191 uint8_t sc_currentmode;
192 };
193
194 /* prototypes */
195
196 static device_probe_t ufoma_probe;
197 static device_attach_t ufoma_attach;
198 static device_detach_t ufoma_detach;
199 static void ufoma_free_softc(struct ufoma_softc *);
200
201 static usb_callback_t ufoma_ctrl_read_callback;
202 static usb_callback_t ufoma_ctrl_write_callback;
203 static usb_callback_t ufoma_intr_callback;
204 static usb_callback_t ufoma_bulk_write_callback;
205 static usb_callback_t ufoma_bulk_read_callback;
206
207 static void *ufoma_get_intconf(struct usb_config_descriptor *,
208 struct usb_interface_descriptor *, uint8_t, uint8_t);
209 static void ufoma_cfg_link_state(struct ufoma_softc *);
210 static void ufoma_cfg_activate_state(struct ufoma_softc *, uint16_t);
211 static void ufoma_free(struct ucom_softc *);
212 static void ufoma_cfg_open(struct ucom_softc *);
213 static void ufoma_cfg_close(struct ucom_softc *);
214 static void ufoma_cfg_set_break(struct ucom_softc *, uint8_t);
215 static void ufoma_cfg_get_status(struct ucom_softc *, uint8_t *,
216 uint8_t *);
217 static void ufoma_cfg_set_dtr(struct ucom_softc *, uint8_t);
218 static void ufoma_cfg_set_rts(struct ucom_softc *, uint8_t);
219 static int ufoma_pre_param(struct ucom_softc *, struct termios *);
220 static void ufoma_cfg_param(struct ucom_softc *, struct termios *);
221 static int ufoma_modem_setup(device_t, struct ufoma_softc *,
222 struct usb_attach_arg *);
223 static void ufoma_start_read(struct ucom_softc *);
224 static void ufoma_stop_read(struct ucom_softc *);
225 static void ufoma_start_write(struct ucom_softc *);
226 static void ufoma_stop_write(struct ucom_softc *);
227 static void ufoma_poll(struct ucom_softc *ucom);
228
229 /*sysctl stuff*/
230 static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS);
231 static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS);
232 static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS);
233
234 static const struct usb_config
235 ufoma_ctrl_config[UFOMA_CTRL_ENDPT_MAX] = {
236 [UFOMA_CTRL_ENDPT_INTR] = {
237 .type = UE_INTERRUPT,
238 .endpoint = UE_ADDR_ANY,
239 .direction = UE_DIR_IN,
240 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
241 .bufsize = sizeof(struct usb_cdc_notification),
242 .callback = &ufoma_intr_callback,
243 },
244
245 [UFOMA_CTRL_ENDPT_READ] = {
246 .type = UE_CONTROL,
247 .endpoint = 0x00, /* Control pipe */
248 .direction = UE_DIR_ANY,
249 .bufsize = (sizeof(struct usb_device_request) + UFOMA_CMD_BUF_SIZE),
250 .flags = {.short_xfer_ok = 1,},
251 .callback = &ufoma_ctrl_read_callback,
252 .timeout = 1000, /* 1 second */
253 },
254
255 [UFOMA_CTRL_ENDPT_WRITE] = {
256 .type = UE_CONTROL,
257 .endpoint = 0x00, /* Control pipe */
258 .direction = UE_DIR_ANY,
259 .bufsize = (sizeof(struct usb_device_request) + 1),
260 .callback = &ufoma_ctrl_write_callback,
261 .timeout = 1000, /* 1 second */
262 },
263 };
264
265 static const struct usb_config
266 ufoma_bulk_config[UFOMA_BULK_ENDPT_MAX] = {
267 [UFOMA_BULK_ENDPT_WRITE] = {
268 .type = UE_BULK,
269 .endpoint = UE_ADDR_ANY,
270 .direction = UE_DIR_OUT,
271 .bufsize = UFOMA_BULK_BUF_SIZE,
272 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
273 .callback = &ufoma_bulk_write_callback,
274 },
275
276 [UFOMA_BULK_ENDPT_READ] = {
277 .type = UE_BULK,
278 .endpoint = UE_ADDR_ANY,
279 .direction = UE_DIR_IN,
280 .bufsize = UFOMA_BULK_BUF_SIZE,
281 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
282 .callback = &ufoma_bulk_read_callback,
283 },
284 };
285
286 static const struct ucom_callback ufoma_callback = {
287 .ucom_cfg_get_status = &ufoma_cfg_get_status,
288 .ucom_cfg_set_dtr = &ufoma_cfg_set_dtr,
289 .ucom_cfg_set_rts = &ufoma_cfg_set_rts,
290 .ucom_cfg_set_break = &ufoma_cfg_set_break,
291 .ucom_cfg_param = &ufoma_cfg_param,
292 .ucom_cfg_open = &ufoma_cfg_open,
293 .ucom_cfg_close = &ufoma_cfg_close,
294 .ucom_pre_param = &ufoma_pre_param,
295 .ucom_start_read = &ufoma_start_read,
296 .ucom_stop_read = &ufoma_stop_read,
297 .ucom_start_write = &ufoma_start_write,
298 .ucom_stop_write = &ufoma_stop_write,
299 .ucom_poll = &ufoma_poll,
300 .ucom_free = &ufoma_free,
301 };
302
303 static device_method_t ufoma_methods[] = {
304 /* Device methods */
305 DEVMETHOD(device_probe, ufoma_probe),
306 DEVMETHOD(device_attach, ufoma_attach),
307 DEVMETHOD(device_detach, ufoma_detach),
308 DEVMETHOD_END
309 };
310
311 static driver_t ufoma_driver = {
312 .name = "ufoma",
313 .methods = ufoma_methods,
314 .size = sizeof(struct ufoma_softc),
315 };
316
317 static const STRUCT_USB_HOST_ID ufoma_devs[] = {
318 {USB_IFACE_CLASS(UICLASS_CDC),
319 USB_IFACE_SUBCLASS(UISUBCLASS_MCPC),},
320 };
321
322 DRIVER_MODULE(ufoma, uhub, ufoma_driver, NULL, NULL);
323 MODULE_DEPEND(ufoma, ucom, 1, 1, 1);
324 MODULE_DEPEND(ufoma, usb, 1, 1, 1);
325 MODULE_VERSION(ufoma, 1);
326 USB_PNP_HOST_INFO(ufoma_devs);
327
328 static int
329 ufoma_probe(device_t dev)
330 {
331 struct usb_attach_arg *uaa = device_get_ivars(dev);
332 struct usb_interface_descriptor *id;
333 struct usb_config_descriptor *cd;
334 usb_mcpc_acm_descriptor *mad;
335 int error;
336
337 if (uaa->usb_mode != USB_MODE_HOST)
338 return (ENXIO);
339
340 error = usbd_lookup_id_by_uaa(ufoma_devs, sizeof(ufoma_devs), uaa);
341 if (error)
342 return (error);
343
344 id = usbd_get_interface_descriptor(uaa->iface);
345 cd = usbd_get_config_descriptor(uaa->device);
346
347 if (id == NULL || cd == NULL)
348 return (ENXIO);
349
350 mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
351 if (mad == NULL)
352 return (ENXIO);
353
354 #ifndef UFOMA_HANDSFREE
355 if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
356 (mad->bType == UMCPC_ACM_TYPE_AB6))
357 return (ENXIO);
358 #endif
359 return (BUS_PROBE_GENERIC);
360 }
361
362 static int
363 ufoma_attach(device_t dev)
364 {
365 struct usb_attach_arg *uaa = device_get_ivars(dev);
366 struct ufoma_softc *sc = device_get_softc(dev);
367 struct usb_config_descriptor *cd;
368 struct usb_interface_descriptor *id;
369 struct sysctl_ctx_list *sctx;
370 struct sysctl_oid *soid;
371
372 usb_mcpc_acm_descriptor *mad;
373 uint8_t elements;
374 int32_t error;
375
376 sc->sc_udev = uaa->device;
377 sc->sc_dev = dev;
378 sc->sc_unit = device_get_unit(dev);
379
380 mtx_init(&sc->sc_mtx, "ufoma", NULL, MTX_DEF);
381 ucom_ref(&sc->sc_super_ucom);
382 cv_init(&sc->sc_cv, "CWAIT");
383
384 device_set_usb_desc(dev);
385
386 DPRINTF("\n");
387
388 /* setup control transfers */
389
390 cd = usbd_get_config_descriptor(uaa->device);
391 id = usbd_get_interface_descriptor(uaa->iface);
392 sc->sc_ctrl_iface_no = id->bInterfaceNumber;
393 sc->sc_ctrl_iface_index = uaa->info.bIfaceIndex;
394
395 error = usbd_transfer_setup(uaa->device,
396 &sc->sc_ctrl_iface_index, sc->sc_ctrl_xfer,
397 ufoma_ctrl_config, UFOMA_CTRL_ENDPT_MAX, sc, &sc->sc_mtx);
398
399 if (error) {
400 device_printf(dev, "allocating control USB "
401 "transfers failed\n");
402 goto detach;
403 }
404 mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
405 if (mad == NULL) {
406 goto detach;
407 }
408 if (mad->bFunctionLength < sizeof(*mad)) {
409 device_printf(dev, "invalid MAD descriptor\n");
410 goto detach;
411 }
412 if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
413 (mad->bType == UMCPC_ACM_TYPE_AB6)) {
414 sc->sc_nobulk = 1;
415 } else {
416 sc->sc_nobulk = 0;
417 if (ufoma_modem_setup(dev, sc, uaa)) {
418 goto detach;
419 }
420 }
421
422 elements = (mad->bFunctionLength - sizeof(*mad) + 1);
423
424 /* initialize mode variables */
425
426 sc->sc_modetable = malloc(elements + 1, M_USBDEV, M_WAITOK);
427
428 if (sc->sc_modetable == NULL) {
429 goto detach;
430 }
431 sc->sc_modetable[0] = (elements + 1);
432 memcpy(&sc->sc_modetable[1], mad->bMode, elements);
433
434 sc->sc_currentmode = UMCPC_ACM_MODE_UNLINKED;
435 sc->sc_modetoactivate = mad->bMode[0];
436
437 /* clear stall at first run, if any */
438 mtx_lock(&sc->sc_mtx);
439 usbd_xfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]);
440 usbd_xfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]);
441 mtx_unlock(&sc->sc_mtx);
442
443 error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
444 &ufoma_callback, &sc->sc_mtx);
445 if (error) {
446 DPRINTF("ucom_attach failed\n");
447 goto detach;
448 }
449 ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
450
451 /*Sysctls*/
452 sctx = device_get_sysctl_ctx(dev);
453 soid = device_get_sysctl_tree(dev);
454
455 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "supportmode",
456 CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_MPSAFE, sc, 0,
457 ufoma_sysctl_support, "A", "Supporting port role");
458
459 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "currentmode",
460 CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_MPSAFE, sc, 0,
461 ufoma_sysctl_current, "A", "Current port role");
462
463 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "openmode",
464 CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_MPSAFE, sc, 0,
465 ufoma_sysctl_open, "A", "Mode to transit when port is opened");
466 SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "comunit",
467 CTLFLAG_RD, &(sc->sc_super_ucom.sc_unit), 0,
468 "Unit number as USB serial");
469
470 return (0); /* success */
471
472 detach:
473 ufoma_detach(dev);
474 return (ENXIO); /* failure */
475 }
476
477 static int
478 ufoma_detach(device_t dev)
479 {
480 struct ufoma_softc *sc = device_get_softc(dev);
481
482 ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
483 usbd_transfer_unsetup(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX);
484 usbd_transfer_unsetup(sc->sc_bulk_xfer, UFOMA_BULK_ENDPT_MAX);
485
486 if (sc->sc_modetable) {
487 free(sc->sc_modetable, M_USBDEV);
488 }
489 cv_destroy(&sc->sc_cv);
490
491 device_claim_softc(dev);
492
493 ufoma_free_softc(sc);
494
495 return (0);
496 }
497
498 UCOM_UNLOAD_DRAIN(ufoma);
499
500 static void
501 ufoma_free_softc(struct ufoma_softc *sc)
502 {
503 if (ucom_unref(&sc->sc_super_ucom)) {
504 mtx_destroy(&sc->sc_mtx);
505 device_free_softc(sc);
506 }
507 }
508
509 static void
510 ufoma_free(struct ucom_softc *ucom)
511 {
512 ufoma_free_softc(ucom->sc_parent);
513 }
514
515 static void *
516 ufoma_get_intconf(struct usb_config_descriptor *cd, struct usb_interface_descriptor *id,
517 uint8_t type, uint8_t subtype)
518 {
519 struct usb_descriptor *desc = (void *)id;
520
521 while ((desc = usb_desc_foreach(cd, desc))) {
522 if (desc->bDescriptorType == UDESC_INTERFACE) {
523 return (NULL);
524 }
525 if ((desc->bDescriptorType == type) &&
526 (desc->bDescriptorSubtype == subtype)) {
527 break;
528 }
529 }
530 return (desc);
531 }
532
533 static void
534 ufoma_cfg_link_state(struct ufoma_softc *sc)
535 {
536 struct usb_device_request req;
537 int32_t error;
538
539 req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
540 req.bRequest = UMCPC_SET_LINK;
541 USETW(req.wValue, UMCPC_CM_MOBILE_ACM);
542 USETW(req.wIndex, sc->sc_ctrl_iface_no);
543 USETW(req.wLength, sc->sc_modetable[0]);
544
545 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
546 &req, sc->sc_modetable, 0, 1000);
547
548 error = cv_timedwait(&sc->sc_cv, &sc->sc_mtx, hz);
549
550 if (error) {
551 DPRINTF("NO response\n");
552 }
553 }
554
555 static void
556 ufoma_cfg_activate_state(struct ufoma_softc *sc, uint16_t state)
557 {
558 struct usb_device_request req;
559 int32_t error;
560
561 req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
562 req.bRequest = UMCPC_ACTIVATE_MODE;
563 USETW(req.wValue, state);
564 USETW(req.wIndex, sc->sc_ctrl_iface_no);
565 USETW(req.wLength, 0);
566
567 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
568 &req, NULL, 0, 1000);
569
570 error = cv_timedwait(&sc->sc_cv, &sc->sc_mtx,
571 (UFOMA_MAX_TIMEOUT * hz));
572 if (error) {
573 DPRINTF("No response\n");
574 }
575 }
576
577 static void
578 ufoma_ctrl_read_callback(struct usb_xfer *xfer, usb_error_t error)
579 {
580 struct ufoma_softc *sc = usbd_xfer_softc(xfer);
581 struct usb_device_request req;
582 struct usb_page_cache *pc0, *pc1;
583 int len, aframes, nframes;
584
585 usbd_xfer_status(xfer, NULL, NULL, &aframes, &nframes);
586
587 switch (USB_GET_STATE(xfer)) {
588 case USB_ST_TRANSFERRED:
589 tr_transferred:
590 if (aframes != nframes)
591 goto tr_setup;
592 pc1 = usbd_xfer_get_frame(xfer, 1);
593 len = usbd_xfer_frame_len(xfer, 1);
594 if (len > 0)
595 ucom_put_data(&sc->sc_ucom, pc1, 0, len);
596 /* FALLTHROUGH */
597 case USB_ST_SETUP:
598 tr_setup:
599 if (sc->sc_num_msg) {
600 sc->sc_num_msg--;
601
602 req.bmRequestType = UT_READ_CLASS_INTERFACE;
603 req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE;
604 USETW(req.wIndex, sc->sc_ctrl_iface_no);
605 USETW(req.wValue, 0);
606 USETW(req.wLength, UFOMA_CMD_BUF_SIZE);
607
608 pc0 = usbd_xfer_get_frame(xfer, 0);
609 usbd_copy_in(pc0, 0, &req, sizeof(req));
610
611 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
612 usbd_xfer_set_frame_len(xfer, 1, UFOMA_CMD_BUF_SIZE);
613 usbd_xfer_set_frames(xfer, 2);
614 usbd_transfer_submit(xfer);
615 }
616 return;
617
618 default: /* Error */
619 DPRINTF("error = %s\n",
620 usbd_errstr(error));
621
622 if (error == USB_ERR_CANCELLED) {
623 return;
624 }
625 goto tr_transferred;
626 }
627 }
628
629 static void
630 ufoma_ctrl_write_callback(struct usb_xfer *xfer, usb_error_t error)
631 {
632 struct ufoma_softc *sc = usbd_xfer_softc(xfer);
633 struct usb_device_request req;
634 struct usb_page_cache *pc;
635 uint32_t actlen;
636
637 switch (USB_GET_STATE(xfer)) {
638 case USB_ST_TRANSFERRED:
639 tr_transferred:
640 case USB_ST_SETUP:
641 pc = usbd_xfer_get_frame(xfer, 1);
642 if (ucom_get_data(&sc->sc_ucom, pc, 0, 1, &actlen)) {
643 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
644 req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
645 USETW(req.wIndex, sc->sc_ctrl_iface_no);
646 USETW(req.wValue, 0);
647 USETW(req.wLength, 1);
648
649 pc = usbd_xfer_get_frame(xfer, 0);
650 usbd_copy_in(pc, 0, &req, sizeof(req));
651
652 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
653 usbd_xfer_set_frame_len(xfer, 1, 1);
654 usbd_xfer_set_frames(xfer, 2);
655
656 usbd_transfer_submit(xfer);
657 }
658 return;
659
660 default: /* Error */
661 DPRINTF("error = %s\n", usbd_errstr(error));
662
663 if (error == USB_ERR_CANCELLED) {
664 return;
665 }
666 goto tr_transferred;
667 }
668 }
669
670 static void
671 ufoma_intr_callback(struct usb_xfer *xfer, usb_error_t error)
672 {
673 struct ufoma_softc *sc = usbd_xfer_softc(xfer);
674 struct usb_cdc_notification pkt;
675 struct usb_page_cache *pc;
676 uint16_t wLen;
677 uint16_t temp;
678 uint8_t mstatus;
679 int actlen;
680
681 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
682
683 switch (USB_GET_STATE(xfer)) {
684 case USB_ST_TRANSFERRED:
685 if (actlen < 8) {
686 DPRINTF("too short message\n");
687 goto tr_setup;
688 }
689 if (actlen > (int)sizeof(pkt)) {
690 DPRINTF("truncating message\n");
691 actlen = sizeof(pkt);
692 }
693 pc = usbd_xfer_get_frame(xfer, 0);
694 usbd_copy_out(pc, 0, &pkt, actlen);
695
696 actlen -= 8;
697
698 wLen = UGETW(pkt.wLength);
699 if (actlen > wLen) {
700 actlen = wLen;
701 }
702 if ((pkt.bmRequestType == UT_READ_VENDOR_INTERFACE) &&
703 (pkt.bNotification == UMCPC_REQUEST_ACKNOWLEDGE)) {
704 temp = UGETW(pkt.wValue);
705 sc->sc_currentmode = (temp >> 8);
706 if (!(temp & 0xff)) {
707 DPRINTF("Mode change failed!\n");
708 }
709 cv_signal(&sc->sc_cv);
710 }
711 if (pkt.bmRequestType != UCDC_NOTIFICATION) {
712 goto tr_setup;
713 }
714 switch (pkt.bNotification) {
715 case UCDC_N_RESPONSE_AVAILABLE:
716 if (!(sc->sc_nobulk)) {
717 DPRINTF("Wrong serial state!\n");
718 break;
719 }
720 if (sc->sc_num_msg != 0xFF) {
721 sc->sc_num_msg++;
722 }
723 usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
724 break;
725
726 case UCDC_N_SERIAL_STATE:
727 if (sc->sc_nobulk) {
728 DPRINTF("Wrong serial state!\n");
729 break;
730 }
731 /*
732 * Set the serial state in ucom driver based on
733 * the bits from the notify message
734 */
735 if (actlen < 2) {
736 DPRINTF("invalid notification "
737 "length, %d bytes!\n", actlen);
738 break;
739 }
740 DPRINTF("notify bytes = 0x%02x, 0x%02x\n",
741 pkt.data[0], pkt.data[1]);
742
743 /* currently, lsr is always zero. */
744 sc->sc_lsr = 0;
745 sc->sc_msr = 0;
746
747 mstatus = pkt.data[0];
748
749 if (mstatus & UCDC_N_SERIAL_RI) {
750 sc->sc_msr |= SER_RI;
751 }
752 if (mstatus & UCDC_N_SERIAL_DSR) {
753 sc->sc_msr |= SER_DSR;
754 }
755 if (mstatus & UCDC_N_SERIAL_DCD) {
756 sc->sc_msr |= SER_DCD;
757 }
758 ucom_status_change(&sc->sc_ucom);
759 break;
760
761 default:
762 break;
763 }
764
765 case USB_ST_SETUP:
766 tr_setup:
767 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
768 usbd_transfer_submit(xfer);
769 return;
770
771 default: /* Error */
772 if (error != USB_ERR_CANCELLED) {
773 /* try to clear stall first */
774 usbd_xfer_set_stall(xfer);
775 goto tr_setup;
776 }
777 return;
778 }
779 }
780
781 static void
782 ufoma_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
783 {
784 struct ufoma_softc *sc = usbd_xfer_softc(xfer);
785 struct usb_page_cache *pc;
786 uint32_t actlen;
787
788 switch (USB_GET_STATE(xfer)) {
789 case USB_ST_SETUP:
790 case USB_ST_TRANSFERRED:
791 tr_setup:
792 pc = usbd_xfer_get_frame(xfer, 0);
793 if (ucom_get_data(&sc->sc_ucom, pc, 0,
794 UFOMA_BULK_BUF_SIZE, &actlen)) {
795 usbd_xfer_set_frame_len(xfer, 0, actlen);
796 usbd_transfer_submit(xfer);
797 }
798 return;
799
800 default: /* Error */
801 if (error != USB_ERR_CANCELLED) {
802 /* try to clear stall first */
803 usbd_xfer_set_stall(xfer);
804 goto tr_setup;
805 }
806 return;
807 }
808 }
809
810 static void
811 ufoma_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
812 {
813 struct ufoma_softc *sc = usbd_xfer_softc(xfer);
814 struct usb_page_cache *pc;
815 int actlen;
816
817 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
818
819 switch (USB_GET_STATE(xfer)) {
820 case USB_ST_TRANSFERRED:
821 pc = usbd_xfer_get_frame(xfer, 0);
822 ucom_put_data(&sc->sc_ucom, pc, 0, actlen);
823
824 case USB_ST_SETUP:
825 tr_setup:
826 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
827 usbd_transfer_submit(xfer);
828 return;
829
830 default: /* Error */
831 if (error != USB_ERR_CANCELLED) {
832 /* try to clear stall first */
833 usbd_xfer_set_stall(xfer);
834 goto tr_setup;
835 }
836 return;
837 }
838 }
839
840 static void
841 ufoma_cfg_open(struct ucom_softc *ucom)
842 {
843 struct ufoma_softc *sc = ucom->sc_parent;
844
845 /* empty input queue */
846
847 if (sc->sc_num_msg != 0xFF) {
848 sc->sc_num_msg++;
849 }
850 if (sc->sc_currentmode == UMCPC_ACM_MODE_UNLINKED) {
851 ufoma_cfg_link_state(sc);
852 }
853 if (sc->sc_currentmode == UMCPC_ACM_MODE_DEACTIVATED) {
854 ufoma_cfg_activate_state(sc, sc->sc_modetoactivate);
855 }
856 }
857
858 static void
859 ufoma_cfg_close(struct ucom_softc *ucom)
860 {
861 struct ufoma_softc *sc = ucom->sc_parent;
862
863 ufoma_cfg_activate_state(sc, UMCPC_ACM_MODE_DEACTIVATED);
864 }
865
866 static void
867 ufoma_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
868 {
869 struct ufoma_softc *sc = ucom->sc_parent;
870 struct usb_device_request req;
871 uint16_t wValue;
872
873 if (sc->sc_nobulk ||
874 (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) {
875 return;
876 }
877 if (!(sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK)) {
878 return;
879 }
880 wValue = onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF;
881
882 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
883 req.bRequest = UCDC_SEND_BREAK;
884 USETW(req.wValue, wValue);
885 req.wIndex[0] = sc->sc_ctrl_iface_no;
886 req.wIndex[1] = 0;
887 USETW(req.wLength, 0);
888
889 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
890 &req, NULL, 0, 1000);
891 }
892
893 static void
894 ufoma_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
895 {
896 struct ufoma_softc *sc = ucom->sc_parent;
897
898 /* XXX Note: sc_lsr is always zero */
899 *lsr = sc->sc_lsr;
900 *msr = sc->sc_msr;
901 }
902
903 static void
904 ufoma_cfg_set_line_state(struct ufoma_softc *sc)
905 {
906 struct usb_device_request req;
907
908 /* Don't send line state emulation request for OBEX port */
909 if (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX) {
910 return;
911 }
912 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
913 req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
914 USETW(req.wValue, sc->sc_line);
915 req.wIndex[0] = sc->sc_ctrl_iface_no;
916 req.wIndex[1] = 0;
917 USETW(req.wLength, 0);
918
919 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
920 &req, NULL, 0, 1000);
921 }
922
923 static void
924 ufoma_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
925 {
926 struct ufoma_softc *sc = ucom->sc_parent;
927
928 if (sc->sc_nobulk) {
929 return;
930 }
931 if (onoff)
932 sc->sc_line |= UCDC_LINE_DTR;
933 else
934 sc->sc_line &= ~UCDC_LINE_DTR;
935
936 ufoma_cfg_set_line_state(sc);
937 }
938
939 static void
940 ufoma_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
941 {
942 struct ufoma_softc *sc = ucom->sc_parent;
943
944 if (sc->sc_nobulk) {
945 return;
946 }
947 if (onoff)
948 sc->sc_line |= UCDC_LINE_RTS;
949 else
950 sc->sc_line &= ~UCDC_LINE_RTS;
951
952 ufoma_cfg_set_line_state(sc);
953 }
954
955 static int
956 ufoma_pre_param(struct ucom_softc *ucom, struct termios *t)
957 {
958 return (0); /* we accept anything */
959 }
960
961 static void
962 ufoma_cfg_param(struct ucom_softc *ucom, struct termios *t)
963 {
964 struct ufoma_softc *sc = ucom->sc_parent;
965 struct usb_device_request req;
966 struct usb_cdc_line_state ls;
967
968 if (sc->sc_nobulk ||
969 (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) {
970 return;
971 }
972 DPRINTF("\n");
973
974 memset(&ls, 0, sizeof(ls));
975
976 USETDW(ls.dwDTERate, t->c_ospeed);
977
978 if (t->c_cflag & CSTOPB) {
979 ls.bCharFormat = UCDC_STOP_BIT_2;
980 } else {
981 ls.bCharFormat = UCDC_STOP_BIT_1;
982 }
983
984 if (t->c_cflag & PARENB) {
985 if (t->c_cflag & PARODD) {
986 ls.bParityType = UCDC_PARITY_ODD;
987 } else {
988 ls.bParityType = UCDC_PARITY_EVEN;
989 }
990 } else {
991 ls.bParityType = UCDC_PARITY_NONE;
992 }
993
994 switch (t->c_cflag & CSIZE) {
995 case CS5:
996 ls.bDataBits = 5;
997 break;
998 case CS6:
999 ls.bDataBits = 6;
1000 break;
1001 case CS7:
1002 ls.bDataBits = 7;
1003 break;
1004 case CS8:
1005 ls.bDataBits = 8;
1006 break;
1007 }
1008
1009 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1010 req.bRequest = UCDC_SET_LINE_CODING;
1011 USETW(req.wValue, 0);
1012 req.wIndex[0] = sc->sc_ctrl_iface_no;
1013 req.wIndex[1] = 0;
1014 USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
1015
1016 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
1017 &req, &ls, 0, 1000);
1018 }
1019
1020 static int
1021 ufoma_modem_setup(device_t dev, struct ufoma_softc *sc,
1022 struct usb_attach_arg *uaa)
1023 {
1024 struct usb_config_descriptor *cd;
1025 struct usb_cdc_acm_descriptor *acm;
1026 struct usb_cdc_cm_descriptor *cmd;
1027 struct usb_interface_descriptor *id;
1028 struct usb_interface *iface;
1029 uint8_t i;
1030 int32_t error;
1031
1032 cd = usbd_get_config_descriptor(uaa->device);
1033 id = usbd_get_interface_descriptor(uaa->iface);
1034
1035 cmd = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM);
1036
1037 if ((cmd == NULL) ||
1038 (cmd->bLength < sizeof(*cmd))) {
1039 return (EINVAL);
1040 }
1041 sc->sc_cm_cap = cmd->bmCapabilities;
1042 sc->sc_data_iface_no = cmd->bDataInterface;
1043
1044 acm = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM);
1045
1046 if ((acm == NULL) ||
1047 (acm->bLength < sizeof(*acm))) {
1048 return (EINVAL);
1049 }
1050 sc->sc_acm_cap = acm->bmCapabilities;
1051
1052 device_printf(dev, "data interface %d, has %sCM over data, "
1053 "has %sbreak\n",
1054 sc->sc_data_iface_no,
1055 sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ",
1056 sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no ");
1057
1058 /* get the data interface too */
1059
1060 for (i = 0;; i++) {
1061 iface = usbd_get_iface(uaa->device, i);
1062
1063 if (iface) {
1064 id = usbd_get_interface_descriptor(iface);
1065
1066 if (id && (id->bInterfaceNumber == sc->sc_data_iface_no)) {
1067 sc->sc_data_iface_index = i;
1068 usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex);
1069 break;
1070 }
1071 } else {
1072 device_printf(dev, "no data interface\n");
1073 return (EINVAL);
1074 }
1075 }
1076
1077 error = usbd_transfer_setup(uaa->device,
1078 &sc->sc_data_iface_index, sc->sc_bulk_xfer,
1079 ufoma_bulk_config, UFOMA_BULK_ENDPT_MAX, sc, &sc->sc_mtx);
1080
1081 if (error) {
1082 device_printf(dev, "allocating BULK USB "
1083 "transfers failed\n");
1084 return (EINVAL);
1085 }
1086 return (0);
1087 }
1088
1089 static void
1090 ufoma_start_read(struct ucom_softc *ucom)
1091 {
1092 struct ufoma_softc *sc = ucom->sc_parent;
1093
1094 /* start interrupt transfer */
1095 usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR]);
1096
1097 /* start data transfer */
1098 if (sc->sc_nobulk) {
1099 usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
1100 } else {
1101 usbd_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]);
1102 }
1103 }
1104
1105 static void
1106 ufoma_stop_read(struct ucom_softc *ucom)
1107 {
1108 struct ufoma_softc *sc = ucom->sc_parent;
1109
1110 /* stop interrupt transfer */
1111 usbd_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR]);
1112
1113 /* stop data transfer */
1114 if (sc->sc_nobulk) {
1115 usbd_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
1116 } else {
1117 usbd_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]);
1118 }
1119 }
1120
1121 static void
1122 ufoma_start_write(struct ucom_softc *ucom)
1123 {
1124 struct ufoma_softc *sc = ucom->sc_parent;
1125
1126 if (sc->sc_nobulk) {
1127 usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_WRITE]);
1128 } else {
1129 usbd_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]);
1130 }
1131 }
1132
1133 static void
1134 ufoma_stop_write(struct ucom_softc *ucom)
1135 {
1136 struct ufoma_softc *sc = ucom->sc_parent;
1137
1138 if (sc->sc_nobulk) {
1139 usbd_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_WRITE]);
1140 } else {
1141 usbd_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]);
1142 }
1143 }
1144
1145 static struct umcpc_modetostr_tab{
1146 int mode;
1147 char *str;
1148 }umcpc_modetostr_tab[]={
1149 {UMCPC_ACM_MODE_DEACTIVATED, "deactivated"},
1150 {UMCPC_ACM_MODE_MODEM, "modem"},
1151 {UMCPC_ACM_MODE_ATCOMMAND, "handsfree"},
1152 {UMCPC_ACM_MODE_OBEX, "obex"},
1153 {UMCPC_ACM_MODE_VENDOR1, "vendor1"},
1154 {UMCPC_ACM_MODE_VENDOR2, "vendor2"},
1155 {UMCPC_ACM_MODE_UNLINKED, "unlinked"},
1156 {0, NULL}
1157 };
1158
1159 static char *ufoma_mode_to_str(int mode)
1160 {
1161 int i;
1162 for(i = 0 ;umcpc_modetostr_tab[i].str != NULL; i++){
1163 if(umcpc_modetostr_tab[i].mode == mode){
1164 return umcpc_modetostr_tab[i].str;
1165 }
1166 }
1167 return NULL;
1168 }
1169
1170 static int ufoma_str_to_mode(char *str)
1171 {
1172 int i;
1173 for(i = 0 ;umcpc_modetostr_tab[i].str != NULL; i++){
1174 if(strcmp(str, umcpc_modetostr_tab[i].str)==0){
1175 return umcpc_modetostr_tab[i].mode;
1176 }
1177 }
1178 return -1;
1179 }
1180
1181 static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS)
1182 {
1183 struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1;
1184 struct sbuf sb;
1185 int i;
1186 char *mode;
1187
1188 sbuf_new(&sb, NULL, 1, SBUF_AUTOEXTEND);
1189 for(i = 1; i < sc->sc_modetable[0]; i++){
1190 mode = ufoma_mode_to_str(sc->sc_modetable[i]);
1191 if(mode !=NULL){
1192 sbuf_cat(&sb, mode);
1193 }else{
1194 sbuf_printf(&sb, "(%02x)", sc->sc_modetable[i]);
1195 }
1196 if(i < (sc->sc_modetable[0]-1))
1197 sbuf_cat(&sb, ",");
1198 }
1199 sbuf_trim(&sb);
1200 sbuf_finish(&sb);
1201 sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
1202 sbuf_delete(&sb);
1203
1204 return 0;
1205 }
1206 static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS)
1207 {
1208 struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1;
1209 char *mode;
1210 char subbuf[]="(XXX)";
1211 mode = ufoma_mode_to_str(sc->sc_currentmode);
1212 if(!mode){
1213 mode = subbuf;
1214 snprintf(subbuf, sizeof(subbuf), "(%02x)", sc->sc_currentmode);
1215 }
1216 sysctl_handle_string(oidp, mode, strlen(mode), req);
1217
1218 return 0;
1219
1220 }
1221 static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS)
1222 {
1223 struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1;
1224 char *mode;
1225 char subbuf[40];
1226 int newmode;
1227 int error;
1228 int i;
1229
1230 mode = ufoma_mode_to_str(sc->sc_modetoactivate);
1231 if(mode){
1232 strncpy(subbuf, mode, sizeof(subbuf));
1233 }else{
1234 snprintf(subbuf, sizeof(subbuf), "(%02x)", sc->sc_modetoactivate);
1235 }
1236 error = sysctl_handle_string(oidp, subbuf, sizeof(subbuf), req);
1237 if(error != 0 || req->newptr == NULL){
1238 return error;
1239 }
1240
1241 if((newmode = ufoma_str_to_mode(subbuf)) == -1){
1242 return EINVAL;
1243 }
1244
1245 for(i = 1 ; i < sc->sc_modetable[0] ; i++){
1246 if(sc->sc_modetable[i] == newmode){
1247 sc->sc_modetoactivate = newmode;
1248 return 0;
1249 }
1250 }
1251
1252 return EINVAL;
1253 }
1254
1255 static void
1256 ufoma_poll(struct ucom_softc *ucom)
1257 {
1258 struct ufoma_softc *sc = ucom->sc_parent;
1259 usbd_transfer_poll(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX);
1260 usbd_transfer_poll(sc->sc_bulk_xfer, UFOMA_BULK_ENDPT_MAX);
1261 }
Cache object: 3a29d691cb123462eaa36bd396041a5f
|