PERFORCE change 99084 for review

Hans Petter Selasky hselasky at FreeBSD.org
Mon Jun 12 21:31:49 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=99084

Change 99084 by hselasky at hselasky_mini_itx on 2006/06/12 21:28:43

	Finished reworking "ubsa.c". Again, alot of changes. Please test!

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/ubsa.c#4 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/ubsa.c#4 (text+ko) ====

@@ -1,0 +1,1076 @@
+/*-
+ * Copyright (c) 2002, Alexander Kabaev <kan.FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Ichiro FUKUHARA (ichiro at ichiro.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/termios.h>
+#include <sys/serial.h>
+#include <sys/taskqueue.h>
+
+#include <dev/usb/usb_port.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usb_subr.h>
+#include <dev/usb/usb_quirks.h>
+#include <dev/usb/usb_cdc.h>
+
+#include <dev/usb/ucomvar.h>
+
+#include "usbdevs.h"
+
+__FBSDID("$FreeBSD: src/sys/dev/usb/ubsa.c $");
+
+#ifdef USB_DEBUG
+#define DPRINTF(n,fmt,...)						\
+  do { if (ubsa_debug > (n)) {						\
+      printf("%s: " fmt, __FUNCTION__,## __VA_ARGS__); } } while (0)
+
+static int ubsa_debug = 0;
+SYSCTL_NODE(_hw_usb, OID_AUTO, ubsa, CTLFLAG_RW, 0, "USB ubsa");
+SYSCTL_INT(_hw_usb_ubsa, OID_AUTO, debug, CTLFLAG_RW,
+	   &ubsa_debug, 0, "ubsa debug level");
+#else
+#define	DPRINTF(...)
+#endif
+
+#define UBSA_MODVER		1 /* module version */
+
+#define UBSA_N_TRANSFER         14 /* units */
+#define UBSA_BSIZE              64 /* bytes */
+
+#define UBSA_CONFIG_INDEX	1
+#define UBSA_IFACE_INDEX	0
+
+enum {
+  UBSA_REG_BAUDRATE,
+  UBSA_REG_STOP_BITS,
+  UBSA_REG_DATA_BITS,
+  UBSA_REG_PARITY,
+  UBSA_REG_DTR,
+  UBSA_REG_RTS,
+  UBSA_REG_BREAK,
+  UBSA_REG_FLOW_CTRL,
+  USBA_N_REG
+};
+
+#define UBSA_PARITY_NONE	0x00
+#define UBSA_PARITY_EVEN	0x01
+#define UBSA_PARITY_ODD		0x02
+#define UBSA_PARITY_MARK	0x03
+#define UBSA_PARITY_SPACE	0x04
+
+#define UBSA_FLOW_NONE		0x0000
+#define UBSA_FLOW_OCTS		0x0001
+#define UBSA_FLOW_ODSR		0x0002
+#define UBSA_FLOW_IDSR		0x0004
+#define UBSA_FLOW_IDTR		0x0008
+#define UBSA_FLOW_IRTS		0x0010
+#define UBSA_FLOW_ORTS		0x0020
+#define UBSA_FLOW_UNKNOWN	0x0040
+#define UBSA_FLOW_OXON		0x0080
+#define UBSA_FLOW_IXON		0x0100
+
+/* line status register */
+#define UBSA_LSR_TSRE		0x40	/* Transmitter empty: byte sent */
+#define UBSA_LSR_TXRDY		0x20	/* Transmitter buffer empty */
+#define UBSA_LSR_BI		0x10	/* Break detected */
+#define UBSA_LSR_FE		0x08	/* Framing error: bad stop bit */
+#define UBSA_LSR_PE		0x04	/* Parity error */
+#define UBSA_LSR_OE		0x02	/* Overrun, lost incoming byte */
+#define UBSA_LSR_RXRDY		0x01	/* Byte ready in Receive Buffer */
+#define UBSA_LSR_RCV_MASK	0x1f	/* Mask for incoming data or error */
+
+/* modem status register */
+/* All deltas are from the last read of the MSR. */
+#define UBSA_MSR_DCD		0x80	/* Current Data Carrier Detect */
+#define UBSA_MSR_RI		0x40	/* Current Ring Indicator */
+#define UBSA_MSR_DSR		0x20	/* Current Data Set Ready */
+#define	UBSA_MSR_CTS		0x10	/* Current Clear to Send */
+#define UBSA_MSR_DDCD		0x08	/* DCD has changed state */
+#define UBSA_MSR_TERI		0x04	/* RI has toggled low to high */
+#define UBSA_MSR_DDSR		0x02	/* DSR has changed state */
+#define UBSA_MSR_DCTS		0x01	/* CTS has changed state */
+
+struct	ubsa_softc {
+	struct ucom_softc	sc_ucom;
+	struct usbd_memory_wait sc_mem_wait;
+
+	struct usbd_xfer *	sc_xfer[UBSA_N_TRANSFER];
+
+	u_int16_t		sc_flag;
+#define UBSA_FLAG_WRITE_STALL   0x0001
+#define UBSA_FLAG_READ_STALL    0x0002
+#define UBSA_FLAG_INTR_STALL    0x0004
+
+	u_int16_t		sc_reg_flag;
+	u_int16_t		sc_reg[USBA_N_REG];
+
+	u_int8_t		sc_iface_no; /* interface number */
+	u_int8_t		sc_iface_index; /* interface index */
+	u_int8_t		sc_dtr; /* current DTR state */
+	u_int8_t		sc_rts; /* current RTS state */
+	u_int8_t		sc_lsr; /* local status register */
+	u_int8_t		sc_msr; /* UBSA status register */
+};
+
+static device_probe_t ubsa_probe;
+static device_attach_t ubsa_attach;
+static device_detach_t ubsa_detach;
+
+static void
+ubsa_request(struct ubsa_softc *sc, u_int8_t index, u_int16_t value);
+
+static void
+ubsa_set_dtr(struct ucom_softc *ucom, u_int8_t onoff);
+
+static void
+ubsa_set_rts(struct ucom_softc *ucom, u_int8_t onoff);
+
+static void
+ubsa_set_break(struct ucom_softc *ucom, u_int8_t onoff);
+
+static u_int8_t
+ubsa_baudrate(struct ubsa_softc *sc, speed_t speed);
+
+static void
+ubsa_parity(struct ubsa_softc *sc, tcflag_t cflag);
+
+static void
+ubsa_databits(struct ubsa_softc *sc, tcflag_t cflag);
+
+static void
+ubsa_stopbits(struct ubsa_softc *sc, tcflag_t cflag);
+
+static void
+ubsa_flow(struct ubsa_softc *sc, tcflag_t cflag, tcflag_t iflag);
+
+static int
+ubsa_param(struct ucom_softc *ucom, struct termios *ti);
+
+static int
+ubsa_open(struct ucom_softc *ucom);
+
+static void
+ubsa_close(struct ucom_softc *ucom);
+
+static void
+ubsa_start_read(struct ucom_softc *ucom);
+
+static void
+ubsa_stop_read(struct ucom_softc *ucom);
+
+static void
+ubsa_start_write(struct ucom_softc *ucom);
+
+static void
+ubsa_stop_write(struct ucom_softc *ucom);
+
+static void
+ubsa_get_status(struct ucom_softc *ucom, u_int8_t *lsr, u_int8_t *msr);
+
+static void
+ubsa_write_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_write_clear_stall_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_read_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_read_clear_stall_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_intr_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_intr_clear_stall_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_request_callback(struct usbd_xfer *xfer, u_int8_t index);
+
+static void
+ubsa_set_baudrate_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_set_stop_bits_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_set_data_bits_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_set_parity_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_set_dtr_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_set_rts_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_set_break_callback(struct usbd_xfer *xfer);
+
+static void
+ubsa_set_flow_ctrl_callback(struct usbd_xfer *xfer);
+
+static const struct usbd_config ubsa_config[UBSA_N_TRANSFER] = {
+
+    [0] = {
+      .type      = UE_BULK,
+      .endpoint  = -1, /* any */
+      .direction = UE_DIR_OUT,
+      .bufsize   = UBSA_BSIZE, /* bytes */
+      .flags     = 0,
+      .callback  = &ubsa_write_callback,
+    },
+
+    [1] = {
+      .type      = UE_BULK,
+      .endpoint  = -1, /* any */
+      .direction = UE_DIR_IN,
+      .bufsize   = UBSA_BSIZE, /* bytes */
+      .flags     = USBD_SHORT_XFER_OK,
+      .callback  = &ubsa_read_callback,
+    },
+
+    [2] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .callback  = &ubsa_write_clear_stall_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [3] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .callback  = &ubsa_read_clear_stall_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [4] = {
+      .type      = UE_INTERRUPT,
+      .endpoint  = -1, /* any */
+      .direction = UE_DIR_IN,
+      .flags     = USBD_SHORT_XFER_OK,
+      .bufsize   = 0, /* use wMaxPacketSize */
+      .callback  = &ubsa_intr_callback,
+    },
+
+    [5] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .callback  = &ubsa_intr_clear_stall_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [6+UBSA_REG_BAUDRATE] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .callback  = &ubsa_set_baudrate_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [6+UBSA_REG_STOP_BITS] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .callback  = &ubsa_set_stop_bits_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [6+UBSA_REG_DATA_BITS] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .callback  = &ubsa_set_data_bits_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [6+UBSA_REG_PARITY] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .callback  = &ubsa_set_parity_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [6+UBSA_REG_DTR] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .callback  = &ubsa_set_dtr_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [6+UBSA_REG_RTS] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .callback  = &ubsa_set_rts_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [6+UBSA_REG_BREAK] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .callback  = &ubsa_set_break_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [6+UBSA_REG_FLOW_CTRL] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .callback  = &ubsa_set_flow_ctrl_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+};
+
+static const struct ucom_callback ubsa_callback = {
+    .ucom_get_status  = &ubsa_get_status,
+    .ucom_set_dtr     = &ubsa_set_dtr,
+    .ucom_set_rts     = &ubsa_set_rts,
+    .ucom_set_break   = &ubsa_set_break,
+    .ucom_param       = &ubsa_param,
+    .ucom_open        = &ubsa_open,
+    .ucom_close       = &ubsa_close,
+    .ucom_start_read  = &ubsa_start_read,
+    .ucom_stop_read   = &ubsa_stop_read,
+    .ucom_start_write = &ubsa_start_write,
+    .ucom_stop_write  = &ubsa_stop_write,
+};
+
+static const struct ubsa_product {
+	u_int16_t	vendor;
+	u_int16_t	product;
+} ubsa_products [] = {
+    /* BELKIN F5U103 */
+    { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U103 },
+    /* BELKIN F5U120 */
+    { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U120 },
+    /* GoHubs GO-COM232 */
+    { USB_VENDOR_ETEK, USB_PRODUCT_ETEK_1COM },
+    /* GoHubs GO-COM232 */
+    { USB_VENDOR_GOHUBS, USB_PRODUCT_GOHUBS_GOCOM232 },
+    /* Peracom */
+    { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_SERIAL1 },
+    /* Vodafone */
+    { USB_VENDOR_VODAFONE, USB_PRODUCT_VODAFONE_MC3G },
+    { 0, 0 }
+};
+
+static device_method_t ubsa_methods[] = {
+    DEVMETHOD(device_probe, ubsa_probe),
+    DEVMETHOD(device_attach, ubsa_attach),
+    DEVMETHOD(device_detach, ubsa_detach),
+    { 0, 0 }
+};
+
+static driver_t ubsa_driver = {
+    .name    = "ucom",
+    .methods = ubsa_methods,
+    .size    = sizeof(struct ubsa_softc),
+};
+
+DRIVER_MODULE(ubsa, uhub, ubsa_driver, ucom_devclass, usbd_driver_load, 0);
+MODULE_DEPEND(ubsa, usb, 1, 1, 1);
+MODULE_DEPEND(ubsa, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
+MODULE_VERSION(ubsa, UBSA_MODVER);
+
+static int
+ubsa_probe(device_t dev)
+{
+	struct usb_attach_arg *uaa = device_get_ivars(dev);
+	const struct ubsa_product *up = ubsa_products;
+
+	if (uaa->iface) {
+	    return UMATCH_NONE;
+	}
+
+	while (up->vendor) {
+	    if ((up->vendor == uaa->vendor) &&
+		(up->product == uaa->product)) {
+	        return UMATCH_VENDOR_PRODUCT;
+	    }
+	}
+
+	return UMATCH_NONE;
+}
+
+static int
+ubsa_attach(device_t dev)
+{
+	struct usb_attach_arg *uaa = device_get_ivars(dev);
+	struct ubsa_softc *sc = device_get_softc(dev);
+	struct usbd_interface *iface;
+	usb_interface_descriptor_t *id;
+	int error;
+
+	DPRINTF(0, "sc=%p\n", sc);
+
+	if (sc == NULL) {
+	    return ENOMEM;
+	}
+
+	usbd_set_desc(dev, uaa->device);
+
+	/* configure the device */
+
+	error = usbd_set_config_index(uaa->device, UBSA_CONFIG_INDEX, 1);
+
+	if (error) {
+	    DPRINTF(0, "failed to set configuration, error=%s\n",
+		    usbd_errstr(error));
+	    goto detach;
+	}
+
+	iface = usbd_get_iface(uaa->device, UBSA_IFACE_INDEX);
+
+	if (iface == NULL) {
+	    DPRINTF(0, "no interface\n");
+	    goto detach;
+	}
+
+	id = usbd_get_interface_descriptor(iface);
+
+	if (id == NULL) {
+	    DPRINTF(0, "no interface descriptor\n");
+	    goto detach;
+	}
+
+	sc->sc_iface_no = id->bInterfaceNumber;
+	sc->sc_iface_index = UBSA_IFACE_INDEX;
+
+	error = usbd_transfer_setup(uaa->device, sc->sc_iface_index,
+				    sc->sc_xfer, ubsa_config, UBSA_N_TRANSFER,
+				    sc, &Giant, &(sc->sc_mem_wait));
+	if (error) {
+	    DPRINTF(0, "could not allocate all pipes\n");
+	    goto detach;
+	}
+
+	sc->sc_dtr = -1;
+	sc->sc_rts = -1;
+
+	sc->sc_ucom.sc_parent = sc;
+	sc->sc_ucom.sc_portno = 0;
+	sc->sc_ucom.sc_callback = &ubsa_callback;
+
+	error = ucom_attach(&(sc->sc_ucom), dev);
+
+	if (error) {
+	    DPRINTF(0, "ucom_attach failed\n");
+	    goto detach;
+	}
+
+	return 0;
+
+ detach:
+	ubsa_detach(dev);
+	return ENXIO;
+}
+
+static int
+ubsa_detach(device_t dev)
+{
+	struct ubsa_softc *sc = device_get_softc(dev);
+
+	DPRINTF(0, "sc=%p\n", sc);
+
+	ucom_detach(&(sc->sc_ucom));
+
+	usbd_transfer_unsetup(sc->sc_xfer, UBSA_N_TRANSFER);
+
+	usbd_transfer_drain(&(sc->sc_mem_wait), &Giant);
+
+	return 0;
+}
+
+static void
+ubsa_request(struct ubsa_softc *sc, u_int8_t index, u_int16_t value)
+{
+	if (index >= USBA_N_REG) {
+	    panic("invalid register index!");
+	}
+	sc->sc_reg_flag |= (1 << index);
+	sc->sc_reg[index] = value;
+	usbd_transfer_start(sc->sc_xfer[6+index]);
+	return;
+}
+
+static void
+ubsa_set_dtr(struct ucom_softc *ucom, u_int8_t onoff)
+{
+	struct ubsa_softc *sc = ucom->sc_parent;
+
+	DPRINTF(0, "onoff = %d\n", onoff);
+
+	if (sc->sc_dtr != onoff) {
+	    sc->sc_dtr = onoff;
+	    ubsa_request(sc, UBSA_REG_DTR, onoff ? 1 : 0);
+	}
+	return;
+}
+
+static void
+ubsa_set_rts(struct ucom_softc *ucom, u_int8_t onoff)
+{
+	struct ubsa_softc *sc = ucom->sc_parent;
+
+	DPRINTF(0, "onoff = %d\n", onoff);
+
+	if (sc->sc_rts != onoff) {
+	    sc->sc_rts = onoff;
+	    ubsa_request(sc, UBSA_REG_RTS, onoff ? 1 : 0);
+	}
+	return;
+}
+
+static void
+ubsa_set_break(struct ucom_softc *ucom, u_int8_t onoff)
+{
+	struct ubsa_softc *sc = ucom->sc_parent;
+
+	DPRINTF(0, "onoff = %d\n", onoff);
+
+	ubsa_request(sc, UBSA_REG_BREAK, onoff ? 1 : 0);
+	return;
+}
+
+static u_int8_t
+ubsa_baudrate(struct ubsa_softc *sc, speed_t speed)
+{
+	u_int16_t value = 0;
+
+	DPRINTF(0, "speed = %d\n", speed);
+
+	switch(speed) {
+	case B0:
+		break;
+	case B300:
+	case B600:
+	case B1200:
+	case B2400:
+	case B4800:
+	case B9600:
+	case B19200:
+	case B38400:
+	case B57600:
+	case B115200:
+	case B230400:
+	    value = B230400 / speed;
+	    break;
+
+	default:
+	    DPRINTF(0, "unsupported baudrate\n");
+	    return 1;
+	};
+
+	if (speed == B0) {
+	    ubsa_flow(sc, 0, 0);
+	    ubsa_set_dtr(&(sc->sc_ucom), 0);
+	    ubsa_set_rts(&(sc->sc_ucom), 0);
+	} else {
+	    ubsa_request(sc, UBSA_REG_BAUDRATE, value);
+	}
+	return 0;
+}
+
+static void
+ubsa_parity(struct ubsa_softc *sc, tcflag_t cflag)
+{
+	u_int16_t value;
+
+	DPRINTF(0, "flag = 0x%x\n", cflag);
+
+	if (cflag & PARENB)
+		value = (cflag & PARODD) ? UBSA_PARITY_ODD : UBSA_PARITY_EVEN;
+	else
+		value = UBSA_PARITY_NONE;
+
+	ubsa_request(sc, UBSA_REG_PARITY, value);
+	return;
+}
+
+static void
+ubsa_databits(struct ubsa_softc *sc, tcflag_t cflag)
+{
+	u_int16_t value;
+
+	DPRINTF(0, "cflag = 0x%x\n", cflag);
+
+	switch (cflag & CSIZE) {
+	case CS5: value = 0; break;
+	case CS6: value = 1; break;
+	case CS7: value = 2; break;
+	case CS8: value = 3; break;
+	default:
+	    DPRINTF(0, "unsupported databits requested, "
+		    "forcing default of 8\n");
+	    value = 3;
+	}
+
+	ubsa_request(sc, UBSA_REG_DATA_BITS, value);
+	return;
+}
+
+static void
+ubsa_stopbits(struct ubsa_softc *sc, tcflag_t cflag)
+{
+	u_int16_t value;
+
+	DPRINTF(0, "cflag = 0x%x\n", cflag);
+
+	value = (cflag & CSTOPB) ? 1 : 0;
+
+	ubsa_request(sc, UBSA_REG_STOP_BITS, value);
+	return;
+}
+
+static void
+ubsa_flow(struct ubsa_softc *sc, tcflag_t cflag, tcflag_t iflag)
+{
+	u_int16_t value;
+
+	DPRINTF(0, "cflag = 0x%x, iflag = 0x%x\n", cflag, iflag);
+
+	value = 0;
+	if (cflag & CRTSCTS)
+		value |= UBSA_FLOW_OCTS | UBSA_FLOW_IRTS;
+	if (iflag & (IXON|IXOFF))
+		value |= UBSA_FLOW_OXON | UBSA_FLOW_IXON;
+
+	ubsa_request(sc, UBSA_REG_FLOW_CTRL, value);
+	return;
+}
+
+static int
+ubsa_param(struct ucom_softc *ucom, struct termios *ti)
+{
+	struct ubsa_softc *sc = ucom->sc_parent;
+
+	DPRINTF(0, "sc = %p\n", sc);
+
+	if (ubsa_baudrate(sc, ti->c_ospeed)) {
+	    return EIO;
+	}
+	ubsa_parity(sc, ti->c_cflag);
+	ubsa_databits(sc, ti->c_cflag);
+	ubsa_stopbits(sc, ti->c_cflag);
+	ubsa_flow(sc, ti->c_cflag, ti->c_iflag);
+
+	return (0);
+}
+
+static int
+ubsa_open(struct ucom_softc *ucom)
+{
+	struct ubsa_softc *sc = ucom->sc_parent;
+	usbd_transfer_start(sc->sc_xfer[4]);
+	return 0;
+}
+
+static void
+ubsa_close(struct ucom_softc *ucom)
+{
+	struct ubsa_softc *sc = ucom->sc_parent;
+	usbd_transfer_stop(sc->sc_xfer[5]);
+	usbd_transfer_stop(sc->sc_xfer[4]);
+	return;
+}
+
+static void
+ubsa_start_read(struct ucom_softc *ucom)
+{
+	struct ubsa_softc *sc = ucom->sc_parent;
+	usbd_transfer_start(sc->sc_xfer[1]);
+	return;
+}
+
+static void
+ubsa_stop_read(struct ucom_softc *ucom)
+{
+	struct ubsa_softc *sc = ucom->sc_parent;
+	usbd_transfer_stop(sc->sc_xfer[3]);
+	usbd_transfer_stop(sc->sc_xfer[1]);
+	return;
+}
+
+static void
+ubsa_start_write(struct ucom_softc *ucom)
+{
+	struct ubsa_softc *sc = ucom->sc_parent;
+	usbd_transfer_start(sc->sc_xfer[0]);
+	return;
+}
+
+static void
+ubsa_stop_write(struct ucom_softc *ucom)
+{
+	struct ubsa_softc *sc = ucom->sc_parent;
+	usbd_transfer_stop(sc->sc_xfer[2]);
+	usbd_transfer_stop(sc->sc_xfer[0]);
+	return;
+}
+
+static void
+ubsa_get_status(struct ucom_softc *ucom, u_int8_t *lsr, u_int8_t *msr)
+{
+	struct ubsa_softc *sc = ucom->sc_parent;
+
+	DPRINTF(0, "\n");
+
+	if (lsr) {
+	    *lsr = sc->sc_lsr;
+	}
+
+	if (msr) {
+	    *msr = sc->sc_msr;
+	}
+	return;
+}
+
+static void
+ubsa_write_callback(struct usbd_xfer *xfer)
+{
+	struct ubsa_softc *sc = xfer->priv_sc;
+	u_int32_t actlen;
+
+	USBD_CHECK_STATUS(xfer);
+tr_error:
+	if (xfer->error != USBD_CANCELLED) {
+	    sc->sc_flag |= UBSA_FLAG_WRITE_STALL;
+	    usbd_transfer_start(sc->sc_xfer[2]);
+	}
+	return;
+
+tr_setup:
+tr_transferred:
+	if (sc->sc_flag & UBSA_FLAG_WRITE_STALL) {
+	    usbd_transfer_start(sc->sc_xfer[2]);
+	    return;
+	}
+
+	if(ucom_get_data(&(sc->sc_ucom), xfer->buffer, UBSA_BSIZE, &actlen)) {
+
+	    xfer->length = actlen;
+
+	    usbd_start_hardware(xfer);
+	}
+	return;
+}
+
+static void
+ubsa_write_clear_stall_callback(struct usbd_xfer *xfer)
+{
+	struct ubsa_softc *sc = xfer->priv_sc;
+
+	USBD_CHECK_STATUS(xfer);
+
+ tr_setup:
+	/* start clear stall */
+	usbd_clear_stall_tr_setup(xfer, sc->sc_xfer[0]);
+	return;
+
+ tr_transferred:
+	usbd_clear_stall_tr_transferred(xfer, sc->sc_xfer[0]);
+	sc->sc_flag &= ~UBSA_FLAG_WRITE_STALL;
+	usbd_transfer_start(sc->sc_xfer[0]);
+	return;
+
+ tr_error:
+	sc->sc_flag &= ~UBSA_FLAG_WRITE_STALL;
+	DPRINTF(0, "clear stall failed, error=%s\n",
+		usbd_errstr(xfer->error));
+	return;
+}
+
+static void
+ubsa_read_callback(struct usbd_xfer *xfer)
+{
+	struct ubsa_softc *sc = xfer->priv_sc;
+
+	USBD_CHECK_STATUS(xfer);
+
+ tr_error:
+	if (xfer->error != USBD_CANCELLED) {
+	    sc->sc_flag |= UBSA_FLAG_READ_STALL;
+	    usbd_transfer_start(sc->sc_xfer[3]);
+	}
+	return;
+
+ tr_transferred:
+	ucom_put_data(&(sc->sc_ucom), xfer->buffer, xfer->actlen);
+
+ tr_setup:
+	if (sc->sc_flag & UBSA_FLAG_READ_STALL) {
+	    usbd_transfer_start(sc->sc_xfer[3]);
+	} else {
+	    usbd_start_hardware(xfer);
+	}
+	return;
+}
+
+static void
+ubsa_read_clear_stall_callback(struct usbd_xfer *xfer)
+{
+	struct ubsa_softc *sc = xfer->priv_sc;
+
+	USBD_CHECK_STATUS(xfer);
+
+ tr_setup:
+	/* start clear stall */
+	usbd_clear_stall_tr_setup(xfer, sc->sc_xfer[1]);
+	return;
+
+ tr_transferred:
+	usbd_clear_stall_tr_transferred(xfer, sc->sc_xfer[1]);
+	sc->sc_flag &= ~UBSA_FLAG_READ_STALL;
+	usbd_transfer_start(sc->sc_xfer[1]);
+	return;
+
+ tr_error:
+	sc->sc_flag &= ~UBSA_FLAG_READ_STALL;
+	DPRINTF(0, "clear stall failed, error=%s\n",
+		usbd_errstr(xfer->error));
+	return;
+}
+
+static void
+ubsa_intr_callback(struct usbd_xfer *xfer)
+{
+	struct ubsa_softc *sc = xfer->priv_sc;
+	u_int8_t *buf = xfer->buffer;
+
+	USBD_CHECK_STATUS(xfer);
+
+ tr_error:
+	if (xfer->error != USBD_CANCELLED) {
+	    sc->sc_flag |= UBSA_FLAG_INTR_STALL;
+	    usbd_transfer_start(sc->sc_xfer[5]);
+	}
+	return;
+
+ tr_transferred:
+
+	if (xfer->actlen >= 4) {
+
+	    /* incidentally, Belkin adapter status bits match UART 16550 bits */
+	    sc->sc_lsr = buf[2];
+	    sc->sc_msr = buf[3];
+
+	    DPRINTF(0, "lsr = 0x%02x, msr = 0x%02x\n",
+		    sc->sc_lsr, sc->sc_msr);
+
+	    ucom_status_change(&(sc->sc_ucom));
+	} else {
+	    DPRINTF(0, "ignoring short packet, %d bytes\n",
+		    xfer->actlen);
+	}
+
+ tr_setup:
+	if (sc->sc_flag & UBSA_FLAG_INTR_STALL) {
+	    usbd_transfer_start(sc->sc_xfer[5]);
+	} else {
+	    usbd_start_hardware(xfer);
+	}
+	return;
+}
+
+static void
+ubsa_intr_clear_stall_callback(struct usbd_xfer *xfer)
+{
+	struct ubsa_softc *sc = xfer->priv_sc;
+
+	USBD_CHECK_STATUS(xfer);
+
+ tr_setup:
+	/* start clear stall */
+	usbd_clear_stall_tr_setup(xfer, sc->sc_xfer[4]);
+	return;
+
+ tr_transferred:
+	usbd_clear_stall_tr_transferred(xfer, sc->sc_xfer[4]);
+	sc->sc_flag &= ~UBSA_FLAG_INTR_STALL;
+	usbd_transfer_start(sc->sc_xfer[4]);
+	return;
+
+ tr_error:
+	sc->sc_flag &= ~UBSA_FLAG_INTR_STALL;
+	DPRINTF(0, "clear stall failed, error=%s\n",
+		usbd_errstr(xfer->error));
+	return;
+}
+
+static void
+ubsa_request_callback(struct usbd_xfer *xfer, u_int8_t index)
+{
+	static const u_int8_t mapping[USBA_N_REG] = {
+	  [UBSA_REG_BAUDRATE]  = 0x00,
+	  [UBSA_REG_STOP_BITS] = 0x01,
+	  [UBSA_REG_DATA_BITS] = 0x02,

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list