File:  [DragonFly] / src / sys / dev / usbmisc / uplcom / uplcom.c
Revision 1.6: download - view: text, annotated - select for diffs
Wed Feb 11 15:13:06 2004 UTC (10 years, 9 months ago) by joerg
Branches: MAIN
CVS tags: HEAD
Add defined(__FreeBSD__) and defined(__DragonFly__) where appropiriate.

    1: /*
    2:  * $NetBSD: uplcom.c,v 1.21 2001/11/13 06:24:56 lukem Exp $
    3:  * $FreeBSD: src/sys/dev/usb/uplcom.c,v 1.17 2003/11/16 13:13:16 akiyama Exp $
    4:  * $DragonFly: src/sys/dev/usbmisc/uplcom/uplcom.c,v 1.6 2004/02/11 15:13:06 joerg Exp $
    5:  */
    6: 
    7: /*-
    8:  * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
    9:  * All rights reserved.
   10:  *
   11:  * Redistribution and use in source and binary forms, with or without
   12:  * modification, are permitted provided that the following conditions
   13:  * are met:
   14:  * 1. Redistributions of source code must retain the above copyright
   15:  *    notice, this list of conditions and the following disclaimer.
   16:  * 2. Redistributions in binary form must reproduce the above copyright
   17:  *    notice, this list of conditions and the following disclaimer in the
   18:  *    documentation and/or other materials provided with the distribution.
   19:  *
   20:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30:  * SUCH DAMAGE.
   31:  */
   32: 
   33: /*
   34:  * Copyright (c) 2001 The NetBSD Foundation, Inc.
   35:  * All rights reserved.
   36:  *
   37:  * This code is derived from software contributed to The NetBSD Foundation
   38:  * by Ichiro FUKUHARA (ichiro@ichiro.org).
   39:  *
   40:  * Redistribution and use in source and binary forms, with or without
   41:  * modification, are permitted provided that the following conditions
   42:  * are met:
   43:  * 1. Redistributions of source code must retain the above copyright
   44:  *    notice, this list of conditions and the following disclaimer.
   45:  * 2. Redistributions in binary form must reproduce the above copyright
   46:  *    notice, this list of conditions and the following disclaimer in the
   47:  *    documentation and/or other materials provided with the distribution.
   48:  * 3. All advertising materials mentioning features or use of this software
   49:  *    must display the following acknowledgement:
   50:  *        This product includes software developed by the NetBSD
   51:  *        Foundation, Inc. and its contributors.
   52:  * 4. Neither the name of The NetBSD Foundation nor the names of its
   53:  *    contributors may be used to endorse or promote products derived
   54:  *    from this software without specific prior written permission.
   55:  *
   56:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   57:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   58:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   59:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   60:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   61:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   62:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   63:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   64:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   65:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   66:  * POSSIBILITY OF SUCH DAMAGE.
   67:  */
   68: 
   69: /*
   70:  * Simple datasheet
   71:  * http://www.prolific.com.tw/download/DataSheet/pl2303_ds11.PDF
   72:  * http://www.nisseisg.co.jp/jyouhou/_cp/@gif/2303.pdf
   73:  * 	(english)
   74:  *
   75:  */
   76: 
   77: #include <sys/param.h>
   78: #include <sys/systm.h>
   79: #include <sys/kernel.h>
   80: #include <sys/malloc.h>
   81: #include <sys/bus.h>
   82: #include <sys/ioccom.h>
   83: #include <sys/fcntl.h>
   84: #include <sys/conf.h>
   85: #include <sys/tty.h>
   86: #include <sys/file.h>
   87: #if defined(__FreeBSD__) && __FreeBSD_version >= 500014
   88: #include <sys/selinfo.h>
   89: #else
   90: #include <sys/select.h>
   91: #endif
   92: #include <sys/proc.h>
   93: #include <sys/vnode.h>
   94: #include <sys/poll.h>
   95: #include <sys/sysctl.h>
   96: 
   97: #include <bus/usb/usb.h>
   98: #include <bus/usb/usbcdc.h>
   99: 
  100: #include <bus/usb/usbdi.h>
  101: #include <bus/usb/usbdi_util.h>
  102: #include <bus/usb/usbdevs.h>
  103: #include <bus/usb/usb_quirks.h>
  104: 
  105: #include "../ucom/ucomvar.h"
  106: 
  107: SYSCTL_NODE(_hw_usb, OID_AUTO, uplcom, CTLFLAG_RW, 0, "USB uplcom");
  108: #ifdef USB_DEBUG
  109: static int	uplcomdebug = 0;
  110: SYSCTL_INT(_hw_usb_uplcom, OID_AUTO, debug, CTLFLAG_RW,
  111: 	   &uplcomdebug, 0, "uplcom debug level");
  112: 
  113: #define DPRINTFN(n, x)	do { \
  114: 				if (uplcomdebug > (n)) \
  115: 					logprintf x; \
  116: 			} while (0)
  117: #else
  118: #define DPRINTFN(n, x)
  119: #endif
  120: #define DPRINTF(x) DPRINTFN(0, x)
  121: 
  122: #define UPLCOM_MODVER			1	/* module version */
  123: 
  124: #define	UPLCOM_CONFIG_INDEX		0
  125: #define	UPLCOM_IFACE_INDEX		0
  126: #define	UPLCOM_SECOND_IFACE_INDEX	1
  127: 
  128: #ifndef UPLCOM_INTR_INTERVAL
  129: #define UPLCOM_INTR_INTERVAL		100	/* ms */
  130: #endif
  131: 
  132: #define	UPLCOM_SET_REQUEST		0x01
  133: #define	UPLCOM_SET_CRTSCTS		0x41
  134: #define RSAQ_STATUS_DSR			0x02
  135: #define RSAQ_STATUS_DCD			0x01
  136: 
  137: struct	uplcom_softc {
  138: 	struct ucom_softc	sc_ucom;
  139: 
  140: 	int			sc_iface_number;	/* interface number */
  141: 
  142: 	usbd_interface_handle	sc_intr_iface;	/* interrupt interface */
  143: 	int			sc_intr_number;	/* interrupt number */
  144: 	usbd_pipe_handle	sc_intr_pipe;	/* interrupt pipe */
  145: 	u_char			*sc_intr_buf;	/* interrupt buffer */
  146: 	int			sc_isize;
  147: 
  148: 	usb_cdc_line_state_t	sc_line_state;	/* current line state */
  149: 	u_char			sc_dtr;		/* current DTR state */
  150: 	u_char			sc_rts;		/* current RTS state */
  151: 	u_char			sc_status;
  152: 
  153: 	u_char			sc_lsr;		/* Local status register */
  154: 	u_char			sc_msr;		/* uplcom status register */
  155: };
  156: 
  157: /*
  158:  * These are the maximum number of bytes transferred per frame.
  159:  * The output buffer size cannot be increased due to the size encoding.
  160:  */
  161: #define UPLCOMIBUFSIZE 256
  162: #define UPLCOMOBUFSIZE 256
  163: 
  164: Static	usbd_status uplcom_reset(struct uplcom_softc *);
  165: Static	usbd_status uplcom_set_line_coding(struct uplcom_softc *,
  166: 					   usb_cdc_line_state_t *);
  167: Static	usbd_status uplcom_set_crtscts(struct uplcom_softc *);
  168: Static	void uplcom_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
  169: 
  170: Static	void uplcom_set(void *, int, int, int);
  171: Static	void uplcom_dtr(struct uplcom_softc *, int);
  172: Static	void uplcom_rts(struct uplcom_softc *, int);
  173: Static	void uplcom_break(struct uplcom_softc *, int);
  174: Static	void uplcom_set_line_state(struct uplcom_softc *);
  175: Static	void uplcom_get_status(void *, int, u_char *, u_char *);
  176: #if TODO
  177: Static	int  uplcom_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr);
  178: #endif
  179: Static	int  uplcom_param(void *, int, struct termios *);
  180: Static	int  uplcom_open(void *, int);
  181: Static	void uplcom_close(void *, int);
  182: 
  183: struct ucom_callback uplcom_callback = {
  184: 	uplcom_get_status,
  185: 	uplcom_set,
  186: 	uplcom_param,
  187: 	NULL, /* uplcom_ioctl, TODO */
  188: 	uplcom_open,
  189: 	uplcom_close,
  190: 	NULL,
  191: 	NULL
  192: };
  193: 
  194: static const struct uplcom_product {
  195: 	uint16_t	vendor;
  196: 	uint16_t	product;
  197: } uplcom_products [] = {
  198: 	/* I/O DATA USB-RSAQ */
  199: 	{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ },
  200: 	/* I/O DATA USB-RSAQ2 */
  201: 	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 },
  202: 	/* PLANEX USB-RS232 URS-03 */
  203: 	{ USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A },
  204: 	/* IOGEAR/ATEN UC-232A */
  205: 	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
  206: 	/* TDK USB-PHS Adapter UHA6400 */
  207: 	{ USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 },
  208: 	/* RATOC REX-USB60 */
  209: 	{ USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 },
  210: 	/* ELECOM UC-SGT */
  211: 	{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT },
  212: 	/* SOURCENEXT KeikaiDenwa 8 */
  213: 	{ USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8 },
  214: 	/* SOURCENEXT KeikaiDenwa 8 with charger */
  215: 	{ USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG },
  216: 	/* HAL Corporation Crossam2+USB */
  217: 	{ USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001 },
  218: 	{ 0, 0 }
  219: };
  220: 
  221: Static device_probe_t uplcom_match;
  222: Static device_attach_t uplcom_attach;
  223: Static device_detach_t uplcom_detach;
  224: 
  225: Static device_method_t uplcom_methods[] = {
  226: 	/* Device interface */
  227: 	DEVMETHOD(device_probe, uplcom_match),
  228: 	DEVMETHOD(device_attach, uplcom_attach),
  229: 	DEVMETHOD(device_detach, uplcom_detach),
  230: 	{ 0, 0 }
  231: };
  232: 
  233: Static driver_t uplcom_driver = {
  234: 	"ucom",
  235: 	uplcom_methods,
  236: 	sizeof (struct uplcom_softc)
  237: };
  238: 
  239: DRIVER_MODULE(uplcom, uhub, uplcom_driver, ucom_devclass, usbd_driver_load, 0);
  240: MODULE_DEPEND(uplcom, usb, 1, 1, 1);
  241: MODULE_DEPEND(uplcom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
  242: MODULE_VERSION(uplcom, UPLCOM_MODVER);
  243: 
  244: static int     uplcominterval = UPLCOM_INTR_INTERVAL;
  245: 
  246: static int
  247: sysctl_hw_usb_uplcom_interval(SYSCTL_HANDLER_ARGS)
  248: {
  249: 	int err, val;
  250: 
  251: 	val = uplcominterval;
  252: 	err = sysctl_handle_int(oidp, &val, sizeof(val), req);
  253: 	if (err != 0 || req->newptr == NULL)
  254: 		return (err);
  255: 	if (0 < val && val <= 1000)
  256: 		uplcominterval = val;
  257: 	else
  258: 		err = EINVAL;
  259: 
  260: 	return (err);
  261: }
  262: 
  263: SYSCTL_PROC(_hw_usb_uplcom, OID_AUTO, interval, CTLTYPE_INT | CTLFLAG_RW,
  264: 	0, sizeof(int), sysctl_hw_usb_uplcom_interval,
  265: 	"I", "uplcom interrpt pipe interval");
  266: 
  267: USB_MATCH(uplcom)
  268: {
  269: 	USB_MATCH_START(uplcom, uaa);
  270: 	int i;
  271: 
  272: 	if (uaa->iface != NULL)
  273: 		return (UMATCH_NONE);
  274: 
  275: 	for (i = 0; uplcom_products[i].vendor != 0; i++) {
  276: 		if (uplcom_products[i].vendor == uaa->vendor &&
  277: 		    uplcom_products[i].product == uaa->product) {
  278: 			return (UMATCH_VENDOR_PRODUCT);
  279: 		}
  280: 	}
  281: 	return (UMATCH_NONE);
  282: }
  283: 
  284: USB_ATTACH(uplcom)
  285: {
  286: 	USB_ATTACH_START(uplcom, sc, uaa);
  287: 	usbd_device_handle dev = uaa->device;
  288: 	struct ucom_softc *ucom;
  289: 	usb_config_descriptor_t *cdesc;
  290: 	usb_interface_descriptor_t *id;
  291: 	usb_endpoint_descriptor_t *ed;
  292: 	char *devinfo;
  293: 	const char *devname;
  294: 	usbd_status err;
  295: 	int i;
  296: 
  297: 	devinfo = malloc(1024, M_USBDEV, M_WAITOK);
  298: 	ucom = &sc->sc_ucom;
  299: 
  300: 	bzero(sc, sizeof (struct uplcom_softc));
  301: 
  302: 	usbd_devinfo(dev, 0, devinfo);
  303: 	/* USB_ATTACH_SETUP; */
  304: 	ucom->sc_dev = self;
  305: 	device_set_desc_copy(self, devinfo);
  306: 	/* USB_ATTACH_SETUP; */
  307: 
  308: 	ucom->sc_udev = dev;
  309: 	ucom->sc_iface = uaa->iface;
  310: 
  311: 	devname = USBDEVNAME(ucom->sc_dev);
  312: 	printf("%s: %s\n", devname, devinfo);
  313: 
  314: 	DPRINTF(("uplcom attach: sc = %p\n", sc));
  315: 
  316: 	/* initialize endpoints */
  317: 	ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;
  318: 	sc->sc_intr_number = -1;
  319: 	sc->sc_intr_pipe = NULL;
  320: 
  321: 	/* Move the device into the configured state. */
  322: 	err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1);
  323: 	if (err) {
  324: 		printf("%s: failed to set configuration: %s\n",
  325: 			devname, usbd_errstr(err));
  326: 		ucom->sc_dying = 1;
  327: 		goto error;
  328: 	}
  329: 
  330: 	/* get the config descriptor */
  331: 	cdesc = usbd_get_config_descriptor(ucom->sc_udev);
  332: 
  333: 	if (cdesc == NULL) {
  334: 		printf("%s: failed to get configuration descriptor\n",
  335: 			USBDEVNAME(ucom->sc_dev));
  336: 		ucom->sc_dying = 1;
  337: 		goto error;
  338: 	}
  339: 
  340: 	/* get the (first/common) interface */
  341: 	err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX,
  342: 					   &ucom->sc_iface);
  343: 	if (err) {
  344: 		printf("%s: failed to get interface: %s\n",
  345: 			devname, usbd_errstr(err));
  346: 		ucom->sc_dying = 1;
  347: 		goto error;
  348: 	}
  349: 
  350: 	/* Find the interrupt endpoints */
  351: 
  352: 	id = usbd_get_interface_descriptor(ucom->sc_iface);
  353: 	sc->sc_iface_number = id->bInterfaceNumber;
  354: 
  355: 	for (i = 0; i < id->bNumEndpoints; i++) {
  356: 		ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
  357: 		if (ed == NULL) {
  358: 			printf("%s: no endpoint descriptor for %d\n",
  359: 				USBDEVNAME(ucom->sc_dev), i);
  360: 			ucom->sc_dying = 1;
  361: 			goto error;
  362: 		}
  363: 
  364: 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  365: 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
  366: 			sc->sc_intr_number = ed->bEndpointAddress;
  367: 			sc->sc_isize = UGETW(ed->wMaxPacketSize);
  368: 		}
  369: 	}
  370: 
  371: 	if (sc->sc_intr_number == -1) {
  372: 		printf("%s: Could not find interrupt in\n",
  373: 			USBDEVNAME(ucom->sc_dev));
  374: 		ucom->sc_dying = 1;
  375: 		goto error;
  376: 	}
  377: 
  378: 	/* keep interface for interrupt */
  379: 	sc->sc_intr_iface = ucom->sc_iface;
  380: 
  381: 	/*
  382: 	 * USB-RSAQ1 has two interface
  383: 	 *
  384: 	 *  USB-RSAQ1       | USB-RSAQ2
  385: 	 * -----------------+-----------------
  386: 	 * Interface 0      |Interface 0
  387: 	 *  Interrupt(0x81) | Interrupt(0x81)
  388: 	 * -----------------+ BulkIN(0x02)
  389: 	 * Interface 1	    | BulkOUT(0x83)
  390: 	 *   BulkIN(0x02)   |
  391: 	 *   BulkOUT(0x83)  |
  392: 	 */
  393: 	if (cdesc->bNumInterface == 2) {
  394: 		err = usbd_device2interface_handle(dev,
  395: 						   UPLCOM_SECOND_IFACE_INDEX,
  396: 						   &ucom->sc_iface);
  397: 		if (err) {
  398: 			printf("%s: failed to get second interface: %s\n",
  399: 				devname, usbd_errstr(err));
  400: 			ucom->sc_dying = 1;
  401: 			goto error;
  402: 		}
  403: 	}
  404: 
  405: 	/* Find the bulk{in,out} endpoints */
  406: 
  407: 	id = usbd_get_interface_descriptor(ucom->sc_iface);
  408: 	sc->sc_iface_number = id->bInterfaceNumber;
  409: 
  410: 	for (i = 0; i < id->bNumEndpoints; i++) {
  411: 		ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
  412: 		if (ed == NULL) {
  413: 			printf("%s: no endpoint descriptor for %d\n",
  414: 				USBDEVNAME(ucom->sc_dev), i);
  415: 			ucom->sc_dying = 1;
  416: 			goto error;
  417: 		}
  418: 
  419: 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  420: 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  421: 			ucom->sc_bulkin_no = ed->bEndpointAddress;
  422: 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
  423: 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  424: 			ucom->sc_bulkout_no = ed->bEndpointAddress;
  425: 		}
  426: 	}
  427: 
  428: 	if (ucom->sc_bulkin_no == -1) {
  429: 		printf("%s: Could not find data bulk in\n",
  430: 			USBDEVNAME(ucom->sc_dev));
  431: 		ucom->sc_dying = 1;
  432: 		goto error;
  433: 	}
  434: 
  435: 	if (ucom->sc_bulkout_no == -1) {
  436: 		printf("%s: Could not find data bulk out\n",
  437: 			USBDEVNAME(ucom->sc_dev));
  438: 		ucom->sc_dying = 1;
  439: 		goto error;
  440: 	}
  441: 
  442: 	sc->sc_dtr = sc->sc_rts = -1;
  443: 	ucom->sc_parent = sc;
  444: 	ucom->sc_portno = UCOM_UNK_PORTNO;
  445: 	/* bulkin, bulkout set above */
  446: 	ucom->sc_ibufsize = UPLCOMIBUFSIZE;
  447: 	ucom->sc_obufsize = UPLCOMOBUFSIZE;
  448: 	ucom->sc_ibufsizepad = UPLCOMIBUFSIZE;
  449: 	ucom->sc_opkthdrlen = 0;
  450: 	ucom->sc_callback = &uplcom_callback;
  451: 
  452: 	err = uplcom_reset(sc);
  453: 
  454: 	if (err) {
  455: 		printf("%s: reset failed: %s\n",
  456: 		       USBDEVNAME(ucom->sc_dev), usbd_errstr(err));
  457: 		ucom->sc_dying = 1;
  458: 		goto error;
  459: 	}
  460: 
  461: 	DPRINTF(("uplcom: in = 0x%x, out = 0x%x, intr = 0x%x\n",
  462: 		 ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number));
  463: 
  464: 	ucom_attach(&sc->sc_ucom);
  465: 
  466: 	free(devinfo, M_USBDEV);
  467: 	USB_ATTACH_SUCCESS_RETURN;
  468: 
  469: error:
  470: 	free(devinfo, M_USBDEV);
  471: 	USB_ATTACH_ERROR_RETURN;
  472: }
  473: 
  474: USB_DETACH(uplcom)
  475: {
  476: 	USB_DETACH_START(uplcom, sc);
  477: 	int rv = 0;
  478: 
  479: 	DPRINTF(("uplcom_detach: sc = %p\n", sc));
  480: 
  481: 	if (sc->sc_intr_pipe != NULL) {
  482: 		usbd_abort_pipe(sc->sc_intr_pipe);
  483: 		usbd_close_pipe(sc->sc_intr_pipe);
  484: 		free(sc->sc_intr_buf, M_USBDEV);
  485: 		sc->sc_intr_pipe = NULL;
  486: 	}
  487: 
  488: 	sc->sc_ucom.sc_dying = 1;
  489: 
  490: 	rv = ucom_detach(&sc->sc_ucom);
  491: 
  492: 	return (rv);
  493: }
  494: 
  495: Static usbd_status
  496: uplcom_reset(struct uplcom_softc *sc)
  497: {
  498: 	usb_device_request_t req;
  499: 	usbd_status err;
  500: 
  501: 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  502: 	req.bRequest = UPLCOM_SET_REQUEST;
  503: 	USETW(req.wValue, 0);
  504: 	USETW(req.wIndex, sc->sc_iface_number);
  505: 	USETW(req.wLength, 0);
  506: 
  507: 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
  508: 	if (err) {
  509: 		printf("%s: uplcom_reset: %s\n",
  510: 		       USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
  511: 		return (EIO);
  512: 	}
  513: 
  514: 	return (0);
  515: }
  516: 
  517: Static void
  518: uplcom_set_line_state(struct uplcom_softc *sc)
  519: {
  520: 	usb_device_request_t req;
  521: 	int ls;
  522: 	usbd_status err;
  523: 
  524: 	ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) |
  525: 		(sc->sc_rts ? UCDC_LINE_RTS : 0);
  526: 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  527: 	req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
  528: 	USETW(req.wValue, ls);
  529: 	USETW(req.wIndex, sc->sc_iface_number);
  530: 	USETW(req.wLength, 0);
  531: 
  532: 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
  533: 	if (err)
  534: 		printf("%s: uplcom_set_line_status: %s\n",
  535: 		       USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
  536: }
  537: 
  538: Static void
  539: uplcom_set(void *addr, int portno, int reg, int onoff)
  540: {
  541: 	struct uplcom_softc *sc = addr;
  542: 
  543: 	switch (reg) {
  544: 	case UCOM_SET_DTR:
  545: 		uplcom_dtr(sc, onoff);
  546: 		break;
  547: 	case UCOM_SET_RTS:
  548: 		uplcom_rts(sc, onoff);
  549: 		break;
  550: 	case UCOM_SET_BREAK:
  551: 		uplcom_break(sc, onoff);
  552: 		break;
  553: 	default:
  554: 		break;
  555: 	}
  556: }
  557: 
  558: Static void
  559: uplcom_dtr(struct uplcom_softc *sc, int onoff)
  560: {
  561: 	DPRINTF(("uplcom_dtr: onoff = %d\n", onoff));
  562: 
  563: 	if (sc->sc_dtr == onoff)
  564: 		return;
  565: 	sc->sc_dtr = onoff;
  566: 
  567: 	uplcom_set_line_state(sc);
  568: }
  569: 
  570: Static void
  571: uplcom_rts(struct uplcom_softc *sc, int onoff)
  572: {
  573: 	DPRINTF(("uplcom_rts: onoff = %d\n", onoff));
  574: 
  575: 	if (sc->sc_rts == onoff)
  576: 		return;
  577: 	sc->sc_rts = onoff;
  578: 
  579: 	uplcom_set_line_state(sc);
  580: }
  581: 
  582: Static void
  583: uplcom_break(struct uplcom_softc *sc, int onoff)
  584: {
  585: 	usb_device_request_t req;
  586: 	usbd_status err;
  587: 
  588: 	DPRINTF(("uplcom_break: onoff = %d\n", onoff));
  589: 
  590: 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  591: 	req.bRequest = UCDC_SEND_BREAK;
  592: 	USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
  593: 	USETW(req.wIndex, sc->sc_iface_number);
  594: 	USETW(req.wLength, 0);
  595: 
  596: 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
  597: 	if (err)
  598: 		printf("%s: uplcom_break: %s\n",
  599: 		       USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
  600: }
  601: 
  602: Static usbd_status
  603: uplcom_set_crtscts(struct uplcom_softc *sc)
  604: {
  605: 	usb_device_request_t req;
  606: 	usbd_status err;
  607: 
  608: 	DPRINTF(("uplcom_set_crtscts: on\n"));
  609: 
  610: 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  611: 	req.bRequest = UPLCOM_SET_REQUEST;
  612: 	USETW(req.wValue, 0);
  613: 	USETW(req.wIndex, UPLCOM_SET_CRTSCTS);
  614: 	USETW(req.wLength, 0);
  615: 
  616: 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
  617: 	if (err) {
  618: 		printf("%s: uplcom_set_crtscts: %s\n",
  619: 		       USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
  620: 		return (err);
  621: 	}
  622: 
  623: 	return (USBD_NORMAL_COMPLETION);
  624: }
  625: 
  626: Static usbd_status
  627: uplcom_set_line_coding(struct uplcom_softc *sc, usb_cdc_line_state_t *state)
  628: {
  629: 	usb_device_request_t req;
  630: 	usbd_status err;
  631: 
  632: 	DPRINTF((
  633: "uplcom_set_line_coding: rate = %d, fmt = %d, parity = %d bits = %d\n",
  634: 		 UGETDW(state->dwDTERate), state->bCharFormat,
  635: 		 state->bParityType, state->bDataBits));
  636: 
  637: 	if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) {
  638: 		DPRINTF(("uplcom_set_line_coding: already set\n"));
  639: 		return (USBD_NORMAL_COMPLETION);
  640: 	}
  641: 
  642: 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  643: 	req.bRequest = UCDC_SET_LINE_CODING;
  644: 	USETW(req.wValue, 0);
  645: 	USETW(req.wIndex, sc->sc_iface_number);
  646: 	USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
  647: 
  648: 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, state);
  649: 	if (err) {
  650: 		printf("%s: uplcom_set_line_coding: %s\n",
  651: 		       USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
  652: 		return (err);
  653: 	}
  654: 
  655: 	sc->sc_line_state = *state;
  656: 
  657: 	return (USBD_NORMAL_COMPLETION);
  658: }
  659: 
  660: Static int
  661: uplcom_param(void *addr, int portno, struct termios *t)
  662: {
  663: 	struct uplcom_softc *sc = addr;
  664: 	usbd_status err;
  665: 	usb_cdc_line_state_t ls;
  666: 
  667: 	DPRINTF(("uplcom_param: sc = %p\n", sc));
  668: 
  669: 	USETDW(ls.dwDTERate, t->c_ospeed);
  670: 	if (ISSET(t->c_cflag, CSTOPB))
  671: 		ls.bCharFormat = UCDC_STOP_BIT_2;
  672: 	else
  673: 		ls.bCharFormat = UCDC_STOP_BIT_1;
  674: 	if (ISSET(t->c_cflag, PARENB)) {
  675: 		if (ISSET(t->c_cflag, PARODD))
  676: 			ls.bParityType = UCDC_PARITY_ODD;
  677: 		else
  678: 			ls.bParityType = UCDC_PARITY_EVEN;
  679: 	} else
  680: 		ls.bParityType = UCDC_PARITY_NONE;
  681: 	switch (ISSET(t->c_cflag, CSIZE)) {
  682: 	case CS5:
  683: 		ls.bDataBits = 5;
  684: 		break;
  685: 	case CS6:
  686: 		ls.bDataBits = 6;
  687: 		break;
  688: 	case CS7:
  689: 		ls.bDataBits = 7;
  690: 		break;
  691: 	case CS8:
  692: 		ls.bDataBits = 8;
  693: 		break;
  694: 	}
  695: 
  696: 	err = uplcom_set_line_coding(sc, &ls);
  697: 	if (err)
  698: 		return (EIO);
  699: 
  700: 	if (ISSET(t->c_cflag, CRTSCTS)) {
  701: 		err = uplcom_set_crtscts(sc);
  702: 		if (err)
  703: 			return (EIO);
  704: 	}
  705: 
  706: 	return (0);
  707: }
  708: 
  709: Static int
  710: uplcom_open(void *addr, int portno)
  711: {
  712: 	struct uplcom_softc *sc = addr;
  713: 	int err;
  714: 
  715: 	if (sc->sc_ucom.sc_dying)
  716: 		return (ENXIO);
  717: 
  718: 	DPRINTF(("uplcom_open: sc = %p\n", sc));
  719: 
  720: 	if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
  721: 		sc->sc_status = 0; /* clear status bit */
  722: 		sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
  723: 		err = usbd_open_pipe_intr(sc->sc_intr_iface,
  724: 					  sc->sc_intr_number,
  725: 					  USBD_SHORT_XFER_OK,
  726: 					  &sc->sc_intr_pipe,
  727: 					  sc,
  728: 					  sc->sc_intr_buf,
  729: 					  sc->sc_isize,
  730: 					  uplcom_intr,
  731: 					  uplcominterval);
  732: 		if (err) {
  733: 			printf("%s: cannot open interrupt pipe (addr %d)\n",
  734: 			       USBDEVNAME(sc->sc_ucom.sc_dev),
  735: 			       sc->sc_intr_number);
  736: 			return (EIO);
  737: 		}
  738: 	}
  739: 
  740: 	return (0);
  741: }
  742: 
  743: Static void
  744: uplcom_close(void *addr, int portno)
  745: {
  746: 	struct uplcom_softc *sc = addr;
  747: 	int err;
  748: 
  749: 	if (sc->sc_ucom.sc_dying)
  750: 		return;
  751: 
  752: 	DPRINTF(("uplcom_close: close\n"));
  753: 
  754: 	if (sc->sc_intr_pipe != NULL) {
  755: 		err = usbd_abort_pipe(sc->sc_intr_pipe);
  756: 		if (err)
  757: 			printf("%s: abort interrupt pipe failed: %s\n",
  758: 			       USBDEVNAME(sc->sc_ucom.sc_dev),
  759: 			       usbd_errstr(err));
  760: 		err = usbd_close_pipe(sc->sc_intr_pipe);
  761: 		if (err)
  762: 			printf("%s: close interrupt pipe failed: %s\n",
  763: 			       USBDEVNAME(sc->sc_ucom.sc_dev),
  764: 			       usbd_errstr(err));
  765: 		free(sc->sc_intr_buf, M_USBDEV);
  766: 		sc->sc_intr_pipe = NULL;
  767: 	}
  768: }
  769: 
  770: Static void
  771: uplcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
  772: {
  773: 	struct uplcom_softc *sc = priv;
  774: 	u_char *buf = sc->sc_intr_buf;
  775: 	u_char pstatus;
  776: 
  777: 	if (sc->sc_ucom.sc_dying)
  778: 		return;
  779: 
  780: 	if (status != USBD_NORMAL_COMPLETION) {
  781: 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
  782: 			return;
  783: 
  784: 		DPRINTF(("%s: uplcom_intr: abnormal status: %s\n",
  785: 			USBDEVNAME(sc->sc_ucom.sc_dev),
  786: 			usbd_errstr(status)));
  787: 		usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
  788: 		return;
  789: 	}
  790: 
  791: 	DPRINTF(("%s: uplcom status = %02x\n",
  792: 		 USBDEVNAME(sc->sc_ucom.sc_dev), buf[8]));
  793: 
  794: 	sc->sc_lsr = sc->sc_msr = 0;
  795: 	pstatus = buf[8];
  796: 	if (ISSET(pstatus, RSAQ_STATUS_DSR))
  797: 		sc->sc_msr |= UMSR_DSR;
  798: 	if (ISSET(pstatus, RSAQ_STATUS_DCD))
  799: 		sc->sc_msr |= UMSR_DCD;
  800: 	ucom_status_change(&sc->sc_ucom);
  801: }
  802: 
  803: Static void
  804: uplcom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
  805: {
  806: 	struct uplcom_softc *sc = addr;
  807: 
  808: 	DPRINTF(("uplcom_get_status:\n"));
  809: 
  810: 	if (lsr != NULL)
  811: 		*lsr = sc->sc_lsr;
  812: 	if (msr != NULL)
  813: 		*msr = sc->sc_msr;
  814: }
  815: 
  816: #if TODO
  817: Static int
  818: uplcom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
  819: 	     usb_proc_ptr p)
  820: {
  821: 	struct uplcom_softc *sc = addr;
  822: 	int error = 0;
  823: 
  824: 	if (sc->sc_ucom.sc_dying)
  825: 		return (EIO);
  826: 
  827: 	DPRINTF(("uplcom_ioctl: cmd = 0x%08lx\n", cmd));
  828: 
  829: 	switch (cmd) {
  830: 	case TIOCNOTTY:
  831: 	case TIOCMGET:
  832: 	case TIOCMSET:
  833: 	case USB_GET_CM_OVER_DATA:
  834: 	case USB_SET_CM_OVER_DATA:
  835: 		break;
  836: 
  837: 	default:
  838: 		DPRINTF(("uplcom_ioctl: unknown\n"));
  839: 		error = ENOTTY;
  840: 		break;
  841: 	}
  842: 
  843: 	return (error);
  844: }
  845: #endif