From owner-svn-src-all@FreeBSD.ORG Sat Nov 12 08:40:52 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 7AD7F1065672; Sat, 12 Nov 2011 08:40:52 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 69EBC8FC15; Sat, 12 Nov 2011 08:40:52 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id pAC8eq6f033811; Sat, 12 Nov 2011 08:40:52 GMT (envelope-from hselasky@svn.freebsd.org) Received: (from hselasky@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id pAC8eqSI033808; Sat, 12 Nov 2011 08:40:52 GMT (envelope-from hselasky@svn.freebsd.org) Message-Id: <201111120840.pAC8eqSI033808@svn.freebsd.org> From: Hans Petter Selasky Date: Sat, 12 Nov 2011 08:40:52 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r227463 - in head/sys/dev/usb: . serial X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 12 Nov 2011 08:40:52 -0000 Author: hselasky Date: Sat Nov 12 08:40:52 2011 New Revision: 227463 URL: http://svn.freebsd.org/changeset/base/227463 Log: - This patch adds custom IOCTLs to read and write the 4 GPIO pins on the cp2103 usb-to-serial chip. - This patch also makes the line status polling asynchronous, to reduce the time needed to change the GPIO pins. Submitted by: JD Louw MFC after: 1 week Modified: head/sys/dev/usb/serial/uslcom.c head/sys/dev/usb/usb_ioctl.h Modified: head/sys/dev/usb/serial/uslcom.c ============================================================================== --- head/sys/dev/usb/serial/uslcom.c Sat Nov 12 08:19:36 2011 (r227462) +++ head/sys/dev/usb/serial/uslcom.c Sat Nov 12 08:40:52 2011 (r227463) @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include "usbdevs.h" #define USB_DEBUG_VAR uslcom_debug @@ -75,6 +76,7 @@ SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, deb #define USLCOM_CTRL 0x07 #define USLCOM_RCTRL 0x08 #define USLCOM_SET_FLOWCTRL 0x13 +#define USLCOM_VENDOR_SPECIFIC 0xff /* USLCOM_UART values */ #define USLCOM_UART_DISABLE 0x00 @@ -113,6 +115,10 @@ SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, deb #define USLCOM_FLOW_RTS_ON 0x00000040 /* RTS static active */ #define USLCOM_FLOW_RTS_HS 0x00000080 /* RTS handshake */ +/* USLCOM_VENDOR_SPECIFIC values */ +#define USLCOM_WRITE_LATCH 0x37E1 +#define USLCOM_READ_LATCH 0x00C2 + enum { USLCOM_BULK_DT_WR, USLCOM_BULK_DT_RD, @@ -123,6 +129,7 @@ enum { struct uslcom_softc { struct ucom_super_softc sc_super_ucom; struct ucom_softc sc_ucom; + struct usb_callout sc_watchdog; struct usb_xfer *sc_xfer[USLCOM_N_TRANSFER]; struct usb_device *sc_udev; @@ -145,6 +152,8 @@ static void uslcom_close(struct ucom_sof static void uslcom_set_dtr(struct ucom_softc *, uint8_t); static void uslcom_set_rts(struct ucom_softc *, uint8_t); static void uslcom_set_break(struct ucom_softc *, uint8_t); +static int uslcom_ioctl(struct ucom_softc *, uint32_t, caddr_t, int, + struct thread *); static int uslcom_pre_param(struct ucom_softc *, struct termios *); static void uslcom_param(struct ucom_softc *, struct termios *); static void uslcom_get_status(struct ucom_softc *, uint8_t *, uint8_t *); @@ -177,7 +186,6 @@ static const struct usb_config uslcom_co .type = UE_CONTROL, .endpoint = 0x00, .direction = UE_DIR_ANY, - .interval = 150, /* poll status every 150 ms */ .bufsize = sizeof(struct usb_device_request) + 8, .flags = {.pipe_bof = 1,}, .callback = &uslcom_control_callback, @@ -192,6 +200,7 @@ static struct ucom_callback uslcom_callb .ucom_cfg_set_dtr = &uslcom_set_dtr, .ucom_cfg_set_rts = &uslcom_set_rts, .ucom_cfg_set_break = &uslcom_set_break, + .ucom_ioctl = &uslcom_ioctl, .ucom_cfg_param = &uslcom_param, .ucom_pre_param = &uslcom_pre_param, .ucom_start_read = &uslcom_start_read, @@ -308,6 +317,19 @@ MODULE_DEPEND(uslcom, ucom, 1, 1, 1); MODULE_DEPEND(uslcom, usb, 1, 1, 1); MODULE_VERSION(uslcom, 1); +static void +uslcom_watchdog(void *arg) +{ + struct uslcom_softc *sc = arg; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + usbd_transfer_start(sc->sc_xfer[USLCOM_CTRL_DT_RD]); + + usb_callout_reset(&sc->sc_watchdog, + hz / 4, &uslcom_watchdog, sc); +} + static int uslcom_probe(device_t dev) { @@ -338,6 +360,7 @@ uslcom_attach(device_t dev) device_set_usb_desc(dev); mtx_init(&sc->sc_mtx, "uslcom", NULL, MTX_DEF); + usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0); sc->sc_udev = uaa->device; @@ -378,6 +401,8 @@ uslcom_detach(device_t dev) ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); usbd_transfer_unsetup(sc->sc_xfer, USLCOM_N_TRANSFER); + + usb_callout_drain(&sc->sc_watchdog); mtx_destroy(&sc->sc_mtx); return (0); @@ -399,8 +424,9 @@ uslcom_open(struct ucom_softc *ucom) &req, NULL, 0, 1000)) { DPRINTF("UART enable failed (ignored)\n"); } - /* Start polling status */ - usbd_transfer_start(sc->sc_xfer[USLCOM_CTRL_DT_RD]); + + /* start polling status */ + uslcom_watchdog(sc); } static void @@ -409,8 +435,8 @@ uslcom_close(struct ucom_softc *ucom) struct uslcom_softc *sc = ucom->sc_parent; struct usb_device_request req; - /* Stop polling status */ - usbd_transfer_stop(sc->sc_xfer[USLCOM_CTRL_DT_RD]); + /* stop polling status */ + usb_callout_stop(&sc->sc_watchdog); req.bmRequestType = USLCOM_WRITE; req.bRequest = USLCOM_UART; @@ -591,6 +617,55 @@ uslcom_set_break(struct ucom_softc *ucom } } +static int +uslcom_ioctl(struct ucom_softc *ucom, uint32_t cmd, caddr_t data, + int flag, struct thread *td) +{ + struct uslcom_softc *sc = ucom->sc_parent; + struct usb_device_request req; + int error = 0; + uint8_t latch; + + DPRINTF("cmd=0x%08x\n", cmd); + + switch (cmd) { + case USB_GET_GPIO: + req.bmRequestType = USLCOM_READ; + req.bRequest = USLCOM_VENDOR_SPECIFIC; + USETW(req.wValue, USLCOM_READ_LATCH); + USETW(req.wIndex, 0); + USETW(req.wLength, sizeof(latch)); + + if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, + &req, &latch, 0, 1000)) { + DPRINTF("Get LATCH failed\n"); + error = EIO; + } + *(int *)data = latch; + break; + + case USB_SET_GPIO: + req.bmRequestType = USLCOM_WRITE; + req.bRequest = USLCOM_VENDOR_SPECIFIC; + USETW(req.wValue, USLCOM_WRITE_LATCH); + USETW(req.wIndex, (*(int *)data)); + USETW(req.wLength, 0); + + if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, + &req, NULL, 0, 1000)) { + DPRINTF("Set LATCH failed\n"); + error = EIO; + } + break; + + default: + DPRINTF("Unknown IOCTL\n"); + error = ENOIOCTL; + break; + } + return (error); +} + static void uslcom_write_callback(struct usb_xfer *xfer, usb_error_t error) { @@ -681,11 +756,9 @@ uslcom_control_callback(struct usb_xfer sc->sc_msr = msr; ucom_status_change(&sc->sc_ucom); } - - /* FALLTHROUGH */ + break; case USB_ST_SETUP: -tr_setup: req.bmRequestType = USLCOM_READ; req.bRequest = USLCOM_RCTRL; USETW(req.wValue, 0); @@ -702,10 +775,8 @@ tr_setup: break; default: /* error */ - if (error != USB_ERR_CANCELLED) { + if (error != USB_ERR_CANCELLED) DPRINTF("error=%s\n", usbd_errstr(error)); - goto tr_setup; - } break; } } Modified: head/sys/dev/usb/usb_ioctl.h ============================================================================== --- head/sys/dev/usb/usb_ioctl.h Sat Nov 12 08:19:36 2011 (r227462) +++ head/sys/dev/usb/usb_ioctl.h Sat Nov 12 08:40:52 2011 (r227463) @@ -289,6 +289,10 @@ struct usb_gen_quirk { #define USB_GET_CM_OVER_DATA _IOR ('U', 180, int) #define USB_SET_CM_OVER_DATA _IOW ('U', 181, int) +/* GPIO control */ +#define USB_GET_GPIO _IOR ('U', 182, int) +#define USB_SET_GPIO _IOW ('U', 183, int) + /* USB file system interface */ #define USB_FS_START _IOW ('U', 192, struct usb_fs_start) #define USB_FS_STOP _IOW ('U', 193, struct usb_fs_stop)