2d67cab6fea94e322f03da84b9d73bf7209b337e
[dragonfly.git] / sys / bus / u4b / serial / ufoma.c
1 /*      $NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $       */
2
3 #define UFOMA_HANDSFREE
4 /*-
5  * Copyright (c) 2005, Takanori Watanabe
6  * Copyright (c) 2003, M. Warner Losh <imp@FreeBSD.org>.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 /*-
32  * Copyright (c) 1998 The NetBSD Foundation, Inc.
33  * All rights reserved.
34  *
35  * This code is derived from software contributed to The NetBSD Foundation
36  * by Lennart Augustsson (lennart@augustsson.net) at
37  * Carlstedt Research & Technology.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. All advertising materials mentioning features or use of this software
48  *    must display the following acknowledgement:
49  *        This product includes software developed by the NetBSD
50  *        Foundation, Inc. and its contributors.
51  * 4. Neither the name of The NetBSD Foundation nor the names of its
52  *    contributors may be used to endorse or promote products derived
53  *    from this software without specific prior written permission.
54  *
55  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
56  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
57  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
58  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
59  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
60  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
61  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
62  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
63  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
65  * POSSIBILITY OF SUCH DAMAGE.
66  */
67
68 /*
69  * Comm Class spec:  http://www.usb.org/developers/devclass_docs/usbccs10.pdf
70  *                   http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
71  */
72
73 /*
74  * TODO:
75  * - Implement a Call Device for modems without multiplexed commands.
76  */
77
78 /*
79  * NOTE: all function names beginning like "ufoma_cfg_" can only
80  * be called from within the config thread function !
81  */
82
83 #include <sys/stdint.h>
84 #include <sys/param.h>
85 #include <sys/queue.h>
86 #include <sys/types.h>
87 #include <sys/systm.h>
88 #include <sys/kernel.h>
89 #include <sys/bus.h>
90 #include <sys/module.h>
91 #include <sys/lock.h>
92 #include <sys/condvar.h>
93 #include <sys/sysctl.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 <bus/u4b/usb.h>
101 #include <bus/u4b/usbdi.h>
102 #include <bus/u4b/usbdi_util.h>
103 #include <bus/u4b/usb_cdc.h>
104 #include <bus/u4b/usbdevs.h>
105
106 #define USB_DEBUG_VAR usb_debug
107 #include <bus/u4b/usb_debug.h>
108 #include <bus/u4b/usb_process.h>
109
110 #include <bus/u4b/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 lock sc_lock;
170         struct sysctl_ctx_list sc_sysctl_ctx;
171         struct sysctl_oid *sc_sysctl_tree;
172
173         struct usb_xfer *sc_ctrl_xfer[UFOMA_CTRL_ENDPT_MAX];
174         struct usb_xfer *sc_bulk_xfer[UFOMA_BULK_ENDPT_MAX];
175         uint8_t *sc_modetable;
176         device_t sc_dev;
177         struct usb_device *sc_udev;
178
179         uint32_t sc_unit;
180
181         uint16_t sc_line;
182
183         uint8_t sc_num_msg;
184         uint8_t sc_nobulk;
185         uint8_t sc_ctrl_iface_no;
186         uint8_t sc_ctrl_iface_index;
187         uint8_t sc_data_iface_no;
188         uint8_t sc_data_iface_index;
189         uint8_t sc_cm_cap;
190         uint8_t sc_acm_cap;
191         uint8_t sc_lsr;
192         uint8_t sc_msr;
193         uint8_t sc_modetoactivate;
194         uint8_t sc_currentmode;
195         uint8_t sc_name[16];
196 };
197
198 /* prototypes */
199
200 static device_probe_t ufoma_probe;
201 static device_attach_t ufoma_attach;
202 static device_detach_t ufoma_detach;
203
204 static usb_callback_t ufoma_ctrl_read_callback;
205 static usb_callback_t ufoma_ctrl_write_callback;
206 static usb_callback_t ufoma_intr_callback;
207 static usb_callback_t ufoma_bulk_write_callback;
208 static usb_callback_t ufoma_bulk_read_callback;
209
210 static void     *ufoma_get_intconf(struct usb_config_descriptor *,
211                     struct usb_interface_descriptor *, uint8_t, uint8_t);
212 static void     ufoma_cfg_link_state(struct ufoma_softc *);
213 static void     ufoma_cfg_activate_state(struct ufoma_softc *, uint16_t);
214 static void     ufoma_cfg_open(struct ucom_softc *);
215 static void     ufoma_cfg_close(struct ucom_softc *);
216 static void     ufoma_cfg_set_break(struct ucom_softc *, uint8_t);
217 static void     ufoma_cfg_get_status(struct ucom_softc *, uint8_t *,
218                     uint8_t *);
219 static void     ufoma_cfg_set_dtr(struct ucom_softc *, uint8_t);
220 static void     ufoma_cfg_set_rts(struct ucom_softc *, uint8_t);
221 static int      ufoma_pre_param(struct ucom_softc *, struct termios *);
222 static void     ufoma_cfg_param(struct ucom_softc *, struct termios *);
223 static int      ufoma_modem_setup(device_t, struct ufoma_softc *,
224                     struct usb_attach_arg *);
225 static void     ufoma_start_read(struct ucom_softc *);
226 static void     ufoma_stop_read(struct ucom_softc *);
227 static void     ufoma_start_write(struct ucom_softc *);
228 static void     ufoma_stop_write(struct ucom_softc *);
229 static void     ufoma_poll(struct ucom_softc *ucom);
230
231 /*sysctl stuff*/
232 static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS);
233 static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS);
234 static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS);
235
236 static const struct usb_config
237         ufoma_ctrl_config[UFOMA_CTRL_ENDPT_MAX] = {
238
239         [UFOMA_CTRL_ENDPT_INTR] = {
240                 .type = UE_INTERRUPT,
241                 .endpoint = UE_ADDR_ANY,
242                 .direction = UE_DIR_IN,
243                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
244                 .bufsize = sizeof(struct usb_cdc_notification),
245                 .callback = &ufoma_intr_callback,
246         },
247
248         [UFOMA_CTRL_ENDPT_READ] = {
249                 .type = UE_CONTROL,
250                 .endpoint = 0x00,       /* Control pipe */
251                 .direction = UE_DIR_ANY,
252                 .bufsize = (sizeof(struct usb_device_request) + UFOMA_CMD_BUF_SIZE),
253                 .flags = {.short_xfer_ok = 1,},
254                 .callback = &ufoma_ctrl_read_callback,
255                 .timeout = 1000,        /* 1 second */
256         },
257
258         [UFOMA_CTRL_ENDPT_WRITE] = {
259                 .type = UE_CONTROL,
260                 .endpoint = 0x00,       /* Control pipe */
261                 .direction = UE_DIR_ANY,
262                 .bufsize = (sizeof(struct usb_device_request) + 1),
263                 .callback = &ufoma_ctrl_write_callback,
264                 .timeout = 1000,        /* 1 second */
265         },
266 };
267
268 static const struct usb_config
269         ufoma_bulk_config[UFOMA_BULK_ENDPT_MAX] = {
270
271         [UFOMA_BULK_ENDPT_WRITE] = {
272                 .type = UE_BULK,
273                 .endpoint = UE_ADDR_ANY,
274                 .direction = UE_DIR_OUT,
275                 .bufsize = UFOMA_BULK_BUF_SIZE,
276                 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
277                 .callback = &ufoma_bulk_write_callback,
278         },
279
280         [UFOMA_BULK_ENDPT_READ] = {
281                 .type = UE_BULK,
282                 .endpoint = UE_ADDR_ANY,
283                 .direction = UE_DIR_IN,
284                 .bufsize = UFOMA_BULK_BUF_SIZE,
285                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
286                 .callback = &ufoma_bulk_read_callback,
287         },
288 };
289
290 static const struct ucom_callback ufoma_callback = {
291         .ucom_cfg_get_status = &ufoma_cfg_get_status,
292         .ucom_cfg_set_dtr = &ufoma_cfg_set_dtr,
293         .ucom_cfg_set_rts = &ufoma_cfg_set_rts,
294         .ucom_cfg_set_break = &ufoma_cfg_set_break,
295         .ucom_cfg_param = &ufoma_cfg_param,
296         .ucom_cfg_open = &ufoma_cfg_open,
297         .ucom_cfg_close = &ufoma_cfg_close,
298         .ucom_pre_param = &ufoma_pre_param,
299         .ucom_start_read = &ufoma_start_read,
300         .ucom_stop_read = &ufoma_stop_read,
301         .ucom_start_write = &ufoma_start_write,
302         .ucom_stop_write = &ufoma_stop_write,
303         .ucom_poll = &ufoma_poll,
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         {0, 0}
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 DRIVER_MODULE(ufoma, uhub, ufoma_driver, ufoma_devclass, NULL, 0);
323 MODULE_DEPEND(ufoma, ucom, 1, 1, 1);
324 MODULE_DEPEND(ufoma, usb, 1, 1, 1);
325 MODULE_VERSION(ufoma, 1);
326
327 static const STRUCT_USB_HOST_ID ufoma_devs[] = {
328         {USB_IFACE_CLASS(UICLASS_CDC),
329          USB_IFACE_SUBCLASS(UISUBCLASS_MCPC),},
330 };
331
332 static int
333 ufoma_probe(device_t dev)
334 {
335         struct usb_attach_arg *uaa = device_get_ivars(dev);
336         struct usb_interface_descriptor *id;
337         struct usb_config_descriptor *cd;
338         usb_mcpc_acm_descriptor *mad;
339         int error;
340
341         if (uaa->usb_mode != USB_MODE_HOST)
342                 return (ENXIO);
343
344         error = usbd_lookup_id_by_uaa(ufoma_devs, sizeof(ufoma_devs), uaa);
345         if (error)
346                 return (error);
347
348         id = usbd_get_interface_descriptor(uaa->iface);
349         cd = usbd_get_config_descriptor(uaa->device);
350
351         if (id == NULL || cd == NULL)
352                 return (ENXIO);
353
354         mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
355         if (mad == NULL)
356                 return (ENXIO);
357
358 #ifndef UFOMA_HANDSFREE
359         if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
360             (mad->bType == UMCPC_ACM_TYPE_AB6))
361                 return (ENXIO);
362 #endif
363         return (BUS_PROBE_GENERIC);
364 }
365
366 static int
367 ufoma_attach(device_t dev)
368 {
369         struct usb_attach_arg *uaa = device_get_ivars(dev);
370         struct ufoma_softc *sc = device_get_softc(dev);
371         struct usb_config_descriptor *cd;
372         struct usb_interface_descriptor *id;
373
374         usb_mcpc_acm_descriptor *mad;
375         uint8_t elements;
376         int32_t error;
377
378         sc->sc_udev = uaa->device;
379         sc->sc_dev = dev;
380         sc->sc_unit = device_get_unit(dev);
381
382         lockinit(&sc->sc_lock, "ufoma", 0, LK_CANRECURSE);
383         cv_init(&sc->sc_cv, "CWAIT");
384
385         device_set_usb_desc(dev);
386
387         ksnprintf(sc->sc_name, sizeof(sc->sc_name),
388             "%s", device_get_nameunit(dev));
389
390         DPRINTF("\n");
391
392         /* setup control transfers */
393
394         cd = usbd_get_config_descriptor(uaa->device);
395         id = usbd_get_interface_descriptor(uaa->iface);
396         sc->sc_ctrl_iface_no = id->bInterfaceNumber;
397         sc->sc_ctrl_iface_index = uaa->info.bIfaceIndex;
398
399         error = usbd_transfer_setup(uaa->device,
400             &sc->sc_ctrl_iface_index, sc->sc_ctrl_xfer,
401             ufoma_ctrl_config, UFOMA_CTRL_ENDPT_MAX, sc, &sc->sc_lock);
402
403         if (error) {
404                 device_printf(dev, "allocating control USB "
405                     "transfers failed\n");
406                 goto detach;
407         }
408         mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
409         if (mad == NULL) {
410                 goto detach;
411         }
412         if (mad->bFunctionLength < sizeof(*mad)) {
413                 device_printf(dev, "invalid MAD descriptor\n");
414                 goto detach;
415         }
416         if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
417             (mad->bType == UMCPC_ACM_TYPE_AB6)) {
418                 sc->sc_nobulk = 1;
419         } else {
420                 sc->sc_nobulk = 0;
421                 if (ufoma_modem_setup(dev, sc, uaa)) {
422                         goto detach;
423                 }
424         }
425
426         elements = (mad->bFunctionLength - sizeof(*mad) + 1);
427
428         /* initialize mode variables */
429
430         sc->sc_modetable = kmalloc(elements + 1, M_USBDEV, M_WAITOK);
431
432         if (sc->sc_modetable == NULL) {
433                 goto detach;
434         }
435         sc->sc_modetable[0] = (elements + 1);
436         memcpy(&sc->sc_modetable[1], mad->bMode, elements);
437
438         sc->sc_currentmode = UMCPC_ACM_MODE_UNLINKED;
439         sc->sc_modetoactivate = mad->bMode[0];
440
441         /* clear stall at first run, if any */
442         lockmgr(&sc->sc_lock, LK_EXCLUSIVE);
443         usbd_xfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]);
444         usbd_xfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]);
445         lockmgr(&sc->sc_lock, LK_RELEASE);
446
447         error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
448             &ufoma_callback, &sc->sc_lock);
449         if (error) {
450                 DPRINTF("ucom_attach failed\n");
451                 goto detach;
452         }
453         ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
454
455         /*Sysctls*/
456         sysctl_ctx_init(&sc->sc_sysctl_ctx);
457         sc->sc_sysctl_tree = SYSCTL_ADD_NODE(&sc->sc_sysctl_ctx,
458             SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
459             device_get_nameunit(sc->sc_dev), CTLFLAG_RD, 0, "");
460         if (sc->sc_sysctl_tree == NULL) {
461                 DPRINTF("can't add sysctl node\n");
462                 goto detach;
463         }
464
465         SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx,
466                         SYSCTL_CHILDREN(sc->sc_sysctl_tree),
467                         OID_AUTO, "supportmode",
468                         CTLFLAG_RD|CTLTYPE_STRING, sc, 0, ufoma_sysctl_support,
469                         "A", "Supporting port role");
470
471         SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx,
472                         SYSCTL_CHILDREN(sc->sc_sysctl_tree),
473                         OID_AUTO, "currentmode",
474                         CTLFLAG_RD|CTLTYPE_STRING, sc, 0, ufoma_sysctl_current,
475                         "A", "Current port role");
476
477         SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx,
478                         SYSCTL_CHILDREN(sc->sc_sysctl_tree),
479                         OID_AUTO, "openmode",
480                         CTLFLAG_RW|CTLTYPE_STRING, sc, 0, ufoma_sysctl_open,
481                         "A", "Mode to transit when port is opened");
482         SYSCTL_ADD_UINT(&sc->sc_sysctl_ctx,
483                         SYSCTL_CHILDREN(sc->sc_sysctl_tree),
484                         OID_AUTO, "comunit",
485                         CTLFLAG_RD, &(sc->sc_super_ucom.sc_unit), 0, 
486                         "Unit number as USB serial");
487
488         return (0);                     /* success */
489
490 detach:
491         ufoma_detach(dev);
492         return (ENXIO);                 /* failure */
493 }
494
495 static int
496 ufoma_detach(device_t dev)
497 {
498         struct ufoma_softc *sc = device_get_softc(dev);
499
500         ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
501         usbd_transfer_unsetup(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX);
502         usbd_transfer_unsetup(sc->sc_bulk_xfer, UFOMA_BULK_ENDPT_MAX);
503
504         if (sc->sc_modetable) {
505                 kfree(sc->sc_modetable, M_USBDEV);
506         }
507         lockuninit(&sc->sc_lock);
508         cv_destroy(&sc->sc_cv);
509         sysctl_ctx_free(&sc->sc_sysctl_ctx);
510
511         return (0);
512 }
513
514 static void *
515 ufoma_get_intconf(struct usb_config_descriptor *cd, struct usb_interface_descriptor *id,
516     uint8_t type, uint8_t subtype)
517 {
518         struct usb_descriptor *desc = (void *)id;
519
520         while ((desc = usb_desc_foreach(cd, desc))) {
521
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_lock, 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_lock,
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                 } else {
625                         goto tr_setup;
626                 }
627
628                 goto tr_transferred;
629         }
630 }
631
632 static void
633 ufoma_ctrl_write_callback(struct usb_xfer *xfer, usb_error_t error)
634 {
635         struct ufoma_softc *sc = usbd_xfer_softc(xfer);
636         struct usb_device_request req;
637         struct usb_page_cache *pc;
638         uint32_t actlen;
639
640         switch (USB_GET_STATE(xfer)) {
641         case USB_ST_TRANSFERRED:
642 tr_transferred:
643         case USB_ST_SETUP:
644 tr_setup:
645                 pc = usbd_xfer_get_frame(xfer, 1);
646                 if (ucom_get_data(&sc->sc_ucom, pc, 0, 1, &actlen)) {
647
648                         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
649                         req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
650                         USETW(req.wIndex, sc->sc_ctrl_iface_no);
651                         USETW(req.wValue, 0);
652                         USETW(req.wLength, 1);
653
654                         pc = usbd_xfer_get_frame(xfer, 0);
655                         usbd_copy_in(pc, 0, &req, sizeof(req));
656
657                         usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
658                         usbd_xfer_set_frame_len(xfer, 1, 1);
659                         usbd_xfer_set_frames(xfer, 2);
660
661                         usbd_transfer_submit(xfer);
662                 }
663                 return;
664
665         default:                        /* Error */
666                 DPRINTF("error = %s\n", usbd_errstr(error));
667
668                 if (error == USB_ERR_CANCELLED) {
669                         return;
670                 } else {
671                         goto tr_setup;
672                 }
673
674                 goto tr_transferred;
675         }
676 }
677
678 static void
679 ufoma_intr_callback(struct usb_xfer *xfer, usb_error_t error)
680 {
681         struct ufoma_softc *sc = usbd_xfer_softc(xfer);
682         struct usb_cdc_notification pkt;
683         struct usb_page_cache *pc;
684         uint16_t wLen;
685         uint16_t temp;
686         uint8_t mstatus;
687         int actlen;
688
689         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
690
691         switch (USB_GET_STATE(xfer)) {
692         case USB_ST_TRANSFERRED:
693                 if (actlen < 8) {
694                         DPRINTF("too short message\n");
695                         goto tr_setup;
696                 }
697                 if (actlen > sizeof(pkt)) {
698                         DPRINTF("truncating message\n");
699                         actlen = sizeof(pkt);
700                 }
701                 pc = usbd_xfer_get_frame(xfer, 0);
702                 usbd_copy_out(pc, 0, &pkt, actlen);
703
704                 actlen -= 8;
705
706                 wLen = UGETW(pkt.wLength);
707                 if (actlen > wLen) {
708                         actlen = wLen;
709                 }
710                 if ((pkt.bmRequestType == UT_READ_VENDOR_INTERFACE) &&
711                     (pkt.bNotification == UMCPC_REQUEST_ACKNOWLEDGE)) {
712                         temp = UGETW(pkt.wValue);
713                         sc->sc_currentmode = (temp >> 8);
714                         if (!(temp & 0xff)) {
715                                 DPRINTF("Mode change failed!\n");
716                         }
717                         cv_signal(&sc->sc_cv);
718                 }
719                 if (pkt.bmRequestType != UCDC_NOTIFICATION) {
720                         goto tr_setup;
721                 }
722                 switch (pkt.bNotification) {
723                 case UCDC_N_RESPONSE_AVAILABLE:
724                         if (!(sc->sc_nobulk)) {
725                                 DPRINTF("Wrong serial state!\n");
726                                 break;
727                         }
728                         if (sc->sc_num_msg != 0xFF) {
729                                 sc->sc_num_msg++;
730                         }
731                         usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
732                         break;
733
734                 case UCDC_N_SERIAL_STATE:
735                         if (sc->sc_nobulk) {
736                                 DPRINTF("Wrong serial state!\n");
737                                 break;
738                         }
739                         /*
740                          * Set the serial state in ucom driver based on
741                          * the bits from the notify message
742                          */
743                         if (actlen < 2) {
744                                 DPRINTF("invalid notification "
745                                     "length, %d bytes!\n", actlen);
746                                 break;
747                         }
748                         DPRINTF("notify bytes = 0x%02x, 0x%02x\n",
749                             pkt.data[0], pkt.data[1]);
750
751                         /* currently, lsr is always zero. */
752                         sc->sc_lsr = 0;
753                         sc->sc_msr = 0;
754
755                         mstatus = pkt.data[0];
756
757                         if (mstatus & UCDC_N_SERIAL_RI) {
758                                 sc->sc_msr |= SER_RI;
759                         }
760                         if (mstatus & UCDC_N_SERIAL_DSR) {
761                                 sc->sc_msr |= SER_DSR;
762                         }
763                         if (mstatus & UCDC_N_SERIAL_DCD) {
764                                 sc->sc_msr |= SER_DCD;
765                         }
766                         ucom_status_change(&sc->sc_ucom);
767                         break;
768
769                 default:
770                         break;
771                 }
772
773         case USB_ST_SETUP:
774 tr_setup:
775                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
776                 usbd_transfer_submit(xfer);
777                 return;
778
779         default:                        /* Error */
780                 if (error != USB_ERR_CANCELLED) {
781                         /* try to clear stall first */
782                         usbd_xfer_set_stall(xfer);
783                         goto tr_setup;
784                 }
785                 return;
786         }
787 }
788
789 static void
790 ufoma_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
791 {
792         struct ufoma_softc *sc = usbd_xfer_softc(xfer);
793         struct usb_page_cache *pc;
794         uint32_t actlen;
795
796         switch (USB_GET_STATE(xfer)) {
797         case USB_ST_SETUP:
798         case USB_ST_TRANSFERRED:
799 tr_setup:
800                 pc = usbd_xfer_get_frame(xfer, 0);
801                 if (ucom_get_data(&sc->sc_ucom, pc, 0,
802                     UFOMA_BULK_BUF_SIZE, &actlen)) {
803                         usbd_xfer_set_frame_len(xfer, 0, actlen);
804                         usbd_transfer_submit(xfer);
805                 }
806                 return;
807
808         default:                        /* Error */
809                 if (error != USB_ERR_CANCELLED) {
810                         /* try to clear stall first */
811                         usbd_xfer_set_stall(xfer);
812                         goto tr_setup;
813                 }
814                 return;
815         }
816 }
817
818 static void
819 ufoma_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
820 {
821         struct ufoma_softc *sc = usbd_xfer_softc(xfer);
822         struct usb_page_cache *pc;
823         int actlen;
824
825         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
826
827         switch (USB_GET_STATE(xfer)) {
828         case USB_ST_TRANSFERRED:
829                 pc = usbd_xfer_get_frame(xfer, 0);
830                 ucom_put_data(&sc->sc_ucom, pc, 0, actlen);
831
832         case USB_ST_SETUP:
833 tr_setup:
834                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
835                 usbd_transfer_submit(xfer);
836                 return;
837
838         default:                        /* Error */
839                 if (error != USB_ERR_CANCELLED) {
840                         /* try to clear stall first */
841                         usbd_xfer_set_stall(xfer);
842                         goto tr_setup;
843                 }
844                 return;
845         }
846 }
847
848 static void
849 ufoma_cfg_open(struct ucom_softc *ucom)
850 {
851         struct ufoma_softc *sc = ucom->sc_parent;
852
853         /* empty input queue */
854
855         if (sc->sc_num_msg != 0xFF) {
856                 sc->sc_num_msg++;
857         }
858         if (sc->sc_currentmode == UMCPC_ACM_MODE_UNLINKED) {
859                 ufoma_cfg_link_state(sc);
860         }
861         if (sc->sc_currentmode == UMCPC_ACM_MODE_DEACTIVATED) {
862                 ufoma_cfg_activate_state(sc, sc->sc_modetoactivate);
863         }
864 }
865
866 static void
867 ufoma_cfg_close(struct ucom_softc *ucom)
868 {
869         struct ufoma_softc *sc = ucom->sc_parent;
870
871         ufoma_cfg_activate_state(sc, UMCPC_ACM_MODE_DEACTIVATED);
872 }
873
874 static void
875 ufoma_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
876 {
877         struct ufoma_softc *sc = ucom->sc_parent;
878         struct usb_device_request req;
879         uint16_t wValue;
880
881         if (sc->sc_nobulk ||
882             (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) {
883                 return;
884         }
885         if (!(sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK)) {
886                 return;
887         }
888         wValue = onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF;
889
890         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
891         req.bRequest = UCDC_SEND_BREAK;
892         USETW(req.wValue, wValue);
893         req.wIndex[0] = sc->sc_ctrl_iface_no;
894         req.wIndex[1] = 0;
895         USETW(req.wLength, 0);
896
897         ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
898             &req, NULL, 0, 1000);
899 }
900
901 static void
902 ufoma_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
903 {
904         struct ufoma_softc *sc = ucom->sc_parent;
905
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_lock);
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                 ksnprintf(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                 ksnprintf(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 }