ufoma.c revision 184736
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 184736 2008-11-06 17:26:12Z imp $");
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 *sc, struct usb2_device_request *req, void *data);
199static void *ufoma_get_intconf(struct usb2_config_descriptor *cd, struct usb2_interface_descriptor *id, uint8_t type, uint8_t subtype);
200static void ufoma_cfg_link_state(struct ufoma_softc *sc);
201static void ufoma_cfg_activate_state(struct ufoma_softc *sc, uint16_t state);
202static void ufoma_cfg_open(struct usb2_com_softc *ucom);
203static void ufoma_cfg_close(struct usb2_com_softc *ucom);
204static void ufoma_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff);
205static void ufoma_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr);
206static void ufoma_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff);
207static void ufoma_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff);
208static int ufoma_pre_param(struct usb2_com_softc *ucom, struct termios *t);
209static void ufoma_cfg_param(struct usb2_com_softc *ucom, struct termios *t);
210static int ufoma_modem_setup(device_t dev, struct ufoma_softc *sc, struct usb2_attach_arg *uaa);
211static void ufoma_start_read(struct usb2_com_softc *ucom);
212static void ufoma_stop_read(struct usb2_com_softc *ucom);
213static void ufoma_start_write(struct usb2_com_softc *ucom);
214static void ufoma_stop_write(struct usb2_com_softc *ucom);
215
216static const struct usb2_config
217	ufoma_ctrl_config[UFOMA_CTRL_ENDPT_MAX] = {
218
219	[0] = {
220		.type = UE_INTERRUPT,
221		.endpoint = UE_ADDR_ANY,
222		.direction = UE_DIR_IN,
223		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
224		.mh.bufsize = sizeof(struct usb2_cdc_notification),
225		.mh.callback = &ufoma_intr_callback,
226	},
227
228	[1] = {
229		.type = UE_CONTROL,
230		.endpoint = 0x00,	/* Control pipe */
231		.direction = UE_DIR_ANY,
232		.mh.bufsize = sizeof(struct usb2_device_request),
233		.mh.flags = {},
234		.mh.callback = &ufoma_intr_clear_stall_callback,
235		.mh.timeout = 1000,	/* 1 second */
236		.mh.interval = 50,	/* 50ms */
237	},
238
239	[2] = {
240		.type = UE_CONTROL,
241		.endpoint = 0x00,	/* Control pipe */
242		.direction = UE_DIR_ANY,
243		.mh.bufsize = (sizeof(struct usb2_device_request) + UFOMA_CMD_BUF_SIZE),
244		.mh.flags = {.short_xfer_ok = 1,},
245		.mh.callback = &ufoma_ctrl_read_callback,
246		.mh.timeout = 1000,	/* 1 second */
247	},
248
249	[3] = {
250		.type = UE_CONTROL,
251		.endpoint = 0x00,	/* Control pipe */
252		.direction = UE_DIR_ANY,
253		.mh.bufsize = (sizeof(struct usb2_device_request) + 1),
254		.mh.flags = {},
255		.mh.callback = &ufoma_ctrl_write_callback,
256		.mh.timeout = 1000,	/* 1 second */
257	},
258};
259
260static const struct usb2_config
261	ufoma_bulk_config[UFOMA_BULK_ENDPT_MAX] = {
262
263	[0] = {
264		.type = UE_BULK,
265		.endpoint = UE_ADDR_ANY,
266		.direction = UE_DIR_OUT,
267		.mh.bufsize = UFOMA_BULK_BUF_SIZE,
268		.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
269		.mh.callback = &ufoma_bulk_write_callback,
270	},
271
272	[1] = {
273		.type = UE_BULK,
274		.endpoint = UE_ADDR_ANY,
275		.direction = UE_DIR_IN,
276		.mh.bufsize = UFOMA_BULK_BUF_SIZE,
277		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
278		.mh.callback = &ufoma_bulk_read_callback,
279	},
280
281	[2] = {
282		.type = UE_CONTROL,
283		.endpoint = 0x00,	/* Control pipe */
284		.direction = UE_DIR_ANY,
285		.mh.bufsize = sizeof(struct usb2_device_request),
286		.mh.flags = {},
287		.mh.callback = &ufoma_bulk_write_clear_stall_callback,
288		.mh.timeout = 1000,	/* 1 second */
289		.mh.interval = 50,	/* 50ms */
290	},
291
292	[3] = {
293		.type = UE_CONTROL,
294		.endpoint = 0x00,	/* Control pipe */
295		.direction = UE_DIR_ANY,
296		.mh.bufsize = sizeof(struct usb2_device_request),
297		.mh.flags = {},
298		.mh.callback = &ufoma_bulk_read_clear_stall_callback,
299		.mh.timeout = 1000,	/* 1 second */
300		.mh.interval = 50,	/* 50ms */
301	},
302};
303
304static const struct usb2_com_callback ufoma_callback = {
305	.usb2_com_cfg_get_status = &ufoma_cfg_get_status,
306	.usb2_com_cfg_set_dtr = &ufoma_cfg_set_dtr,
307	.usb2_com_cfg_set_rts = &ufoma_cfg_set_rts,
308	.usb2_com_cfg_set_break = &ufoma_cfg_set_break,
309	.usb2_com_cfg_param = &ufoma_cfg_param,
310	.usb2_com_cfg_open = &ufoma_cfg_open,
311	.usb2_com_cfg_close = &ufoma_cfg_close,
312	.usb2_com_pre_param = &ufoma_pre_param,
313	.usb2_com_start_read = &ufoma_start_read,
314	.usb2_com_stop_read = &ufoma_stop_read,
315	.usb2_com_start_write = &ufoma_start_write,
316	.usb2_com_stop_write = &ufoma_stop_write,
317};
318
319static device_method_t ufoma_methods[] = {
320	/* Device methods */
321	DEVMETHOD(device_probe, ufoma_probe),
322	DEVMETHOD(device_attach, ufoma_attach),
323	DEVMETHOD(device_detach, ufoma_detach),
324	{0, 0}
325};
326
327static devclass_t ufoma_devclass;
328
329static driver_t ufoma_driver = {
330	.name = "ufoma",
331	.methods = ufoma_methods,
332	.size = sizeof(struct ufoma_softc),
333};
334
335DRIVER_MODULE(ufoma, ushub, ufoma_driver, ufoma_devclass, NULL, 0);
336MODULE_DEPEND(ufoma, usb2_serial, 1, 1, 1);
337MODULE_DEPEND(ufoma, usb2_core, 1, 1, 1);
338
339static int
340ufoma_probe(device_t dev)
341{
342	struct usb2_attach_arg *uaa = device_get_ivars(dev);
343	struct usb2_interface_descriptor *id;
344	struct usb2_config_descriptor *cd;
345	usb2_mcpc_acm_descriptor *mad;
346
347	if (uaa->usb2_mode != USB_MODE_HOST) {
348		return (ENXIO);
349	}
350	id = usb2_get_interface_descriptor(uaa->iface);
351	cd = usb2_get_config_descriptor(uaa->device);
352
353	if ((id == NULL) ||
354	    (cd == NULL) ||
355	    (id->bInterfaceClass != UICLASS_CDC) ||
356	    (id->bInterfaceSubClass != UISUBCLASS_MCPC)) {
357		return (ENXIO);
358	}
359	mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
360	if (mad == NULL) {
361		return (ENXIO);
362	}
363#ifndef UFOMA_HANDSFREE
364	if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
365	    (mad->bType == UMCPC_ACM_TYPE_AB6)) {
366		return (ENXIO);
367	}
368#endif
369	return (0);
370}
371
372static int
373ufoma_attach(device_t dev)
374{
375	struct usb2_attach_arg *uaa = device_get_ivars(dev);
376	struct ufoma_softc *sc = device_get_softc(dev);
377	struct usb2_config_descriptor *cd;
378	struct usb2_interface_descriptor *id;
379	usb2_mcpc_acm_descriptor *mad;
380	uint8_t elements;
381	int32_t error;
382
383	if (sc == NULL) {
384		return (ENOMEM);
385	}
386	sc->sc_udev = uaa->device;
387	sc->sc_dev = dev;
388	sc->sc_unit = device_get_unit(dev);
389
390	usb2_cv_init(&sc->sc_cv, "CWAIT");
391
392	device_set_usb2_desc(dev);
393
394	snprintf(sc->sc_name, sizeof(sc->sc_name),
395	    "%s", device_get_nameunit(dev));
396
397	DPRINTF("\n");
398
399	/* setup control transfers */
400
401	cd = usb2_get_config_descriptor(uaa->device);
402	id = usb2_get_interface_descriptor(uaa->iface);
403	sc->sc_ctrl_iface_no = id->bInterfaceNumber;
404	sc->sc_ctrl_iface_index = uaa->info.bIfaceIndex;
405
406	error = usb2_transfer_setup(uaa->device,
407	    &sc->sc_ctrl_iface_index, sc->sc_ctrl_xfer,
408	    ufoma_ctrl_config, UFOMA_CTRL_ENDPT_MAX, sc, &Giant);
409
410	if (error) {
411		device_printf(dev, "allocating control USB "
412		    "transfers failed!\n");
413		goto detach;
414	}
415	mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
416	if (mad == NULL) {
417		goto detach;
418	}
419	if (mad->bFunctionLength < sizeof(*mad)) {
420		device_printf(dev, "invalid MAD descriptor\n");
421		goto detach;
422	}
423	if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
424	    (mad->bType == UMCPC_ACM_TYPE_AB6)) {
425		sc->sc_is_pseudo = 1;
426	} else {
427		sc->sc_is_pseudo = 0;
428		if (ufoma_modem_setup(dev, sc, uaa)) {
429			goto detach;
430		}
431	}
432
433	elements = (mad->bFunctionLength - sizeof(*mad) + 1);
434
435	/* initialize mode variables */
436
437	sc->sc_modetable = malloc(elements + 1, M_USBDEV, M_WAITOK);
438
439	if (sc->sc_modetable == NULL) {
440		goto detach;
441	}
442	sc->sc_modetable[0] = (elements + 1);
443	bcopy(mad->bMode, &sc->sc_modetable[1], elements);
444
445	sc->sc_currentmode = UMCPC_ACM_MODE_UNLINKED;
446	sc->sc_modetoactivate = mad->bMode[0];
447
448	/* clear stall at first run */
449	sc->sc_flags |= (UFOMA_FLAG_BULK_WRITE_STALL |
450	    UFOMA_FLAG_BULK_READ_STALL);
451
452	error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
453	    &ufoma_callback, &Giant);
454	if (error) {
455		DPRINTF("usb2_com_attach failed\n");
456		goto detach;
457	}
458	return (0);			/* success */
459
460detach:
461	ufoma_detach(dev);
462	return (ENXIO);			/* failure */
463}
464
465static int
466ufoma_detach(device_t dev)
467{
468	struct ufoma_softc *sc = device_get_softc(dev);
469
470	usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
471
472	usb2_transfer_unsetup(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX);
473
474	usb2_transfer_unsetup(sc->sc_bulk_xfer, UFOMA_BULK_ENDPT_MAX);
475
476	if (sc->sc_modetable) {
477		free(sc->sc_modetable, M_USBDEV);
478	}
479	usb2_cv_destroy(&sc->sc_cv);
480
481	return (0);
482}
483
484static void
485ufoma_cfg_do_request(struct ufoma_softc *sc, struct usb2_device_request *req,
486    void *data)
487{
488	uint16_t length;
489	usb2_error_t err;
490
491	if (usb2_com_cfg_is_gone(&sc->sc_ucom)) {
492		goto error;
493	}
494	err = usb2_do_request_flags
495	    (sc->sc_udev, &Giant, req, data, 0, NULL, 1000);
496
497	if (err) {
498
499		DPRINTFN(0, "device request failed, err=%s "
500		    "(ignored)\n", usb2_errstr(err));
501
502error:
503		length = UGETW(req->wLength);
504
505		if ((req->bmRequestType & UT_READ) && length) {
506			bzero(data, length);
507		}
508	}
509	return;
510}
511
512static void *
513ufoma_get_intconf(struct usb2_config_descriptor *cd, struct usb2_interface_descriptor *id,
514    uint8_t type, uint8_t subtype)
515{
516	struct usb2_descriptor *desc = (void *)id;
517
518	while ((desc = usb2_desc_foreach(cd, desc))) {
519
520		if (desc->bDescriptorType == UDESC_INTERFACE) {
521			return (NULL);
522		}
523		if ((desc->bDescriptorType == type) &&
524		    (desc->bDescriptorSubtype == subtype)) {
525			break;
526		}
527	}
528	return (desc);
529}
530
531static void
532ufoma_cfg_link_state(struct ufoma_softc *sc)
533{
534	struct usb2_device_request req;
535	int32_t error;
536
537	req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
538	req.bRequest = UMCPC_SET_LINK;
539	USETW(req.wValue, UMCPC_CM_MOBILE_ACM);
540	USETW(req.wIndex, sc->sc_ctrl_iface_no);
541	USETW(req.wLength, sc->sc_modetable[0]);
542
543	ufoma_cfg_do_request(sc, &req, sc->sc_modetable);
544
545	error = usb2_cv_timedwait(&sc->sc_cv, &Giant, hz);
546
547	if (error) {
548		DPRINTF("NO response\n");
549	}
550	return;
551}
552
553static void
554ufoma_cfg_activate_state(struct ufoma_softc *sc, uint16_t state)
555{
556	struct usb2_device_request req;
557	int32_t error;
558
559	req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
560	req.bRequest = UMCPC_ACTIVATE_MODE;
561	USETW(req.wValue, state);
562	USETW(req.wIndex, sc->sc_ctrl_iface_no);
563	USETW(req.wLength, 0);
564
565	ufoma_cfg_do_request(sc, &req, NULL);
566
567	error = usb2_cv_timedwait(&sc->sc_cv, &Giant,
568	    (UFOMA_MAX_TIMEOUT * hz));
569	if (error) {
570		DPRINTF("No response\n");
571	}
572	return;
573}
574
575static void
576ufoma_ctrl_read_callback(struct usb2_xfer *xfer)
577{
578	struct ufoma_softc *sc = xfer->priv_sc;
579	struct usb2_device_request req;
580
581	switch (USB_GET_STATE(xfer)) {
582	case USB_ST_TRANSFERRED:
583tr_transferred:
584		if (xfer->aframes != xfer->nframes) {
585			goto tr_setup;
586		}
587		if (xfer->frlengths[1] > 0) {
588			usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers + 1,
589			    0, xfer->frlengths[1]);
590		}
591	case USB_ST_SETUP:
592tr_setup:
593		if (sc->sc_num_msg) {
594			sc->sc_num_msg--;
595
596			req.bmRequestType = UT_READ_CLASS_INTERFACE;
597			req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE;
598			USETW(req.wIndex, sc->sc_ctrl_iface_no);
599			USETW(req.wValue, 0);
600			USETW(req.wLength, UFOMA_CMD_BUF_SIZE);
601
602			usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req));
603
604			xfer->frlengths[0] = sizeof(req);
605			xfer->frlengths[1] = UFOMA_CMD_BUF_SIZE;
606			xfer->nframes = 2;
607			usb2_start_hardware(xfer);
608		}
609		return;
610
611	default:			/* Error */
612		DPRINTF("error = %s\n",
613		    usb2_errstr(xfer->error));
614
615		if (xfer->error == USB_ERR_CANCELLED) {
616			return;
617		} else {
618			goto tr_setup;
619		}
620
621		goto tr_transferred;
622	}
623}
624
625static void
626ufoma_ctrl_write_callback(struct usb2_xfer *xfer)
627{
628	struct ufoma_softc *sc = xfer->priv_sc;
629	struct usb2_device_request req;
630	uint32_t actlen;
631
632	switch (USB_GET_STATE(xfer)) {
633	case USB_ST_TRANSFERRED:
634tr_transferred:
635	case USB_ST_SETUP:
636tr_setup:
637		if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers + 1,
638		    0, 1, &actlen)) {
639
640			req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
641			req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
642			USETW(req.wIndex, sc->sc_ctrl_iface_no);
643			USETW(req.wValue, 0);
644			USETW(req.wLength, 1);
645
646			usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req));
647
648			xfer->frlengths[0] = sizeof(req);
649			xfer->frlengths[1] = 1;
650			xfer->nframes = 2;
651
652			usb2_start_hardware(xfer);
653		}
654		return;
655
656	default:			/* Error */
657		DPRINTF("error = %s\n",
658		    usb2_errstr(xfer->error));
659
660		if (xfer->error == USB_ERR_CANCELLED) {
661			return;
662		} else {
663			goto tr_setup;
664		}
665
666		goto tr_transferred;
667	}
668}
669
670static void
671ufoma_intr_clear_stall_callback(struct usb2_xfer *xfer)
672{
673	struct ufoma_softc *sc = xfer->priv_sc;
674	struct usb2_xfer *xfer_other = sc->sc_ctrl_xfer[0];
675
676	if (usb2_clear_stall_callback(xfer, xfer_other)) {
677		DPRINTF("stall cleared\n");
678		sc->sc_flags &= ~UFOMA_FLAG_INTR_STALL;
679		usb2_transfer_start(xfer_other);
680	}
681	return;
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	return;
837}
838
839static void
840ufoma_bulk_read_callback(struct usb2_xfer *xfer)
841{
842	struct ufoma_softc *sc = xfer->priv_sc;
843
844	switch (USB_GET_STATE(xfer)) {
845	case USB_ST_TRANSFERRED:
846		usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0,
847		    xfer->actlen);
848
849	case USB_ST_SETUP:
850		if (sc->sc_flags & UFOMA_FLAG_BULK_READ_STALL) {
851			usb2_transfer_start(sc->sc_bulk_xfer[3]);
852		} else {
853			xfer->frlengths[0] = xfer->max_data_length;
854			usb2_start_hardware(xfer);
855		}
856		return;
857
858	default:			/* Error */
859		if (xfer->error != USB_ERR_CANCELLED) {
860			sc->sc_flags |= UFOMA_FLAG_BULK_READ_STALL;
861			usb2_transfer_start(sc->sc_bulk_xfer[3]);
862		}
863		return;
864
865	}
866}
867
868static void
869ufoma_bulk_read_clear_stall_callback(struct usb2_xfer *xfer)
870{
871	struct ufoma_softc *sc = xfer->priv_sc;
872	struct usb2_xfer *xfer_other = sc->sc_bulk_xfer[1];
873
874	if (usb2_clear_stall_callback(xfer, xfer_other)) {
875		DPRINTF("stall cleared\n");
876		sc->sc_flags &= ~UFOMA_FLAG_BULK_READ_STALL;
877		usb2_transfer_start(xfer_other);
878	}
879	return;
880}
881
882static void
883ufoma_cfg_open(struct usb2_com_softc *ucom)
884{
885	struct ufoma_softc *sc = ucom->sc_parent;
886
887	/* empty input queue */
888
889	if (sc->sc_num_msg != 0xFF) {
890		sc->sc_num_msg++;
891	}
892	if (sc->sc_currentmode == UMCPC_ACM_MODE_UNLINKED) {
893		ufoma_cfg_link_state(sc);
894	}
895	if (sc->sc_currentmode == UMCPC_ACM_MODE_DEACTIVATED) {
896		ufoma_cfg_activate_state(sc, sc->sc_modetoactivate);
897	}
898	return;
899}
900
901static void
902ufoma_cfg_close(struct usb2_com_softc *ucom)
903{
904	struct ufoma_softc *sc = ucom->sc_parent;
905
906	ufoma_cfg_activate_state(sc, UMCPC_ACM_MODE_DEACTIVATED);
907	return;
908}
909
910static void
911ufoma_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
912{
913	struct ufoma_softc *sc = ucom->sc_parent;
914	struct usb2_device_request req;
915	uint16_t wValue;
916
917	if (sc->sc_is_pseudo) {
918		return;
919	}
920	if (!(sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK)) {
921		return;
922	}
923	wValue = onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF;
924
925	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
926	req.bRequest = UCDC_SEND_BREAK;
927	USETW(req.wValue, wValue);
928	req.wIndex[0] = sc->sc_ctrl_iface_no;
929	req.wIndex[1] = 0;
930	USETW(req.wLength, 0);
931
932	ufoma_cfg_do_request(sc, &req, 0);
933	return;
934}
935
936static void
937ufoma_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
938{
939	struct ufoma_softc *sc = ucom->sc_parent;
940
941	*lsr = sc->sc_lsr;
942	*msr = sc->sc_msr;
943	return;
944}
945
946static void
947ufoma_cfg_set_line_state(struct ufoma_softc *sc)
948{
949	struct usb2_device_request req;
950
951	/* Don't send line state emulation request for OBEX port */
952	if (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX) {
953		return;
954	}
955	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
956	req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
957	USETW(req.wValue, sc->sc_line);
958	req.wIndex[0] = sc->sc_ctrl_iface_no;
959	req.wIndex[1] = 0;
960	USETW(req.wLength, 0);
961
962	ufoma_cfg_do_request(sc, &req, 0);
963	return;
964}
965
966static void
967ufoma_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
968{
969	struct ufoma_softc *sc = ucom->sc_parent;
970
971	if (sc->sc_is_pseudo) {
972		return;
973	}
974	if (onoff)
975		sc->sc_line |= UCDC_LINE_DTR;
976	else
977		sc->sc_line &= ~UCDC_LINE_DTR;
978
979	ufoma_cfg_set_line_state(sc);
980	return;
981}
982
983static void
984ufoma_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
985{
986	struct ufoma_softc *sc = ucom->sc_parent;
987
988	if (sc->sc_is_pseudo) {
989		return;
990	}
991	if (onoff)
992		sc->sc_line |= UCDC_LINE_RTS;
993	else
994		sc->sc_line &= ~UCDC_LINE_RTS;
995
996	ufoma_cfg_set_line_state(sc);
997	return;
998}
999
1000static int
1001ufoma_pre_param(struct usb2_com_softc *ucom, struct termios *t)
1002{
1003	return (0);			/* we accept anything */
1004}
1005
1006static void
1007ufoma_cfg_param(struct usb2_com_softc *ucom, struct termios *t)
1008{
1009	struct ufoma_softc *sc = ucom->sc_parent;
1010	struct usb2_device_request req;
1011	struct usb2_cdc_line_state ls;
1012
1013	if (sc->sc_is_pseudo ||
1014	    (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) {
1015		return;
1016	}
1017	DPRINTF("\n");
1018
1019	bzero(&ls, sizeof(ls));
1020
1021	USETDW(ls.dwDTERate, t->c_ospeed);
1022
1023	if (t->c_cflag & CSTOPB) {
1024		ls.bCharFormat = UCDC_STOP_BIT_2;
1025	} else {
1026		ls.bCharFormat = UCDC_STOP_BIT_1;
1027	}
1028
1029	if (t->c_cflag & PARENB) {
1030		if (t->c_cflag & PARODD) {
1031			ls.bParityType = UCDC_PARITY_ODD;
1032		} else {
1033			ls.bParityType = UCDC_PARITY_EVEN;
1034		}
1035	} else {
1036		ls.bParityType = UCDC_PARITY_NONE;
1037	}
1038
1039	switch (t->c_cflag & CSIZE) {
1040	case CS5:
1041		ls.bDataBits = 5;
1042		break;
1043	case CS6:
1044		ls.bDataBits = 6;
1045		break;
1046	case CS7:
1047		ls.bDataBits = 7;
1048		break;
1049	case CS8:
1050		ls.bDataBits = 8;
1051		break;
1052	}
1053
1054	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1055	req.bRequest = UCDC_SET_LINE_CODING;
1056	USETW(req.wValue, 0);
1057	req.wIndex[0] = sc->sc_ctrl_iface_no;
1058	req.wIndex[1] = 0;
1059	USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
1060
1061	ufoma_cfg_do_request(sc, &req, &ls);
1062	return;
1063}
1064
1065static int
1066ufoma_modem_setup(device_t dev, struct ufoma_softc *sc,
1067    struct usb2_attach_arg *uaa)
1068{
1069	struct usb2_config_descriptor *cd;
1070	struct usb2_cdc_acm_descriptor *acm;
1071	struct usb2_cdc_cm_descriptor *cmd;
1072	struct usb2_interface_descriptor *id;
1073	struct usb2_interface *iface;
1074	uint8_t i;
1075	int32_t error;
1076
1077	cd = usb2_get_config_descriptor(uaa->device);
1078	id = usb2_get_interface_descriptor(uaa->iface);
1079
1080	cmd = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM);
1081
1082	if ((cmd == NULL) ||
1083	    (cmd->bLength < sizeof(*cmd))) {
1084		return (EINVAL);
1085	}
1086	sc->sc_cm_cap = cmd->bmCapabilities;
1087	sc->sc_data_iface_no = cmd->bDataInterface;
1088
1089	acm = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM);
1090
1091	if ((acm == NULL) ||
1092	    (acm->bLength < sizeof(*acm))) {
1093		return (EINVAL);
1094	}
1095	sc->sc_acm_cap = acm->bmCapabilities;
1096
1097	device_printf(dev, "data interface %d, has %sCM over data, "
1098	    "has %sbreak\n",
1099	    sc->sc_data_iface_no,
1100	    sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ",
1101	    sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no ");
1102
1103	/* get the data interface too */
1104
1105	for (i = 0;; i++) {
1106
1107		iface = usb2_get_iface(uaa->device, i);
1108
1109		if (iface) {
1110
1111			id = usb2_get_interface_descriptor(iface);
1112
1113			if (id && (id->bInterfaceNumber == sc->sc_data_iface_no)) {
1114				sc->sc_data_iface_index = i;
1115				usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex);
1116				break;
1117			}
1118		} else {
1119			device_printf(dev, "no data interface!\n");
1120			return (EINVAL);
1121		}
1122	}
1123
1124	error = usb2_transfer_setup(uaa->device,
1125	    &sc->sc_data_iface_index, sc->sc_bulk_xfer,
1126	    ufoma_bulk_config, UFOMA_BULK_ENDPT_MAX, sc, &Giant);
1127
1128	if (error) {
1129		device_printf(dev, "allocating BULK USB "
1130		    "transfers failed!\n");
1131		return (EINVAL);
1132	}
1133	return (0);
1134}
1135
1136static void
1137ufoma_start_read(struct usb2_com_softc *ucom)
1138{
1139	struct ufoma_softc *sc = ucom->sc_parent;
1140
1141	/* start interrupt transfer */
1142	usb2_transfer_start(sc->sc_ctrl_xfer[0]);
1143
1144	/* start data transfer */
1145	if (sc->sc_is_pseudo) {
1146		usb2_transfer_start(sc->sc_ctrl_xfer[2]);
1147	} else {
1148		usb2_transfer_start(sc->sc_bulk_xfer[1]);
1149	}
1150	return;
1151}
1152
1153static void
1154ufoma_stop_read(struct usb2_com_softc *ucom)
1155{
1156	struct ufoma_softc *sc = ucom->sc_parent;
1157
1158	/* stop interrupt transfer */
1159	usb2_transfer_stop(sc->sc_ctrl_xfer[1]);
1160	usb2_transfer_stop(sc->sc_ctrl_xfer[0]);
1161
1162	/* stop data transfer */
1163	if (sc->sc_is_pseudo) {
1164		usb2_transfer_stop(sc->sc_ctrl_xfer[2]);
1165	} else {
1166		usb2_transfer_stop(sc->sc_bulk_xfer[3]);
1167		usb2_transfer_stop(sc->sc_bulk_xfer[1]);
1168	}
1169	return;
1170}
1171
1172static void
1173ufoma_start_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_start(sc->sc_ctrl_xfer[3]);
1179	} else {
1180		usb2_transfer_start(sc->sc_bulk_xfer[0]);
1181	}
1182	return;
1183}
1184
1185static void
1186ufoma_stop_write(struct usb2_com_softc *ucom)
1187{
1188	struct ufoma_softc *sc = ucom->sc_parent;
1189
1190	if (sc->sc_is_pseudo) {
1191		usb2_transfer_stop(sc->sc_ctrl_xfer[3]);
1192	} else {
1193		usb2_transfer_stop(sc->sc_bulk_xfer[2]);
1194		usb2_transfer_stop(sc->sc_bulk_xfer[0]);
1195	}
1196	return;
1197}
1198