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

    1: /*-
    2:  * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  *
   14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24:  * SUCH DAMAGE.
   25:  *
   26:  * $NetBSD: usb/uvscom.c,v 1.1 2002/03/19 15:08:42 augustss Exp $
   27:  * $FreeBSD: src/sys/dev/usb/uvscom.c,v 1.19 2003/11/16 12:26:10 akiyama Exp $
   28:  * $DragonFly: src/sys/dev/usbmisc/uvscom/uvscom.c,v 1.6 2004/02/11 15:13:06 joerg Exp $
   29:  */
   30: 
   31: /*
   32:  * uvscom: SUNTAC Slipper U VS-10U driver.
   33:  * Slipper U is a PC card to USB converter for data communication card
   34:  * adapter.  It supports DDI Pocket's Air H" C@rd, C@rd H" 64, NTT's P-in,
   35:  * P-in m@ater and various data communication card adapters.
   36:  */
   37: 
   38: #include <sys/param.h>
   39: #include <sys/systm.h>
   40: #include <sys/kernel.h>
   41: #include <sys/malloc.h>
   42: #include <sys/fcntl.h>
   43: #include <sys/conf.h>
   44: #include <sys/tty.h>
   45: #include <sys/file.h>
   46: #if defined(__FreeBSD__) || defined(__DragonFly__)
   47: #include <sys/bus.h>
   48: #include <sys/ioccom.h>
   49: #if defined(__FreeBSD__) &&  __FreeBSD_version >= 500014
   50: #include <sys/selinfo.h>
   51: #else
   52: #include <sys/select.h>
   53: #endif
   54: #else
   55: #include <sys/ioctl.h>
   56: #include <sys/device.h>
   57: #endif
   58: #include <sys/proc.h>
   59: #include <sys/vnode.h>
   60: #include <sys/poll.h>
   61: #include <sys/sysctl.h>
   62: 
   63: #include <bus/usb/usb.h>
   64: #include <bus/usb/usbcdc.h>
   65: 
   66: #include <bus/usb/usbdi.h>
   67: #include <bus/usb/usbdi_util.h>
   68: #include <bus/usb/usbdevs.h>
   69: #include <bus/usb/usb_quirks.h>
   70: 
   71: #include "../ucom/ucomvar.h"
   72: 
   73: #ifdef USB_DEBUG
   74: static int	uvscomdebug = 0;
   75: SYSCTL_NODE(_hw_usb, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom");
   76: SYSCTL_INT(_hw_usb_uvscom, OID_AUTO, debug, CTLFLAG_RW,
   77: 	   &uvscomdebug, 0, "uvscom debug level");
   78: 
   79: #define DPRINTFN(n, x) do { \
   80: 				if (uvscomdebug > (n)) \
   81: 					logprintf x; \
   82: 			} while (0)
   83: #else
   84: #define DPRINTFN(n, x)
   85: #endif
   86: #define DPRINTF(x) DPRINTFN(0, x)
   87: 
   88: #define UVSCOM_MODVER		1	/* module version */
   89: 
   90: #define	UVSCOM_CONFIG_INDEX	0
   91: #define	UVSCOM_IFACE_INDEX	0
   92: 
   93: #define UVSCOM_INTR_INTERVAL	100	/* mS */
   94: 
   95: #define UVSCOM_UNIT_WAIT	5
   96: 
   97: /* Request */
   98: #define UVSCOM_SET_SPEED	0x10
   99: #define UVSCOM_LINE_CTL		0x11
  100: #define UVSCOM_SET_PARAM	0x12
  101: #define UVSCOM_READ_STATUS	0xd0
  102: #define UVSCOM_SHUTDOWN		0xe0
  103: 
  104: /* UVSCOM_SET_SPEED parameters */
  105: #define UVSCOM_SPEED_150BPS	0x00
  106: #define UVSCOM_SPEED_300BPS	0x01
  107: #define UVSCOM_SPEED_600BPS	0x02
  108: #define UVSCOM_SPEED_1200BPS	0x03
  109: #define UVSCOM_SPEED_2400BPS	0x04
  110: #define UVSCOM_SPEED_4800BPS	0x05
  111: #define UVSCOM_SPEED_9600BPS	0x06
  112: #define UVSCOM_SPEED_19200BPS	0x07
  113: #define UVSCOM_SPEED_38400BPS	0x08
  114: #define UVSCOM_SPEED_57600BPS	0x09
  115: #define UVSCOM_SPEED_115200BPS	0x0a
  116: 
  117: /* UVSCOM_LINE_CTL parameters */
  118: #define UVSCOM_BREAK		0x40
  119: #define UVSCOM_RTS		0x02
  120: #define UVSCOM_DTR		0x01
  121: #define UVSCOM_LINE_INIT	0x08
  122: 
  123: /* UVSCOM_SET_PARAM parameters */
  124: #define UVSCOM_DATA_MASK	0x03
  125: #define UVSCOM_DATA_BIT_8	0x03
  126: #define UVSCOM_DATA_BIT_7	0x02
  127: #define UVSCOM_DATA_BIT_6	0x01
  128: #define UVSCOM_DATA_BIT_5	0x00
  129: 
  130: #define UVSCOM_STOP_MASK	0x04
  131: #define UVSCOM_STOP_BIT_2	0x04
  132: #define UVSCOM_STOP_BIT_1	0x00
  133: 
  134: #define UVSCOM_PARITY_MASK	0x18
  135: #define UVSCOM_PARITY_EVEN	0x18
  136: #if 0
  137: #define UVSCOM_PARITY_UNK	0x10
  138: #endif
  139: #define UVSCOM_PARITY_ODD	0x08
  140: #define UVSCOM_PARITY_NONE	0x00
  141: 
  142: /* Status bits */
  143: #define UVSCOM_TXRDY		0x04
  144: #define UVSCOM_RXRDY		0x01
  145: 
  146: #define UVSCOM_DCD		0x08
  147: #define UVSCOM_NOCARD		0x04
  148: #define UVSCOM_DSR		0x02
  149: #define UVSCOM_CTS		0x01
  150: #define UVSCOM_USTAT_MASK	(UVSCOM_NOCARD | UVSCOM_DSR | UVSCOM_CTS)
  151: 
  152: struct	uvscom_softc {
  153: 	struct ucom_softc	sc_ucom;
  154: 
  155: 	int			sc_iface_number;/* interface number */
  156: 
  157: 	usbd_interface_handle	sc_intr_iface;	/* interrupt interface */
  158: 	int			sc_intr_number;	/* interrupt number */
  159: 	usbd_pipe_handle	sc_intr_pipe;	/* interrupt pipe */
  160: 	u_char			*sc_intr_buf;	/* interrupt buffer */
  161: 	int			sc_isize;
  162: 
  163: 	u_char			sc_dtr;		/* current DTR state */
  164: 	u_char			sc_rts;		/* current RTS state */
  165: 
  166: 	u_char			sc_lsr;		/* Local status register */
  167: 	u_char			sc_msr;		/* uvscom status register */
  168: 
  169: 	uint16_t		sc_lcr;		/* Line control */
  170: 	u_char			sc_usr;		/* unit status */
  171: };
  172: 
  173: /*
  174:  * These are the maximum number of bytes transferred per frame.
  175:  * The output buffer size cannot be increased due to the size encoding.
  176:  */
  177: #define UVSCOMIBUFSIZE 512
  178: #define UVSCOMOBUFSIZE 64
  179: 
  180: Static	usbd_status uvscom_shutdown(struct uvscom_softc *);
  181: Static	usbd_status uvscom_reset(struct uvscom_softc *);
  182: Static	usbd_status uvscom_set_line_coding(struct uvscom_softc *,
  183: 					   uint16_t, uint16_t);
  184: Static	usbd_status uvscom_set_line(struct uvscom_softc *, uint16_t);
  185: Static	usbd_status uvscom_set_crtscts(struct uvscom_softc *);
  186: Static	void uvscom_get_status(void *, int, u_char *, u_char *);
  187: Static	void uvscom_dtr(struct uvscom_softc *, int);
  188: Static	void uvscom_rts(struct uvscom_softc *, int);
  189: Static	void uvscom_break(struct uvscom_softc *, int);
  190: 
  191: Static	void uvscom_set(void *, int, int, int);
  192: Static	void uvscom_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
  193: #if TODO
  194: Static	int  uvscom_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr);
  195: #endif
  196: Static	int  uvscom_param(void *, int, struct termios *);
  197: Static	int  uvscom_open(void *, int);
  198: Static	void uvscom_close(void *, int);
  199: 
  200: struct ucom_callback uvscom_callback = {
  201: 	uvscom_get_status,
  202: 	uvscom_set,
  203: 	uvscom_param,
  204: 	NULL, /* uvscom_ioctl, TODO */
  205: 	uvscom_open,
  206: 	uvscom_close,
  207: 	NULL,
  208: 	NULL
  209: };
  210: 
  211: static const struct usb_devno uvscom_devs [] = {
  212: 	/* SUNTAC U-Cable type D2 */
  213: 	{ USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_DS96L },
  214: 	/* SUNTAC Ir-Trinity */
  215: 	{ USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_IS96U },
  216: 	/* SUNTAC U-Cable type P1 */
  217: 	{ USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_PS64P1 },
  218: 	/* SUNTAC Slipper U */
  219: 	{ USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_VS10U },
  220: };
  221: #define uvscom_lookup(v, p) usb_lookup(uvscom_devs, v, p)
  222: 
  223: Static device_probe_t uvscom_match;
  224: Static device_attach_t uvscom_attach;
  225: Static device_detach_t uvscom_detach;
  226: 
  227: Static device_method_t uvscom_methods[] = {
  228: 	/* Device interface */
  229: 	DEVMETHOD(device_probe, uvscom_match),
  230: 	DEVMETHOD(device_attach, uvscom_attach),
  231: 	DEVMETHOD(device_detach, uvscom_detach),
  232: 	{ 0, 0 }
  233: };
  234: 
  235: Static driver_t uvscom_driver = {
  236: 	"uvscom",
  237: 	uvscom_methods,
  238: 	sizeof (struct uvscom_softc)
  239: };
  240: 
  241: DRIVER_MODULE(uvscom, uhub, uvscom_driver, ucom_devclass, usbd_driver_load, 0);
  242: MODULE_DEPEND(uvscom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
  243: MODULE_VERSION(uvscom, UVSCOM_MODVER);
  244: 
  245: USB_MATCH(uvscom)
  246: {
  247: 	USB_MATCH_START(uvscom, uaa);
  248: 
  249: 	if (uaa->iface != NULL)
  250: 		return (UMATCH_NONE);
  251: 
  252: 	return (uvscom_lookup(uaa->vendor, uaa->product) != NULL ?
  253: 		UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
  254: }
  255: 
  256: USB_ATTACH(uvscom)
  257: {
  258: 	USB_ATTACH_START(uvscom, sc, uaa);
  259: 	usbd_device_handle dev = uaa->device;
  260: 	struct ucom_softc *ucom;
  261: 	usb_config_descriptor_t *cdesc;
  262: 	usb_interface_descriptor_t *id;
  263: 	usb_endpoint_descriptor_t *ed;
  264: 	char *devinfo;
  265: 	const char *devname;
  266: 	usbd_status err;
  267: 	int i;
  268: 
  269: 	devinfo = malloc(1024, M_USBDEV, M_WAITOK);
  270: 	ucom = &sc->sc_ucom;
  271: 
  272: 	bzero(sc, sizeof (struct uvscom_softc));
  273: 
  274: 	usbd_devinfo(dev, 0, devinfo);
  275: 	/* USB_ATTACH_SETUP; */
  276: 	ucom->sc_dev = self;
  277: 	device_set_desc_copy(self, devinfo);
  278: 	/* USB_ATTACH_SETUP; */
  279: 
  280: 	ucom->sc_udev = dev;
  281: 	ucom->sc_iface = uaa->iface;
  282: 
  283: 	devname = USBDEVNAME(ucom->sc_dev);
  284: 	printf("%s: %s\n", devname, devinfo);
  285: 
  286: 	DPRINTF(("uvscom attach: sc = %p\n", sc));
  287: 
  288: 	/* initialize endpoints */
  289: 	ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;
  290: 	sc->sc_intr_number = -1;
  291: 	sc->sc_intr_pipe = NULL;
  292: 
  293: 	/* Move the device into the configured state. */
  294: 	err = usbd_set_config_index(dev, UVSCOM_CONFIG_INDEX, 1);
  295: 	if (err) {
  296: 		printf("%s: failed to set configuration, err=%s\n",
  297: 			devname, usbd_errstr(err));
  298: 		goto error;
  299: 	}
  300: 
  301: 	/* get the config descriptor */
  302: 	cdesc = usbd_get_config_descriptor(ucom->sc_udev);
  303: 
  304: 	if (cdesc == NULL) {
  305: 		printf("%s: failed to get configuration descriptor\n",
  306: 			USBDEVNAME(ucom->sc_dev));
  307: 		goto error;
  308: 	}
  309: 
  310: 	/* get the common interface */
  311: 	err = usbd_device2interface_handle(dev, UVSCOM_IFACE_INDEX,
  312: 					   &ucom->sc_iface);
  313: 	if (err) {
  314: 		printf("%s: failed to get interface, err=%s\n",
  315: 			devname, usbd_errstr(err));
  316: 		goto error;
  317: 	}
  318: 
  319: 	id = usbd_get_interface_descriptor(ucom->sc_iface);
  320: 	sc->sc_iface_number = id->bInterfaceNumber;
  321: 
  322: 	/* Find endpoints */
  323: 	for (i = 0; i < id->bNumEndpoints; i++) {
  324: 		ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
  325: 		if (ed == NULL) {
  326: 			printf("%s: no endpoint descriptor for %d\n",
  327: 				USBDEVNAME(ucom->sc_dev), i);
  328: 			goto error;
  329: 		}
  330: 
  331: 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  332: 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  333: 			ucom->sc_bulkin_no = ed->bEndpointAddress;
  334: 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
  335: 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  336: 			ucom->sc_bulkout_no = ed->bEndpointAddress;
  337: 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  338: 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
  339: 			sc->sc_intr_number = ed->bEndpointAddress;
  340: 			sc->sc_isize = UGETW(ed->wMaxPacketSize);
  341: 		}
  342: 	}
  343: 
  344: 	if (ucom->sc_bulkin_no == -1) {
  345: 		printf("%s: Could not find data bulk in\n",
  346: 			USBDEVNAME(ucom->sc_dev));
  347: 		goto error;
  348: 	}
  349: 	if (ucom->sc_bulkout_no == -1) {
  350: 		printf("%s: Could not find data bulk out\n",
  351: 			USBDEVNAME(ucom->sc_dev));
  352: 		goto error;
  353: 	}
  354: 	if (sc->sc_intr_number == -1) {
  355: 		printf("%s: Could not find interrupt in\n",
  356: 			USBDEVNAME(ucom->sc_dev));
  357: 		goto error;
  358: 	}
  359: 
  360: 	sc->sc_dtr = sc->sc_rts = 0;
  361: 	sc->sc_lcr = UVSCOM_LINE_INIT;
  362: 
  363: 	ucom->sc_parent = sc;
  364: 	ucom->sc_portno = UCOM_UNK_PORTNO;
  365: 	/* bulkin, bulkout set above */
  366: 	ucom->sc_ibufsize = UVSCOMIBUFSIZE;
  367: 	ucom->sc_obufsize = UVSCOMOBUFSIZE;
  368: 	ucom->sc_ibufsizepad = UVSCOMIBUFSIZE;
  369: 	ucom->sc_opkthdrlen = 0;
  370: 	ucom->sc_callback = &uvscom_callback;
  371: 
  372: 	err = uvscom_reset(sc);
  373: 
  374: 	if (err) {
  375: 		printf("%s: reset failed, %s\n", USBDEVNAME(ucom->sc_dev),
  376: 			usbd_errstr(err));
  377: 		goto error;
  378: 	}
  379: 
  380: 	DPRINTF(("uvscom: in = 0x%x out = 0x%x intr = 0x%x\n",
  381: 		 ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number));
  382: 
  383: 	ucom_attach(&sc->sc_ucom);
  384: 
  385: 	free(devinfo, M_USBDEV);
  386: 	USB_ATTACH_SUCCESS_RETURN;
  387: 
  388: error:
  389: 	ucom->sc_dying = 1;
  390: 	free(devinfo, M_USBDEV);
  391: 	USB_ATTACH_ERROR_RETURN;
  392: }
  393: 
  394: USB_DETACH(uvscom)
  395: {
  396: 	USB_DETACH_START(uvscom, sc);
  397: 	int rv = 0;
  398: 
  399: 	DPRINTF(("uvscom_detach: sc = %p\n", sc));
  400: 
  401: 	sc->sc_ucom.sc_dying = 1;
  402: 
  403: 	if (sc->sc_intr_pipe != NULL) {
  404: 		usbd_abort_pipe(sc->sc_intr_pipe);
  405: 		usbd_close_pipe(sc->sc_intr_pipe);
  406: 		free(sc->sc_intr_buf, M_USBDEV);
  407: 		sc->sc_intr_pipe = NULL;
  408: 	}
  409: 
  410: 	rv = ucom_detach(&sc->sc_ucom);
  411: 
  412: 	return (rv);
  413: }
  414: 
  415: Static usbd_status
  416: uvscom_readstat(struct uvscom_softc *sc)
  417: {
  418: 	usb_device_request_t req;
  419: 	usbd_status err;
  420: 	uint16_t r;
  421: 
  422: 	DPRINTF(("%s: send readstat\n", USBDEVNAME(sc->sc_ucom.sc_dev)));
  423: 
  424: 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
  425: 	req.bRequest = UVSCOM_READ_STATUS;
  426: 	USETW(req.wValue, 0);
  427: 	USETW(req.wIndex, 0);
  428: 	USETW(req.wLength, 2);
  429: 
  430: 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, &r);
  431: 	if (err) {
  432: 		printf("%s: uvscom_readstat: %s\n",
  433: 		       USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
  434: 		return (err);
  435: 	}
  436: 
  437: 	DPRINTF(("%s: uvscom_readstat: r = %d\n",
  438: 		 USBDEVNAME(sc->sc_ucom.sc_dev), r));
  439: 
  440: 	return (USBD_NORMAL_COMPLETION);
  441: }
  442: 
  443: Static usbd_status
  444: uvscom_shutdown(struct uvscom_softc *sc)
  445: {
  446: 	usb_device_request_t req;
  447: 	usbd_status err;
  448: 
  449: 	DPRINTF(("%s: send shutdown\n", USBDEVNAME(sc->sc_ucom.sc_dev)));
  450: 
  451: 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  452: 	req.bRequest = UVSCOM_SHUTDOWN;
  453: 	USETW(req.wValue, 0);
  454: 	USETW(req.wIndex, 0);
  455: 	USETW(req.wLength, 0);
  456: 
  457: 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  458: 	if (err) {
  459: 		printf("%s: uvscom_shutdown: %s\n",
  460: 		       USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
  461: 		return (err);
  462: 	}
  463: 
  464: 	return (USBD_NORMAL_COMPLETION);
  465: }
  466: 
  467: Static usbd_status
  468: uvscom_reset(struct uvscom_softc *sc)
  469: {
  470: 	DPRINTF(("%s: uvscom_reset\n", USBDEVNAME(sc->sc_ucom.sc_dev)));
  471: 
  472: 	return (USBD_NORMAL_COMPLETION);
  473: }
  474: 
  475: Static usbd_status
  476: uvscom_set_crtscts(struct uvscom_softc *sc)
  477: {
  478: 	DPRINTF(("%s: uvscom_set_crtscts\n", USBDEVNAME(sc->sc_ucom.sc_dev)));
  479: 
  480: 	return (USBD_NORMAL_COMPLETION);
  481: }
  482: 
  483: Static usbd_status
  484: uvscom_set_line(struct uvscom_softc *sc, uint16_t line)
  485: {
  486: 	usb_device_request_t req;
  487: 	usbd_status err;
  488: 
  489: 	DPRINTF(("%s: uvscom_set_line: %04x\n",
  490: 		 USBDEVNAME(sc->sc_ucom.sc_dev), line));
  491: 
  492: 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  493: 	req.bRequest = UVSCOM_LINE_CTL;
  494: 	USETW(req.wValue, line);
  495: 	USETW(req.wIndex, 0);
  496: 	USETW(req.wLength, 0);
  497: 
  498: 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  499: 	if (err) {
  500: 		printf("%s: uvscom_set_line: %s\n",
  501: 		       USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
  502: 		return (err);
  503: 	}
  504: 
  505: 	return (USBD_NORMAL_COMPLETION);
  506: }
  507: 
  508: Static usbd_status
  509: uvscom_set_line_coding(struct uvscom_softc *sc, uint16_t lsp, uint16_t ls)
  510: {
  511: 	usb_device_request_t req;
  512: 	usbd_status err;
  513: 
  514: 	DPRINTF(("%s: uvscom_set_line_coding: %02x %02x\n",
  515: 		 USBDEVNAME(sc->sc_ucom.sc_dev), lsp, ls));
  516: 
  517: 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  518: 	req.bRequest = UVSCOM_SET_SPEED;
  519: 	USETW(req.wValue, lsp);
  520: 	USETW(req.wIndex, 0);
  521: 	USETW(req.wLength, 0);
  522: 
  523: 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  524: 	if (err) {
  525: 		printf("%s: uvscom_set_line_coding: %s\n",
  526: 		       USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
  527: 		return (err);
  528: 	}
  529: 
  530: 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  531: 	req.bRequest = UVSCOM_SET_PARAM;
  532: 	USETW(req.wValue, ls);
  533: 	USETW(req.wIndex, 0);
  534: 	USETW(req.wLength, 0);
  535: 
  536: 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  537: 	if (err) {
  538: 		printf("%s: uvscom_set_line_coding: %s\n",
  539: 		       USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
  540: 		return (err);
  541: 	}
  542: 
  543: 	return (USBD_NORMAL_COMPLETION);
  544: }
  545: 
  546: Static void
  547: uvscom_dtr(struct uvscom_softc *sc, int onoff)
  548: {
  549: 	DPRINTF(("%s: uvscom_dtr: onoff = %d\n",
  550: 		 USBDEVNAME(sc->sc_ucom.sc_dev), onoff));
  551: 
  552: 	if (sc->sc_dtr == onoff)
  553: 		return;			/* no change */
  554: 
  555: 	sc->sc_dtr = onoff;
  556: 
  557: 	if (onoff)
  558: 		SET(sc->sc_lcr, UVSCOM_DTR);
  559: 	else
  560: 		CLR(sc->sc_lcr, UVSCOM_DTR);
  561: 
  562: 	uvscom_set_line(sc, sc->sc_lcr);
  563: }
  564: 
  565: Static void
  566: uvscom_rts(struct uvscom_softc *sc, int onoff)
  567: {
  568: 	DPRINTF(("%s: uvscom_rts: onoff = %d\n",
  569: 		 USBDEVNAME(sc->sc_ucom.sc_dev), onoff));
  570: 
  571: 	if (sc->sc_rts == onoff)
  572: 		return;			/* no change */
  573: 
  574: 	sc->sc_rts = onoff;
  575: 
  576: 	if (onoff)
  577: 		SET(sc->sc_lcr, UVSCOM_RTS);
  578: 	else
  579: 		CLR(sc->sc_lcr, UVSCOM_RTS);
  580: 
  581: 	uvscom_set_line(sc, sc->sc_lcr);
  582: }
  583: 
  584: Static void
  585: uvscom_break(struct uvscom_softc *sc, int onoff)
  586: {
  587: 	DPRINTF(("%s: uvscom_break: onoff = %d\n",
  588: 		 USBDEVNAME(sc->sc_ucom.sc_dev), onoff));
  589: 
  590: 	if (onoff)
  591: 		uvscom_set_line(sc, SET(sc->sc_lcr, UVSCOM_BREAK));
  592: }
  593: 
  594: Static void
  595: uvscom_set(void *addr, int portno, int reg, int onoff)
  596: {
  597: 	struct uvscom_softc *sc = addr;
  598: 
  599: 	switch (reg) {
  600: 	case UCOM_SET_DTR:
  601: 		uvscom_dtr(sc, onoff);
  602: 		break;
  603: 	case UCOM_SET_RTS:
  604: 		uvscom_rts(sc, onoff);
  605: 		break;
  606: 	case UCOM_SET_BREAK:
  607: 		uvscom_break(sc, onoff);
  608: 		break;
  609: 	default:
  610: 		break;
  611: 	}
  612: }
  613: 
  614: Static int
  615: uvscom_param(void *addr, int portno, struct termios *t)
  616: {
  617: 	struct uvscom_softc *sc = addr;
  618: 	usbd_status err;
  619: 	uint16_t lsp;
  620: 	uint16_t ls;
  621: 
  622: 	DPRINTF(("%s: uvscom_param: sc = %p\n",
  623: 		 USBDEVNAME(sc->sc_ucom.sc_dev), sc));
  624: 
  625: 	ls = 0;
  626: 
  627: 	switch (t->c_ospeed) {
  628: 	case B150:
  629: 		lsp = UVSCOM_SPEED_150BPS;
  630: 		break;
  631: 	case B300:
  632: 		lsp = UVSCOM_SPEED_300BPS;
  633: 		break;
  634: 	case B600:
  635: 		lsp = UVSCOM_SPEED_600BPS;
  636: 		break;
  637: 	case B1200:
  638: 		lsp = UVSCOM_SPEED_1200BPS;
  639: 		break;
  640: 	case B2400:
  641: 		lsp = UVSCOM_SPEED_2400BPS;
  642: 		break;
  643: 	case B4800:
  644: 		lsp = UVSCOM_SPEED_4800BPS;
  645: 		break;
  646: 	case B9600:
  647: 		lsp = UVSCOM_SPEED_9600BPS;
  648: 		break;
  649: 	case B19200:
  650: 		lsp = UVSCOM_SPEED_19200BPS;
  651: 		break;
  652: 	case B38400:
  653: 		lsp = UVSCOM_SPEED_38400BPS;
  654: 		break;
  655: 	case B57600:
  656: 		lsp = UVSCOM_SPEED_57600BPS;
  657: 		break;
  658: 	case B115200:
  659: 		lsp = UVSCOM_SPEED_115200BPS;
  660: 		break;
  661: 	default:
  662: 		return (EIO);
  663: 	}
  664: 
  665: 	if (ISSET(t->c_cflag, CSTOPB))
  666: 		SET(ls, UVSCOM_STOP_BIT_2);
  667: 	else
  668: 		SET(ls, UVSCOM_STOP_BIT_1);
  669: 
  670: 	if (ISSET(t->c_cflag, PARENB)) {
  671: 		if (ISSET(t->c_cflag, PARODD))
  672: 			SET(ls, UVSCOM_PARITY_ODD);
  673: 		else
  674: 			SET(ls, UVSCOM_PARITY_EVEN);
  675: 	} else
  676: 		SET(ls, UVSCOM_PARITY_NONE);
  677: 
  678: 	switch (ISSET(t->c_cflag, CSIZE)) {
  679: 	case CS5:
  680: 		SET(ls, UVSCOM_DATA_BIT_5);
  681: 		break;
  682: 	case CS6:
  683: 		SET(ls, UVSCOM_DATA_BIT_6);
  684: 		break;
  685: 	case CS7:
  686: 		SET(ls, UVSCOM_DATA_BIT_7);
  687: 		break;
  688: 	case CS8:
  689: 		SET(ls, UVSCOM_DATA_BIT_8);
  690: 		break;
  691: 	default:
  692: 		return (EIO);
  693: 	}
  694: 
  695: 	err = uvscom_set_line_coding(sc, lsp, ls);
  696: 	if (err)
  697: 		return (EIO);
  698: 
  699: 	if (ISSET(t->c_cflag, CRTSCTS)) {
  700: 		err = uvscom_set_crtscts(sc);
  701: 		if (err)
  702: 			return (EIO);
  703: 	}
  704: 
  705: 	return (0);
  706: }
  707: 
  708: Static int
  709: uvscom_open(void *addr, int portno)
  710: {
  711: 	struct uvscom_softc *sc = addr;
  712: 	int err;
  713: 	int i;
  714: 
  715: 	if (sc->sc_ucom.sc_dying)
  716: 		return (ENXIO);
  717: 
  718: 	DPRINTF(("uvscom_open: sc = %p\n", sc));
  719: 
  720: 	if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
  721: 		DPRINTF(("uvscom_open: open interrupt pipe.\n"));
  722: 
  723: 		sc->sc_usr = 0;		/* clear unit status */
  724: 
  725: 		err = uvscom_readstat(sc);
  726: 		if (err) {
  727: 			DPRINTF(("%s: uvscom_open: readstat faild\n",
  728: 				 USBDEVNAME(sc->sc_ucom.sc_dev)));
  729: 			return (ENXIO);
  730: 		}
  731: 
  732: 		sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
  733: 		err = usbd_open_pipe_intr(sc->sc_ucom.sc_iface,
  734: 					  sc->sc_intr_number,
  735: 					  USBD_SHORT_XFER_OK,
  736: 					  &sc->sc_intr_pipe,
  737: 					  sc,
  738: 					  sc->sc_intr_buf,
  739: 					  sc->sc_isize,
  740: 					  uvscom_intr,
  741: 					  UVSCOM_INTR_INTERVAL);
  742: 		if (err) {
  743: 			printf("%s: cannot open interrupt pipe (addr %d)\n",
  744: 				 USBDEVNAME(sc->sc_ucom.sc_dev),
  745: 				 sc->sc_intr_number);
  746: 			return (ENXIO);
  747: 		}
  748: 	} else {
  749: 		DPRINTF(("uvscom_open: did not open interrupt pipe.\n"));
  750: 	}
  751: 
  752: 	if ((sc->sc_usr & UVSCOM_USTAT_MASK) == 0) {
  753: 		/* unit is not ready */
  754: 
  755: 		for (i = UVSCOM_UNIT_WAIT; i > 0; --i) {
  756: 			tsleep(&err, 0, "uvsop", hz);	/* XXX */
  757: 			if (ISSET(sc->sc_usr, UVSCOM_USTAT_MASK))
  758: 				break;
  759: 		}
  760: 		if (i == 0) {
  761: 			DPRINTF(("%s: unit is not ready\n",
  762: 				 USBDEVNAME(sc->sc_ucom.sc_dev)));
  763: 			return (ENXIO);
  764: 		}
  765: 
  766: 		/* check PC card was inserted */
  767: 		if (ISSET(sc->sc_usr, UVSCOM_NOCARD)) {
  768: 			DPRINTF(("%s: no card\n",
  769: 				 USBDEVNAME(sc->sc_ucom.sc_dev)));
  770: 			return (ENXIO);
  771: 		}
  772: 	}
  773: 
  774: 	return (0);
  775: }
  776: 
  777: Static void
  778: uvscom_close(void *addr, int portno)
  779: {
  780: 	struct uvscom_softc *sc = addr;
  781: 	int err;
  782: 
  783: 	if (sc->sc_ucom.sc_dying)
  784: 		return;
  785: 
  786: 	DPRINTF(("uvscom_close: close\n"));
  787: 
  788: 	uvscom_shutdown(sc);
  789: 
  790: 	if (sc->sc_intr_pipe != NULL) {
  791: 		err = usbd_abort_pipe(sc->sc_intr_pipe);
  792: 		if (err)
  793: 			printf("%s: abort interrupt pipe failed: %s\n",
  794: 				USBDEVNAME(sc->sc_ucom.sc_dev),
  795: 					   usbd_errstr(err));
  796: 		err = usbd_close_pipe(sc->sc_intr_pipe);
  797: 		if (err)
  798: 			printf("%s: close interrupt pipe failed: %s\n",
  799: 				USBDEVNAME(sc->sc_ucom.sc_dev),
  800: 					   usbd_errstr(err));
  801: 		free(sc->sc_intr_buf, M_USBDEV);
  802: 		sc->sc_intr_pipe = NULL;
  803: 	}
  804: }
  805: 
  806: Static void
  807: uvscom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
  808: {
  809: 	struct uvscom_softc *sc = priv;
  810: 	u_char *buf = sc->sc_intr_buf;
  811: 	u_char pstatus;
  812: 
  813: 	if (sc->sc_ucom.sc_dying)
  814: 		return;
  815: 
  816: 	if (status != USBD_NORMAL_COMPLETION) {
  817: 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
  818: 			return;
  819: 
  820: 		printf("%s: uvscom_intr: abnormal status: %s\n",
  821: 			USBDEVNAME(sc->sc_ucom.sc_dev),
  822: 			usbd_errstr(status));
  823: 		usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
  824: 		return;
  825: 	}
  826: 
  827: 	DPRINTFN(2, ("%s: uvscom status = %02x %02x\n",
  828: 		 USBDEVNAME(sc->sc_ucom.sc_dev), buf[0], buf[1]));
  829: 
  830: 	sc->sc_lsr = sc->sc_msr = 0;
  831: 	sc->sc_usr = buf[1];
  832: 
  833: 	pstatus = buf[0];
  834: 	if (ISSET(pstatus, UVSCOM_TXRDY))
  835: 		SET(sc->sc_lsr, ULSR_TXRDY);
  836: 	if (ISSET(pstatus, UVSCOM_RXRDY))
  837: 		SET(sc->sc_lsr, ULSR_RXRDY);
  838: 
  839: 	pstatus = buf[1];
  840: 	if (ISSET(pstatus, UVSCOM_CTS))
  841: 		SET(sc->sc_msr, UMSR_CTS);
  842: 	if (ISSET(pstatus, UVSCOM_DSR))
  843: 		SET(sc->sc_msr, UMSR_DSR);
  844: 	if (ISSET(pstatus, UVSCOM_DCD))
  845: 		SET(sc->sc_msr, UMSR_DCD);
  846: 
  847: 	ucom_status_change(&sc->sc_ucom);
  848: }
  849: 
  850: Static void
  851: uvscom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
  852: {
  853: 	struct uvscom_softc *sc = addr;
  854: 
  855: 	if (lsr != NULL)
  856: 		*lsr = sc->sc_lsr;
  857: 	if (msr != NULL)
  858: 		*msr = sc->sc_msr;
  859: }
  860: 
  861: #if TODO
  862: Static int
  863: uvscom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
  864: 	     usb_proc_ptr p)
  865: {
  866: 	struct uvscom_softc *sc = addr;
  867: 	int error = 0;
  868: 
  869: 	if (sc->sc_ucom.sc_dying)
  870: 		return (EIO);
  871: 
  872: 	DPRINTF(("uvscom_ioctl: cmd = 0x%08lx\n", cmd));
  873: 
  874: 	switch (cmd) {
  875: 	case TIOCNOTTY:
  876: 	case TIOCMGET:
  877: 	case TIOCMSET:
  878: 		break;
  879: 
  880: 	default:
  881: 		DPRINTF(("uvscom_ioctl: unknown\n"));
  882: 		error = ENOTTY;
  883: 		break;
  884: 	}
  885: 
  886: 	return (error);
  887: }
  888: #endif