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