From owner-svn-src-all@FreeBSD.ORG Mon Oct 27 22:44:22 2008 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 C606E106566C; Mon, 27 Oct 2008 22:44:22 +0000 (UTC) (envelope-from n_hibma@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id B26908FC0A; Mon, 27 Oct 2008 22:44:22 +0000 (UTC) (envelope-from n_hibma@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id m9RMiMYC055358; Mon, 27 Oct 2008 22:44:22 GMT (envelope-from n_hibma@svn.freebsd.org) Received: (from n_hibma@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id m9RMiMK6055357; Mon, 27 Oct 2008 22:44:22 GMT (envelope-from n_hibma@svn.freebsd.org) Message-Id: <200810272244.m9RMiMK6055357@svn.freebsd.org> From: Nick Hibma Date: Mon, 27 Oct 2008 22:44:22 +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: r184381 - head/sys/dev/usb 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: Mon, 27 Oct 2008 22:44:22 -0000 Author: n_hibma Date: Mon Oct 27 22:44:22 2008 New Revision: 184381 URL: http://svn.freebsd.org/changeset/base/184381 Log: Grab Sierra and Novatel init functions from NetBSD version of the u3g driver (rev 1.3), by Joerg Sonnenberger. Note: This change is untested as I do not own the hardware. Let me know if things work or do not work for you by sending me the output dmesg (and usbctl -f /dev/usbX if possible). Thanks. Modified: head/sys/dev/usb/u3g.c Modified: head/sys/dev/usb/u3g.c ============================================================================== --- head/sys/dev/usb/u3g.c Mon Oct 27 22:10:01 2008 (r184380) +++ head/sys/dev/usb/u3g.c Mon Oct 27 22:44:22 2008 (r184381) @@ -53,7 +53,7 @@ //#define U3G_DEBUG #ifdef U3G_DEBUG -#define DPRINTF(x...) do { if (u3gdebug) device_printf(self, ##x); } while (0) +#define DPRINTF(x...) do { if (u3gdebug) device_printf(sc->dev, ##x); } while (0) #define DPRINTFN(n, x...) do { if (u3gdebug > (n)) device_printf(self, ##x); } while (0) int u3gdebug = 1; #else @@ -118,8 +118,10 @@ struct u3g_dev_type_s { u_int8_t speed; u_int8_t flags; #define U3GFL_NONE 0x00 -#define U3GFL_HUAWEI_INIT 0x01 // Requires init (Huawei cards) -#define U3GFL_STUB_WAIT 0x02 // Device reappears after a short delay +#define U3GFL_HUAWEI_INIT 0x01 // Requires init command (Huawei cards) +#define U3GFL_SCSI_EJECT 0x02 // Requires SCSI eject command (Novatel) +#define U3GFL_SIERRA_INIT 0x04 // Requires init command (Sierra cards) +#define U3GFL_STUB_WAIT 0x08 // Device reappears after a short delay }; // Note: The entries marked with XXX should be checked for the correct speed @@ -138,22 +140,22 @@ static const struct u3g_dev_type_s u3g_d {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE }, U3GSP_HSDPA, U3GFL_HUAWEI_INIT }, {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 }, U3GSP_HSPA, U3GFL_HUAWEI_INIT }, /* OEM: Novatel */ - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_CDMA_MODEM }, U3GSP_CDMA, U3GFL_STUB_WAIT }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620 }, U3GSP_UMTS, U3GFL_STUB_WAIT }, // XXX - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC950D }, U3GSP_HSUPA, U3GFL_STUB_WAIT }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720 }, U3GSP_UMTS, U3GFL_STUB_WAIT }, // XXX - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U727 }, U3GSP_UMTS, U3GFL_STUB_WAIT }, // XXX - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740 }, U3GSP_HSDPA, U3GFL_STUB_WAIT }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740_2 }, U3GSP_HSDPA, U3GFL_STUB_WAIT }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U870 }, U3GSP_UMTS, U3GFL_STUB_WAIT }, // XXX - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V620 }, U3GSP_UMTS, U3GFL_STUB_WAIT }, // XXX - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V640 }, U3GSP_UMTS, U3GFL_STUB_WAIT }, // XXX - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V720 }, U3GSP_UMTS, U3GFL_STUB_WAIT }, // XXX - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V740 }, U3GSP_HSDPA, U3GFL_STUB_WAIT }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_X950D }, U3GSP_HSUPA, U3GFL_STUB_WAIT }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870 }, U3GSP_HSDPA, U3GFL_STUB_WAIT }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ZEROCD }, U3GSP_HSUPA, U3GFL_STUB_WAIT }, - {{ USB_VENDOR_DELL, USB_PRODUCT_DELL_U740 }, U3GSP_HSDPA, U3GFL_STUB_WAIT }, + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_CDMA_MODEM }, U3GSP_CDMA, U3GFL_SCSI_EJECT }, + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620 }, U3GSP_UMTS, U3GFL_SCSI_EJECT }, // XXX + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC950D }, U3GSP_HSUPA, U3GFL_SCSI_EJECT }, + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720 }, U3GSP_UMTS, U3GFL_SCSI_EJECT }, // XXX + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U727 }, U3GSP_UMTS, U3GFL_SCSI_EJECT }, // XXX + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740 }, U3GSP_HSDPA, U3GFL_SCSI_EJECT }, + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740_2 }, U3GSP_HSDPA, U3GFL_SCSI_EJECT }, + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U870 }, U3GSP_UMTS, U3GFL_SCSI_EJECT }, // XXX + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V620 }, U3GSP_UMTS, U3GFL_SCSI_EJECT }, // XXX + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V640 }, U3GSP_UMTS, U3GFL_SCSI_EJECT }, // XXX + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V720 }, U3GSP_UMTS, U3GFL_SCSI_EJECT }, // XXX + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V740 }, U3GSP_HSDPA, U3GFL_SCSI_EJECT }, + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_X950D }, U3GSP_HSUPA, U3GFL_SCSI_EJECT }, + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870 }, U3GSP_HSDPA, U3GFL_SCSI_EJECT }, + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ZEROCD }, U3GSP_HSUPA, U3GFL_SCSI_EJECT }, + {{ USB_VENDOR_DELL, USB_PRODUCT_DELL_U740 }, U3GSP_HSDPA, U3GFL_SCSI_EJECT }, /* OEM: Merlin */ {{ USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620 }, U3GSP_UMTS, U3GFL_NONE }, // XXX /* OEM: Sierra Wireless: */ @@ -182,6 +184,7 @@ static const struct u3g_dev_type_s u3g_d {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2 }, U3GSP_UMTS, U3GFL_NONE }, // XXX {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780 }, U3GSP_UMTS, U3GFL_NONE }, // XXX {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_TRUINSTALL }, U3GSP_UMTS, U3GFL_SIERRA_INIT }, // Sierra TruInstaller device ID }; #define u3g_lookup(v, p) ((const struct u3g_dev_type_s *)usb_lookup(u3g_devs, v, p)) @@ -423,8 +426,15 @@ MODULE_VERSION(u3g, 1); ****** Stub driver to hide devices that need to reinitialise ****** *******************************************************************/ -static void -u3gstub_huawei_init(usbd_device_handle dev) +struct u3gstub_softc { + device_t sc_dev; + usbd_device_handle sc_udev; + usbd_pipe_handle sc_pipe; + usbd_xfer_handle sc_xfer; +}; + +static int +u3gstub_huawei_init(struct u3gstub_softc *sc, struct usb_attach_arg *uaa) { usb_device_request_t req; @@ -434,7 +444,89 @@ u3gstub_huawei_init(usbd_device_handle d USETW(req.wIndex, UHF_PORT_SUSPEND); USETW(req.wLength, 0); - (void) usbd_do_request(dev, &req, 0); /* ignore any error */ + (void) usbd_do_request(uaa->device, &req, 0); /* ignore any error */ + + return 1; +} + +static int +u3gstub_scsi_eject(struct u3gstub_softc *sc, struct usb_attach_arg *uaa) +{ + unsigned char cmd[31]; +#ifdef U3G_DEBUG + device_t self = uaa->device; +#endif + usb_interface_descriptor_t *id; + usb_endpoint_descriptor_t *ed = NULL; + int i; + + memset(cmd, 0, sizeof(cmd)); + cmd[0] = 0x55; /* Byte 0..3: Command Block Wrapper (CBW) signature */ + cmd[1] = 0x53; + cmd[2] = 0x42; + cmd[3] = 0x43; + cmd[4] = 0x01; /* 4..7: CBW Tag, has to unique, but only a single transfer used. */ + /* 8..11: CBW Transfer Length, no data here */ + /* 12: CBW Flag: output, so 0 */ + /* 13: CBW Lun: 0 */ + /* 14: CBW Length */ + cmd[14] = 0x06; + cmd[15] = 0x1b; /* 0: SCSI START/STOP opcode */ + /* 1..3 unused */ + cmd[15+4] = 0x02; /* 4 Load/Eject command */ + /* 5: unused */ + + + /* Find the bulk-out endpoints */ + id = usbd_get_interface_descriptor(uaa->iface); + for (i = 0 ; i < id->bNumEndpoints ; i++) { + ed = usbd_interface2endpoint_descriptor(uaa->iface, i); + if (ed != NULL + && UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT + && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) + break; + } + + if (i == id->bNumEndpoints) + return 0; + + if (usbd_open_pipe(uaa->iface, ed->bEndpointAddress, + USBD_EXCLUSIVE_USE, &sc->sc_pipe) != USBD_NORMAL_COMPLETION) { + DPRINTF("failed to open bulk-out pipe on endpoint %d\n", + ed->bEndpointAddress); + return 0; + } + + sc->sc_xfer = usbd_alloc_xfer(uaa->device); + if (sc->sc_xfer == NULL) { + DPRINTF("failed to allocate xfer\n"); + return 0; + } + + usbd_setup_xfer(sc->sc_xfer, sc->sc_pipe, NULL, cmd, sizeof(cmd), + 0, USBD_DEFAULT_TIMEOUT, NULL); + if (usbd_transfer(sc->sc_xfer) != USBD_NORMAL_COMPLETION) { + DPRINTF("failed to start transfer\n"); + return 0; + } + + return 1; +} + +static int +u3gstub_sierra_init(struct u3gstub_softc *sc, struct usb_attach_arg *uaa) +{ + usb_device_request_t req; + + req.bmRequestType = UT_VENDOR; + req.bRequest = UR_SET_INTERFACE; + USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP); + USETW(req.wIndex, UHF_PORT_CONNECTION); + USETW(req.wLength, 0); + + (void) usbd_do_request(uaa->device, &req, 0); /* ignore any error */ + + return 1; } static int @@ -457,6 +549,8 @@ u3gstub_match(device_t self) return UMATCH_NONE; if (u3g_dev_type->flags&U3GFL_HUAWEI_INIT + || u3g_dev_type->flags&U3GFL_SIERRA_INIT + || u3g_dev_type->flags&U3GFL_SCSI_EJECT || u3g_dev_type->flags&U3GFL_STUB_WAIT) { /* We assume that if the first interface is still a mass * storage device the device has not yet changed appearance. @@ -472,6 +566,7 @@ u3gstub_match(device_t self) static int u3gstub_attach(device_t self) { + struct u3gstub_softc *sc = device_get_softc(self); struct usb_attach_arg *uaa = device_get_ivars(self); const struct u3g_dev_type_s *u3g_dev_type; int i; @@ -480,16 +575,26 @@ u3gstub_attach(device_t self) device_quiet(self); #endif + sc->sc_dev = self; + sc->sc_udev = uaa->device; + if (uaa->iface) for (i = 0; i < uaa->nifaces; i++) uaa->ifaces[i] = NULL; // claim all interfaces u3g_dev_type = u3g_lookup(uaa->vendor, uaa->product); if (u3g_dev_type->flags&U3GFL_HUAWEI_INIT) { - /* XXX Should we delay the kick? - */ DPRINTF("changing Huawei modem to modem mode\n"); - u3gstub_huawei_init(uaa->device); + if (!u3gstub_huawei_init(sc, uaa)) + return ENXIO; + } else if (u3g_dev_type->flags&U3GFL_SCSI_EJECT) { + DPRINTF("sending CD eject command to change to modem mode \n"); + if (!u3gstub_scsi_eject(sc, uaa)) + return ENXIO; + } else if (u3g_dev_type->flags&U3GFL_SIERRA_INIT) { + DPRINTF("changing Sierra modem to modem mode\n"); + if (!u3gstub_sierra_init(sc, uaa)) + return ENXIO; } else if (u3g_dev_type->flags&U3GFL_STUB_WAIT) { /* nop */ } @@ -500,6 +605,16 @@ u3gstub_attach(device_t self) static int u3gstub_detach(device_t self) { + struct u3gstub_softc *sc = device_get_softc(self); + + if (sc->sc_xfer) + usbd_free_xfer(sc->sc_xfer); + + if (sc->sc_pipe) { + usbd_abort_pipe(sc->sc_pipe); + usbd_close_pipe(sc->sc_pipe); + } + return 0; } @@ -515,7 +630,7 @@ static device_method_t u3gstub_methods[] static driver_t u3gstub_driver = { "u3gstub", u3gstub_methods, - 0 + sizeof (struct u3gstub_softc) }; DRIVER_MODULE(u3gstub, uhub, u3gstub_driver, ucom_devclass, usbd_driver_load, 0);