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