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