Home | History | Annotate | Line # | Download | only in usb
umodem.c revision 1.15.4.1
      1  1.15.4.1      fvdl /*	$NetBSD: umodem.c,v 1.15.4.1 1999/11/15 00:41:37 fvdl Exp $	*/
      2       1.1  augustss 
      3       1.1  augustss /*
      4       1.1  augustss  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5       1.1  augustss  * All rights reserved.
      6       1.1  augustss  *
      7       1.1  augustss  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1  augustss  * by Lennart Augustsson (augustss (at) carlstedt.se) at
      9       1.1  augustss  * Carlstedt Research & Technology.
     10       1.1  augustss  *
     11       1.1  augustss  * Redistribution and use in source and binary forms, with or without
     12       1.1  augustss  * modification, are permitted provided that the following conditions
     13       1.1  augustss  * are met:
     14       1.1  augustss  * 1. Redistributions of source code must retain the above copyright
     15       1.1  augustss  *    notice, this list of conditions and the following disclaimer.
     16       1.1  augustss  * 2. Redistributions in binary form must reproduce the above copyright
     17       1.1  augustss  *    notice, this list of conditions and the following disclaimer in the
     18       1.1  augustss  *    documentation and/or other materials provided with the distribution.
     19       1.1  augustss  * 3. All advertising materials mentioning features or use of this software
     20       1.1  augustss  *    must display the following acknowledgement:
     21       1.1  augustss  *        This product includes software developed by the NetBSD
     22       1.1  augustss  *        Foundation, Inc. and its contributors.
     23       1.1  augustss  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24       1.1  augustss  *    contributors may be used to endorse or promote products derived
     25       1.1  augustss  *    from this software without specific prior written permission.
     26       1.1  augustss  *
     27       1.1  augustss  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28       1.1  augustss  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29       1.1  augustss  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30       1.1  augustss  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31       1.1  augustss  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32       1.1  augustss  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33       1.1  augustss  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34       1.1  augustss  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35       1.1  augustss  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36       1.1  augustss  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37       1.1  augustss  * POSSIBILITY OF SUCH DAMAGE.
     38       1.6  augustss  */
     39       1.6  augustss 
     40       1.6  augustss /*
     41       1.9  augustss  * Comm Class spec: http://www.usb.org/developers/data/usbcdc11.pdf
     42       1.9  augustss  */
     43       1.9  augustss 
     44       1.9  augustss /*
     45       1.9  augustss  * TODO:
     46       1.9  augustss  * - Add error recovery in various places; the big problem is what
     47       1.9  augustss  *   to do in a callback if there is an error.
     48       1.9  augustss  * - Implement a Call Device for modems without multiplexed commands.
     49       1.9  augustss  *
     50       1.1  augustss  */
     51       1.1  augustss 
     52       1.1  augustss #include <sys/param.h>
     53       1.1  augustss #include <sys/systm.h>
     54       1.1  augustss #include <sys/kernel.h>
     55       1.1  augustss #include <sys/malloc.h>
     56       1.1  augustss #include <sys/ioctl.h>
     57       1.3  augustss #include <sys/conf.h>
     58       1.1  augustss #include <sys/tty.h>
     59       1.1  augustss #include <sys/file.h>
     60       1.1  augustss #include <sys/select.h>
     61       1.1  augustss #include <sys/proc.h>
     62       1.1  augustss #include <sys/vnode.h>
     63       1.1  augustss #include <sys/device.h>
     64       1.1  augustss #include <sys/poll.h>
     65       1.1  augustss 
     66       1.1  augustss #include <dev/usb/usb.h>
     67       1.9  augustss #include <dev/usb/usbcdc.h>
     68       1.9  augustss 
     69       1.1  augustss #include <dev/usb/usbdi.h>
     70       1.1  augustss #include <dev/usb/usbdi_util.h>
     71       1.1  augustss #include <dev/usb/usbdevs.h>
     72       1.1  augustss #include <dev/usb/usb_quirks.h>
     73       1.1  augustss 
     74       1.9  augustss #include <dev/usb/usbdevs.h>
     75       1.9  augustss 
     76       1.1  augustss #ifdef USB_DEBUG
     77       1.9  augustss #define DPRINTFN(n, x)	if (umodemdebug > (n)) logprintf x
     78       1.1  augustss int	umodemdebug = 0;
     79       1.1  augustss #else
     80       1.9  augustss #define DPRINTFN(n, x)
     81       1.1  augustss #endif
     82       1.9  augustss #define DPRINTF(x) DPRINTFN(0, x)
     83       1.9  augustss 
     84       1.9  augustss /* Macros to clear/set/test flags. */
     85       1.9  augustss #define	SET(t, f)	(t) |= (f)
     86       1.9  augustss #define	CLR(t, f)	(t) &= ~((unsigned)(f))
     87       1.9  augustss #define	ISSET(t, f)	((t) & (f))
     88       1.9  augustss 
     89       1.9  augustss #define	UMODEMUNIT_MASK		0x3ffff
     90       1.9  augustss #define	UMODEMDIALOUT_MASK	0x80000
     91       1.9  augustss #define	UMODEMCALLUNIT_MASK	0x40000
     92       1.9  augustss 
     93       1.9  augustss #define	UMODEMUNIT(x)		(minor(x) & UMODEMUNIT_MASK)
     94       1.9  augustss #define	UMODEMDIALOUT(x)	(minor(x) & UMODEMDIALOUT_MASK)
     95       1.9  augustss #define	UMODEMCALLUNIT(x)	(minor(x) & UMODEMCALLUNIT_MASK)
     96       1.9  augustss 
     97       1.9  augustss #define UMODEMIBUFSIZE 64
     98       1.1  augustss 
     99       1.1  augustss struct umodem_softc {
    100      1.13  augustss 	USBBASEDEVICE		sc_dev;		/* base device */
    101       1.9  augustss 
    102       1.9  augustss 	usbd_device_handle	sc_udev;	/* USB device */
    103       1.9  augustss 
    104       1.9  augustss 	int			sc_ctl_iface_no;
    105       1.9  augustss 	usbd_interface_handle	sc_ctl_iface;	/* control interface */
    106       1.9  augustss 	int			sc_data_iface_no;
    107       1.9  augustss 	usbd_interface_handle	sc_data_iface;	/* data interface */
    108       1.9  augustss 
    109       1.9  augustss 	int			sc_bulkin_no;	/* bulk in endpoint address */
    110       1.9  augustss 	usbd_pipe_handle	sc_bulkin_pipe;	/* bulk in pipe */
    111  1.15.4.1      fvdl 	usbd_xfer_handle	sc_ixfer;	/* read request */
    112       1.9  augustss 	u_char			*sc_ibuf;	/* read buffer */
    113       1.9  augustss 
    114       1.9  augustss 	int			sc_bulkout_no;	/* bulk out endpoint address */
    115       1.9  augustss 	usbd_pipe_handle	sc_bulkout_pipe;/* bulk out pipe */
    116  1.15.4.1      fvdl 	usbd_xfer_handle	sc_oxfer;	/* read request */
    117       1.9  augustss 
    118       1.9  augustss 	int			sc_cm_cap;	/* CM capabilities */
    119       1.9  augustss 	int			sc_acm_cap;	/* ACM capabilities */
    120       1.9  augustss 
    121       1.9  augustss 	int			sc_cm_over_data;
    122       1.9  augustss 
    123       1.9  augustss 	struct tty		*sc_tty;	/* our tty */
    124       1.9  augustss 
    125       1.9  augustss 	usb_cdc_line_state_t	sc_line_state;	/* current line state */
    126       1.9  augustss 	u_char			sc_dtr;		/* current DTR state */
    127       1.9  augustss 
    128       1.9  augustss 	u_char			sc_opening;	/* lock during open */
    129       1.9  augustss 	u_char			sc_dying;	/* disconnecting */
    130       1.1  augustss };
    131       1.1  augustss 
    132       1.9  augustss cdev_decl(umodem);
    133       1.9  augustss 
    134       1.9  augustss void *umodem_get_desc
    135       1.9  augustss 	__P((usbd_device_handle dev, int type, int subtype));
    136       1.9  augustss usbd_status umodem_set_comm_feature
    137       1.9  augustss 	__P((struct umodem_softc *sc, int feature, int state));
    138       1.9  augustss usbd_status umodem_set_line_coding
    139       1.9  augustss 	__P((struct umodem_softc *sc, usb_cdc_line_state_t *state));
    140       1.9  augustss 
    141       1.9  augustss void	umodem_get_caps	__P((usbd_device_handle, int *, int *));
    142       1.9  augustss void	umodem_cleanup	__P((struct umodem_softc *));
    143       1.9  augustss int	umodemparam	__P((struct tty *, struct termios *));
    144       1.9  augustss void	umodemstart	__P((struct tty *));
    145       1.9  augustss void	umodem_shutdown	__P((struct umodem_softc *));
    146       1.9  augustss void	umodem_modem	__P((struct umodem_softc *, int));
    147       1.9  augustss void	umodem_break	__P((struct umodem_softc *, int));
    148       1.9  augustss usbd_status umodemstartread __P((struct umodem_softc *));
    149  1.15.4.1      fvdl void	umodemreadcb	__P((usbd_xfer_handle, usbd_private_handle,
    150       1.9  augustss 			     usbd_status status));
    151  1.15.4.1      fvdl void	umodemwritecb	__P((usbd_xfer_handle, usbd_private_handle,
    152       1.9  augustss 			     usbd_status status));
    153       1.1  augustss 
    154       1.3  augustss USB_DECLARE_DRIVER(umodem);
    155       1.1  augustss 
    156       1.3  augustss USB_MATCH(umodem)
    157       1.3  augustss {
    158       1.3  augustss 	USB_MATCH_START(umodem, uaa);
    159       1.1  augustss 	usb_interface_descriptor_t *id;
    160       1.9  augustss 	int cm, acm;
    161       1.1  augustss 
    162       1.1  augustss 	if (!uaa->iface)
    163       1.1  augustss 		return (UMATCH_NONE);
    164       1.9  augustss 
    165       1.1  augustss 	id = usbd_get_interface_descriptor(uaa->iface);
    166       1.9  augustss 	if (id == 0 ||
    167       1.2  augustss 	    id->bInterfaceClass != UCLASS_CDC ||
    168       1.2  augustss 	    id->bInterfaceSubClass != USUBCLASS_ABSTRACT_CONTROL_MODEL ||
    169       1.2  augustss 	    id->bInterfaceProtocol != UPROTO_CDC_AT)
    170       1.1  augustss 		return (UMATCH_NONE);
    171       1.9  augustss 
    172       1.9  augustss 	umodem_get_caps(uaa->device, &cm, &acm);
    173       1.9  augustss 	if (!(cm & USB_CDC_CM_DOES_CM) ||
    174       1.9  augustss 	    !(cm & USB_CDC_CM_OVER_DATA) ||
    175       1.9  augustss 	    !(acm & USB_CDC_ACM_HAS_LINE))
    176       1.9  augustss 		return (UMATCH_NONE);
    177       1.9  augustss 
    178       1.2  augustss 	return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
    179       1.1  augustss }
    180       1.1  augustss 
    181       1.3  augustss USB_ATTACH(umodem)
    182       1.1  augustss {
    183       1.3  augustss 	USB_ATTACH_START(umodem, sc, uaa);
    184       1.9  augustss 	usbd_device_handle dev = uaa->device;
    185       1.1  augustss 	usb_interface_descriptor_t *id;
    186       1.9  augustss 	usb_endpoint_descriptor_t *ed;
    187       1.9  augustss 	usb_cdc_cm_descriptor_t *cmd;
    188       1.1  augustss 	char devinfo[1024];
    189       1.9  augustss 	usbd_status r;
    190       1.9  augustss 	int data_ifaceno;
    191       1.9  augustss 	int i;
    192       1.9  augustss 	struct tty *tp;
    193       1.9  augustss 
    194       1.1  augustss 	usbd_devinfo(uaa->device, 0, devinfo);
    195       1.3  augustss 	USB_ATTACH_SETUP;
    196       1.9  augustss 
    197       1.9  augustss 	sc->sc_udev = dev;
    198       1.9  augustss 
    199       1.9  augustss 	sc->sc_ctl_iface = uaa->iface;
    200       1.9  augustss 	id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
    201       1.3  augustss 	printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
    202       1.1  augustss 	       devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
    203       1.9  augustss 	sc->sc_ctl_iface_no = id->bInterfaceNumber;
    204       1.9  augustss 
    205       1.9  augustss 	umodem_get_caps(dev, &sc->sc_cm_cap, &sc->sc_acm_cap);
    206       1.9  augustss 
    207       1.9  augustss 	/* Get the data interface no. */
    208       1.9  augustss 	cmd = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM);
    209       1.9  augustss 	if (!cmd) {
    210       1.9  augustss 		DPRINTF(("%s: no CM desc\n", USBDEVNAME(sc->sc_dev)));
    211       1.9  augustss 		goto bad;
    212       1.9  augustss 	}
    213       1.9  augustss 	sc->sc_data_iface_no = data_ifaceno = cmd->bDataInterface;
    214       1.9  augustss 
    215       1.9  augustss 	printf("%s: data interface %d, has %sCM over data, has %sbreak\n",
    216       1.9  augustss 	       USBDEVNAME(sc->sc_dev), data_ifaceno,
    217       1.9  augustss 	       sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ",
    218       1.9  augustss 	       sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no ");
    219       1.9  augustss 
    220       1.9  augustss 
    221       1.9  augustss 	/* Get the data interface too. */
    222       1.9  augustss 	for (i = 0; i < uaa->nifaces; i++) {
    223       1.9  augustss 		if (uaa->ifaces[i]) {
    224       1.9  augustss 			id = usbd_get_interface_descriptor(uaa->ifaces[i]);
    225       1.9  augustss 			if (id->bInterfaceNumber == data_ifaceno) {
    226       1.9  augustss 				sc->sc_data_iface = uaa->ifaces[i];
    227       1.9  augustss 				uaa->ifaces[i] = 0;
    228       1.9  augustss 			}
    229       1.9  augustss 		}
    230       1.9  augustss 	}
    231       1.9  augustss 	if (!sc->sc_data_iface) {
    232       1.9  augustss 		printf("%s: no data interface\n", USBDEVNAME(sc->sc_dev));
    233       1.9  augustss 		goto bad;
    234       1.9  augustss 	}
    235       1.9  augustss 
    236       1.9  augustss 	/*
    237       1.9  augustss 	 * Find the bulk endpoints.
    238       1.9  augustss 	 * Iterate over all endpoints in the data interface and take note.
    239       1.9  augustss 	 */
    240       1.9  augustss 	sc->sc_bulkin_no = sc->sc_bulkout_no = -1;
    241       1.9  augustss 
    242       1.9  augustss 	id = usbd_get_interface_descriptor(sc->sc_data_iface);
    243       1.9  augustss 	for (i = 0; i < id->bNumEndpoints; i++) {
    244       1.9  augustss 		ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface, i);
    245       1.9  augustss 		if (!ed) {
    246       1.9  augustss 			printf("%s: no endpoint descriptor for %d\n",
    247       1.9  augustss 				USBDEVNAME(sc->sc_dev), i);
    248       1.9  augustss 			goto bad;
    249       1.9  augustss 		}
    250      1.12  augustss 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    251       1.9  augustss 		    (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
    252       1.9  augustss                         sc->sc_bulkin_no = ed->bEndpointAddress;
    253      1.12  augustss                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    254       1.9  augustss 			   (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
    255       1.9  augustss                         sc->sc_bulkout_no = ed->bEndpointAddress;
    256       1.9  augustss                 }
    257       1.9  augustss         }
    258       1.9  augustss 
    259       1.9  augustss 	if (sc->sc_bulkin_no == -1) {
    260       1.9  augustss 		DPRINTF(("%s: Could not find data bulk in\n",
    261       1.9  augustss 			USBDEVNAME(sc->sc_dev)));
    262       1.9  augustss 		goto bad;
    263       1.9  augustss 	}
    264       1.9  augustss 	if (sc->sc_bulkout_no == -1) {
    265       1.9  augustss 		DPRINTF(("%s: Could not find data bulk out\n",
    266       1.9  augustss 			USBDEVNAME(sc->sc_dev)));
    267       1.9  augustss 		goto bad;
    268       1.9  augustss 	}
    269       1.9  augustss 
    270       1.9  augustss 	if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) {
    271       1.9  augustss 		r = umodem_set_comm_feature(sc, UCDC_ABSTRACT_STATE,
    272       1.9  augustss 					    UCDC_DATA_MULTIPLEXED);
    273       1.9  augustss 		if (r != USBD_NORMAL_COMPLETION)
    274       1.9  augustss 			goto bad;
    275       1.9  augustss 		sc->sc_cm_over_data = 1;
    276       1.9  augustss 	}
    277       1.9  augustss 
    278       1.9  augustss 	tp = ttymalloc();
    279       1.9  augustss 	tp->t_oproc = umodemstart;
    280       1.9  augustss 	tp->t_param = umodemparam;
    281       1.9  augustss 	sc->sc_tty = tp;
    282       1.9  augustss 	DPRINTF(("umodem_attach: tty_attach %p\n", tp));
    283       1.9  augustss 	tty_attach(tp);
    284       1.9  augustss 
    285       1.9  augustss 	sc->sc_dtr = -1;
    286       1.3  augustss 
    287       1.3  augustss 	USB_ATTACH_SUCCESS_RETURN;
    288       1.9  augustss 
    289       1.9  augustss  bad:
    290       1.9  augustss 	sc->sc_dying = 1;
    291       1.9  augustss 	USB_ATTACH_ERROR_RETURN;
    292       1.1  augustss }
    293       1.3  augustss 
    294       1.9  augustss void
    295       1.9  augustss umodem_get_caps(dev, cm, acm)
    296       1.9  augustss 	usbd_device_handle dev;
    297       1.9  augustss 	int *cm, *acm;
    298       1.9  augustss {
    299       1.9  augustss 	usb_cdc_cm_descriptor_t *cmd;
    300       1.9  augustss 	usb_cdc_acm_descriptor_t *cad;
    301       1.9  augustss 
    302       1.9  augustss 	*cm = *acm = 0;
    303       1.9  augustss 
    304       1.9  augustss 	cmd = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM);
    305       1.9  augustss 	if (!cmd) {
    306       1.9  augustss 		DPRINTF(("umodem_get_desc: no CM desc\n"));
    307       1.9  augustss 		return;
    308       1.9  augustss 	}
    309       1.9  augustss 	*cm = cmd->bmCapabilities;
    310       1.9  augustss 
    311       1.9  augustss 	cad = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM);
    312       1.9  augustss 	if (!cad) {
    313       1.9  augustss 		DPRINTF(("umodem_get_desc: no ACM desc\n"));
    314       1.9  augustss 		return;
    315       1.9  augustss 	}
    316       1.9  augustss 	*acm = cad->bmCapabilities;
    317       1.9  augustss }
    318       1.9  augustss 
    319       1.9  augustss void
    320       1.9  augustss umodemstart(tp)
    321       1.9  augustss 	struct tty *tp;
    322       1.9  augustss {
    323       1.9  augustss 	struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(tp->t_dev)];
    324       1.9  augustss 	int s;
    325       1.9  augustss 	u_char *data;
    326       1.9  augustss 	int cnt;
    327       1.9  augustss 
    328       1.9  augustss 	if (sc->sc_dying)
    329       1.9  augustss 		return;
    330       1.9  augustss 
    331       1.9  augustss 	s = spltty();
    332       1.9  augustss 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
    333       1.9  augustss 		DPRINTFN(4,("umodemstart: stopped\n"));
    334       1.9  augustss 		goto out;
    335       1.9  augustss 	}
    336       1.9  augustss 
    337       1.9  augustss 	if (tp->t_outq.c_cc <= tp->t_lowat) {
    338       1.9  augustss 		if (ISSET(tp->t_state, TS_ASLEEP)) {
    339       1.9  augustss 			CLR(tp->t_state, TS_ASLEEP);
    340       1.9  augustss 			wakeup(&tp->t_outq);
    341       1.9  augustss 		}
    342       1.9  augustss 		selwakeup(&tp->t_wsel);
    343       1.9  augustss 		if (tp->t_outq.c_cc == 0)
    344       1.9  augustss 			goto out;
    345       1.9  augustss 	}
    346       1.9  augustss 
    347       1.9  augustss 	/* Grab the first contiguous region of buffer space. */
    348       1.9  augustss 	data = tp->t_outq.c_cf;
    349       1.9  augustss 	cnt = ndqb(&tp->t_outq, 0);
    350       1.9  augustss 
    351       1.9  augustss 	if (cnt == 0) {
    352       1.9  augustss 		DPRINTF(("umodemstart: cnt==0\n"));
    353       1.9  augustss 		splx(s);
    354       1.9  augustss 		return;
    355       1.9  augustss 	}
    356       1.9  augustss 
    357       1.9  augustss 	SET(tp->t_state, TS_BUSY);
    358       1.9  augustss 
    359       1.9  augustss 	DPRINTFN(4,("umodemstart: %d chars\n", cnt));
    360       1.9  augustss 	/* XXX what can we do on error? */
    361  1.15.4.1      fvdl 	usbd_setup_request(sc->sc_oxfer, sc->sc_bulkout_pipe,
    362      1.14  augustss 			   (usbd_private_handle)sc, data, cnt,
    363      1.15  augustss 			   0, USBD_NO_TIMEOUT, umodemwritecb);
    364  1.15.4.1      fvdl 	(void)usbd_transfer(sc->sc_oxfer);
    365       1.9  augustss 
    366       1.9  augustss out:
    367       1.9  augustss 	splx(s);
    368       1.9  augustss }
    369       1.9  augustss 
    370       1.9  augustss void
    371  1.15.4.1      fvdl umodemwritecb(xfer, p, status)
    372  1.15.4.1      fvdl 	usbd_xfer_handle xfer;
    373       1.9  augustss 	usbd_private_handle p;
    374       1.9  augustss 	usbd_status status;
    375       1.9  augustss {
    376       1.9  augustss 	struct umodem_softc *sc = (struct umodem_softc *)p;
    377       1.9  augustss 	struct tty *tp = sc->sc_tty;
    378       1.9  augustss 	u_int32_t cc;
    379       1.9  augustss 	int s;
    380       1.9  augustss 
    381       1.9  augustss 	DPRINTFN(5,("umodemwritecb: status=%d\n", status));
    382       1.9  augustss 
    383       1.9  augustss 	if (status == USBD_CANCELLED)
    384       1.9  augustss 		return;
    385       1.9  augustss 
    386       1.9  augustss 	if (status != USBD_NORMAL_COMPLETION) {
    387       1.9  augustss 		DPRINTF(("umodemwritecb: status=%d\n", status));
    388       1.9  augustss 		usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
    389       1.9  augustss 		/* XXX we should restart after some delay. */
    390       1.9  augustss 		return;
    391       1.9  augustss 	}
    392       1.9  augustss 
    393  1.15.4.1      fvdl 	usbd_get_request_status(xfer, 0, 0, &cc, 0);
    394       1.9  augustss 	DPRINTFN(5,("umodemwritecb: cc=%d\n", cc));
    395       1.9  augustss 
    396       1.9  augustss 	s = spltty();
    397       1.9  augustss 	CLR(tp->t_state, TS_BUSY);
    398       1.9  augustss 	if (ISSET(tp->t_state, TS_FLUSH))
    399       1.9  augustss 		CLR(tp->t_state, TS_FLUSH);
    400       1.9  augustss 	else
    401       1.9  augustss 		ndflush(&tp->t_outq, cc);
    402       1.9  augustss 	(*linesw[tp->t_line].l_start)(tp);
    403       1.9  augustss 	splx(s);
    404       1.9  augustss }
    405       1.9  augustss 
    406       1.9  augustss int
    407       1.9  augustss umodemparam(tp, t)
    408       1.9  augustss 	struct tty *tp;
    409       1.9  augustss 	struct termios *t;
    410       1.9  augustss {
    411       1.9  augustss 	struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(tp->t_dev)];
    412       1.9  augustss 	usb_cdc_line_state_t ls;
    413       1.9  augustss 
    414       1.9  augustss 	if (sc->sc_dying)
    415       1.9  augustss 		return (EIO);
    416       1.9  augustss 
    417       1.9  augustss 	/* Check requested parameters. */
    418       1.9  augustss 	if (t->c_ospeed < 0)
    419       1.9  augustss 		return (EINVAL);
    420       1.9  augustss 	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
    421       1.9  augustss 		return (EINVAL);
    422       1.9  augustss 
    423       1.9  augustss 	/*
    424       1.9  augustss 	 * If there were no changes, don't do anything.  This avoids dropping
    425       1.9  augustss 	 * input and improves performance when all we did was frob things like
    426       1.9  augustss 	 * VMIN and VTIME.
    427       1.9  augustss 	 */
    428       1.9  augustss 	if (tp->t_ospeed == t->c_ospeed &&
    429       1.9  augustss 	    tp->t_cflag == t->c_cflag)
    430       1.9  augustss 		return (0);
    431       1.9  augustss 
    432       1.9  augustss 	/* And copy to tty. */
    433       1.9  augustss 	tp->t_ispeed = 0;
    434       1.9  augustss 	tp->t_ospeed = t->c_ospeed;
    435       1.9  augustss 	tp->t_cflag = t->c_cflag;
    436       1.9  augustss 
    437       1.9  augustss 	USETDW(ls.dwDTERate, t->c_ospeed);
    438       1.9  augustss 	if (ISSET(t->c_cflag, CSTOPB))
    439       1.9  augustss 		ls.bCharFormat = UCDC_STOP_BIT_2;
    440       1.9  augustss 	else
    441       1.9  augustss 		ls.bCharFormat = UCDC_STOP_BIT_1;
    442       1.9  augustss 	if (ISSET(t->c_cflag, PARENB)) {
    443       1.9  augustss 		if (ISSET(t->c_cflag, PARODD))
    444       1.9  augustss 			ls.bParityType = UCDC_PARITY_ODD;
    445       1.9  augustss 		else
    446       1.9  augustss 			ls.bParityType = UCDC_PARITY_EVEN;
    447       1.9  augustss 	} else
    448       1.9  augustss 		ls.bParityType = UCDC_PARITY_NONE;
    449       1.9  augustss 	switch (ISSET(t->c_cflag, CSIZE)) {
    450       1.9  augustss 	case CS5:
    451       1.9  augustss 		ls.bDataBits = 5;
    452       1.9  augustss 		break;
    453       1.9  augustss 	case CS6:
    454       1.9  augustss 		ls.bDataBits = 6;
    455       1.9  augustss 		break;
    456       1.9  augustss 	case CS7:
    457       1.9  augustss 		ls.bDataBits = 7;
    458       1.9  augustss 		break;
    459       1.9  augustss 	case CS8:
    460       1.9  augustss 		ls.bDataBits = 8;
    461       1.9  augustss 		break;
    462       1.9  augustss 	}
    463       1.9  augustss 	/* XXX what can we if it fails? */
    464       1.9  augustss 	(void)umodem_set_line_coding(sc, &ls);
    465       1.9  augustss 
    466       1.9  augustss 	/*
    467       1.9  augustss 	 * Update the tty layer's idea of the carrier bit, in case we changed
    468       1.9  augustss 	 * CLOCAL or MDMBUF.  We don't hang up here; we only do that by
    469       1.9  augustss 	 * explicit request.
    470       1.9  augustss 	 */
    471       1.9  augustss 	(void) (*linesw[tp->t_line].l_modem)(tp, 1 /* XXX carrier */ );
    472       1.9  augustss 
    473       1.9  augustss 	return (0);
    474       1.9  augustss }
    475       1.9  augustss 
    476       1.9  augustss int
    477       1.9  augustss umodemopen(dev, flag, mode, p)
    478       1.9  augustss 	dev_t dev;
    479       1.9  augustss 	int flag, mode;
    480       1.9  augustss 	struct proc *p;
    481       1.9  augustss {
    482       1.9  augustss 	int unit = UMODEMUNIT(dev);
    483       1.9  augustss 	usbd_status r;
    484       1.9  augustss 	struct umodem_softc *sc;
    485       1.9  augustss 	struct tty *tp;
    486       1.9  augustss 	int s;
    487       1.9  augustss 	int error;
    488       1.9  augustss 
    489       1.9  augustss 	if (unit >= umodem_cd.cd_ndevs)
    490       1.9  augustss 		return (ENXIO);
    491       1.9  augustss 	sc = umodem_cd.cd_devs[unit];
    492       1.9  augustss 	if (sc == 0)
    493       1.9  augustss 		return (ENXIO);
    494       1.9  augustss 
    495       1.9  augustss 	if (sc->sc_dying)
    496       1.9  augustss 		return (EIO);
    497       1.9  augustss 
    498       1.9  augustss 	if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
    499       1.9  augustss 		return (ENXIO);
    500       1.9  augustss 
    501       1.9  augustss 	tp = sc->sc_tty;
    502       1.9  augustss 
    503       1.9  augustss 	DPRINTF(("umodemopen: unit=%d, tp=%p\n", unit, tp));
    504       1.9  augustss 
    505       1.9  augustss 	if (ISSET(tp->t_state, TS_ISOPEN) &&
    506       1.9  augustss 	    ISSET(tp->t_state, TS_XCLUDE) &&
    507       1.9  augustss 	    p->p_ucred->cr_uid != 0)
    508       1.9  augustss 		return (EBUSY);
    509       1.9  augustss 
    510       1.9  augustss 	/*
    511       1.9  augustss 	 * Do the following iff this is a first open.
    512       1.9  augustss 	 */
    513       1.9  augustss 	s = spltty();
    514       1.9  augustss 	while (sc->sc_opening)
    515       1.9  augustss 		tsleep(&sc->sc_opening, PRIBIO, "umdmop", 0);
    516       1.9  augustss 	sc->sc_opening = 1;
    517       1.9  augustss 
    518       1.9  augustss 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    519       1.9  augustss 		struct termios t;
    520       1.9  augustss 
    521       1.9  augustss 		tp->t_dev = dev;
    522       1.9  augustss 
    523       1.9  augustss 		/*
    524       1.9  augustss 		 * Initialize the termios status to the defaults.  Add in the
    525       1.9  augustss 		 * sticky bits from TIOCSFLAGS.
    526       1.9  augustss 		 */
    527       1.9  augustss 		t.c_ispeed = 0;
    528       1.9  augustss 		t.c_ospeed = TTYDEF_SPEED;
    529       1.9  augustss 		t.c_cflag = TTYDEF_CFLAG;
    530       1.9  augustss 		/* Make sure umodemparam() will do something. */
    531       1.9  augustss 		tp->t_ospeed = 0;
    532       1.9  augustss 		(void) umodemparam(tp, &t);
    533       1.9  augustss 		tp->t_iflag = TTYDEF_IFLAG;
    534       1.9  augustss 		tp->t_oflag = TTYDEF_OFLAG;
    535       1.9  augustss 		tp->t_lflag = TTYDEF_LFLAG;
    536       1.9  augustss 		ttychars(tp);
    537       1.9  augustss 		ttsetwater(tp);
    538       1.9  augustss 
    539       1.9  augustss 		/*
    540       1.9  augustss 		 * Turn on DTR.  We must always do this, even if carrier is not
    541       1.9  augustss 		 * present, because otherwise we'd have to use TIOCSDTR
    542       1.9  augustss 		 * immediately after setting CLOCAL, which applications do not
    543       1.9  augustss 		 * expect.  We always assert DTR while the device is open
    544       1.9  augustss 		 * unless explicitly requested to deassert it.
    545       1.9  augustss 		 */
    546       1.9  augustss 		umodem_modem(sc, 1);
    547       1.9  augustss 
    548       1.9  augustss 		DPRINTF(("umodemopen: open pipes\n"));
    549       1.9  augustss 
    550       1.9  augustss 		/* Open the bulk pipes */
    551       1.9  augustss 		r = usbd_open_pipe(sc->sc_data_iface, sc->sc_bulkin_no, 0,
    552       1.9  augustss 				   &sc->sc_bulkin_pipe);
    553       1.9  augustss 		if (r != USBD_NORMAL_COMPLETION) {
    554       1.9  augustss 			DPRINTF(("%s: cannot open bulk out pipe (addr %d)\n",
    555       1.9  augustss 				 USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no));
    556       1.9  augustss 			return (EIO);
    557       1.9  augustss 		}
    558       1.9  augustss 		r = usbd_open_pipe(sc->sc_data_iface, sc->sc_bulkout_no,
    559       1.9  augustss 				   USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
    560       1.9  augustss 		if (r != USBD_NORMAL_COMPLETION) {
    561       1.9  augustss 			DPRINTF(("%s: cannot open bulk in pipe (addr %d)\n",
    562       1.9  augustss 				 USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no));
    563       1.9  augustss 			usbd_close_pipe(sc->sc_bulkin_pipe);
    564       1.9  augustss 			return (EIO);
    565       1.9  augustss 		}
    566       1.9  augustss 
    567       1.9  augustss 		/* Allocate a request and an input buffer and start reading. */
    568  1.15.4.1      fvdl 		sc->sc_ixfer = usbd_alloc_request(sc->sc_udev);
    569  1.15.4.1      fvdl 		if (sc->sc_ixfer == 0) {
    570       1.9  augustss 			usbd_close_pipe(sc->sc_bulkin_pipe);
    571       1.9  augustss 			usbd_close_pipe(sc->sc_bulkout_pipe);
    572       1.9  augustss 			return (ENOMEM);
    573       1.9  augustss 		}
    574  1.15.4.1      fvdl 		sc->sc_oxfer = usbd_alloc_request(sc->sc_udev);
    575  1.15.4.1      fvdl 		if (sc->sc_oxfer == 0) {
    576       1.9  augustss 			usbd_close_pipe(sc->sc_bulkin_pipe);
    577       1.9  augustss 			usbd_close_pipe(sc->sc_bulkout_pipe);
    578  1.15.4.1      fvdl 			usbd_free_request(sc->sc_ixfer);
    579       1.9  augustss 			return (ENOMEM);
    580       1.9  augustss 		}
    581       1.9  augustss 		sc->sc_ibuf = malloc(UMODEMIBUFSIZE, M_USBDEV, M_WAITOK);
    582       1.9  augustss 		umodemstartread(sc);
    583       1.9  augustss 	}
    584       1.9  augustss 	sc->sc_opening = 0;
    585       1.9  augustss 	wakeup(&sc->sc_opening);
    586       1.9  augustss 	splx(s);
    587       1.9  augustss 
    588       1.9  augustss 	error = ttyopen(tp, UMODEMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
    589       1.9  augustss 	if (error)
    590       1.9  augustss 		goto bad;
    591       1.9  augustss 
    592       1.9  augustss 	error = (*linesw[tp->t_line].l_open)(dev, tp);
    593       1.9  augustss 	if (error)
    594       1.9  augustss 		goto bad;
    595       1.9  augustss 
    596       1.9  augustss 	return (0);
    597       1.9  augustss 
    598       1.9  augustss bad:
    599       1.9  augustss 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    600       1.9  augustss 		/*
    601       1.9  augustss 		 * We failed to open the device, and nobody else had it opened.
    602       1.9  augustss 		 * Clean up the state as appropriate.
    603       1.9  augustss 		 */
    604       1.9  augustss 		umodem_cleanup(sc);
    605       1.9  augustss 	}
    606       1.9  augustss 
    607       1.9  augustss 	return (error);
    608       1.9  augustss }
    609       1.9  augustss 
    610       1.9  augustss usbd_status
    611       1.9  augustss umodemstartread(sc)
    612       1.9  augustss 	struct umodem_softc *sc;
    613       1.9  augustss {
    614       1.9  augustss 	usbd_status r;
    615       1.9  augustss 
    616       1.9  augustss 	DPRINTFN(5,("umodemstartread: start\n"));
    617  1.15.4.1      fvdl 	usbd_setup_request(sc->sc_ixfer, sc->sc_bulkin_pipe,
    618      1.14  augustss 			   (usbd_private_handle)sc,
    619      1.15  augustss 			   sc->sc_ibuf,  UMODEMIBUFSIZE, USBD_SHORT_XFER_OK,
    620      1.14  augustss 			   USBD_NO_TIMEOUT, umodemreadcb);
    621  1.15.4.1      fvdl 	r = usbd_transfer(sc->sc_ixfer);
    622       1.9  augustss 	if (r != USBD_IN_PROGRESS)
    623       1.9  augustss 		return (r);
    624       1.9  augustss 	return (USBD_NORMAL_COMPLETION);
    625       1.9  augustss }
    626       1.9  augustss 
    627       1.9  augustss void
    628  1.15.4.1      fvdl umodemreadcb(xfer, p, status)
    629  1.15.4.1      fvdl 	usbd_xfer_handle xfer;
    630       1.9  augustss 	usbd_private_handle p;
    631       1.9  augustss 	usbd_status status;
    632       1.9  augustss {
    633       1.9  augustss 	struct umodem_softc *sc = (struct umodem_softc *)p;
    634       1.9  augustss 	struct tty *tp = sc->sc_tty;
    635       1.9  augustss 	int (*rint) __P((int c, struct tty *tp)) = linesw[tp->t_line].l_rint;
    636       1.9  augustss 	usbd_status r;
    637       1.9  augustss 	u_int32_t cc;
    638       1.9  augustss 	u_char *cp;
    639       1.9  augustss 	int s;
    640       1.9  augustss 
    641       1.9  augustss 	if (status == USBD_CANCELLED)
    642       1.9  augustss 		return;
    643       1.9  augustss 
    644       1.9  augustss 	if (status != USBD_NORMAL_COMPLETION) {
    645       1.9  augustss 		DPRINTF(("umodemreadcb: status=%d\n", status));
    646       1.9  augustss 		usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
    647       1.9  augustss 		/* XXX we should restart after some delay. */
    648       1.9  augustss 		return;
    649       1.9  augustss 	}
    650       1.9  augustss 
    651  1.15.4.1      fvdl 	usbd_get_request_status(xfer, 0, (void **)&cp, &cc, 0);
    652       1.9  augustss 	DPRINTFN(5,("umodemreadcb: got %d chars, tp=%p\n", cc, tp));
    653       1.9  augustss 	s = spltty();
    654       1.9  augustss 	/* Give characters to tty layer. */
    655       1.9  augustss 	while (cc-- > 0) {
    656       1.9  augustss 		DPRINTFN(7,("umodemreadcb: char=0x%02x\n", *cp));
    657       1.9  augustss 		if ((*rint)(*cp++, tp) == -1) {
    658       1.9  augustss 			/* XXX what should we do? */
    659       1.9  augustss 			break;
    660       1.9  augustss 		}
    661       1.9  augustss 	}
    662       1.9  augustss 	splx(s);
    663       1.9  augustss 
    664       1.9  augustss 	r = umodemstartread(sc);
    665       1.9  augustss 	if (r != USBD_NORMAL_COMPLETION) {
    666       1.9  augustss 		printf("%s: read start failed\n", USBDEVNAME(sc->sc_dev));
    667       1.9  augustss 		/* XXX what should we dow now? */
    668       1.9  augustss 	}
    669       1.9  augustss }
    670       1.9  augustss 
    671       1.9  augustss int
    672       1.9  augustss umodemclose(dev, flag, mode, p)
    673       1.9  augustss 	dev_t dev;
    674       1.9  augustss 	int flag, mode;
    675       1.9  augustss 	struct proc *p;
    676       1.9  augustss {
    677       1.9  augustss 	struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(dev)];
    678       1.9  augustss 	struct tty *tp = sc->sc_tty;
    679       1.9  augustss 
    680       1.9  augustss 	DPRINTF(("umodemclose: unit=%d\n", UMODEMUNIT(dev)));
    681       1.9  augustss 	if (!ISSET(tp->t_state, TS_ISOPEN))
    682       1.9  augustss 		return (0);
    683       1.9  augustss 
    684       1.9  augustss 	(*linesw[tp->t_line].l_close)(tp, flag);
    685       1.9  augustss 	ttyclose(tp);
    686       1.9  augustss 
    687       1.9  augustss 	if (sc->sc_dying)
    688       1.9  augustss 		return (0);
    689       1.9  augustss 
    690       1.9  augustss 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    691       1.9  augustss 		/*
    692       1.9  augustss 		 * Although we got a last close, the device may still be in
    693       1.9  augustss 		 * use; e.g. if this was the dialout node, and there are still
    694       1.9  augustss 		 * processes waiting for carrier on the non-dialout node.
    695       1.9  augustss 		 */
    696       1.9  augustss 		umodem_cleanup(sc);
    697       1.9  augustss 	}
    698       1.9  augustss 
    699       1.9  augustss 	return (0);
    700       1.9  augustss }
    701       1.9  augustss 
    702       1.9  augustss void
    703       1.9  augustss umodem_cleanup(sc)
    704       1.9  augustss 	struct umodem_softc *sc;
    705       1.9  augustss {
    706       1.9  augustss 	umodem_shutdown(sc);
    707       1.9  augustss 	DPRINTF(("umodem_cleanup: closing pipes\n"));
    708       1.9  augustss 	usbd_abort_pipe(sc->sc_bulkin_pipe);
    709       1.9  augustss 	usbd_close_pipe(sc->sc_bulkin_pipe);
    710       1.9  augustss 	usbd_abort_pipe(sc->sc_bulkout_pipe);
    711       1.9  augustss 	usbd_close_pipe(sc->sc_bulkout_pipe);
    712  1.15.4.1      fvdl 	usbd_free_request(sc->sc_ixfer);
    713  1.15.4.1      fvdl 	usbd_free_request(sc->sc_oxfer);
    714       1.9  augustss 	free(sc->sc_ibuf, M_USBDEV);
    715       1.9  augustss }
    716       1.9  augustss 
    717       1.9  augustss int
    718       1.9  augustss umodemread(dev, uio, flag)
    719       1.9  augustss 	dev_t dev;
    720       1.9  augustss 	struct uio *uio;
    721       1.9  augustss 	int flag;
    722       1.9  augustss {
    723       1.9  augustss 	struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(dev)];
    724       1.9  augustss 	struct tty *tp = sc->sc_tty;
    725       1.9  augustss 
    726       1.9  augustss 	if (sc->sc_dying)
    727       1.9  augustss 		return (EIO);
    728       1.9  augustss 
    729       1.9  augustss 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
    730       1.9  augustss }
    731       1.9  augustss 
    732       1.9  augustss int
    733       1.9  augustss umodemwrite(dev, uio, flag)
    734       1.9  augustss 	dev_t dev;
    735       1.9  augustss 	struct uio *uio;
    736       1.9  augustss 	int flag;
    737       1.9  augustss {
    738       1.9  augustss 	struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(dev)];
    739       1.9  augustss 	struct tty *tp = sc->sc_tty;
    740       1.9  augustss 
    741       1.9  augustss 	if (sc->sc_dying)
    742       1.9  augustss 		return (EIO);
    743       1.9  augustss 
    744       1.9  augustss 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
    745       1.9  augustss }
    746       1.9  augustss 
    747       1.9  augustss void
    748       1.9  augustss umodemstop(tp, flag)
    749       1.9  augustss 	struct tty *tp;
    750       1.9  augustss 	int flag;
    751       1.9  augustss {
    752       1.9  augustss 	/*struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(tp->t_dev)];*/
    753       1.9  augustss 	int s;
    754       1.9  augustss 
    755       1.9  augustss 	DPRINTF(("umodemstop: %d\n", flag));
    756       1.9  augustss 	s = spltty();
    757       1.9  augustss 	if (ISSET(tp->t_state, TS_BUSY)) {
    758       1.9  augustss 		DPRINTF(("umodemstop: XXX\n"));
    759       1.9  augustss 		/* XXX do what? */
    760       1.9  augustss 		if (!ISSET(tp->t_state, TS_TTSTOP))
    761       1.9  augustss 			SET(tp->t_state, TS_FLUSH);
    762       1.9  augustss 	}
    763       1.9  augustss 	splx(s);
    764       1.9  augustss }
    765       1.9  augustss 
    766       1.9  augustss struct tty *
    767       1.9  augustss umodemtty(dev)
    768       1.9  augustss 	dev_t dev;
    769       1.9  augustss {
    770       1.9  augustss 	struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(dev)];
    771       1.9  augustss 	struct tty *tp = sc->sc_tty;
    772       1.9  augustss 
    773       1.9  augustss 	return (tp);
    774       1.9  augustss }
    775       1.9  augustss 
    776       1.9  augustss int
    777       1.9  augustss umodemioctl(dev, cmd, data, flag, p)
    778       1.9  augustss 	dev_t dev;
    779       1.9  augustss 	u_long cmd;
    780       1.9  augustss 	caddr_t data;
    781       1.9  augustss 	int flag;
    782       1.9  augustss 	struct proc *p;
    783       1.9  augustss {
    784       1.9  augustss 	struct umodem_softc *sc = umodem_cd.cd_devs[UMODEMUNIT(dev)];
    785       1.9  augustss 	struct tty *tp = sc->sc_tty;
    786       1.9  augustss 	int error;
    787       1.9  augustss 	int s;
    788       1.9  augustss 
    789       1.9  augustss 	if (sc->sc_dying)
    790       1.9  augustss 		return (EIO);
    791       1.9  augustss 
    792       1.9  augustss 	DPRINTF(("umodemioctl: cmd=0x%08lx\n", cmd));
    793       1.9  augustss 
    794       1.9  augustss 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
    795       1.9  augustss 	if (error >= 0)
    796       1.9  augustss 		return (error);
    797       1.9  augustss 
    798       1.9  augustss 	error = ttioctl(tp, cmd, data, flag, p);
    799       1.9  augustss 	if (error >= 0)
    800       1.9  augustss 		return (error);
    801       1.9  augustss 
    802       1.9  augustss 	error = 0;
    803       1.9  augustss 
    804       1.9  augustss 	DPRINTF(("umodemioctl: our cmd=0x%08lx\n", cmd));
    805       1.9  augustss 	s = spltty();
    806       1.9  augustss 
    807       1.9  augustss 	switch (cmd) {
    808       1.9  augustss 	case TIOCSBRK:
    809       1.9  augustss 		umodem_break(sc, 1);
    810       1.9  augustss 		break;
    811       1.9  augustss 
    812       1.9  augustss 	case TIOCCBRK:
    813       1.9  augustss 		umodem_break(sc, 0);
    814       1.9  augustss 		break;
    815       1.9  augustss 
    816       1.9  augustss 	case TIOCSDTR:
    817       1.9  augustss 		umodem_modem(sc, 1);
    818       1.9  augustss 		break;
    819       1.9  augustss 
    820       1.9  augustss 	case TIOCCDTR:
    821       1.9  augustss 		umodem_modem(sc, 0);
    822       1.9  augustss 		break;
    823       1.9  augustss 
    824       1.9  augustss 	case USB_GET_CM_OVER_DATA:
    825       1.9  augustss 		*(int *)data = sc->sc_cm_over_data;
    826       1.9  augustss 		break;
    827       1.9  augustss 
    828       1.9  augustss 	case USB_SET_CM_OVER_DATA:
    829       1.9  augustss 		if (*(int *)data != sc->sc_cm_over_data) {
    830       1.9  augustss 			/* XXX change it */
    831       1.9  augustss 		}
    832       1.9  augustss 		break;
    833       1.9  augustss 
    834       1.9  augustss 	default:
    835       1.9  augustss 		DPRINTF(("umodemioctl: unknown\n"));
    836       1.9  augustss 		error = ENOTTY;
    837       1.9  augustss 		break;
    838       1.9  augustss 	}
    839       1.9  augustss 
    840       1.9  augustss 	splx(s);
    841       1.9  augustss 
    842       1.9  augustss 	return (error);
    843       1.9  augustss }
    844       1.9  augustss 
    845       1.9  augustss void
    846       1.9  augustss umodem_shutdown(sc)
    847       1.9  augustss 	struct umodem_softc *sc;
    848       1.9  augustss {
    849       1.9  augustss 	struct tty *tp = sc->sc_tty;
    850       1.9  augustss 
    851       1.9  augustss 	DPRINTF(("umodem_shutdown\n"));
    852       1.9  augustss 	/*
    853       1.9  augustss 	 * Hang up if necessary.  Wait a bit, so the other side has time to
    854       1.9  augustss 	 * notice even if we immediately open the port again.
    855       1.9  augustss 	 */
    856       1.9  augustss 	if (ISSET(tp->t_cflag, HUPCL)) {
    857       1.9  augustss 		umodem_modem(sc, 0);
    858       1.9  augustss 		(void) tsleep(sc, TTIPRI, ttclos, hz);
    859       1.9  augustss 	}
    860       1.9  augustss }
    861       1.9  augustss 
    862       1.9  augustss void
    863       1.9  augustss umodem_modem(sc, onoff)
    864       1.9  augustss 	struct umodem_softc *sc;
    865       1.9  augustss 	int onoff;
    866       1.9  augustss {
    867       1.9  augustss 	usb_device_request_t req;
    868       1.9  augustss 
    869       1.9  augustss 	DPRINTF(("umodem_modem: onoff=%d\n", onoff));
    870       1.9  augustss 
    871       1.9  augustss 	if (sc->sc_dtr == onoff)
    872       1.9  augustss 		return;
    873       1.9  augustss 
    874       1.9  augustss 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
    875       1.9  augustss 	req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
    876       1.9  augustss 	USETW(req.wValue, onoff ? UCDC_LINE_DTR : 0);
    877       1.9  augustss 	USETW(req.wIndex, sc->sc_ctl_iface_no);
    878       1.9  augustss 	USETW(req.wLength, 0);
    879       1.9  augustss 
    880       1.9  augustss 	(void)usbd_do_request(sc->sc_udev, &req, 0);
    881       1.9  augustss 
    882       1.9  augustss 	sc->sc_dtr = onoff;
    883       1.9  augustss }
    884       1.9  augustss 
    885       1.9  augustss void
    886       1.9  augustss umodem_break(sc, onoff)
    887       1.9  augustss 	struct umodem_softc *sc;
    888       1.9  augustss 	int onoff;
    889       1.9  augustss {
    890       1.9  augustss 	usb_device_request_t req;
    891       1.9  augustss 
    892       1.9  augustss 	DPRINTF(("umodem_break: onoff=%d\n", onoff));
    893       1.9  augustss 
    894       1.9  augustss 	if (!(sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK))
    895       1.9  augustss 		return;
    896       1.9  augustss 
    897       1.9  augustss 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
    898       1.9  augustss 	req.bRequest = UCDC_SEND_BREAK;
    899       1.9  augustss 	USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
    900       1.9  augustss 	USETW(req.wIndex, sc->sc_ctl_iface_no);
    901       1.9  augustss 	USETW(req.wLength, 0);
    902       1.9  augustss 
    903       1.9  augustss 	(void)usbd_do_request(sc->sc_udev, &req, 0);
    904       1.9  augustss }
    905       1.9  augustss 
    906       1.9  augustss void *
    907       1.9  augustss umodem_get_desc(dev, type, subtype)
    908       1.9  augustss 	usbd_device_handle dev;
    909       1.9  augustss 	int type;
    910       1.9  augustss 	int subtype;
    911       1.9  augustss {
    912       1.9  augustss 	usb_descriptor_t *desc;
    913       1.9  augustss 	usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
    914       1.9  augustss         uByte *p = (uByte *)cd;
    915       1.9  augustss         uByte *end = p + UGETW(cd->wTotalLength);
    916       1.9  augustss 
    917       1.9  augustss 	while (p < end) {
    918       1.9  augustss 		desc = (usb_descriptor_t *)p;
    919       1.9  augustss 		if (desc->bDescriptorType == type &&
    920       1.9  augustss 		    desc->bDescriptorSubtype == subtype)
    921       1.9  augustss 			return (desc);
    922       1.9  augustss 		p += desc->bLength;
    923       1.9  augustss 	}
    924       1.9  augustss 
    925       1.9  augustss 	return (0);
    926       1.9  augustss }
    927       1.9  augustss 
    928       1.9  augustss usbd_status
    929       1.9  augustss umodem_set_comm_feature(sc, feature, state)
    930       1.9  augustss 	struct umodem_softc *sc;
    931       1.9  augustss 	int feature;
    932       1.9  augustss 	int state;
    933       1.9  augustss {
    934       1.9  augustss 	usb_device_request_t req;
    935       1.9  augustss 	usbd_status r;
    936       1.9  augustss 	usb_cdc_abstract_state_t ast;
    937       1.9  augustss 
    938       1.9  augustss 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
    939       1.9  augustss 	req.bRequest = UCDC_SET_COMM_FEATURE;
    940       1.9  augustss 	USETW(req.wValue, feature);
    941       1.9  augustss 	USETW(req.wIndex, sc->sc_ctl_iface_no);
    942       1.9  augustss 	USETW(req.wLength, UCDC_ABSTRACT_STATE_LENGTH);
    943       1.9  augustss 	USETW(ast.wState, state);
    944       1.9  augustss 
    945       1.9  augustss 	r = usbd_do_request(sc->sc_udev, &req, &ast);
    946       1.9  augustss 	if (r != USBD_NORMAL_COMPLETION) {
    947       1.9  augustss 		DPRINTF(("umodem_set_comm_feature: feature=%d failed, r=%d\n",
    948       1.9  augustss 			 feature, r));
    949       1.9  augustss 		return (r);
    950       1.9  augustss 	}
    951       1.9  augustss 
    952       1.9  augustss 	return (USBD_NORMAL_COMPLETION);
    953       1.9  augustss }
    954       1.9  augustss 
    955       1.9  augustss usbd_status
    956       1.9  augustss umodem_set_line_coding(sc, state)
    957       1.9  augustss 	struct umodem_softc *sc;
    958       1.9  augustss 	usb_cdc_line_state_t *state;
    959       1.9  augustss {
    960       1.9  augustss 	usb_device_request_t req;
    961       1.9  augustss 	usbd_status r;
    962       1.9  augustss 
    963       1.9  augustss 	DPRINTF(("umodem_set_line_coding: rate=%d fmt=%d parity=%d bits=%d\n",
    964       1.9  augustss 		 UGETDW(state->dwDTERate), state->bCharFormat,
    965       1.9  augustss 		 state->bParityType, state->bDataBits));
    966       1.9  augustss 
    967       1.9  augustss 	if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) {
    968       1.9  augustss 		DPRINTF(("umodem_set_line_coding: already set\n"));
    969       1.9  augustss 		return (USBD_NORMAL_COMPLETION);
    970       1.9  augustss 	}
    971       1.9  augustss 
    972       1.9  augustss 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
    973       1.9  augustss 	req.bRequest = UCDC_SET_LINE_CODING;
    974       1.9  augustss 	USETW(req.wValue, 0);
    975       1.9  augustss 	USETW(req.wIndex, sc->sc_ctl_iface_no);
    976       1.9  augustss 	USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
    977       1.9  augustss 
    978       1.9  augustss 	r = usbd_do_request(sc->sc_udev, &req, state);
    979       1.9  augustss 	if (r != USBD_NORMAL_COMPLETION) {
    980       1.9  augustss 		DPRINTF(("umodem_set_line_coding: failed, r=%d\n", r));
    981       1.9  augustss 		return (r);
    982       1.9  augustss 	}
    983       1.9  augustss 
    984       1.9  augustss 	sc->sc_line_state = *state;
    985       1.9  augustss 
    986       1.9  augustss 	return (USBD_NORMAL_COMPLETION);
    987       1.9  augustss }
    988       1.9  augustss 
    989       1.9  augustss int
    990       1.9  augustss umodem_activate(self, act)
    991      1.13  augustss 	device_ptr_t self;
    992       1.9  augustss 	enum devact act;
    993       1.9  augustss {
    994       1.9  augustss 	struct umodem_softc *sc = (struct umodem_softc *)self;
    995       1.9  augustss 
    996       1.9  augustss 	switch (act) {
    997       1.9  augustss 	case DVACT_ACTIVATE:
    998       1.9  augustss 		return (EOPNOTSUPP);
    999       1.9  augustss 		break;
   1000       1.9  augustss 
   1001       1.9  augustss 	case DVACT_DEACTIVATE:
   1002       1.9  augustss 		sc->sc_dying = 1;
   1003       1.9  augustss 		break;
   1004       1.9  augustss 	}
   1005       1.9  augustss 	return (0);
   1006       1.9  augustss }
   1007       1.9  augustss 
   1008       1.9  augustss int
   1009       1.9  augustss umodem_detach(self, flags)
   1010      1.13  augustss 	device_ptr_t self;
   1011       1.9  augustss 	int flags;
   1012       1.9  augustss {
   1013       1.9  augustss 	struct umodem_softc *sc = (struct umodem_softc *)self;
   1014       1.9  augustss 	int maj, mn;
   1015       1.9  augustss 
   1016       1.9  augustss 	DPRINTF(("umodem_detach: sc=%p flags=%d tp=%p\n",
   1017       1.9  augustss 		 sc, flags, sc->sc_tty));
   1018       1.9  augustss 
   1019       1.9  augustss 	sc->sc_dying = 1;
   1020       1.9  augustss 
   1021       1.9  augustss #ifdef DIAGNOSTIC
   1022       1.9  augustss 	if (sc->sc_tty == 0) {
   1023       1.9  augustss 		DPRINTF(("umodem_detach: no tty\n"));
   1024       1.9  augustss 		return (0);
   1025       1.9  augustss 	}
   1026       1.3  augustss #endif
   1027       1.3  augustss 
   1028       1.9  augustss 	/* use refernce count? XXX */
   1029       1.9  augustss 
   1030       1.9  augustss 	/* locate the major number */
   1031       1.9  augustss 	for (maj = 0; maj < nchrdev; maj++)
   1032       1.9  augustss 		if (cdevsw[maj].d_open == umodemopen)
   1033       1.9  augustss 			break;
   1034       1.9  augustss 
   1035       1.9  augustss 	/* Nuke the vnodes for any open instances. */
   1036       1.9  augustss 	mn = self->dv_unit;
   1037       1.9  augustss 	vdevgone(maj, mn, mn, VCHR);
   1038       1.9  augustss 	vdevgone(maj, mn, mn | UMODEMDIALOUT_MASK, VCHR);
   1039       1.9  augustss 	vdevgone(maj, mn, mn | UMODEMCALLUNIT_MASK, VCHR);
   1040       1.9  augustss 
   1041       1.9  augustss 	/* Detach and free the tty. */
   1042       1.9  augustss 	tty_detach(sc->sc_tty);
   1043       1.9  augustss 	ttyfree(sc->sc_tty);
   1044       1.9  augustss 	sc->sc_tty = 0;
   1045       1.9  augustss 
   1046       1.9  augustss 	return (0);
   1047       1.9  augustss }
   1048