PERFORCE change 98989 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sun Jun 11 15:53:55 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=98989
Change 98989 by hselasky at hselasky_mini_itx on 2006/06/11 15:50:48
Finished reworking "uplcom.c". Had to change alot. Please test!
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/uplcom.c#4 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/uplcom.c#4 (text+ko) ====
@@ -1,0 +1,1237 @@
+/* $NetBSD: uplcom.c,v 1.21 2001/11/13 06:24:56 lukem Exp $ */
+
+/*-
+ * Copyright (c) 2001-2003, 2005 Shunsuke Akiyama <akiyama at jp.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.
+ */
+
+/*
+ * This driver supports several USB-to-RS232 serial adapters driven by
+ * Prolific PL-2303, PL-2303X and probably PL-2303HX USB-to-RS232
+ * bridge chip. The adapters are sold under many different brand
+ * names.
+ *
+ * Datasheets are available at Prolific www site at
+ * http://www.prolific.com.tw. The datasheets don't contain full
+ * programming information for the chip.
+ *
+ * PL-2303HX is probably programmed the same as PL-2303X.
+ *
+ * There are several differences between PL-2303 and PL-2303(H)X.
+ * PL-2303(H)X can do higher bitrate in bulk mode, has _probably_
+ * different command for controlling CRTSCTS and needs special
+ * sequence of commands for initialization which aren't also
+ * documented in the datasheet.
+ */
+
+#include "opt_uplcom.h" /* XXX remove this */
+
+#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/uplcom.c $");
+
+#ifdef USB_DEBUG
+#define DPRINTF(n,fmt,...) \
+ do { if (uplcom_debug > (n)) { \
+ printf("%s: " fmt, __FUNCTION__,## __VA_ARGS__); } } while (0)
+
+static int uplcom_debug = 0;
+SYSCTL_NODE(_hw_usb, OID_AUTO, uplcom, CTLFLAG_RW, 0, "USB uplcom");
+SYSCTL_INT(_hw_usb_uplcom, OID_AUTO, debug, CTLFLAG_RW,
+ &uplcom_debug, 0, "uplcom debug level");
+#else
+#define DPRINTF(...)
+#endif
+
+#define UPLCOM_MODVER 1 /* module version */
+
+#define UPLCOM_CONFIG_INDEX 0
+#define UPLCOM_IFACE_INDEX 0
+#define UPLCOM_SECOND_IFACE_INDEX 1
+#define UPLCOM_INTR_SIZE 64 /* bytes */
+
+#ifndef UPLCOM_INTR_INTERVAL
+#define UPLCOM_INTR_INTERVAL 0 /* default */
+#endif
+
+/*
+ * These are the maximum number of bytes transferred per frame.
+ * The output buffer size cannot be increased due to the size encoding.
+ */
+#define UPLCOM_IBUFSIZE 256
+#define UPLCOM_OBUFSIZE 256
+#define UPLCOM_N_DATA_TRANSFER 7
+#define UPLCOM_N_INTR_TRANSFER 2
+
+#define UPLCOM_SET_REQUEST 0x01
+#define UPLCOM_SET_CRTSCTS 0x41
+#define UPLCOM_SET_CRTSCTS_PL2303X 0x61
+#define RSAQ_STATUS_CTS 0x80
+#define RSAQ_STATUS_DSR 0x02
+#define RSAQ_STATUS_DCD 0x01
+
+#define TYPE_PL2303 0
+#define TYPE_PL2303X 1
+
+struct uplcom_softc {
+ struct ucom_softc sc_ucom;
+ usb_cdc_line_state_t sc_line_state; /* current line state */
+
+ struct usbd_xfer * sc_xfer_intr[UPLCOM_N_INTR_TRANSFER];
+ struct usbd_xfer * sc_xfer_data[UPLCOM_N_DATA_TRANSFER];
+
+ u_int16_t sc_flag;
+#define UPLCOM_FLAG_WAIT_USB_1 0x0001
+#define UPLCOM_FLAG_WAIT_USB_2 0x0002
+#define UPLCOM_FLAG_SET_LS 0x0004
+#define UPLCOM_FLAG_SET_BREAK 0x0008
+#define UPLCOM_FLAG_SET_LC 0x0010
+#define UPLCOM_FLAG_SET_CRTSCTS 0x0020
+#define UPLCOM_FLAG_INTR_STALL 0x0040
+#define UPLCOM_FLAG_READ_STALL 0x0080
+#define UPLCOM_FLAG_WRITE_STALL 0x0100
+
+ u_int8_t sc_dtr; /* current DTR state */
+ u_int8_t sc_rts; /* current RTS state */
+ u_int8_t sc_break; /* current BREAK state */
+ u_int8_t sc_lsr; /* local status register */
+ u_int8_t sc_msr; /* uplcom status register */
+ u_int8_t sc_chiptype; /* type of chip */
+ u_int8_t sc_ctrl_iface_no;
+ u_int8_t sc_ctrl_iface_index;
+ u_int8_t sc_data_iface_no;
+ u_int8_t sc_data_iface_index;
+ u_int8_t sc_crtscts;
+
+ u_int8_t sc_wakeup_detach; /* dummy */
+};
+
+static const struct uplcom_product *
+uplcom_find_up(struct usb_attach_arg *uaa);
+
+static void
+uplcom_detach_complete_1(struct usbd_memory_info *info);
+
+static void
+uplcom_detach_complete_2(struct usbd_memory_info *info);
+
+static usbd_status
+uplcom_reset(struct uplcom_softc *sc, struct usbd_device *udev);
+
+static int
+uplcom_pl2303x_init(struct usbd_device *udev);
+
+static void
+uplcom_set_dtr(struct ucom_softc *ucom, u_int8_t onoff);
+
+static void
+uplcom_set_rts(struct ucom_softc *ucom, u_int8_t onoff);
+
+static void
+uplcom_set_break(struct ucom_softc *sc, u_int8_t onoff);
+
+static int
+uplcom_param(struct ucom_softc *ucom, struct termios *t);
+
+static int
+uplcom_open(struct ucom_softc *ucom);
+
+static void
+uplcom_close(struct ucom_softc *ucom);
+
+static void
+uplcom_start_read(struct ucom_softc *ucom);
+
+static void
+uplcom_stop_read(struct ucom_softc *ucom);
+
+static void
+uplcom_start_write(struct ucom_softc *ucom);
+
+static void
+uplcom_stop_write(struct ucom_softc *ucom);
+
+static void
+uplcom_get_status(struct ucom_softc *ucom, u_int8_t *lsr, u_int8_t *msr);
+
+static int
+uplcom_ioctl(struct ucom_softc *ucom, u_long cmd, caddr_t data, int flag,
+ struct thread *td);
+static void
+uplcom_set_line_state_callback(struct usbd_xfer *xfer);
+
+static void
+uplcom_set_break_callback(struct usbd_xfer *xfer);
+
+static void
+uplcom_set_line_coding_callback(struct usbd_xfer *xfer);
+
+static void
+uplcom_intr_callback(struct usbd_xfer *xfer);
+
+static void
+uplcom_intr_clear_stall_callback(struct usbd_xfer *xfer);
+
+static void
+uplcom_write_callback(struct usbd_xfer *xfer);
+
+static void
+uplcom_write_clear_stall_callback(struct usbd_xfer *xfer);
+
+static void
+uplcom_read_callback(struct usbd_xfer *xfer);
+
+static void
+uplcom_read_clear_stall_callback(struct usbd_xfer *xfer);
+
+static device_probe_t uplcom_probe;
+static device_attach_t uplcom_attach;
+static device_detach_t uplcom_detach;
+
+static const struct usbd_config uplcom_config_data[UPLCOM_N_DATA_TRANSFER] = {
+
+ [0] = {
+ .type = UE_BULK,
+ .endpoint = -1, /* any */
+ .direction = UE_DIR_OUT,
+ .bufsize = UPLCOM_OBUFSIZE,
+ .flags = 0,
+ .callback = &uplcom_write_callback,
+ },
+
+ [1] = {
+ .type = UE_BULK,
+ .endpoint = -1, /* any */
+ .direction = UE_DIR_IN,
+ .bufsize = UPLCOM_IBUFSIZE,
+ .flags = USBD_SHORT_XFER_OK,
+ .callback = &uplcom_read_callback,
+ },
+
+ [2] = {
+ .type = UE_CONTROL,
+ .endpoint = 0x00, /* Control pipe */
+ .direction = -1,
+ .bufsize = sizeof(usb_device_request_t),
+ .callback = &uplcom_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 = &uplcom_read_clear_stall_callback,
+ .timeout = 1000, /* 1 second */
+ },
+
+ [4] = {
+ .type = UE_CONTROL,
+ .endpoint = 0x00, /* Control pipe */
+ .direction = -1,
+ .bufsize = sizeof(usb_device_request_t),
+ .callback = &uplcom_set_line_state_callback,
+ .timeout = 1000, /* 1 second */
+ },
+
+ [5] = {
+ .type = UE_CONTROL,
+ .endpoint = 0x00, /* Control pipe */
+ .direction = -1,
+ .bufsize = sizeof(usb_device_request_t),
+ .callback = &uplcom_set_break_callback,
+ .timeout = 1000, /* 1 second */
+ },
+
+ [6] = {
+ .type = UE_CONTROL,
+ .endpoint = 0x00, /* Control pipe */
+ .direction = -1,
+ .bufsize = sizeof(usb_device_request_t) + sizeof(usb_cdc_line_state_t),
+ .callback = &uplcom_set_line_coding_callback,
+ .timeout = 1000, /* 1 second */
+ },
+};
+
+static const struct usbd_config uplcom_config_intr[UPLCOM_N_INTR_TRANSFER] = {
+ [0] = {
+ .type = UE_INTERRUPT,
+ .endpoint = -1, /* any */
+ .direction = UE_DIR_IN,
+ .flags = USBD_SHORT_XFER_OK,
+ .bufsize = UPLCOM_INTR_SIZE,
+ .callback = &uplcom_intr_callback,
+ },
+
+ [1] = {
+ .type = UE_CONTROL,
+ .endpoint = 0x00, /* Control pipe */
+ .direction = -1,
+ .bufsize = sizeof(usb_device_request_t),
+ .callback = &uplcom_intr_clear_stall_callback,
+ .timeout = 1000, /* 1 second */
+ },
+};
+
+struct ucom_callback uplcom_callback = {
+ .ucom_get_status = &uplcom_get_status,
+ .ucom_set_dtr = &uplcom_set_dtr,
+ .ucom_set_rts = &uplcom_set_rts,
+ .ucom_set_break = &uplcom_set_break,
+ .ucom_param = &uplcom_param,
+ .ucom_open = &uplcom_open,
+ .ucom_close = &uplcom_close,
+ .ucom_ioctl = &uplcom_ioctl,
+ .ucom_start_read = &uplcom_start_read,
+ .ucom_stop_read = &uplcom_stop_read,
+ .ucom_start_write = &uplcom_start_write,
+ .ucom_stop_write = &uplcom_stop_write,
+};
+
+static const struct uplcom_product {
+ u_int16_t vendor;
+ u_int16_t product;
+ u_int16_t release; /* the highest release value accepted,
+ * 0xFFFF means any value, first match
+ * wins
+ */
+ u_int8_t chiptype;
+} uplcom_products [] = {
+ /* I/O DATA USB-RSAQ */
+ { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ, 0xFFFF, TYPE_PL2303 },
+ /* I/O DATA USB-RSAQ2 */
+ { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2, 0xFFFF, TYPE_PL2303 },
+ /* I/O DATA USB-RSAQ3 */
+ { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3, 0xFFFF, TYPE_PL2303X },
+ /* PLANEX USB-RS232 URS-03 */
+ { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A, 0xFFFF, TYPE_PL2303 },
+ /* ST Lab USB-SERIAL-4 */
+ { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, 0x0300, TYPE_PL2303X },
+ /* IOGEAR/ATEN UC-232A (also ST Lab USB-SERIAL-1) */
+ { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, 0xFFFF, TYPE_PL2303 },
+ /* TDK USB-PHS Adapter UHA6400 */
+ { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400, 0xFFFF, TYPE_PL2303 },
+ /* RATOC REX-USB60 */
+ { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60, 0xFFFF, TYPE_PL2303 },
+ /* ELECOM UC-SGT */
+ { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT, 0xFFFF, TYPE_PL2303 },
+ { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0, 0xFFFF, TYPE_PL2303 },
+ /* Sony Ericsson USB Cable */
+ { USB_VENDOR_SONYERICSSON, USB_PRODUCT_SONYERICSSON_DCU10, 0xFFFF,TYPE_PL2303 },
+ /* SOURCENEXT KeikaiDenwa 8 */
+ { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8, 0xFFFF, TYPE_PL2303 },
+ /* SOURCENEXT KeikaiDenwa 8 with charger */
+ { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG,
+ 0xFFFF, TYPE_PL2303 },
+ /* HAL Corporation Crossam2+USB */
+ { USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001, 0xFFFF, TYPE_PL2303 },
+ /* Sitecom USB to Serial */
+ { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_SERIAL, 0xFFFF, TYPE_PL2303 },
+ /* Tripp-Lite U209-000-R */
+ { USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209, 0xFFFF, TYPE_PL2303X },
+ { 0, 0 }
+};
+
+static device_method_t uplcom_methods[] = {
+ DEVMETHOD(device_probe, uplcom_probe),
+ DEVMETHOD(device_attach, uplcom_attach),
+ DEVMETHOD(device_detach, uplcom_detach),
+ { 0, 0 }
+};
+
+static driver_t uplcom_driver = {
+ .name = "ucom",
+ .methods = uplcom_methods,
+ .size = sizeof (struct uplcom_softc),
+};
+
+DRIVER_MODULE(uplcom, uhub, uplcom_driver, ucom_devclass, usbd_driver_load, 0);
+MODULE_DEPEND(uplcom, usb, 1, 1, 1);
+MODULE_DEPEND(uplcom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
+MODULE_VERSION(uplcom, UPLCOM_MODVER);
+
+static const struct uplcom_product *
+uplcom_find_up(struct usb_attach_arg *uaa)
+{
+ const struct uplcom_product *up = uplcom_products;
+
+ if (uaa->iface == NULL) {
+ while(up->product) {
+ if ((up->vendor == uaa->vendor) &&
+ (up->product == uaa->product) &&
+ (up->release <= uaa->release)) {
+ return up;
+ }
+ up++;
+ }
+ }
+ return NULL;
+}
+
+static int
+uplcom_probe(device_t dev)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+
+ DPRINTF(10, "\n");
+
+ return (uplcom_find_up(uaa) ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
+}
+
+static int
+uplcom_attach(device_t dev)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ const struct uplcom_product *up = uplcom_find_up(uaa);
+ struct uplcom_softc *sc = device_get_softc(dev);
+ struct usbd_interface *iface;
+ usb_interface_descriptor_t *id;
+ u_int16_t isize;
+ int error;
+
+ DPRINTF(10, "\n");
+
+ if (sc == NULL) {
+ return ENOMEM;
+ }
+
+ usbd_set_desc(dev, uaa->device);
+
+ DPRINTF(0, "sc = %p\n", sc);
+
+ sc->sc_chiptype = up->chiptype;
+
+ DPRINTF(0, "chiptype: %s\n",
+ (sc->sc_chiptype == TYPE_PL2303X) ?
+ "2303X" : "2303");
+
+ /* configure the chip */
+
+ error = usbd_set_config_index(uaa->device, UPLCOM_CONFIG_INDEX, 1);
+
+ if (error) {
+ device_printf(dev, "failed to set configuration, "
+ "error=%s\n", usbd_errstr(error));
+ goto detach;
+ }
+
+ /*
+ * USB-RSAQ1 has two interface
+ *
+ * USB-RSAQ1 | USB-RSAQ2
+ * -----------------+-----------------
+ * Interface 0 |Interface 0
+ * Interrupt(0x81) | Interrupt(0x81)
+ * -----------------+ BulkIN(0x02)
+ * Interface 1 | BulkOUT(0x83)
+ * BulkIN(0x02) |
+ * BulkOUT(0x83) |
+ */
+ iface = usbd_get_iface(uaa->device, UPLCOM_IFACE_INDEX);
+
+ if (iface == NULL) {
+ DPRINTF(0, "no interface (1)!\n");
+ goto detach;
+ }
+
+ id = usbd_get_interface_descriptor(iface);
+
+ if (id == NULL) {
+ DPRINTF(0, "no interface descriptor (1)!\n");
+ goto detach;
+ }
+
+ sc->sc_ctrl_iface_no = id->bInterfaceNumber;
+ sc->sc_ctrl_iface_index = UPLCOM_IFACE_INDEX;
+
+ iface = usbd_get_iface(uaa->device, UPLCOM_SECOND_IFACE_INDEX);
+
+ if (iface) {
+ id = usbd_get_interface_descriptor(iface);
+
+ if (id == NULL) {
+ device_printf(dev, "no interface descriptor (2)!\n");
+ goto detach;
+ }
+
+ sc->sc_data_iface_no = id->bInterfaceNumber;
+ sc->sc_data_iface_index = UPLCOM_SECOND_IFACE_INDEX;
+ } else {
+ sc->sc_data_iface_no = sc->sc_ctrl_iface_no;
+ sc->sc_data_iface_index = sc->sc_ctrl_iface_index;
+ }
+
+ error = usbd_transfer_setup(uaa->device, sc->sc_data_iface_index,
+ sc->sc_xfer_data, uplcom_config_data,
+ UPLCOM_N_DATA_TRANSFER,
+ sc, &Giant, &(uplcom_detach_complete_1));
+ if (error) {
+ DPRINTF(0, "one or more missing data "
+ "pipes, error=%s\n", usbd_errstr(error));
+ goto detach;
+ }
+
+ sc->sc_flag |= UPLCOM_FLAG_WAIT_USB_1;
+
+ error = usbd_transfer_setup(uaa->device, sc->sc_ctrl_iface_index,
+ sc->sc_xfer_intr, uplcom_config_intr,
+ UPLCOM_N_INTR_TRANSFER,
+ sc, &Giant, &(uplcom_detach_complete_2));
+ if (error) {
+ DPRINTF(0, "no interrupt pipe, error=%s\n",
+ usbd_errstr(error));
+ goto detach;
+ }
+
+ sc->sc_flag |= UPLCOM_FLAG_WAIT_USB_2;
+
+ isize = UGETW(sc->sc_xfer_intr[0]->pipe->edesc->wMaxPacketSize);
+
+ if (isize > UPLCOM_INTR_SIZE) {
+ DPRINTF(0, "cannot handle an interrupt "
+ "packet of %d bytes\n", isize);
+ goto detach;
+ }
+
+ /* set transfer length */
+ sc->sc_xfer_intr[0]->length = isize;
+
+ sc->sc_dtr = -1;
+ sc->sc_rts = -1;
+ sc->sc_break = -1;
+
+ sc->sc_ucom.sc_parent = sc;
+ sc->sc_ucom.sc_portno = 0;
+ sc->sc_ucom.sc_callback = &uplcom_callback;
+
+ error = uplcom_reset(sc, uaa->device);
+
+ if (error) {
+ device_printf(dev, "reset failed, error=%s\n",
+ usbd_errstr(error));
+ goto detach;
+ }
+
+ error = ucom_attach(&(sc->sc_ucom), dev);
+
+ if (error) {
+ goto detach;
+ }
+
+ /* do the initialization during attach
+ * so that the system does not sleep
+ * during open:
+ */
+ if (sc->sc_chiptype == TYPE_PL2303X) {
+ if (uplcom_pl2303x_init(uaa->device)) {
+ device_printf(dev, "init failed!\n");
+ goto detach;
+ }
+ }
+ return 0;
+
+ detach:
+ uplcom_detach(dev);
+ return ENXIO;
+}
+
+static void
+uplcom_detach_complete_1(struct usbd_memory_info *info)
+{
+ struct uplcom_softc *sc = info->priv_sc;
+
+ mtx_lock(&Giant);
+
+ if (sc->sc_flag & UPLCOM_FLAG_WAIT_USB_1) {
+ sc->sc_flag &= ~UPLCOM_FLAG_WAIT_USB_1;
+ wakeup(&(sc->sc_wakeup_detach));
+ }
+
+ mtx_unlock(&Giant);
+
+ return;
+}
+
+static void
+uplcom_detach_complete_2(struct usbd_memory_info *info)
+{
+ struct uplcom_softc *sc = info->priv_sc;
+
+ mtx_lock(&Giant);
+
+ if (sc->sc_flag & UPLCOM_FLAG_WAIT_USB_2) {
+ sc->sc_flag &= ~UPLCOM_FLAG_WAIT_USB_2;
+ wakeup(&(sc->sc_wakeup_detach));
+ }
+
+ mtx_unlock(&Giant);
+
+ return;
+}
+
+static int
+uplcom_detach(device_t dev)
+{
+ struct uplcom_softc *sc = device_get_softc(dev);
+ int error;
+
+ DPRINTF(0, "sc=%p\n", sc);
+
+ ucom_detach(&(sc->sc_ucom));
+
+ usbd_transfer_unsetup(sc->sc_xfer_intr, UPLCOM_N_INTR_TRANSFER);
+
+ usbd_transfer_unsetup(sc->sc_xfer_data, UPLCOM_N_DATA_TRANSFER);
+
+ /* wait for callbacks to finish */
+
+ while (sc->sc_flag & (UPLCOM_FLAG_WAIT_USB_1|UPLCOM_FLAG_WAIT_USB_2)) {
+
+ error = msleep(&(sc->sc_wakeup_detach), &Giant,
+ PRIBIO, "uplcom_sync", 0);
+ }
+
+ return 0;
+}
+
+static usbd_status
+uplcom_reset(struct uplcom_softc *sc, struct usbd_device *udev)
+{
+ usb_device_request_t req;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = UPLCOM_SET_REQUEST;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, sc->sc_data_iface_no);
+ USETW(req.wLength, 0);
+
+ return usbd_do_request(udev, &req, NULL);
+}
+
+struct pl2303x_init {
+ uint8_t req_type;
+ uint8_t request;
+ uint16_t value;
+ uint16_t index;
+ uint16_t length;
+};
+
+static const struct pl2303x_init pl2303x[] = {
+ { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 0 },
+ { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 0, 0 },
+ { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 0 },
+ { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 0 },
+ { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 0 },
+ { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 1, 0 },
+ { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 0 },
+ { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 0 },
+ { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0, 1, 0 },
+ { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0, 0 },
+ { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44, 0 }
+};
+#define N_PL2302X_INIT (sizeof(pl2303x)/sizeof(pl2303x[0]))
+
+static int
+uplcom_pl2303x_init(struct usbd_device *udev)
+{
+ usb_device_request_t req;
+ usbd_status err;
+ int i;
+
+ for (i = 0; i < N_PL2302X_INIT; i++) {
+ req.bmRequestType = pl2303x[i].req_type;
+ req.bRequest = pl2303x[i].request;
+ USETW(req.wValue, pl2303x[i].value);
+ USETW(req.wIndex, pl2303x[i].index);
+ USETW(req.wLength, pl2303x[i].length);
+
+ err = usbd_do_request(udev, &req, NULL);
+ if (err) {
+ DPRINTF(0, "error=%s\n", usbd_errstr(err));
+ return EIO;
+ }
+ }
+ return 0;
+}
+
+static void
+uplcom_set_dtr(struct ucom_softc *ucom, u_int8_t onoff)
+{
+ struct uplcom_softc *sc = ucom->sc_parent;
+
+ DPRINTF(0, "onoff = %d\n", onoff);
+
+ if (sc->sc_dtr != onoff) {
+ sc->sc_dtr = onoff;
+ sc->sc_flag |= UPLCOM_FLAG_SET_LS;
+ usbd_transfer_start(sc->sc_xfer_data[4]);
+ }
+ return;
+}
+
+static void
+uplcom_set_rts(struct ucom_softc *ucom, u_int8_t onoff)
+{
+ struct uplcom_softc *sc = ucom->sc_parent;
+
+ DPRINTF(0, "onoff = %d\n", onoff);
+
+ if (sc->sc_rts != onoff) {
+ sc->sc_rts = onoff;
+ sc->sc_flag |= UPLCOM_FLAG_SET_LS;
+ usbd_transfer_start(sc->sc_xfer_data[4]);
+ }
+ return;
+}
+
+static void
+uplcom_set_break(struct ucom_softc *ucom, u_int8_t onoff)
+{
+ struct uplcom_softc *sc = ucom->sc_parent;
+
+ DPRINTF(0, "onoff = %d\n", onoff);
+
+ sc->sc_break = onoff;
+ sc->sc_flag |= UPLCOM_FLAG_SET_BREAK;
+ usbd_transfer_start(sc->sc_xfer_data[5]);
+ return;
+}
+
+static const int32_t uplcom_rates[] = {
+ 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400,
+ 19200, 28800, 38400, 57600, 115200,
+ /*
+ * Higher speeds are probably possible. PL2303X supports up to
+ * 6Mb and can set any rate
+ */
+ 230400, 460800, 614400, 921600, 1228800
+};
+#define N_UPLCOM_RATES (sizeof(uplcom_rates)/sizeof(uplcom_rates[0]))
+
+static int
+uplcom_param(struct ucom_softc *ucom, struct termios *t)
+{
+ struct uplcom_softc *sc = ucom->sc_parent;
+ u_int32_t i;
+
+ DPRINTF(0, "sc = %p\n", sc);
+
+ /* check requested baud rate */
+
+ for (i = 0; ; i++) {
+
+ if (i < N_UPLCOM_RATES) {
+ if (uplcom_rates[i] == t->c_ospeed) {
+ break;
+ }
+ } else {
+ DPRINTF(0, "invalid baud rate (%d)\n", t->c_ospeed);
+ return EIO;
+ }
+ }
+
+ USETDW(sc->sc_line_state.dwDTERate, t->c_ospeed);
+
+ sc->sc_line_state.bCharFormat = (t->c_cflag & CSTOPB) ?
+ UCDC_STOP_BIT_2 : UCDC_STOP_BIT_1;
+
+ sc->sc_line_state.bParityType = (t->c_cflag & PARENB) ?
+ ((t->c_cflag & PARODD) ?
+ UCDC_PARITY_ODD : UCDC_PARITY_EVEN) : UCDC_PARITY_NONE;
+
+ switch (t->c_cflag & CSIZE) {
+ case CS5:
+ sc->sc_line_state.bDataBits = 5;
+ break;
+ case CS6:
+ sc->sc_line_state.bDataBits = 6;
+ break;
+ case CS7:
+ sc->sc_line_state.bDataBits = 7;
+ break;
+ case CS8:
+ sc->sc_line_state.bDataBits = 8;
+ break;
+ }
+
+ sc->sc_crtscts = (t->c_cflag & CRTSCTS) ? 1 : 0;
+
+ sc->sc_flag |= (UPLCOM_FLAG_SET_LC|UPLCOM_FLAG_SET_CRTSCTS);
+ usbd_transfer_start(sc->sc_xfer_data[6]);
+ return 0;
+}
+
+static int
+uplcom_open(struct ucom_softc *ucom)
+{
+ struct uplcom_softc *sc = ucom->sc_parent;
+
+ DPRINTF(0, "sc=%p\n", sc);
+
+ usbd_transfer_start(sc->sc_xfer_intr[0]);
+
+ return (0);
+}
+
+static void
+uplcom_close(struct ucom_softc *ucom)
+{
+ struct uplcom_softc *sc = ucom->sc_parent;
+
+ DPRINTF(0, "sc=%p\n", sc);
+
+ usbd_transfer_stop(sc->sc_xfer_intr[0]);
+
+ return;
+}
+
+static void
+uplcom_start_read(struct ucom_softc *ucom)
+{
+ struct uplcom_softc *sc = ucom->sc_parent;
+ usbd_transfer_start(sc->sc_xfer_data[1]);
+ return;
+}
+
+static void
+uplcom_stop_read(struct ucom_softc *ucom)
+{
+ struct uplcom_softc *sc = ucom->sc_parent;
+ usbd_transfer_stop(sc->sc_xfer_data[3]);
+ usbd_transfer_stop(sc->sc_xfer_data[1]);
+ return;
+}
+
+static void
+uplcom_start_write(struct ucom_softc *ucom)
+{
+ struct uplcom_softc *sc = ucom->sc_parent;
+ usbd_transfer_start(sc->sc_xfer_data[0]);
+ return;
+}
+
+static void
+uplcom_stop_write(struct ucom_softc *ucom)
+{
+ struct uplcom_softc *sc = ucom->sc_parent;
+ usbd_transfer_stop(sc->sc_xfer_data[2]);
+ usbd_transfer_stop(sc->sc_xfer_data[0]);
+ return;
+}
+
+static void
+uplcom_get_status(struct ucom_softc *ucom, u_int8_t *lsr, u_int8_t *msr)
+{
+ struct uplcom_softc *sc = ucom->sc_parent;
+
+ DPRINTF(0, "\n");
+
+ if (lsr) {
+ *lsr = sc->sc_lsr;
+ }
+
+ if (msr) {
+ *msr = sc->sc_msr;
+ }
+ return;
+}
+
+static int
+uplcom_ioctl(struct ucom_softc *ucom, u_long cmd, caddr_t data, int flag,
+ struct thread *td)
+{
+ int error = ENOTTY;
+
+ /* TODO: */
+
+ DPRINTF(0, "cmd = 0x%08lx\n", cmd);
+
+ switch (cmd) {
+ case TIOCNOTTY:
+ case TIOCMGET:
+ case TIOCMSET:
+ case USB_GET_CM_OVER_DATA:
+ case USB_SET_CM_OVER_DATA:
+ break;
+
+ default:
+ DPRINTF(0, "unknown command\n");
+ error = ENOTTY;
+ break;
+ }
+
+ return error;
+}
+
+static void
+uplcom_set_line_state_callback(struct usbd_xfer *xfer)
+{
+ usb_device_request_t *req = xfer->buffer;
+ struct uplcom_softc *sc = xfer->priv_sc;
+ u_int16_t temp;
+
+ USBD_CHECK_STATUS(xfer);
+
+ tr_error:
+ DPRINTF(0, "error=%s\n", usbd_errstr(xfer->error));
+
+ tr_setup:
+ tr_transferred:
+ if (sc->sc_flag & UPLCOM_FLAG_SET_LS) {
+ sc->sc_flag &= ~UPLCOM_FLAG_SET_LS;
+
+ temp = ((sc->sc_dtr ? UCDC_LINE_DTR : 0) |
+ (sc->sc_rts ? UCDC_LINE_RTS : 0));
+
+ req->bmRequestType = UT_WRITE_CLASS_INTERFACE;
+ req->bRequest = UCDC_SET_CONTROL_LINE_STATE;
+ USETW(req->wValue, temp);
+ USETW(req->wIndex, sc->sc_data_iface_no);
+ USETW(req->wLength, 0);
+
+ usbd_start_hardware(xfer);
+ }
+ return;
+}
+
+static void
+uplcom_set_break_callback(struct usbd_xfer *xfer)
+{
+ usb_device_request_t *req = xfer->buffer;
+ struct uplcom_softc *sc = xfer->priv_sc;
+ u_int16_t temp;
+
+ USBD_CHECK_STATUS(xfer);
+
+ tr_error:
+ DPRINTF(0, "error=%s\n", usbd_errstr(xfer->error));
+
+ tr_setup:
+ tr_transferred:
+ if (sc->sc_flag & UPLCOM_FLAG_SET_BREAK) {
+ sc->sc_flag &= ~UPLCOM_FLAG_SET_BREAK;
+
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list