PERFORCE change 105399 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Thu Aug 31 12:44:38 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=105399
Change 105399 by hselasky at hselasky_mini_itx on 2006/08/31 12:44:19
Finished reworking "uftdi". Please test!
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/uftdi.c#4 edit
.. //depot/projects/usb/src/sys/dev/usb/uftdireg.h#3 add
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/uftdi.c#4 (text+ko) ====
@@ -1,0 +1,1087 @@
+/* $NetBSD: uftdi.c,v 1.13 2002/09/23 05:51:23 simonb Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart at augustsson.net).
+ *
+ * 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.
+ */
+
+/*
+ * NOTE: all function names beginning like "uftdi_cfg_" can only
+ * be called from within the config thread function !
+ */
+
+/*
+ * FTDI FT8U100AX serial adapter driver
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/termios.h>
+#include <sys/serial.h>
+
+#define usbd_config_td_cc uftdi_config_copy
+#define usbd_config_td_softc uftdi_softc
+
+#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 <dev/usb/uftdireg.h>
+
+#include "usbdevs.h"
+
+__FBSDID("$FreeBSD: src/sys/dev/usb/uftdi.c,v 1.22 2005/04/05 22:09:18 ticso Exp $");
+
+#ifdef USB_DEBUG
+#define DPRINTF(sc,n,fmt,...) \
+ do { if (uftdi_debug > (n)) { \
+ printf("%s: %s: " fmt, (sc)->sc_name, \
+ __FUNCTION__,## __VA_ARGS__); } } while (0)
+
+static int uftdi_debug = 0;
+SYSCTL_NODE(_hw_usb, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi");
+SYSCTL_INT(_hw_usb_uftdi, OID_AUTO, debug, CTLFLAG_RW,
+ &uftdi_debug, 0, "uftdi debug level");
+#else
+#define DPRINTF(...)
+#endif
+
+#define UFTDI_CONFIG_INDEX 0
+#define UFTDI_IFACE_INDEX 0
+#define UFTDI_ENDPT_MAX 4
+
+/*
+ * These are the maximum number of bytes transferred per frame.
+ * The output buffer size cannot be increased due to the size encoding.
+ */
+#define UFTDI_IBUFSIZE 64
+#define UFTDI_OBUFSIZE 64
+
+struct uftdi_softc {
+ struct ucom_softc sc_ucom;
+ struct usbd_config_td sc_config_td;
+ struct usbd_memory_wait sc_mem_wait;
+
+ struct usbd_device * sc_udev;
+ struct usbd_xfer * sc_xfer[UFTDI_ENDPT_MAX];
+ device_t sc_dev;
+
+ u_int32_t sc_unit;
+ enum uftdi_type sc_type;
+
+ u_int16_t sc_last_lcr;
+ u_int16_t sc_rate;
+
+ u_int8_t sc_iface_index;
+ u_int8_t sc_hdrlen;
+
+ u_int8_t sc_msr;
+ u_int8_t sc_lsr;
+
+ u_int8_t sc_dtr_onoff;
+ u_int8_t sc_rts_onoff;
+ u_int8_t sc_break_onoff;
+
+ u_int8_t sc_flow;
+ u_int8_t sc_flow_v_start;
+ u_int8_t sc_flow_v_stop;
+
+ u_int8_t sc_flag;
+#define UFTDI_FLAG_WRITE_STALL 0x01
+#define UFTDI_FLAG_READ_STALL 0x02
+
+ u_int8_t sc_name[16];
+};
+
+struct uftdi_config_copy {
+ u_int16_t last_lcr;
+ u_int16_t rate;
+
+ u_int8_t dtr_onoff;
+ u_int8_t rts_onoff;
+ u_int8_t break_onoff;
+
+ u_int8_t flow;
+ u_int8_t v_start;
+ u_int8_t v_stop;
+};
+
+/* prototypes */
+
+static device_probe_t uftdi_probe;
+static device_attach_t uftdi_attach;
+static device_detach_t uftdi_detach;
+
+static void
+uftdi_config_copy(struct uftdi_softc *sc,
+ struct uftdi_config_copy *cc, u_int16_t refcount);
+static void
+uftdi_cfg_do_request(struct uftdi_softc *sc, usb_device_request_t *req,
+ void *data);
+static int
+uftdi_open(struct ucom_softc *ucom);
+
+static void
+uftdi_cfg_open(struct uftdi_softc *sc,
+ struct uftdi_config_copy *cc, u_int16_t refcount);
+static void
+uftdi_write_callback(struct usbd_xfer *xfer);
+
+static void
+uftdi_write_clear_stall_callback(struct usbd_xfer *xfer);
+
+static void
+uftdi_read_callback(struct usbd_xfer *xfer);
+
+static void
+uftdi_read_clear_stall_callback(struct usbd_xfer *xfer);
+
+static void
+uftdi_set_dtr(struct ucom_softc *ucom, u_int8_t onoff);
+
+static void
+uftdi_cfg_set_dtr(struct uftdi_softc *sc,
+ struct uftdi_config_copy *cc, u_int16_t refcount);
+static void
+uftdi_set_rts(struct ucom_softc *ucom, u_int8_t onoff);
+
+static void
+uftdi_cfg_set_rts(struct uftdi_softc *sc,
+ struct uftdi_config_copy *cc, u_int16_t refcount);
+static void
+uftdi_set_break(struct ucom_softc *ucom, u_int8_t onoff);
+
+static void
+uftdi_cfg_set_break(struct uftdi_softc *sc,
+ struct uftdi_config_copy *cc, u_int16_t refcount);
+static int
+uftdi_set_parm_soft(struct uftdi_softc *sc, u_int32_t ospeed,
+ u_int8_t v_start, u_int8_t v_stop,
+ u_int32_t cflag, u_int32_t iflag);
+static int
+uftdi_param(struct ucom_softc *ucom, struct termios *t);
+
+static void
+uftdi_cfg_parm(struct uftdi_softc *sc,
+ struct uftdi_config_copy *cc, u_int16_t refcount);
+static void
+uftdi_get_status(struct ucom_softc *ucom, u_int8_t *lsr, u_int8_t *msr);
+
+static void
+uftdi_start_read(struct ucom_softc *ucom);
+
+static void
+uftdi_stop_read(struct ucom_softc *ucom);
+
+static void
+uftdi_start_write(struct ucom_softc *ucom);
+
+static void
+uftdi_stop_write(struct ucom_softc *ucom);
+
+static const struct usbd_config uftdi_config[UFTDI_ENDPT_MAX] = {
+
+ [0] = {
+ .type = UE_BULK,
+ .endpoint = -1, /* any */
+ .direction = UE_DIR_OUT,
+ .bufsize = UFTDI_OBUFSIZE,
+ .flags = 0,
+ .callback = &uftdi_write_callback,
+ },
+
+ [1] = {
+ .type = UE_BULK,
+ .endpoint = -1, /* any */
+ .direction = UE_DIR_IN,
+ .bufsize = UFTDI_IBUFSIZE,
+ .flags = USBD_SHORT_XFER_OK,
+ .callback = &uftdi_read_callback,
+ },
+
+ [2] = {
+ .type = UE_CONTROL,
+ .endpoint = 0x00, /* Control pipe */
+ .direction = -1,
+ .bufsize = sizeof(usb_device_request_t),
+ .flags = (USBD_USE_DMA),
+ .callback = &uftdi_write_clear_stall_callback,
+ .timeout = 1000, /* 1 second */
+ },
+
+ [3] = {
+ .type = UE_CONTROL,
+ .endpoint = 0x00, /* Control pipe */
+ .direction = -1,
+ .bufsize = sizeof(usb_device_request_t),
+ .flags = (USBD_USE_DMA),
+ .callback = &uftdi_read_clear_stall_callback,
+ .timeout = 1000, /* 1 second */
+ },
+};
+
+static const struct ucom_callback uftdi_callback = {
+ .ucom_get_status = &uftdi_get_status,
+ .ucom_set_dtr = &uftdi_set_dtr,
+ .ucom_set_rts = &uftdi_set_rts,
+ .ucom_set_break = &uftdi_set_break,
+ .ucom_param = &uftdi_param,
+ .ucom_open = &uftdi_open,
+ .ucom_start_read = &uftdi_start_read,
+ .ucom_stop_read = &uftdi_stop_read,
+ .ucom_start_write = &uftdi_start_write,
+ .ucom_stop_write = &uftdi_stop_write,
+};
+
+static device_method_t uftdi_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uftdi_probe),
+ DEVMETHOD(device_attach, uftdi_attach),
+ DEVMETHOD(device_detach, uftdi_detach),
+
+ { 0, 0 }
+};
+
+static driver_t uftdi_driver = {
+ "ucom",
+ uftdi_methods,
+ sizeof (struct uftdi_softc)
+};
+
+DRIVER_MODULE(uftdi, uhub, uftdi_driver, ucom_devclass, usbd_driver_load, 0);
+MODULE_DEPEND(uftdi, usb, 1, 1, 1);
+MODULE_DEPEND(uftdi, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
+
+static int
+uftdi_probe(device_t dev)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+
+ if (uaa->iface != NULL) {
+ if ((uaa->vendor == USB_VENDOR_FTDI) &&
+ (uaa->product == USB_PRODUCT_FTDI_SERIAL_2232C)) {
+ return UMATCH_VENDOR_IFACESUBCLASS;
+ }
+ return UMATCH_NONE;
+ }
+
+ if ((uaa->vendor == USB_VENDOR_FTDI) &&
+ ((uaa->product == USB_PRODUCT_FTDI_SERIAL_8U100AX) ||
+ (uaa->product == USB_PRODUCT_FTDI_SERIAL_8U232AM) ||
+ (uaa->product == USB_PRODUCT_FTDI_SEMC_DSS20) ||
+ (uaa->product == USB_PRODUCT_FTDI_CFA_631) ||
+ (uaa->product == USB_PRODUCT_FTDI_CFA_632) ||
+ (uaa->product == USB_PRODUCT_FTDI_CFA_633) ||
+ (uaa->product == USB_PRODUCT_FTDI_CFA_634) ||
+ (uaa->product == USB_PRODUCT_FTDI_USBSERIAL) ||
+ (uaa->product == USB_PRODUCT_FTDI_MX2_3) ||
+ (uaa->product == USB_PRODUCT_FTDI_MX4_5) ||
+ (uaa->product == USB_PRODUCT_FTDI_LK202) ||
+ (uaa->product == USB_PRODUCT_FTDI_LK204))) {
+ return UMATCH_VENDOR_PRODUCT;
+ }
+
+ if ((uaa->vendor == USB_VENDOR_SIIG2) &&
+ (uaa->product == USB_PRODUCT_SIIG2_US2308)) {
+ return UMATCH_VENDOR_PRODUCT;
+ }
+
+ if ((uaa->vendor == USB_VENDOR_INTREPIDCS) &&
+ ((uaa->product == USB_PRODUCT_INTREPIDCS_VALUECAN) ||
+ (uaa->product == USB_PRODUCT_INTREPIDCS_NEOVI))) {
+ return UMATCH_VENDOR_PRODUCT;
+ }
+
+ if ((uaa->vendor == USB_VENDOR_BBELECTRONICS) &&
+ (uaa->product == USB_PRODUCT_BBELECTRONICS_USOTL4)) {
+ return UMATCH_VENDOR_PRODUCT;
+ }
+
+ return (UMATCH_NONE);
+}
+
+static int
+uftdi_attach(device_t dev)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ struct uftdi_softc *sc = device_get_softc(dev);
+ usb_interface_descriptor_t *id;
+ int32_t error;
+
+ if (sc == NULL) {
+ return ENOMEM;
+ }
+
+ sc->sc_udev = uaa->device;
+ sc->sc_dev = dev;
+ sc->sc_unit = device_get_unit(dev);
+
+ usbd_set_desc(dev, uaa->device);
+
+ snprintf(sc->sc_name, sizeof(sc->sc_name),
+ "%s", device_get_nameunit(dev));
+
+ DPRINTF(sc, 0, "\n");
+
+ if (uaa->iface == NULL) {
+
+ error = usbd_set_config_index(uaa->device, UFTDI_CONFIG_INDEX, 1);
+
+ if (error) {
+ device_printf(dev, "failed to set configuration, "
+ "error=%s\n", usbd_errstr(error));
+ goto detach;
+ }
+
+ sc->sc_iface_index = UFTDI_IFACE_INDEX;
+ } else {
+ sc->sc_iface_index = uaa->iface_index;
+ }
+
+ switch( uaa->vendor ) {
+ case USB_VENDOR_FTDI:
+ switch( uaa->product ){
+ case USB_PRODUCT_FTDI_SERIAL_8U100AX:
+ sc->sc_type = UFTDI_TYPE_SIO;
+ sc->sc_hdrlen = 1;
+ break;
+
+ case USB_PRODUCT_FTDI_SEMC_DSS20:
+ case USB_PRODUCT_FTDI_SERIAL_8U232AM:
+ case USB_PRODUCT_FTDI_SERIAL_2232C:
+ case USB_PRODUCT_FTDI_CFA_631:
+ case USB_PRODUCT_FTDI_CFA_632:
+ case USB_PRODUCT_FTDI_CFA_633:
+ case USB_PRODUCT_FTDI_CFA_634:
+ case USB_PRODUCT_FTDI_USBSERIAL:
+ case USB_PRODUCT_FTDI_MX2_3:
+ case USB_PRODUCT_FTDI_MX4_5:
+ case USB_PRODUCT_FTDI_LK202:
+ case USB_PRODUCT_FTDI_LK204:
+ sc->sc_type = UFTDI_TYPE_8U232AM;
+ sc->sc_hdrlen = 0;
+ break;
+
+ default: /* Can't happen */
+ goto detach;
+ }
+ break;
+
+ case USB_VENDOR_INTREPIDCS:
+ switch( uaa->product ){
+ case USB_PRODUCT_INTREPIDCS_VALUECAN:
+ case USB_PRODUCT_INTREPIDCS_NEOVI:
+ sc->sc_type = UFTDI_TYPE_8U232AM;
+ sc->sc_hdrlen = 0;
+ break;
+
+ default: /* Can't happen */
+ goto detach;
+ }
+ break;
+
+ case USB_VENDOR_SIIG2:
+ switch( uaa->product ){
+ case USB_PRODUCT_SIIG2_US2308:
+ sc->sc_type = UFTDI_TYPE_8U232AM;
+ sc->sc_hdrlen = 0;
+ break;
+
+ default: /* Can't happen */
+ goto detach;
+ }
+ break;
+
+ case USB_VENDOR_BBELECTRONICS:
+ switch( uaa->product ){
+ case USB_PRODUCT_BBELECTRONICS_USOTL4:
+ sc->sc_type = UFTDI_TYPE_8U232AM;
+ sc->sc_hdrlen = 0;
+ break;
+
+ default: /* Can't happen */
+ goto detach;
+ }
+ break;
+
+ default: /* Can't happen */
+ goto detach;
+ }
+
+ error = usbd_transfer_setup(uaa->device, sc->sc_iface_index,
+ sc->sc_xfer, uftdi_config, UFTDI_ENDPT_MAX,
+ sc, &Giant, &(sc->sc_mem_wait));
+ if (error) {
+ device_printf(dev, "allocating USB "
+ "transfers failed!\n");
+ goto detach;
+ }
+
+ error = usbd_config_td_setup(&(sc->sc_config_td), sc, &Giant,
+ &uftdi_config_copy, NULL,
+ sizeof(struct uftdi_config_copy), 16);
+ if (error) {
+ device_printf(dev, "could not setup config "
+ "thread!\n");
+ goto detach;
+ }
+
+ sc->sc_ucom.sc_parent = sc;
+ sc->sc_ucom.sc_portno = FTDI_PIT_SIOA;
+ sc->sc_ucom.sc_callback = &uftdi_callback;
+
+ if (uaa->iface) {
+ id = usbd_get_interface_descriptor(uaa->iface);
+
+ if (id == NULL) {
+ goto detach;
+ }
+
+ sc->sc_ucom.sc_portno += id->bInterfaceNumber;
+ }
+
+ error = ucom_attach(&(sc->sc_ucom), dev);
+
+ if (error) {
+ goto detach;
+ }
+
+ return 0; /* success */
+
+ detach:
+ uftdi_detach(dev);
+ return ENXIO;
+}
+
+static int
+uftdi_detach(device_t dev)
+{
+ struct uftdi_softc *sc = device_get_softc(dev);
+
+ mtx_lock(&Giant);
+
+ usbd_config_td_stop(&(sc->sc_config_td));
+
+ mtx_unlock(&Giant);
+
+ ucom_detach(&(sc->sc_ucom));
+
+ usbd_transfer_unsetup(sc->sc_xfer, UFTDI_ENDPT_MAX);
+
+ usbd_transfer_drain(&(sc->sc_mem_wait), &Giant);
+
+ usbd_config_td_unsetup(&(sc->sc_config_td));
+
+ return 0;
+}
+
+static void
+uftdi_config_copy(struct uftdi_softc *sc,
+ struct uftdi_config_copy *cc, u_int16_t refcount)
+{
+ bzero(cc, sizeof(*cc));
+
+ cc->dtr_onoff = sc->sc_dtr_onoff;
+ cc->rts_onoff = sc->sc_rts_onoff;
+ cc->break_onoff = sc->sc_break_onoff;
+ cc->last_lcr = sc->sc_last_lcr;
+ cc->rate = sc->sc_rate;
+ cc->v_stop = sc->sc_flow_v_stop;
+ cc->v_start = sc->sc_flow_v_start;
+ cc->flow = sc->sc_flow;
+
+ return;
+}
+
+static void
+uftdi_cfg_do_request(struct uftdi_softc *sc, usb_device_request_t *req,
+ void *data)
+{
+ u_int16_t length;
+ usbd_status err;
+
+ if (usbd_config_td_is_gone(&(sc->sc_config_td))) {
+ goto error;
+ }
+
+ err = usbd_do_request_flags_mtx(sc->sc_udev, &Giant, req,
+ data, 0, NULL, 1000);
+
+ if (err) {
+
+ DPRINTF(sc, 0, "device request failed, err=%s "
+ "(ignored)\n", usbd_errstr(err));
+
+ error:
+ length = UGETW(req->wLength);
+
+ if ((req->bmRequestType & UT_READ) && length) {
+ bzero(data, length);
+ }
+ }
+ return;
+}
+
+static int
+uftdi_open(struct ucom_softc *ucom)
+{
+ struct uftdi_softc *sc = ucom->sc_parent;
+
+ sc->sc_flag |= (UFTDI_FLAG_WRITE_STALL|
+ UFTDI_FLAG_READ_STALL);
+
+ usbd_config_td_queue_command
+ (&(sc->sc_config_td), &uftdi_cfg_open, 0);
+
+ return 0;
+}
+
+static void
+uftdi_cfg_open(struct uftdi_softc *sc,
+ struct uftdi_config_copy *cc, u_int16_t refcount)
+{
+ u_int16_t wIndex = sc->sc_ucom.sc_portno;
+ usb_device_request_t req;
+
+ if (cc == NULL) {
+
+ /* set 9600 baud, 2 stop bits,
+ * no parity, 8 bits
+ */
+ (void) uftdi_set_parm_soft
+ (sc, 9600, 0, 0, CSTOPB | CS8, 0);
+
+ return;
+ }
+
+ DPRINTF(sc, 0, "");
+
+ /* perform a full reset on the device */
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = FTDI_SIO_RESET;
+ USETW(req.wValue, FTDI_SIO_RESET_SIO);
+ USETW(req.wIndex, wIndex);
+ USETW(req.wLength, 0);
+ uftdi_cfg_do_request(sc, &req, NULL);
+
+ /* write parameters */
+
+ uftdi_cfg_parm(sc, cc, 0);
+
+ /* turn on RTS/CTS flow control */
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
+ USETW(req.wValue, 0);
+ USETW2(req.wIndex, FTDI_SIO_RTS_CTS_HS, wIndex);
+ USETW(req.wLength, 0);
+ uftdi_cfg_do_request(sc, &req, NULL);
+
+ return;
+}
+
+static void
+uftdi_write_callback(struct usbd_xfer *xfer)
+{
+ struct uftdi_softc *sc = xfer->priv_sc;
+ u_int32_t actlen;
+
+ USBD_CHECK_STATUS(xfer);
+
+tr_error:
+ if (xfer->error != USBD_CANCELLED) {
+ sc->sc_flag |= UFTDI_FLAG_WRITE_STALL;
+ usbd_transfer_start(sc->sc_xfer[2]);
+ }
+ return;
+
+tr_setup:
+tr_transferred:
+ if (sc->sc_flag & UFTDI_FLAG_WRITE_STALL) {
+ usbd_transfer_start(sc->sc_xfer[2]);
+ return;
+ }
+
+ if(ucom_get_data(&(sc->sc_ucom), ((u_int8_t *)(xfer->buffer)) +
+ sc->sc_hdrlen, UFTDI_OBUFSIZE - sc->sc_hdrlen,
+ &actlen)) {
+
+ if (sc->sc_hdrlen > 0) {
+ *(u_int8_t *)(xfer->buffer) =
+ FTDI_OUT_TAG(actlen, sc->sc_ucom.sc_portno);
+ }
+
+ xfer->length = actlen + sc->sc_hdrlen;
+
+ usbd_start_hardware(xfer);
+ }
+ return;
+}
+
+static void
+uftdi_write_clear_stall_callback(struct usbd_xfer *xfer)
+{
+ struct uftdi_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 &= ~UFTDI_FLAG_WRITE_STALL;
+ usbd_transfer_start(sc->sc_xfer[0]);
+ return;
+
+ tr_error:
+ sc->sc_flag &= ~UFTDI_FLAG_WRITE_STALL;
+ DPRINTF(sc, 0, "clear stall failed, error=%s\n",
+ usbd_errstr(xfer->error));
+ return;
+}
+
+static void
+uftdi_read_callback(struct usbd_xfer *xfer)
+{
+ struct uftdi_softc *sc = xfer->priv_sc;
+ u_int8_t *ptr = xfer->buffer;
+ u_int8_t msr;
+ u_int8_t lsr;
+
+ USBD_CHECK_STATUS(xfer);
+
+ tr_error:
+ if (xfer->error != USBD_CANCELLED) {
+ sc->sc_flag |= UFTDI_FLAG_READ_STALL;
+ usbd_transfer_start(sc->sc_xfer[3]);
+ }
+ return;
+
+ tr_transferred:
+
+ if (xfer->actlen < 2) {
+ goto tr_setup;
+ }
+
+ msr = FTDI_GET_MSR(ptr);
+ lsr = FTDI_GET_LSR(ptr);
+
+ if ((sc->sc_msr != msr) ||
+ ((sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK))) {
+ DPRINTF(sc, 0, "status change msr=0x%02x (0x%02x) "
+ "lsr=0x%02x (0x%02x)\n", msr, sc->sc_msr,
+ lsr, sc->sc_lsr);
+
+ sc->sc_msr = msr;
+ sc->sc_lsr = lsr;
+
+ ucom_status_change(&(sc->sc_ucom));
+ }
+
+ xfer->actlen -= 2;
+ ptr += 2;
+
+ if (xfer->actlen) {
+ ucom_put_data(&(sc->sc_ucom), ptr, xfer->actlen);
+ }
+
+ tr_setup:
+ if (sc->sc_flag & UFTDI_FLAG_READ_STALL) {
+ usbd_transfer_start(sc->sc_xfer[3]);
+ } else {
+ usbd_start_hardware(xfer);
+ }
+ return;
+}
+
+static void
+uftdi_read_clear_stall_callback(struct usbd_xfer *xfer)
+{
+ struct uftdi_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 &= ~UFTDI_FLAG_READ_STALL;
+ usbd_transfer_start(sc->sc_xfer[1]);
+ return;
+
+ tr_error:
+ sc->sc_flag &= ~UFTDI_FLAG_READ_STALL;
+ DPRINTF(sc, 0, "clear stall failed, error=%s\n",
+ usbd_errstr(xfer->error));
+ return;
+}
+
+static void
+uftdi_set_dtr(struct ucom_softc *ucom, u_int8_t onoff)
+{
+ struct uftdi_softc *sc = ucom->sc_parent;
+
+ sc->sc_dtr_onoff = onoff;
+
+ usbd_config_td_queue_command
+ (&(sc->sc_config_td), &uftdi_cfg_set_dtr, 0);
+
+ return;
+}
+
+static void
+uftdi_cfg_set_dtr(struct uftdi_softc *sc,
+ struct uftdi_config_copy *cc, u_int16_t refcount)
+{
+ u_int16_t wIndex = sc->sc_ucom.sc_portno;
+ u_int16_t wValue;
+ usb_device_request_t req;
+
+ if (cc == NULL) {
+ /* nothing to do */
+ return;
+ }
+
+ wValue = cc->dtr_onoff ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = FTDI_SIO_MODEM_CTRL;
+ USETW(req.wValue, wValue);
+ USETW(req.wIndex, wIndex);
+ USETW(req.wLength, 0);
+ uftdi_cfg_do_request(sc, &req, NULL);
+
+ return;
+}
+
+static void
+uftdi_set_rts(struct ucom_softc *ucom, u_int8_t onoff)
+{
+ struct uftdi_softc *sc = ucom->sc_parent;
+
+ sc->sc_rts_onoff = onoff;
+
+ usbd_config_td_queue_command
+ (&(sc->sc_config_td), &uftdi_cfg_set_rts, 0);
+
+ return;
+}
+
+static void
+uftdi_cfg_set_rts(struct uftdi_softc *sc,
+ struct uftdi_config_copy *cc, u_int16_t refcount)
+{
+ u_int16_t wIndex = sc->sc_ucom.sc_portno;
+ u_int16_t wValue;
+ usb_device_request_t req;
+
+ if (cc == NULL) {
+ /* nothing to do */
+ return;
+ }
+
+ wValue = cc->rts_onoff ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = FTDI_SIO_MODEM_CTRL;
+ USETW(req.wValue, wValue);
+ USETW(req.wIndex, wIndex);
+ USETW(req.wLength, 0);
+ uftdi_cfg_do_request(sc, &req, NULL);
+
+ return;
+}
+
+static void
+uftdi_set_break(struct ucom_softc *ucom, u_int8_t onoff)
+{
+ struct uftdi_softc *sc = ucom->sc_parent;
+
+ sc->sc_break_onoff = onoff;
+
+ usbd_config_td_queue_command
+ (&(sc->sc_config_td), &uftdi_cfg_set_break, 0);
+
+ return;
+}
+
+static void
+uftdi_cfg_set_break(struct uftdi_softc *sc,
+ struct uftdi_config_copy *cc, u_int16_t refcount)
+{
+ u_int16_t wIndex = sc->sc_ucom.sc_portno;
+ u_int16_t wValue;
+ usb_device_request_t req;
+
+ if (cc == NULL) {
+ /* nothing to do */
+ return;
+ }
+
+ if (cc->break_onoff) {
+ wValue = cc->last_lcr | FTDI_SIO_SET_BREAK;
+ } else {
+ wValue = cc->last_lcr;
+ }
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = FTDI_SIO_SET_DATA;
+ USETW(req.wValue, wValue);
+ USETW(req.wIndex, wIndex);
+ USETW(req.wLength, 0);
+ uftdi_cfg_do_request(sc, &req, NULL);
+
+ return;
+}
+
+static int
+uftdi_set_parm_soft(struct uftdi_softc *sc, u_int32_t ospeed,
+ u_int8_t v_start, u_int8_t v_stop,
+ u_int32_t cflag, u_int32_t iflag)
+{
+ u_int16_t rate = 0;
+ u_int16_t data = 0;
+ u_int8_t flow = 0;
+
+ switch (sc->sc_type) {
+ case UFTDI_TYPE_SIO:
+ switch (ospeed) {
+ case 300: rate = ftdi_sio_b300; break;
+ case 600: rate = ftdi_sio_b600; break;
+ case 1200: rate = ftdi_sio_b1200; break;
+ case 2400: rate = ftdi_sio_b2400; break;
+ case 4800: rate = ftdi_sio_b4800; break;
+ case 9600: rate = ftdi_sio_b9600; break;
+ case 19200: rate = ftdi_sio_b19200; break;
+ case 38400: rate = ftdi_sio_b38400; break;
+ case 57600: rate = ftdi_sio_b57600; break;
+ case 115200: rate = ftdi_sio_b115200; break;
+ default:
+ return (EINVAL);
+ }
+ break;
+
+ case UFTDI_TYPE_8U232AM:
+ switch(ospeed) {
+ case 300: rate = ftdi_8u232am_b300; break;
+ case 600: rate = ftdi_8u232am_b600; break;
+ case 1200: rate = ftdi_8u232am_b1200; break;
+ case 2400: rate = ftdi_8u232am_b2400; break;
+ case 4800: rate = ftdi_8u232am_b4800; break;
+ case 9600: rate = ftdi_8u232am_b9600; break;
+ case 19200: rate = ftdi_8u232am_b19200; break;
+ case 38400: rate = ftdi_8u232am_b38400; break;
+ case 57600: rate = ftdi_8u232am_b57600; break;
+ case 115200: rate = ftdi_8u232am_b115200; break;
+ case 230400: rate = ftdi_8u232am_b230400; break;
+ case 460800: rate = ftdi_8u232am_b460800; break;
+ case 921600: rate = ftdi_8u232am_b921600; break;
+ case 2000000: rate = ftdi_8u232am_b2000000; break;
+ case 3000000: rate = ftdi_8u232am_b3000000; break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ }
+ sc->sc_rate = rate;
+
+ if (cflag & CSTOPB)
+ data = FTDI_SIO_SET_DATA_STOP_BITS_2;
+ else
+ data = FTDI_SIO_SET_DATA_STOP_BITS_1;
+
+ if (cflag & PARENB) {
+ if (cflag & PARODD) {
+ data |= FTDI_SIO_SET_DATA_PARITY_ODD;
+ } else {
+ data |= FTDI_SIO_SET_DATA_PARITY_EVEN;
+ }
+ } else {
+ data |= FTDI_SIO_SET_DATA_PARITY_NONE;
+ }
+
+ switch (cflag & CSIZE) {
+ case CS5:
+ data |= FTDI_SIO_SET_DATA_BITS(5);
+ break;
+
+ case CS6:
+ data |= FTDI_SIO_SET_DATA_BITS(6);
+ break;
+
+ case CS7:
+ data |= FTDI_SIO_SET_DATA_BITS(7);
+ break;
+
+ case CS8:
+ data |= FTDI_SIO_SET_DATA_BITS(8);
+ break;
+ }
+ sc->sc_last_lcr = data;
+
+ if (cflag & CRTSCTS) {
+ flow = FTDI_SIO_RTS_CTS_HS;
+ v_start = 0;
+ v_stop = 0;
+ } else if (iflag & (IXON|IXOFF)) {
+ flow = FTDI_SIO_XON_XOFF_HS;
+ } else {
+ flow = FTDI_SIO_DISABLE_FLOW_CTRL;
+ v_start = 0;
+ v_stop = 0;
+ }
+
+ sc->sc_flow = flow;
+ sc->sc_flow_v_start = v_start;
+ sc->sc_flow_v_stop = v_stop;
+ return 0;
+}
+
+static int
+uftdi_param(struct ucom_softc *ucom, struct termios *t)
+{
+ struct uftdi_softc *sc = ucom->sc_parent;
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list