1 /* $NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $ */
3 #define UFOMA_HANDSFREE
5 * Copyright (c) 2005, Takanori Watanabe
6 * Copyright (c) 2003, M. Warner Losh <imp@FreeBSD.org>.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
32 * Copyright (c) 1998 The NetBSD Foundation, Inc.
33 * All rights reserved.
35 * This code is derived from software contributed to The NetBSD Foundation
36 * by Lennart Augustsson (lennart@augustsson.net) at
37 * Carlstedt Research & Technology.
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
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.
48 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
49 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
52 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58 * POSSIBILITY OF SUCH DAMAGE.
62 * Comm Class spec: http://www.usb.org/developers/devclass_docs/usbccs10.pdf
63 * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
68 * - Implement a Call Device for modems without multiplexed commands.
72 * NOTE: all function names beginning like "ufoma_cfg_" can only
73 * be called from within the config thread function !
76 #include <sys/stdint.h>
77 #include <sys/param.h>
78 #include <sys/queue.h>
79 #include <sys/types.h>
80 #include <sys/systm.h>
81 #include <sys/kernel.h>
83 #include <sys/module.h>
85 #include <sys/condvar.h>
86 #include <sys/sysctl.h>
87 #include <sys/unistd.h>
88 #include <sys/callout.h>
89 #include <sys/malloc.h>
92 #include <sys/serial.h>
94 #include <bus/u4b/usb.h>
95 #include <bus/u4b/usbdi.h>
96 #include <bus/u4b/usbdi_util.h>
97 #include <bus/u4b/usb_cdc.h>
100 #define USB_DEBUG_VAR usb_debug
101 #include <bus/u4b/usb_debug.h>
102 #include <bus/u4b/usb_process.h>
104 #include <bus/u4b/serial/usb_serial.h>
106 typedef struct ufoma_mobile_acm_descriptor
{
107 uint8_t bFunctionLength
;
108 uint8_t bDescriptorType
;
109 uint8_t bDescriptorSubtype
;
112 } __packed usb_mcpc_acm_descriptor
;
114 #define UISUBCLASS_MCPC 0x88
116 #define UDESC_VS_INTERFACE 0x44
117 #define UDESCSUB_MCPC_ACM 0x11
119 #define UMCPC_ACM_TYPE_AB1 0x1
120 #define UMCPC_ACM_TYPE_AB2 0x2
121 #define UMCPC_ACM_TYPE_AB5 0x5
122 #define UMCPC_ACM_TYPE_AB6 0x6
124 #define UMCPC_ACM_MODE_DEACTIVATED 0x0
125 #define UMCPC_ACM_MODE_MODEM 0x1
126 #define UMCPC_ACM_MODE_ATCOMMAND 0x2
127 #define UMCPC_ACM_MODE_OBEX 0x60
128 #define UMCPC_ACM_MODE_VENDOR1 0xc0
129 #define UMCPC_ACM_MODE_VENDOR2 0xfe
130 #define UMCPC_ACM_MODE_UNLINKED 0xff
132 #define UMCPC_CM_MOBILE_ACM 0x0
134 #define UMCPC_ACTIVATE_MODE 0x60
135 #define UMCPC_GET_MODETABLE 0x61
136 #define UMCPC_SET_LINK 0x62
137 #define UMCPC_CLEAR_LINK 0x63
139 #define UMCPC_REQUEST_ACKNOWLEDGE 0x31
141 #define UFOMA_MAX_TIMEOUT 15 /* standard says 10 seconds */
142 #define UFOMA_CMD_BUF_SIZE 64 /* bytes */
144 #define UFOMA_BULK_BUF_SIZE 1024 /* bytes */
147 UFOMA_CTRL_ENDPT_INTR
,
148 UFOMA_CTRL_ENDPT_READ
,
149 UFOMA_CTRL_ENDPT_WRITE
,
150 UFOMA_CTRL_ENDPT_MAX
,
154 UFOMA_BULK_ENDPT_WRITE
,
155 UFOMA_BULK_ENDPT_READ
,
156 UFOMA_BULK_ENDPT_MAX
,
160 struct ucom_super_softc sc_super_ucom
;
161 struct ucom_softc sc_ucom
;
165 struct usb_xfer
*sc_ctrl_xfer
[UFOMA_CTRL_ENDPT_MAX
];
166 struct usb_xfer
*sc_bulk_xfer
[UFOMA_BULK_ENDPT_MAX
];
167 uint8_t *sc_modetable
;
169 struct usb_device
*sc_udev
;
177 uint8_t sc_ctrl_iface_no
;
178 uint8_t sc_ctrl_iface_index
;
179 uint8_t sc_data_iface_no
;
180 uint8_t sc_data_iface_index
;
185 uint8_t sc_modetoactivate
;
186 uint8_t sc_currentmode
;
192 static device_probe_t ufoma_probe
;
193 static device_attach_t ufoma_attach
;
194 static device_detach_t ufoma_detach
;
196 static usb_callback_t ufoma_ctrl_read_callback
;
197 static usb_callback_t ufoma_ctrl_write_callback
;
198 static usb_callback_t ufoma_intr_callback
;
199 static usb_callback_t ufoma_bulk_write_callback
;
200 static usb_callback_t ufoma_bulk_read_callback
;
202 static void *ufoma_get_intconf(struct usb_config_descriptor
*,
203 struct usb_interface_descriptor
*, uint8_t, uint8_t);
204 static void ufoma_cfg_link_state(struct ufoma_softc
*);
205 static void ufoma_cfg_activate_state(struct ufoma_softc
*, uint16_t);
206 static void ufoma_cfg_open(struct ucom_softc
*);
207 static void ufoma_cfg_close(struct ucom_softc
*);
208 static void ufoma_cfg_set_break(struct ucom_softc
*, uint8_t);
209 static void ufoma_cfg_get_status(struct ucom_softc
*, uint8_t *,
211 static void ufoma_cfg_set_dtr(struct ucom_softc
*, uint8_t);
212 static void ufoma_cfg_set_rts(struct ucom_softc
*, uint8_t);
213 static int ufoma_pre_param(struct ucom_softc
*, struct termios
*);
214 static void ufoma_cfg_param(struct ucom_softc
*, struct termios
*);
215 static int ufoma_modem_setup(device_t
, struct ufoma_softc
*,
216 struct usb_attach_arg
*);
217 static void ufoma_start_read(struct ucom_softc
*);
218 static void ufoma_stop_read(struct ucom_softc
*);
219 static void ufoma_start_write(struct ucom_softc
*);
220 static void ufoma_stop_write(struct ucom_softc
*);
221 static void ufoma_poll(struct ucom_softc
*ucom
);
224 static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS
);
225 static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS
);
226 static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS
);
228 static const struct usb_config
229 ufoma_ctrl_config
[UFOMA_CTRL_ENDPT_MAX
] = {
231 [UFOMA_CTRL_ENDPT_INTR
] = {
232 .type
= UE_INTERRUPT
,
233 .endpoint
= UE_ADDR_ANY
,
234 .direction
= UE_DIR_IN
,
235 .flags
= {.pipe_bof
= 1,.short_xfer_ok
= 1,},
236 .bufsize
= sizeof(struct usb_cdc_notification
),
237 .callback
= &ufoma_intr_callback
,
240 [UFOMA_CTRL_ENDPT_READ
] = {
242 .endpoint
= 0x00, /* Control pipe */
243 .direction
= UE_DIR_ANY
,
244 .bufsize
= (sizeof(struct usb_device_request
) + UFOMA_CMD_BUF_SIZE
),
245 .flags
= {.short_xfer_ok
= 1,},
246 .callback
= &ufoma_ctrl_read_callback
,
247 .timeout
= 1000, /* 1 second */
250 [UFOMA_CTRL_ENDPT_WRITE
] = {
252 .endpoint
= 0x00, /* Control pipe */
253 .direction
= UE_DIR_ANY
,
254 .bufsize
= (sizeof(struct usb_device_request
) + 1),
255 .callback
= &ufoma_ctrl_write_callback
,
256 .timeout
= 1000, /* 1 second */
260 static const struct usb_config
261 ufoma_bulk_config
[UFOMA_BULK_ENDPT_MAX
] = {
263 [UFOMA_BULK_ENDPT_WRITE
] = {
265 .endpoint
= UE_ADDR_ANY
,
266 .direction
= UE_DIR_OUT
,
267 .bufsize
= UFOMA_BULK_BUF_SIZE
,
268 .flags
= {.pipe_bof
= 1,.force_short_xfer
= 1,},
269 .callback
= &ufoma_bulk_write_callback
,
272 [UFOMA_BULK_ENDPT_READ
] = {
274 .endpoint
= UE_ADDR_ANY
,
275 .direction
= UE_DIR_IN
,
276 .bufsize
= UFOMA_BULK_BUF_SIZE
,
277 .flags
= {.pipe_bof
= 1,.short_xfer_ok
= 1,},
278 .callback
= &ufoma_bulk_read_callback
,
282 static const struct ucom_callback ufoma_callback
= {
283 .ucom_cfg_get_status
= &ufoma_cfg_get_status
,
284 .ucom_cfg_set_dtr
= &ufoma_cfg_set_dtr
,
285 .ucom_cfg_set_rts
= &ufoma_cfg_set_rts
,
286 .ucom_cfg_set_break
= &ufoma_cfg_set_break
,
287 .ucom_cfg_param
= &ufoma_cfg_param
,
288 .ucom_cfg_open
= &ufoma_cfg_open
,
289 .ucom_cfg_close
= &ufoma_cfg_close
,
290 .ucom_pre_param
= &ufoma_pre_param
,
291 .ucom_start_read
= &ufoma_start_read
,
292 .ucom_stop_read
= &ufoma_stop_read
,
293 .ucom_start_write
= &ufoma_start_write
,
294 .ucom_stop_write
= &ufoma_stop_write
,
295 .ucom_poll
= &ufoma_poll
,
298 static device_method_t ufoma_methods
[] = {
300 DEVMETHOD(device_probe
, ufoma_probe
),
301 DEVMETHOD(device_attach
, ufoma_attach
),
302 DEVMETHOD(device_detach
, ufoma_detach
),
306 static devclass_t ufoma_devclass
;
308 static driver_t ufoma_driver
= {
310 .methods
= ufoma_methods
,
311 .size
= sizeof(struct ufoma_softc
),
314 static const STRUCT_USB_HOST_ID ufoma_devs
[] = {
315 {USB_IFACE_CLASS(UICLASS_CDC
),
316 USB_IFACE_SUBCLASS(UISUBCLASS_MCPC
),},
319 DRIVER_MODULE(ufoma
, uhub
, ufoma_driver
, ufoma_devclass
, NULL
, NULL
);
320 MODULE_DEPEND(ufoma
, ucom
, 1, 1, 1);
321 MODULE_DEPEND(ufoma
, usb
, 1, 1, 1);
322 MODULE_VERSION(ufoma
, 1);
325 ufoma_probe(device_t dev
)
327 struct usb_attach_arg
*uaa
= device_get_ivars(dev
);
328 struct usb_interface_descriptor
*id
;
329 struct usb_config_descriptor
*cd
;
330 usb_mcpc_acm_descriptor
*mad
;
333 if (uaa
->usb_mode
!= USB_MODE_HOST
)
336 error
= usbd_lookup_id_by_uaa(ufoma_devs
, sizeof(ufoma_devs
), uaa
);
340 id
= usbd_get_interface_descriptor(uaa
->iface
);
341 cd
= usbd_get_config_descriptor(uaa
->device
);
343 if (id
== NULL
|| cd
== NULL
)
346 mad
= ufoma_get_intconf(cd
, id
, UDESC_VS_INTERFACE
, UDESCSUB_MCPC_ACM
);
350 #ifndef UFOMA_HANDSFREE
351 if ((mad
->bType
== UMCPC_ACM_TYPE_AB5
) ||
352 (mad
->bType
== UMCPC_ACM_TYPE_AB6
))
355 return (BUS_PROBE_GENERIC
);
359 ufoma_attach(device_t dev
)
361 struct usb_attach_arg
*uaa
= device_get_ivars(dev
);
362 struct ufoma_softc
*sc
= device_get_softc(dev
);
363 struct usb_config_descriptor
*cd
;
364 struct usb_interface_descriptor
*id
;
365 struct sysctl_ctx_list
*sctx
;
366 struct sysctl_oid
*soid
;
368 usb_mcpc_acm_descriptor
*mad
;
372 sc
->sc_udev
= uaa
->device
;
374 sc
->sc_unit
= device_get_unit(dev
);
376 lockinit(&sc
->sc_lock
, "ufoma", 0, LK_CANRECURSE
);
377 cv_init(&sc
->sc_cv
, "CWAIT");
379 device_set_usb_desc(dev
);
381 ksnprintf(sc
->sc_name
, sizeof(sc
->sc_name
),
382 "%s", device_get_nameunit(dev
));
386 /* setup control transfers */
388 cd
= usbd_get_config_descriptor(uaa
->device
);
389 id
= usbd_get_interface_descriptor(uaa
->iface
);
390 sc
->sc_ctrl_iface_no
= id
->bInterfaceNumber
;
391 sc
->sc_ctrl_iface_index
= uaa
->info
.bIfaceIndex
;
393 error
= usbd_transfer_setup(uaa
->device
,
394 &sc
->sc_ctrl_iface_index
, sc
->sc_ctrl_xfer
,
395 ufoma_ctrl_config
, UFOMA_CTRL_ENDPT_MAX
, sc
, &sc
->sc_lock
);
398 device_printf(dev
, "allocating control USB "
399 "transfers failed\n");
402 mad
= ufoma_get_intconf(cd
, id
, UDESC_VS_INTERFACE
, UDESCSUB_MCPC_ACM
);
406 if (mad
->bFunctionLength
< sizeof(*mad
)) {
407 device_printf(dev
, "invalid MAD descriptor\n");
410 if ((mad
->bType
== UMCPC_ACM_TYPE_AB5
) ||
411 (mad
->bType
== UMCPC_ACM_TYPE_AB6
)) {
415 if (ufoma_modem_setup(dev
, sc
, uaa
)) {
420 elements
= (mad
->bFunctionLength
- sizeof(*mad
) + 1);
422 /* initialize mode variables */
424 sc
->sc_modetable
= kmalloc(elements
+ 1, M_USBDEV
, M_WAITOK
);
426 if (sc
->sc_modetable
== NULL
) {
429 sc
->sc_modetable
[0] = (elements
+ 1);
430 memcpy(&sc
->sc_modetable
[1], mad
->bMode
, elements
);
432 sc
->sc_currentmode
= UMCPC_ACM_MODE_UNLINKED
;
433 sc
->sc_modetoactivate
= mad
->bMode
[0];
435 /* clear stall at first run, if any */
436 lockmgr(&sc
->sc_lock
, LK_EXCLUSIVE
);
437 usbd_xfer_set_stall(sc
->sc_bulk_xfer
[UFOMA_BULK_ENDPT_WRITE
]);
438 usbd_xfer_set_stall(sc
->sc_bulk_xfer
[UFOMA_BULK_ENDPT_READ
]);
439 lockmgr(&sc
->sc_lock
, LK_RELEASE
);
441 error
= ucom_attach(&sc
->sc_super_ucom
, &sc
->sc_ucom
, 1, sc
,
442 &ufoma_callback
, &sc
->sc_lock
);
444 DPRINTF("ucom_attach failed\n");
447 ucom_set_pnpinfo_usb(&sc
->sc_super_ucom
, dev
);
450 sctx
= device_get_sysctl_ctx(dev
);
451 soid
= device_get_sysctl_tree(dev
);
453 SYSCTL_ADD_PROC(sctx
, SYSCTL_CHILDREN(soid
), OID_AUTO
, "supportmode",
454 CTLFLAG_RD
|CTLTYPE_STRING
, sc
, 0, ufoma_sysctl_support
,
455 "A", "Supporting port role");
457 SYSCTL_ADD_PROC(sctx
, SYSCTL_CHILDREN(soid
), OID_AUTO
, "currentmode",
458 CTLFLAG_RD
|CTLTYPE_STRING
, sc
, 0, ufoma_sysctl_current
,
459 "A", "Current port role");
461 SYSCTL_ADD_PROC(sctx
, SYSCTL_CHILDREN(soid
), OID_AUTO
, "openmode",
462 CTLFLAG_RW
|CTLTYPE_STRING
, sc
, 0, ufoma_sysctl_open
,
463 "A", "Mode to transit when port is opened");
464 SYSCTL_ADD_UINT(sctx
, SYSCTL_CHILDREN(soid
), OID_AUTO
, "comunit",
465 CTLFLAG_RD
, &(sc
->sc_super_ucom
.sc_unit
), 0,
466 "Unit number as USB serial");
468 return (0); /* success */
472 return (ENXIO
); /* failure */
476 ufoma_detach(device_t dev
)
478 struct ufoma_softc
*sc
= device_get_softc(dev
);
480 ucom_detach(&sc
->sc_super_ucom
, &sc
->sc_ucom
);
481 usbd_transfer_unsetup(sc
->sc_ctrl_xfer
, UFOMA_CTRL_ENDPT_MAX
);
482 usbd_transfer_unsetup(sc
->sc_bulk_xfer
, UFOMA_BULK_ENDPT_MAX
);
484 if (sc
->sc_modetable
) {
485 kfree(sc
->sc_modetable
, M_USBDEV
);
487 lockuninit(&sc
->sc_lock
);
488 cv_destroy(&sc
->sc_cv
);
494 ufoma_get_intconf(struct usb_config_descriptor
*cd
, struct usb_interface_descriptor
*id
,
495 uint8_t type
, uint8_t subtype
)
497 struct usb_descriptor
*desc
= (void *)id
;
499 while ((desc
= usb_desc_foreach(cd
, desc
))) {
501 if (desc
->bDescriptorType
== UDESC_INTERFACE
) {
504 if ((desc
->bDescriptorType
== type
) &&
505 (desc
->bDescriptorSubtype
== subtype
)) {
513 ufoma_cfg_link_state(struct ufoma_softc
*sc
)
515 struct usb_device_request req
;
518 req
.bmRequestType
= UT_WRITE_VENDOR_INTERFACE
;
519 req
.bRequest
= UMCPC_SET_LINK
;
520 USETW(req
.wValue
, UMCPC_CM_MOBILE_ACM
);
521 USETW(req
.wIndex
, sc
->sc_ctrl_iface_no
);
522 USETW(req
.wLength
, sc
->sc_modetable
[0]);
524 ucom_cfg_do_request(sc
->sc_udev
, &sc
->sc_ucom
,
525 &req
, sc
->sc_modetable
, 0, 1000);
527 error
= cv_timedwait(&sc
->sc_cv
, &sc
->sc_lock
, hz
);
530 DPRINTF("NO response\n");
535 ufoma_cfg_activate_state(struct ufoma_softc
*sc
, uint16_t state
)
537 struct usb_device_request req
;
540 req
.bmRequestType
= UT_WRITE_VENDOR_INTERFACE
;
541 req
.bRequest
= UMCPC_ACTIVATE_MODE
;
542 USETW(req
.wValue
, state
);
543 USETW(req
.wIndex
, sc
->sc_ctrl_iface_no
);
544 USETW(req
.wLength
, 0);
546 ucom_cfg_do_request(sc
->sc_udev
, &sc
->sc_ucom
,
547 &req
, NULL
, 0, 1000);
549 error
= cv_timedwait(&sc
->sc_cv
, &sc
->sc_lock
,
550 (UFOMA_MAX_TIMEOUT
* hz
));
552 DPRINTF("No response\n");
557 ufoma_ctrl_read_callback(struct usb_xfer
*xfer
, usb_error_t error
)
559 struct ufoma_softc
*sc
= usbd_xfer_softc(xfer
);
560 struct usb_device_request req
;
561 struct usb_page_cache
*pc0
, *pc1
;
562 int len
, aframes
, nframes
;
564 usbd_xfer_status(xfer
, NULL
, NULL
, &aframes
, &nframes
);
566 switch (USB_GET_STATE(xfer
)) {
567 case USB_ST_TRANSFERRED
:
569 if (aframes
!= nframes
)
571 pc1
= usbd_xfer_get_frame(xfer
, 1);
572 len
= usbd_xfer_frame_len(xfer
, 1);
574 ucom_put_data(&sc
->sc_ucom
, pc1
, 0, len
);
578 if (sc
->sc_num_msg
) {
581 req
.bmRequestType
= UT_READ_CLASS_INTERFACE
;
582 req
.bRequest
= UCDC_GET_ENCAPSULATED_RESPONSE
;
583 USETW(req
.wIndex
, sc
->sc_ctrl_iface_no
);
584 USETW(req
.wValue
, 0);
585 USETW(req
.wLength
, UFOMA_CMD_BUF_SIZE
);
587 pc0
= usbd_xfer_get_frame(xfer
, 0);
588 usbd_copy_in(pc0
, 0, &req
, sizeof(req
));
590 usbd_xfer_set_frame_len(xfer
, 0, sizeof(req
));
591 usbd_xfer_set_frame_len(xfer
, 1, UFOMA_CMD_BUF_SIZE
);
592 usbd_xfer_set_frames(xfer
, 2);
593 usbd_transfer_submit(xfer
);
598 DPRINTF("error = %s\n",
601 if (error
== USB_ERR_CANCELLED
) {
612 ufoma_ctrl_write_callback(struct usb_xfer
*xfer
, usb_error_t error
)
614 struct ufoma_softc
*sc
= usbd_xfer_softc(xfer
);
615 struct usb_device_request req
;
616 struct usb_page_cache
*pc
;
619 switch (USB_GET_STATE(xfer
)) {
620 case USB_ST_TRANSFERRED
:
624 pc
= usbd_xfer_get_frame(xfer
, 1);
625 if (ucom_get_data(&sc
->sc_ucom
, pc
, 0, 1, &actlen
)) {
627 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
628 req
.bRequest
= UCDC_SEND_ENCAPSULATED_COMMAND
;
629 USETW(req
.wIndex
, sc
->sc_ctrl_iface_no
);
630 USETW(req
.wValue
, 0);
631 USETW(req
.wLength
, 1);
633 pc
= usbd_xfer_get_frame(xfer
, 0);
634 usbd_copy_in(pc
, 0, &req
, sizeof(req
));
636 usbd_xfer_set_frame_len(xfer
, 0, sizeof(req
));
637 usbd_xfer_set_frame_len(xfer
, 1, 1);
638 usbd_xfer_set_frames(xfer
, 2);
640 usbd_transfer_submit(xfer
);
645 DPRINTF("error = %s\n", usbd_errstr(error
));
647 if (error
== USB_ERR_CANCELLED
) {
658 ufoma_intr_callback(struct usb_xfer
*xfer
, usb_error_t error
)
660 struct ufoma_softc
*sc
= usbd_xfer_softc(xfer
);
661 struct usb_cdc_notification pkt
;
662 struct usb_page_cache
*pc
;
668 usbd_xfer_status(xfer
, &actlen
, NULL
, NULL
, NULL
);
670 switch (USB_GET_STATE(xfer
)) {
671 case USB_ST_TRANSFERRED
:
673 DPRINTF("too short message\n");
676 if (actlen
> sizeof(pkt
)) {
677 DPRINTF("truncating message\n");
678 actlen
= sizeof(pkt
);
680 pc
= usbd_xfer_get_frame(xfer
, 0);
681 usbd_copy_out(pc
, 0, &pkt
, actlen
);
685 wLen
= UGETW(pkt
.wLength
);
689 if ((pkt
.bmRequestType
== UT_READ_VENDOR_INTERFACE
) &&
690 (pkt
.bNotification
== UMCPC_REQUEST_ACKNOWLEDGE
)) {
691 temp
= UGETW(pkt
.wValue
);
692 sc
->sc_currentmode
= (temp
>> 8);
693 if (!(temp
& 0xff)) {
694 DPRINTF("Mode change failed!\n");
696 cv_signal(&sc
->sc_cv
);
698 if (pkt
.bmRequestType
!= UCDC_NOTIFICATION
) {
701 switch (pkt
.bNotification
) {
702 case UCDC_N_RESPONSE_AVAILABLE
:
703 if (!(sc
->sc_nobulk
)) {
704 DPRINTF("Wrong serial state!\n");
707 if (sc
->sc_num_msg
!= 0xFF) {
710 usbd_transfer_start(sc
->sc_ctrl_xfer
[UFOMA_CTRL_ENDPT_READ
]);
713 case UCDC_N_SERIAL_STATE
:
715 DPRINTF("Wrong serial state!\n");
719 * Set the serial state in ucom driver based on
720 * the bits from the notify message
723 DPRINTF("invalid notification "
724 "length, %d bytes!\n", actlen
);
727 DPRINTF("notify bytes = 0x%02x, 0x%02x\n",
728 pkt
.data
[0], pkt
.data
[1]);
730 /* currently, lsr is always zero. */
734 mstatus
= pkt
.data
[0];
736 if (mstatus
& UCDC_N_SERIAL_RI
) {
737 sc
->sc_msr
|= SER_RI
;
739 if (mstatus
& UCDC_N_SERIAL_DSR
) {
740 sc
->sc_msr
|= SER_DSR
;
742 if (mstatus
& UCDC_N_SERIAL_DCD
) {
743 sc
->sc_msr
|= SER_DCD
;
745 ucom_status_change(&sc
->sc_ucom
);
754 usbd_xfer_set_frame_len(xfer
, 0, usbd_xfer_max_len(xfer
));
755 usbd_transfer_submit(xfer
);
759 if (error
!= USB_ERR_CANCELLED
) {
760 /* try to clear stall first */
761 usbd_xfer_set_stall(xfer
);
769 ufoma_bulk_write_callback(struct usb_xfer
*xfer
, usb_error_t error
)
771 struct ufoma_softc
*sc
= usbd_xfer_softc(xfer
);
772 struct usb_page_cache
*pc
;
775 switch (USB_GET_STATE(xfer
)) {
777 case USB_ST_TRANSFERRED
:
779 pc
= usbd_xfer_get_frame(xfer
, 0);
780 if (ucom_get_data(&sc
->sc_ucom
, pc
, 0,
781 UFOMA_BULK_BUF_SIZE
, &actlen
)) {
782 usbd_xfer_set_frame_len(xfer
, 0, actlen
);
783 usbd_transfer_submit(xfer
);
788 if (error
!= USB_ERR_CANCELLED
) {
789 /* try to clear stall first */
790 usbd_xfer_set_stall(xfer
);
798 ufoma_bulk_read_callback(struct usb_xfer
*xfer
, usb_error_t error
)
800 struct ufoma_softc
*sc
= usbd_xfer_softc(xfer
);
801 struct usb_page_cache
*pc
;
804 usbd_xfer_status(xfer
, &actlen
, NULL
, NULL
, NULL
);
806 switch (USB_GET_STATE(xfer
)) {
807 case USB_ST_TRANSFERRED
:
808 pc
= usbd_xfer_get_frame(xfer
, 0);
809 ucom_put_data(&sc
->sc_ucom
, pc
, 0, actlen
);
813 usbd_xfer_set_frame_len(xfer
, 0, usbd_xfer_max_len(xfer
));
814 usbd_transfer_submit(xfer
);
818 if (error
!= USB_ERR_CANCELLED
) {
819 /* try to clear stall first */
820 usbd_xfer_set_stall(xfer
);
828 ufoma_cfg_open(struct ucom_softc
*ucom
)
830 struct ufoma_softc
*sc
= ucom
->sc_parent
;
832 /* empty input queue */
834 if (sc
->sc_num_msg
!= 0xFF) {
837 if (sc
->sc_currentmode
== UMCPC_ACM_MODE_UNLINKED
) {
838 ufoma_cfg_link_state(sc
);
840 if (sc
->sc_currentmode
== UMCPC_ACM_MODE_DEACTIVATED
) {
841 ufoma_cfg_activate_state(sc
, sc
->sc_modetoactivate
);
846 ufoma_cfg_close(struct ucom_softc
*ucom
)
848 struct ufoma_softc
*sc
= ucom
->sc_parent
;
850 ufoma_cfg_activate_state(sc
, UMCPC_ACM_MODE_DEACTIVATED
);
854 ufoma_cfg_set_break(struct ucom_softc
*ucom
, uint8_t onoff
)
856 struct ufoma_softc
*sc
= ucom
->sc_parent
;
857 struct usb_device_request req
;
861 (sc
->sc_currentmode
== UMCPC_ACM_MODE_OBEX
)) {
864 if (!(sc
->sc_acm_cap
& USB_CDC_ACM_HAS_BREAK
)) {
867 wValue
= onoff
? UCDC_BREAK_ON
: UCDC_BREAK_OFF
;
869 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
870 req
.bRequest
= UCDC_SEND_BREAK
;
871 USETW(req
.wValue
, wValue
);
872 req
.wIndex
[0] = sc
->sc_ctrl_iface_no
;
874 USETW(req
.wLength
, 0);
876 ucom_cfg_do_request(sc
->sc_udev
, &sc
->sc_ucom
,
877 &req
, NULL
, 0, 1000);
881 ufoma_cfg_get_status(struct ucom_softc
*ucom
, uint8_t *lsr
, uint8_t *msr
)
883 struct ufoma_softc
*sc
= ucom
->sc_parent
;
890 ufoma_cfg_set_line_state(struct ufoma_softc
*sc
)
892 struct usb_device_request req
;
894 /* Don't send line state emulation request for OBEX port */
895 if (sc
->sc_currentmode
== UMCPC_ACM_MODE_OBEX
) {
898 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
899 req
.bRequest
= UCDC_SET_CONTROL_LINE_STATE
;
900 USETW(req
.wValue
, sc
->sc_line
);
901 req
.wIndex
[0] = sc
->sc_ctrl_iface_no
;
903 USETW(req
.wLength
, 0);
905 ucom_cfg_do_request(sc
->sc_udev
, &sc
->sc_ucom
,
906 &req
, NULL
, 0, 1000);
910 ufoma_cfg_set_dtr(struct ucom_softc
*ucom
, uint8_t onoff
)
912 struct ufoma_softc
*sc
= ucom
->sc_parent
;
918 sc
->sc_line
|= UCDC_LINE_DTR
;
920 sc
->sc_line
&= ~UCDC_LINE_DTR
;
922 ufoma_cfg_set_line_state(sc
);
926 ufoma_cfg_set_rts(struct ucom_softc
*ucom
, uint8_t onoff
)
928 struct ufoma_softc
*sc
= ucom
->sc_parent
;
934 sc
->sc_line
|= UCDC_LINE_RTS
;
936 sc
->sc_line
&= ~UCDC_LINE_RTS
;
938 ufoma_cfg_set_line_state(sc
);
942 ufoma_pre_param(struct ucom_softc
*ucom
, struct termios
*t
)
944 return (0); /* we accept anything */
948 ufoma_cfg_param(struct ucom_softc
*ucom
, struct termios
*t
)
950 struct ufoma_softc
*sc
= ucom
->sc_parent
;
951 struct usb_device_request req
;
952 struct usb_cdc_line_state ls
;
955 (sc
->sc_currentmode
== UMCPC_ACM_MODE_OBEX
)) {
960 memset(&ls
, 0, sizeof(ls
));
962 USETDW(ls
.dwDTERate
, t
->c_ospeed
);
964 if (t
->c_cflag
& CSTOPB
) {
965 ls
.bCharFormat
= UCDC_STOP_BIT_2
;
967 ls
.bCharFormat
= UCDC_STOP_BIT_1
;
970 if (t
->c_cflag
& PARENB
) {
971 if (t
->c_cflag
& PARODD
) {
972 ls
.bParityType
= UCDC_PARITY_ODD
;
974 ls
.bParityType
= UCDC_PARITY_EVEN
;
977 ls
.bParityType
= UCDC_PARITY_NONE
;
980 switch (t
->c_cflag
& CSIZE
) {
995 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
996 req
.bRequest
= UCDC_SET_LINE_CODING
;
997 USETW(req
.wValue
, 0);
998 req
.wIndex
[0] = sc
->sc_ctrl_iface_no
;
1000 USETW(req
.wLength
, UCDC_LINE_STATE_LENGTH
);
1002 ucom_cfg_do_request(sc
->sc_udev
, &sc
->sc_ucom
,
1003 &req
, &ls
, 0, 1000);
1007 ufoma_modem_setup(device_t dev
, struct ufoma_softc
*sc
,
1008 struct usb_attach_arg
*uaa
)
1010 struct usb_config_descriptor
*cd
;
1011 struct usb_cdc_acm_descriptor
*acm
;
1012 struct usb_cdc_cm_descriptor
*cmd
;
1013 struct usb_interface_descriptor
*id
;
1014 struct usb_interface
*iface
;
1018 cd
= usbd_get_config_descriptor(uaa
->device
);
1019 id
= usbd_get_interface_descriptor(uaa
->iface
);
1021 cmd
= ufoma_get_intconf(cd
, id
, UDESC_CS_INTERFACE
, UDESCSUB_CDC_CM
);
1023 if ((cmd
== NULL
) ||
1024 (cmd
->bLength
< sizeof(*cmd
))) {
1027 sc
->sc_cm_cap
= cmd
->bmCapabilities
;
1028 sc
->sc_data_iface_no
= cmd
->bDataInterface
;
1030 acm
= ufoma_get_intconf(cd
, id
, UDESC_CS_INTERFACE
, UDESCSUB_CDC_ACM
);
1032 if ((acm
== NULL
) ||
1033 (acm
->bLength
< sizeof(*acm
))) {
1036 sc
->sc_acm_cap
= acm
->bmCapabilities
;
1038 device_printf(dev
, "data interface %d, has %sCM over data, "
1040 sc
->sc_data_iface_no
,
1041 sc
->sc_cm_cap
& USB_CDC_CM_OVER_DATA
? "" : "no ",
1042 sc
->sc_acm_cap
& USB_CDC_ACM_HAS_BREAK
? "" : "no ");
1044 /* get the data interface too */
1048 iface
= usbd_get_iface(uaa
->device
, i
);
1052 id
= usbd_get_interface_descriptor(iface
);
1054 if (id
&& (id
->bInterfaceNumber
== sc
->sc_data_iface_no
)) {
1055 sc
->sc_data_iface_index
= i
;
1056 usbd_set_parent_iface(uaa
->device
, i
, uaa
->info
.bIfaceIndex
);
1060 device_printf(dev
, "no data interface\n");
1065 error
= usbd_transfer_setup(uaa
->device
,
1066 &sc
->sc_data_iface_index
, sc
->sc_bulk_xfer
,
1067 ufoma_bulk_config
, UFOMA_BULK_ENDPT_MAX
, sc
, &sc
->sc_lock
);
1070 device_printf(dev
, "allocating BULK USB "
1071 "transfers failed\n");
1078 ufoma_start_read(struct ucom_softc
*ucom
)
1080 struct ufoma_softc
*sc
= ucom
->sc_parent
;
1082 /* start interrupt transfer */
1083 usbd_transfer_start(sc
->sc_ctrl_xfer
[UFOMA_CTRL_ENDPT_INTR
]);
1085 /* start data transfer */
1086 if (sc
->sc_nobulk
) {
1087 usbd_transfer_start(sc
->sc_ctrl_xfer
[UFOMA_CTRL_ENDPT_READ
]);
1089 usbd_transfer_start(sc
->sc_bulk_xfer
[UFOMA_BULK_ENDPT_READ
]);
1094 ufoma_stop_read(struct ucom_softc
*ucom
)
1096 struct ufoma_softc
*sc
= ucom
->sc_parent
;
1098 /* stop interrupt transfer */
1099 usbd_transfer_stop(sc
->sc_ctrl_xfer
[UFOMA_CTRL_ENDPT_INTR
]);
1101 /* stop data transfer */
1102 if (sc
->sc_nobulk
) {
1103 usbd_transfer_stop(sc
->sc_ctrl_xfer
[UFOMA_CTRL_ENDPT_READ
]);
1105 usbd_transfer_stop(sc
->sc_bulk_xfer
[UFOMA_BULK_ENDPT_READ
]);
1110 ufoma_start_write(struct ucom_softc
*ucom
)
1112 struct ufoma_softc
*sc
= ucom
->sc_parent
;
1114 if (sc
->sc_nobulk
) {
1115 usbd_transfer_start(sc
->sc_ctrl_xfer
[UFOMA_CTRL_ENDPT_WRITE
]);
1117 usbd_transfer_start(sc
->sc_bulk_xfer
[UFOMA_BULK_ENDPT_WRITE
]);
1122 ufoma_stop_write(struct ucom_softc
*ucom
)
1124 struct ufoma_softc
*sc
= ucom
->sc_parent
;
1126 if (sc
->sc_nobulk
) {
1127 usbd_transfer_stop(sc
->sc_ctrl_xfer
[UFOMA_CTRL_ENDPT_WRITE
]);
1129 usbd_transfer_stop(sc
->sc_bulk_xfer
[UFOMA_BULK_ENDPT_WRITE
]);
1133 static struct umcpc_modetostr_tab
{
1136 }umcpc_modetostr_tab
[]={
1137 {UMCPC_ACM_MODE_DEACTIVATED
, "deactivated"},
1138 {UMCPC_ACM_MODE_MODEM
, "modem"},
1139 {UMCPC_ACM_MODE_ATCOMMAND
, "handsfree"},
1140 {UMCPC_ACM_MODE_OBEX
, "obex"},
1141 {UMCPC_ACM_MODE_VENDOR1
, "vendor1"},
1142 {UMCPC_ACM_MODE_VENDOR2
, "vendor2"},
1143 {UMCPC_ACM_MODE_UNLINKED
, "unlinked"},
1147 static char *ufoma_mode_to_str(int mode
)
1150 for(i
= 0 ;umcpc_modetostr_tab
[i
].str
!= NULL
; i
++){
1151 if(umcpc_modetostr_tab
[i
].mode
== mode
){
1152 return umcpc_modetostr_tab
[i
].str
;
1158 static int ufoma_str_to_mode(char *str
)
1161 for(i
= 0 ;umcpc_modetostr_tab
[i
].str
!= NULL
; i
++){
1162 if(strcmp(str
, umcpc_modetostr_tab
[i
].str
)==0){
1163 return umcpc_modetostr_tab
[i
].mode
;
1169 static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS
)
1171 struct ufoma_softc
*sc
= (struct ufoma_softc
*)oidp
->oid_arg1
;
1176 sbuf_new(&sb
, NULL
, 1, SBUF_AUTOEXTEND
);
1177 for(i
= 1; i
< sc
->sc_modetable
[0]; i
++){
1178 mode
= ufoma_mode_to_str(sc
->sc_modetable
[i
]);
1180 sbuf_cat(&sb
, mode
);
1182 sbuf_printf(&sb
, "(%02x)", sc
->sc_modetable
[i
]);
1184 if(i
< (sc
->sc_modetable
[0]-1))
1189 sysctl_handle_string(oidp
, sbuf_data(&sb
), sbuf_len(&sb
), req
);
1194 static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS
)
1196 struct ufoma_softc
*sc
= (struct ufoma_softc
*)oidp
->oid_arg1
;
1198 char subbuf
[]="(XXX)";
1199 mode
= ufoma_mode_to_str(sc
->sc_currentmode
);
1202 ksnprintf(subbuf
, sizeof(subbuf
), "(%02x)", sc
->sc_currentmode
);
1204 sysctl_handle_string(oidp
, mode
, strlen(mode
), req
);
1208 static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS
)
1210 struct ufoma_softc
*sc
= (struct ufoma_softc
*)oidp
->oid_arg1
;
1217 mode
= ufoma_mode_to_str(sc
->sc_modetoactivate
);
1219 strncpy(subbuf
, mode
, sizeof(subbuf
));
1221 ksnprintf(subbuf
, sizeof(subbuf
), "(%02x)", sc
->sc_modetoactivate
);
1223 error
= sysctl_handle_string(oidp
, subbuf
, sizeof(subbuf
), req
);
1224 if(error
!= 0 || req
->newptr
== NULL
){
1228 if((newmode
= ufoma_str_to_mode(subbuf
)) == -1){
1232 for(i
= 1 ; i
< sc
->sc_modetable
[0] ; i
++){
1233 if(sc
->sc_modetable
[i
] == newmode
){
1234 sc
->sc_modetoactivate
= newmode
;
1243 ufoma_poll(struct ucom_softc
*ucom
)
1245 struct ufoma_softc
*sc
= ucom
->sc_parent
;
1246 usbd_transfer_poll(sc
->sc_ctrl_xfer
, UFOMA_CTRL_ENDPT_MAX
);
1247 usbd_transfer_poll(sc
->sc_bulk_xfer
, UFOMA_BULK_ENDPT_MAX
);