From owner-svn-src-all@FreeBSD.ORG Fri Jan 9 18:40:13 2015 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id AAB6DC08; Fri, 9 Jan 2015 18:40:13 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 8C127C0C; Fri, 9 Jan 2015 18:40:13 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t09IeD5L011866; Fri, 9 Jan 2015 18:40:13 GMT (envelope-from hselasky@FreeBSD.org) Received: (from hselasky@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t09IeDge011865; Fri, 9 Jan 2015 18:40:13 GMT (envelope-from hselasky@FreeBSD.org) Message-Id: <201501091840.t09IeDge011865@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: hselasky set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky Date: Fri, 9 Jan 2015 18:40:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r276892 - head/sys/dev/usb/serial X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 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: Fri, 09 Jan 2015 18:40:13 -0000 Author: hselasky Date: Fri Jan 9 18:40:12 2015 New Revision: 276892 URL: https://svnweb.freebsd.org/changeset/base/276892 Log: Add support for USB device side mode to the USB modem driver. MFC after: 1 week Submitted by: br@ Modified: head/sys/dev/usb/serial/umodem.c Modified: head/sys/dev/usb/serial/umodem.c ============================================================================== --- head/sys/dev/usb/serial/umodem.c Fri Jan 9 18:09:45 2015 (r276891) +++ head/sys/dev/usb/serial/umodem.c Fri Jan 9 18:40:12 2015 (r276892) @@ -98,6 +98,7 @@ __FBSDID("$FreeBSD$"); #include #include #include "usbdevs.h" +#include "usb_if.h" #include @@ -116,7 +117,7 @@ SYSCTL_INT(_hw_usb_umodem, OID_AUTO, deb &umodem_debug, 0, "Debug level"); #endif -static const STRUCT_USB_HOST_ID umodem_devs[] = { +static const STRUCT_USB_DUAL_ID umodem_dual_devs[] = { /* Generic Modem class match */ {USB_IFACE_CLASS(UICLASS_CDC), USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL), @@ -124,6 +125,9 @@ static const STRUCT_USB_HOST_ID umodem_d {USB_IFACE_CLASS(UICLASS_CDC), USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL), USB_IFACE_PROTOCOL(UIPROTO_CDC_NONE)}, +}; + +static const STRUCT_USB_HOST_ID umodem_host_devs[] = { /* Huawei Modem class match */ {USB_VENDOR(USB_VENDOR_HUAWEI),USB_IFACE_CLASS(UICLASS_CDC), USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL), @@ -145,6 +149,7 @@ static const STRUCT_USB_HOST_ID umodem_d enum { UMODEM_BULK_WR, UMODEM_BULK_RD, + UMODEM_INTR_WR, UMODEM_INTR_RD, UMODEM_N_TRANSFER, }; @@ -169,14 +174,19 @@ struct umodem_softc { uint8_t sc_cm_over_data; uint8_t sc_cm_cap; /* CM capabilities */ uint8_t sc_acm_cap; /* ACM capabilities */ + uint8_t sc_line_coding[32]; /* used in USB device mode */ + uint8_t sc_abstract_state[32]; /* used in USB device mode */ }; static device_probe_t umodem_probe; static device_attach_t umodem_attach; static device_detach_t umodem_detach; +static usb_handle_request_t umodem_handle_request; + static void umodem_free_softc(struct umodem_softc *); -static usb_callback_t umodem_intr_callback; +static usb_callback_t umodem_intr_read_callback; +static usb_callback_t umodem_intr_write_callback; static usb_callback_t umodem_write_callback; static usb_callback_t umodem_read_callback; @@ -207,31 +217,45 @@ static const struct usb_config umodem_co [UMODEM_BULK_WR] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, - .direction = UE_DIR_OUT, + .direction = UE_DIR_TX, .if_index = 0, .bufsize = UMODEM_BUF_SIZE, .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, .callback = &umodem_write_callback, + .usb_mode = USB_MODE_DUAL, }, [UMODEM_BULK_RD] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, - .direction = UE_DIR_IN, + .direction = UE_DIR_RX, .if_index = 0, .bufsize = UMODEM_BUF_SIZE, .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, .callback = &umodem_read_callback, + .usb_mode = USB_MODE_DUAL, + }, + + [UMODEM_INTR_WR] = { + .type = UE_INTERRUPT, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_TX, + .if_index = 1, + .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,}, + .bufsize = 0, /* use wMaxPacketSize */ + .callback = &umodem_intr_write_callback, + .usb_mode = USB_MODE_DEVICE, }, [UMODEM_INTR_RD] = { .type = UE_INTERRUPT, .endpoint = UE_ADDR_ANY, - .direction = UE_DIR_IN, + .direction = UE_DIR_RX, .if_index = 1, .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,}, .bufsize = 0, /* use wMaxPacketSize */ - .callback = &umodem_intr_callback, + .callback = &umodem_intr_read_callback, + .usb_mode = USB_MODE_HOST, }, }; @@ -252,6 +276,10 @@ static const struct ucom_callback umodem }; static device_method_t umodem_methods[] = { + /* USB interface */ + DEVMETHOD(usb_handle_request, umodem_handle_request), + + /* Device interface */ DEVMETHOD(device_probe, umodem_probe), DEVMETHOD(device_attach, umodem_attach), DEVMETHOD(device_detach, umodem_detach), @@ -279,13 +307,14 @@ umodem_probe(device_t dev) DPRINTFN(11, "\n"); - if (uaa->usb_mode != USB_MODE_HOST) - return (ENXIO); - - error = usbd_lookup_id_by_uaa(umodem_devs, sizeof(umodem_devs), uaa); - if (error) - return (error); - + error = usbd_lookup_id_by_uaa(umodem_host_devs, + sizeof(umodem_host_devs), uaa); + if (error) { + error = usbd_lookup_id_by_uaa(umodem_dual_devs, + sizeof(umodem_dual_devs), uaa); + if (error) + return (error); + } return (BUS_PROBE_GENERIC); } @@ -400,18 +429,22 @@ umodem_attach(device_t dev) umodem_config, UMODEM_N_TRANSFER, sc, &sc->sc_mtx); if (error) { + device_printf(dev, "Can't setup transfer\n"); goto detach; } - /* clear stall at first run */ - mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[UMODEM_BULK_WR]); - usbd_xfer_set_stall(sc->sc_xfer[UMODEM_BULK_RD]); - mtx_unlock(&sc->sc_mtx); + /* clear stall at first run, if USB host mode */ + if (uaa->usb_mode == USB_MODE_HOST) { + mtx_lock(&sc->sc_mtx); + usbd_xfer_set_stall(sc->sc_xfer[UMODEM_BULK_WR]); + usbd_xfer_set_stall(sc->sc_xfer[UMODEM_BULK_RD]); + mtx_unlock(&sc->sc_mtx); + } error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, &umodem_callback, &sc->sc_mtx); if (error) { + device_printf(dev, "Can't attach com\n"); goto detach; } ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); @@ -482,6 +515,7 @@ umodem_start_write(struct ucom_softc *uc { struct umodem_softc *sc = ucom->sc_parent; + usbd_transfer_start(sc->sc_xfer[UMODEM_INTR_WR]); usbd_transfer_start(sc->sc_xfer[UMODEM_BULK_WR]); } @@ -490,6 +524,7 @@ umodem_stop_write(struct ucom_softc *uco { struct umodem_softc *sc = ucom->sc_parent; + usbd_transfer_stop(sc->sc_xfer[UMODEM_INTR_WR]); usbd_transfer_stop(sc->sc_xfer[UMODEM_BULK_WR]); } @@ -684,7 +719,34 @@ umodem_cfg_set_break(struct ucom_softc * } static void -umodem_intr_callback(struct usb_xfer *xfer, usb_error_t error) +umodem_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) +{ + int actlen; + + usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + + DPRINTF("Transferred %d bytes\n", actlen); + + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + break; + + default: /* Error */ + if (error != USB_ERR_CANCELLED) { + /* start clear stall */ + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + break; + } +} + +static void +umodem_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct usb_cdc_notification pkt; struct umodem_softc *sc = usbd_xfer_softc(xfer); @@ -906,3 +968,56 @@ umodem_poll(struct ucom_softc *ucom) struct umodem_softc *sc = ucom->sc_parent; usbd_transfer_poll(sc->sc_xfer, UMODEM_N_TRANSFER); } + +static int +umodem_handle_request(device_t dev, + const void *preq, void **pptr, uint16_t *plen, + uint16_t offset, uint8_t *pstate) +{ + struct umodem_softc *sc = device_get_softc(dev); + const struct usb_device_request *req = preq; + uint8_t is_complete = *pstate; + + DPRINTF("sc=%p\n", sc); + + if (!is_complete) { + if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && + (req->bRequest == UCDC_SET_LINE_CODING) && + (req->wIndex[0] == sc->sc_ctrl_iface_no) && + (req->wIndex[1] == 0x00) && + (req->wValue[0] == 0x00) && + (req->wValue[1] == 0x00)) { + if (offset == 0) { + *plen = sizeof(sc->sc_line_coding); + *pptr = &sc->sc_line_coding; + } else { + *plen = 0; + } + return (0); + } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && + (req->wIndex[0] == sc->sc_ctrl_iface_no) && + (req->wIndex[1] == 0x00) && + (req->bRequest == UCDC_SET_COMM_FEATURE)) { + if (offset == 0) { + *plen = sizeof(sc->sc_abstract_state); + *pptr = &sc->sc_abstract_state; + } else { + *plen = 0; + } + return (0); + } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && + (req->wIndex[0] == sc->sc_ctrl_iface_no) && + (req->wIndex[1] == 0x00) && + (req->bRequest == UCDC_SET_CONTROL_LINE_STATE)) { + *plen = 0; + return (0); + } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && + (req->wIndex[0] == sc->sc_ctrl_iface_no) && + (req->wIndex[1] == 0x00) && + (req->bRequest == UCDC_SEND_BREAK)) { + *plen = 0; + return (0); + } + } + return (ENXIO); /* use builtin handler */ +}