From owner-svn-src-all@FreeBSD.ORG Wed Oct 15 21:25:12 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 4B69E106568F; Wed, 15 Oct 2008 21:25:12 +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 37A128FC0C; Wed, 15 Oct 2008 21:25:12 +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 m9FLPC4m043717; Wed, 15 Oct 2008 21:25:12 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 m9FLPC0H043714; Wed, 15 Oct 2008 21:25:12 GMT (envelope-from n_hibma@svn.freebsd.org) Message-Id: <200810152125.m9FLPC0H043714@svn.freebsd.org> From: Nick Hibma Date: Wed, 15 Oct 2008 21:25:12 +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: r183925 - 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: Wed, 15 Oct 2008 21:25:12 -0000 Author: n_hibma Date: Wed Oct 15 21:25:11 2008 New Revision: 183925 URL: http://svn.freebsd.org/changeset/base/183925 Log: Rewrite the driver to better support the Huawei devices. It should now support the Sierra and Novatel devices, ignore all umass devices and hide the umass devices that represent the CD ROM devices (but not the SD card slot in the Huawei Mobile dongle). Note: This driver in FBSD7 seems to suffer from memory corruption when used with an Option GT Quad. The E220 however works flawlessly. Also add the ID for the Option GTMaxHSUPA, provided by Olivier Fromme. Modified: head/sys/dev/usb/u3g.c head/sys/dev/usb/ubsa.c head/sys/dev/usb/usbdevs Modified: head/sys/dev/usb/u3g.c ============================================================================== --- head/sys/dev/usb/u3g.c Wed Oct 15 20:44:00 2008 (r183924) +++ head/sys/dev/usb/u3g.c Wed Oct 15 21:25:11 2008 (r183925) @@ -19,6 +19,14 @@ * $FreeBSD$ */ +/* + * Notes: + * - The detour through the tty layer is ridiculously expensive wrt buffering + * due to the high speeds. + * We should consider adding a simple r/w device which allows attaching of PPP + * in a more efficient way. + */ + #include #include #include @@ -40,43 +48,39 @@ #include "usbdevs.h" +#define U3G_DEBUG 1 #ifdef U3G_DEBUG -#define DPRINTFN(n, x) do { if (u3gdebug > (n)) printf x; } while (0) -int u3gtebug = 0; +#define DPRINTF(x...) do { if (u3gdebug) device_printf(self, ##x); } while (0) +#define DPRINTFN(n, x...) do { if (u3gdebug > (n)) device_printf(self, ##x); } while (0) +int u3gdebug = 1; #else -#define DPRINTFN(n, x) +#define DPRINTF(x...) /* nop */ +#define DPRINTFN(n, x...) /* nop */ #endif -#define DPRINTF(x) DPRINTFN(0, x) -#define U3G_BUFSIZ 1024 +#define U3G_BUFSIZ 10240 #define U3G_MAXPORTS 4 #define U3G_CONFIG_INDEX 0 struct u3g_softc { - struct ucom_softc sc_ucom[U3G_MAXPORTS];; + struct ucom_softc sc_ucom[U3G_MAXPORTS]; device_t sc_dev; usbd_device_handle sc_udev; - u_int16_t sc_flags; - u_char sc_msr; - u_char sc_lsr; - u_char numports; - - usbd_interface_handle sc_intr_iface; /* interrupt interface */ -#ifdef U3G_DEBUG - int sc_intr_number; /* interrupt number */ - usbd_pipe_handle sc_intr_pipe; /* interrupt pipe */ - u_char *sc_intr_buf; /* interrupt buffer */ -#endif - int sc_isize; + u_int8_t sc_speed; + u_int8_t sc_flags; + u_char sc_numports; }; +static int u3g_open(void *addr, int portno); +static void u3g_close(void *addr, int portno); + struct ucom_callback u3g_callback = { NULL, NULL, NULL, NULL, - NULL, - NULL, + u3g_open, + u3g_close, NULL, NULL, }; @@ -86,81 +90,106 @@ struct ucom_callback u3g_callback = { * Various supported device vendors/products. */ struct u3g_dev_type_s { - struct usb_devno u3g_dev; - u_int16_t u3g_flags; -#define U3GFL_NONE 0x0000 -#define U3GFL_HUAWEI_INIT 0x0001 /* Send USB command to reset iface to ucom mode */ + struct usb_devno devno; + u_int8_t speed; +#define U3GSP_GPRS 1 +#define U3GSP_EDGE 2 +#define U3GSP_UMTS 3 +#define U3GSP_HSDPA 4 +#define U3GSP_HSUPA 5 +#define U3GSP_HSPA 6 + + 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 }; static const struct u3g_dev_type_s u3g_devs[] = { /* OEM: Option */ - {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3G }, U3GFL_NONE }, - {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GQUAD }, U3GFL_NONE }, - {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GPLUS }, U3GFL_NONE }, - {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAX36 }, U3GFL_NONE }, - {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_VODAFONEMC3G }, U3GFL_NONE }, + {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3G }, U3GSP_UMTS, U3GFL_NONE }, + {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GQUAD }, U3GSP_UMTS, U3GFL_NONE }, + {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GPLUS }, U3GSP_UMTS, U3GFL_NONE }, + {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAX36 }, U3GSP_HSDPA, U3GFL_NONE }, + {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAXHSUPA }, U3GSP_HSDPA, U3GFL_NONE }, + {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_VODAFONEMC3G }, U3GSP_UMTS, U3GFL_NONE }, /* OEM: Qualcomm, Inc. */ - {{ USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM }, U3GFL_NONE }, + {{ USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM }, U3GSP_UMTS, U3GFL_STUB_WAIT }, // XXX /* OEM: Huawei */ - /* Handled separately. Do not add! - {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE }, U3GFL_NONE }, - {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 }, U3GFL_NONE }, - */ + {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE }, U3GSP_HSDPA, U3GFL_HUAWEI_INIT }, + {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 }, U3GSP_HSDPA, U3GFL_HUAWEI_INIT }, /* OEM: Novatel */ - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_CDMA_MODEM }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620 }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC950D }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720 }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U727 }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740 }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740_2 }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U870 }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V620 }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V640 }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V720 }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V740 }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_X950D }, U3GFL_NONE }, - {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870 }, U3GFL_NONE }, - {{ USB_VENDOR_DELL, USB_PRODUCT_DELL_U740 }, U3GFL_NONE }, + {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_CDMA_MODEM }, U3GSP_UMTS, U3GFL_STUB_WAIT }, // XXX + {{ 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_DELL, USB_PRODUCT_DELL_U740 }, U3GSP_HSDPA, U3GFL_STUB_WAIT }, + /* OEM: Merlin */ + {{ USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + /* OEM: Sierra Wireless: */ + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U }, U3GSP_UMTS, U3GFL_NONE }, // XXX + {{ 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 }; #define u3g_lookup(v, p) ((const struct u3g_dev_type_s *)usb_lookup(u3g_devs, v, p)) -#ifdef U3G_DEBUG -static void -u3g_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) -{ - struct u3g_softc *sc = (struct u3g_softc *)priv; - device_printf(sc->sc_dev, "Interrupt callback\n"); -} -#endif - static int u3g_match(device_t self) { struct usb_attach_arg *uaa = device_get_ivars(self); - usb_interface_descriptor_t *id; const struct u3g_dev_type_s *u3g_dev_type; - if (uaa->vendor == USB_VENDOR_HUAWEI) { - if (uaa->iface) { - /* We attach to the interface instead of the device as - * some devices have a built-in SD card reader on the - * second interface. If the interface class of the - * first interface is no longer mass storage it has - * changed appearance and we should attach it. - */ - id = usbd_get_interface_descriptor(uaa->iface); - if (id && id->bInterfaceClass == UICLASS_VENDOR) - return (UMATCH_VENDOR_PRODUCT_CONF_IFACE); - } + if (!uaa->iface) return UMATCH_NONE; - } u3g_dev_type = u3g_lookup(uaa->vendor, uaa->product); - if (u3g_dev_type) - return UMATCH_VENDOR_PRODUCT; + if (!u3g_dev_type) + return UMATCH_NONE; - return UMATCH_NONE; + if (u3g_dev_type->flags&U3GFL_HUAWEI_INIT) { + /* If the interface class of the first interface is no longer + * mass storage the card has changed to modem (see u3g_attach() + * below). + */ + usb_interface_descriptor_t *id; + id = usbd_get_interface_descriptor(uaa->iface); + if (!id || id->bInterfaceClass == UICLASS_MASS) + return UMATCH_NONE; + } + + return UMATCH_VENDOR_PRODUCT_CONF_IFACE; } static int @@ -168,120 +197,105 @@ u3g_attach(device_t self) { struct u3g_softc *sc = device_get_softc(self); struct usb_attach_arg *uaa = device_get_ivars(self); + const struct u3g_dev_type_s *u3g_dev_type; usbd_device_handle dev = uaa->device; - usbd_interface_handle iface; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; - usbd_status error; int i, n; usb_config_descriptor_t *cd; - struct ucom_softc *ucom = NULL; char devnamefmt[32]; - sc->sc_dev = self; -#ifdef U3G_DEBUG - sc->sc_intr_number = -1; - sc->sc_intr_pipe = NULL; -#endif - /* Move the device into the configured state. */ - error = usbd_set_config_index(dev, U3G_CONFIG_INDEX, 1); - if (error) { - device_printf(self, "failed to set configuration: %s\n", - usbd_errstr(error)); - goto bad; - } - /* get the config descriptor */ cd = usbd_get_config_descriptor(dev); - if (cd == NULL) { device_printf(self, "failed to get configuration descriptor\n"); - goto bad; + return ENXIO; } + sc->sc_dev = self; sc->sc_udev = dev; - sc->numports = (cd->bNumInterface <= U3G_MAXPORTS)?cd->bNumInterface:U3G_MAXPORTS; - for ( i = 0; i < sc->numports; i++ ) { - ucom = &sc->sc_ucom[i]; - - ucom->sc_dev = self; - ucom->sc_udev = dev; - error = usbd_device2interface_handle(dev, i, &iface); - if (error) { - device_printf(ucom->sc_dev, - "failed to get interface, err=%s\n", - usbd_errstr(error)); - ucom->sc_dying = 1; - goto bad; + + u3g_dev_type = u3g_lookup(uaa->vendor, uaa->product); + sc->sc_flags = u3g_dev_type->flags; + sc->sc_speed = u3g_dev_type->speed; + + sprintf(devnamefmt,"U%d.%%d", device_get_unit(self)); + int portno = 0; + for (i = 0; i < uaa->nifaces && portno < U3G_MAXPORTS; i++) { + if (uaa->ifaces[i] == NULL) + continue; + + id = usbd_get_interface_descriptor(uaa->ifaces[i]); + if (id && id->bInterfaceClass == UICLASS_MASS) { + /* We attach to the interface instead of the device as + * some devices have a built-in SD card reader. + * Claim the first umass device (cdX) as it contains + * only Windows drivers anyway (CD-ROM), hiding it. + */ +#ifndef U3G_DEBUG + if (!bootverbose) + if (uaa->vendor == USB_VENDOR_HUAWEI) + if (id->bInterfaceNumber == 2) + uaa->ifaces[i] = NULL; +#endif + continue; } - id = usbd_get_interface_descriptor(iface); - ucom->sc_iface = iface; - ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1; + int bulkin_no = -1, bulkout_no = -1; for (n = 0; n < id->bNumEndpoints; n++) { - ed = usbd_interface2endpoint_descriptor(iface, n); - if (ed == NULL) { - device_printf(ucom->sc_dev, - "could not read endpoint descriptor\n"); - goto bad; - } + ed = usbd_interface2endpoint_descriptor(uaa->ifaces[i], n); + if (ed == NULL) + continue; if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) - ucom->sc_bulkin_no = ed->bEndpointAddress; + bulkin_no = ed->bEndpointAddress; else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) - ucom->sc_bulkout_no = ed->bEndpointAddress; - } - if (ucom->sc_bulkin_no == -1 || ucom->sc_bulkout_no == -1) { - device_printf(ucom->sc_dev, "missing endpoint\n"); - goto bad; - } - ucom->sc_parent = sc; - ucom->sc_ibufsize = U3G_BUFSIZ; - ucom->sc_obufsize = U3G_BUFSIZ; - ucom->sc_ibufsizepad = U3G_BUFSIZ; - ucom->sc_opkthdrlen = 0; - - ucom->sc_callback = &u3g_callback; - - sprintf(devnamefmt,"U%d.%%d", device_get_unit(self)); - DPRINTF(("u3g: in=0x%x out=0x%x, devname=%s\n", - ucom->sc_bulkin_no, ucom->sc_bulkout_no, devnamefmt)); + bulkout_no = ed->bEndpointAddress; + + /* If we have found a pair of bulk-in/-out endpoints + * create a serial port for it. Note: We assume that + * the bulk-in and bulk-out endpoints appear in pairs. + */ + if (bulkin_no != -1 && bulkout_no != -1) { + struct ucom_softc *ucom = &sc->sc_ucom[portno]; + + ucom->sc_dev = self; + ucom->sc_udev = dev; + ucom->sc_iface = uaa->ifaces[i]; + ucom->sc_bulkin_no = bulkin_no; + ucom->sc_ibufsize = U3G_BUFSIZ; + ucom->sc_ibufsizepad = U3G_BUFSIZ; // XXX What's this? + ucom->sc_bulkout_no = bulkout_no; + ucom->sc_obufsize = U3G_BUFSIZ; + ucom->sc_opkthdrlen = 0; + + ucom->sc_callback = &u3g_callback; + ucom->sc_parent = sc; + ucom->sc_portno = portno; + + DPRINTF("port=%d iface=%d in=0x%x out=0x%x\n", + portno, i, + ucom->sc_bulkin_no, + ucom->sc_bulkout_no); #if __FreeBSD_version < 800000 - ucom_attach_tty(ucom, TS_CALLOUT, devnamefmt, i); + ucom_attach_tty(ucom, TS_CALLOUT, devnamefmt, portno); #else - ucom_attach_tty(ucom, devnamefmt, i); + ucom_attach_tty(ucom, devnamefmt, portno); #endif - } -#ifdef U3G_DEBUG - if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) { - sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); - error = usbd_open_pipe_intr(sc->sc_intr_iface, - sc->sc_intr_number, - USBD_SHORT_XFER_OK, - &sc->sc_intr_pipe, - sc, - sc->sc_intr_buf, - sc->sc_isize, - u3g_intr, - 100); - if (error) { - device_printf(self, - "cannot open interrupt pipe (addr %d)\n", - sc->sc_intr_number); - goto bad; + + uaa->ifaces[i] = NULL; + portno++; + bulkin_no = bulkout_no = -1; + } } + } -#endif - device_printf(self, "configured %d serial ports (/dev/cuaU%d.X)\n", - sc->numports, device_get_unit(self)); + sc->sc_numports = portno; + device_printf(self, "configured %d serial ports (%s)\n", + sc->sc_numports, devnamefmt); return 0; - -bad: - DPRINTF(("u3g_attach: ATTACH ERROR\n")); - ucom->sc_dying = 1; - return ENXIO; } static int @@ -291,39 +305,98 @@ u3g_detach(device_t self) int rv = 0; int i; - DPRINTF(("u3g_detach: sc=%p\n", sc)); - - for (i = 0; i < sc->numports; i++) { - if(sc->sc_ucom[i].sc_udev) { - sc->sc_ucom[i].sc_dying = 1; - rv = ucom_detach(&sc->sc_ucom[i]); - if(rv != 0) { - device_printf(self, "Can't deallocat port %d\n", i); - return rv; - } + for (i = 0; i < sc->sc_numports; i++) { + sc->sc_ucom[i].sc_dying = 1; + rv = ucom_detach(&sc->sc_ucom[i]); + if (rv != 0) { + device_printf(self, "ucom_detach(U%d.%d\n", device_get_unit(self), i); + return rv; } } + return 0; +} + +static int +u3g_open(void *addr, int portno) +{ +#if __FreeBSD_version < 800000 + /* Supply generous buffering for these cards to avoid disappointments + * when setting the speed incorrectly. Only do this for the first port + * assuming that the rest of the ports are used for diagnostics only + * anyway. + * Note: We abuse the fact that ucom sets the speed through + * ispeed/ospeed, not through ispeedwat/ospeedwat. + */ + if (portno == 0) { + struct u3g_softc *sc = addr; + struct ucom_softc *ucom = &sc->sc_ucom[portno]; + struct tty *tp = ucom->sc_tty; #ifdef U3G_DEBUG - if (sc->sc_intr_pipe != NULL) { - int err = usbd_abort_pipe(sc->sc_intr_pipe); - if (err) - device_printf(self, - "abort interrupt pipe failed: %s\n", - usbd_errstr(err)); - err = usbd_close_pipe(sc->sc_intr_pipe); - if (err) - device_printf(self, - "close interrupt pipe failed: %s\n", - usbd_errstr(err)); - free(sc->sc_intr_buf, M_USBDEV); - sc->sc_intr_pipe = NULL; + device_t self = sc->sc_dev; +#endif + + if (sc->sc_speed&U3GSP_HSPA) { + tp->t_ispeedwat = 7200000; + tp->t_ospeedwat = 384000; + } else if (sc->sc_speed&U3GSP_HSUPA) { + tp->t_ispeedwat = 1200000; + tp->t_ospeedwat = 384000; + } else if (sc->sc_speed&U3GSP_HSDPA) { + tp->t_ispeedwat = 1200000; + tp->t_ospeedwat = 384000; + } else if (sc->sc_speed&U3GSP_UMTS) { + tp->t_ispeedwat = 384000; + tp->t_ospeedwat = 64000; + } else if (sc->sc_speed&U3GSP_EDGE) { + tp->t_ispeedwat = 384000; + tp->t_ospeedwat = 64000; + } else { + tp->t_ispeedwat = 64000; + tp->t_ospeedwat = 64000; + } + + /* Avoid excessive buffer sizes. On modern fast machines this is + * not needed. + * XXX The values here should be checked. Lower them and see + * whether 'lost chars' messages appear. + */ + if (tp->t_ispeedwat > 384000) + tp->t_ispeedwat = 384000; + if (tp->t_ospeedwat > 384000) + tp->t_ospeedwat = 384000; + + DPRINTF("ispeedwat = %d, ospeedwat = %d\n", + tp->t_ispeedwat, tp->t_ospeedwat); + ttsetwater(tp); } #endif return 0; } +static void +u3g_close(void *addr, int portno) +{ +#if __FreeBSD_version < 800000 + if (portno == 0) { /* see u3g_open() */ + /* Reduce the buffers allocated above again */ + struct u3g_softc *sc = addr; + struct ucom_softc *ucom = &sc->sc_ucom[portno]; + struct tty *tp = ucom->sc_tty; +#ifdef U3G_DEBUG + device_t self = sc->sc_dev; +#endif + + tp->t_ispeedwat = (speed_t)-1; + tp->t_ospeedwat = (speed_t)-1; + + DPRINTF("ispeedwat = default, ospeedwat = default\n"); + ttsetwater(tp); + } +#endif +} + static device_method_t u3g_methods[] = { /* Device interface */ DEVMETHOD(device_probe, u3g_match), @@ -365,32 +438,29 @@ static int u3gstub_match(device_t self) { struct usb_attach_arg *uaa = device_get_ivars(self); - usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device); + const struct u3g_dev_type_s *u3g_dev_type; usb_interface_descriptor_t *id; - /* These are 3G modem devices (E220, Mobile, etc.) with auto-install - * flash disks for Windows/MacOSX through the first interface. + /* This stub handles 3G modem devices (E220, Mobile, etc.) with + * auto-install flash disks for Windows/MacOSX on the first interface. + * After some command or some delay they change appearance to a modem. */ - if (uaa->vendor == USB_VENDOR_HUAWEI) { - /* The Huawei device presents itself as a umass device with - * Windows drivers on it. After installation of the driver, it - * reinits into a 3G serial device. - */ - if (uaa->iface) { - id = usbd_get_interface_descriptor(uaa->iface); - if (id && id->bInterfaceNumber == 0 && id->bInterfaceClass == UICLASS_MASS) { - u3gstub_huawei_init(uaa->device); - return (UMATCH_VENDOR_PRODUCT_CONF_IFACE); - } - } - } - if (UGETW(dd->idVendor) == USB_VENDOR_QUALCOMMINC - || UGETW(dd->idVendor) == USB_VENDOR_NOVATEL) { - /* Device by these vendors will automatically reappear as a - * ucom device if ignored (or if sent an eject command). + if (!uaa->iface) + return UMATCH_NONE; + + u3g_dev_type = u3g_lookup(uaa->vendor, uaa->product); + if (!u3g_dev_type) + return UMATCH_NONE; + + if (u3g_dev_type->flags&U3GFL_HUAWEI_INIT + || 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. */ - return UMATCH_VENDOR_PRODUCT; + id = usbd_get_interface_descriptor(uaa->iface); + if (id && id->bInterfaceNumber == 0 && id->bInterfaceClass == UICLASS_MASS) + return UMATCH_VENDOR_PRODUCT; } return UMATCH_NONE; @@ -399,11 +469,28 @@ u3gstub_match(device_t self) static int u3gstub_attach(device_t self) { -#if 0 - if (!bootverbose) + struct usb_attach_arg *uaa = device_get_ivars(self); + const struct u3g_dev_type_s *u3g_dev_type; + int i; +#ifndef U3G_DEBUG + if (!bootverbose) // hide the stub attachment device_quiet(self); #endif + 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); + } else if (u3g_dev_type->flags&U3GFL_STUB_WAIT) { + /* nop */ + } + return 0; } Modified: head/sys/dev/usb/ubsa.c ============================================================================== --- head/sys/dev/usb/ubsa.c Wed Oct 15 20:44:00 2008 (r183924) +++ head/sys/dev/usb/ubsa.c Wed Oct 15 21:25:11 2008 (r183925) @@ -226,52 +226,6 @@ static const struct ubsa_product { { USB_VENDOR_GOHUBS, USB_PRODUCT_GOHUBS_GOCOM232 }, /* Peracom */ { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_SERIAL1 }, - /* Merlin */ - { USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620 }, - /* Sierra Wireless AirCard 580 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 }, - /* Sierra Wireless AirCard 595 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595 }, - /* Sierra Wireless AirCard 595U */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U }, - /* Sierra Wireless AirCard 597E */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E }, - /* Sierra Wireless Compass 597 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597 }, - /* Sierra Wireless AirCard 880 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880 }, - /* Sierra Wireless AirCard 880E */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E }, - /* Sierra Wireless AirCard 880U */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U }, - /* Sierra Wireless AirCard 881 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881 }, - /* Sierra Wireless AirCard 881E */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E }, - /* Sierra Wireless AirCard 881U */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U }, - /* Sierra Wireless EM5625 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 }, - /* Sierra Wireless MC5720 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 }, - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2 }, - /* Sierra Wireless MC5725 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 }, - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725 }, - /* Sierra Wireless MC8755 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875 }, - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 }, - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 }, - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 }, - /* Sierra Wireless MC8765 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 }, - /* Sierra Wireless MC8775 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U }, - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2 }, - /* Sierra Wireless MC8780 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780 }, - /* Sierra Wireless MC8781 */ - { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781 }, { 0, 0 } }; Modified: head/sys/dev/usb/usbdevs ============================================================================== --- head/sys/dev/usb/usbdevs Wed Oct 15 20:44:00 2008 (r183924) +++ head/sys/dev/usb/usbdevs Wed Oct 15 21:25:11 2008 (r183925) @@ -1872,6 +1872,7 @@ product OPTION GT3G 0x6000 GlobeTrotter product OPTION GT3GQUAD 0x6300 GlobeTrotter 3G QUAD datacard product OPTION GT3GPLUS 0x6600 GlobeTrotter 3G+ datacard product OPTION GTMAX36 0x6701 GlobeTrotter Max 3.6 Modem +product OPTION GTMAXHSUPA 0x7001 GlobeTrotter HSUPA /* OQO */ product OQO WIFI01 0x0002 model 01 WiFi interface