From owner-freebsd-usb@FreeBSD.ORG Sun Oct 14 15:10:02 2007 Return-Path: Delivered-To: freebsd-usb@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 9ED9F16A421 for ; Sun, 14 Oct 2007 15:10:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 4105213C481 for ; Sun, 14 Oct 2007 15:10:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.1/8.14.1) with ESMTP id l9EFA19V009267 for ; Sun, 14 Oct 2007 15:10:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.1/8.14.1/Submit) id l9EFA1F1009266; Sun, 14 Oct 2007 15:10:01 GMT (envelope-from gnats) Resent-Date: Sun, 14 Oct 2007 15:10:01 GMT Resent-Message-Id: <200710141510.l9EFA1F1009266@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-usb@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Eugene Grosbein Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 30C9B16A417 for ; Sun, 14 Oct 2007 15:06:09 +0000 (UTC) (envelope-from eugen@grosbein.pp.ru) Received: from grosbein.pp.ru (grgw.svzserv.kemerovo.su [213.184.64.166]) by mx1.freebsd.org (Postfix) with ESMTP id 3C59713C47E for ; Sun, 14 Oct 2007 15:06:07 +0000 (UTC) (envelope-from eugen@grosbein.pp.ru) Received: from grosbein.pp.ru (localhost [127.0.0.1]) by grosbein.pp.ru (8.14.1/8.14.1) with ESMTP id l9EF66Q1001549 for ; Sun, 14 Oct 2007 23:06:06 +0800 (KRAST) (envelope-from eugen@grosbein.pp.ru) Received: (from eugen@localhost) by grosbein.pp.ru (8.14.1/8.14.1/Submit) id l9EF66X2001548; Sun, 14 Oct 2007 23:06:06 +0800 (KRAST) (envelope-from eugen) Message-Id: <200710141506.l9EF66X2001548@grosbein.pp.ru> Date: Sun, 14 Oct 2007 23:06:06 +0800 (KRAST) From: Eugene Grosbein To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: Subject: usb/117185: [umodem] Add support for UNION interface descriptor X-BeenThere: freebsd-usb@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Eugene Grosbein List-Id: FreeBSD support for USB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 14 Oct 2007 15:10:02 -0000 >Number: 117185 >Category: usb >Synopsis: [umodem] Add support for UNION interface descriptor >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-usb >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Sun Oct 14 15:10:01 UTC 2007 >Closed-Date: >Last-Modified: >Originator: Eugene Grosbein >Release: FreeBSD 7.0-PRERELEASE i386 >Organization: Svyaz-Service >Environment: System: FreeBSD grosbein.pp.ru 7.0-PRERELEASE FreeBSD 7.0-PRERELEASE #1: Sun Oct 14 20:41:31 KRAST 2007 eu@grosbein.pp.ru:/usr/local/obj/usr/local/src/sys/DADV i386 >Description: Currently, umodem(4) does not attach USB modems not having CM interface descriptor but having UNION interface descriptor instead. Examples are Nokia smartphones like E50, N73 etc. >How-To-Repeat: Attach Nokia E50 using its USB data cable (choose 'PC Suite mode') and see that it's detected as 'ugen' device. >Fix: The following patch teaches umodem(4) to use UNION descriptor, it creates /dev/cuaU0 device node that works just fine for PPP over GPRS. This obsoletes usb/91546 containing incomplete patch by PR originator and version of this patch for 6.2-STABLE by me. --- sys/dev/usb/umodem.c.orig 2007-10-14 20:51:58.000000000 +0800 +++ sys/dev/usb/umodem.c 2007-10-14 21:03:58.000000000 +0800 @@ -172,13 +172,14 @@ struct task sc_task; }; -static void *umodem_get_desc(usbd_device_handle dev, int type, int subtype); +static void *umodem_get_desc(usbd_device_handle dev, usb_descriptor_t *, int type, int subtype); +static usbd_interface_handle umodem_get_interface(struct usb_attach_arg *uaa, int ifcno); static usbd_status umodem_set_comm_feature(struct umodem_softc *sc, int feature, int state); static usbd_status umodem_set_line_coding(struct umodem_softc *sc, usb_cdc_line_state_t *state); -static void umodem_get_caps(usbd_device_handle, int *, int *); +static int umodem_get_caps(struct usb_attach_arg *, int, int *, int *); static void umodem_get_status(void *, int portno, u_char *lsr, u_char *msr); static void umodem_set(void *, int, int, int); @@ -262,10 +263,7 @@ if (ret == UMATCH_NONE) return (ret); - umodem_get_caps(uaa->device, &cm, &acm); - if (!(cm & USB_CDC_CM_DOES_CM) || - !(cm & USB_CDC_CM_OVER_DATA) || - !(acm & USB_CDC_ACM_HAS_LINE)) + if (umodem_get_caps(uaa, -1, &cm, &acm) == -1) return (UMATCH_NONE); return ret; @@ -279,7 +277,6 @@ usbd_device_handle dev = uaa->device; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; - usb_cdc_cm_descriptor_t *cmd; int data_ifcno; int i; struct ucom_softc *ucom; @@ -297,15 +294,14 @@ device_printf(self, "iclass %d/%d\n", id->bInterfaceClass, id->bInterfaceSubClass); - umodem_get_caps(dev, &sc->sc_cm_cap, &sc->sc_acm_cap); - /* Get the data interface no. */ - cmd = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); - if (cmd == NULL) { - device_printf(sc->sc_dev, "no CM descriptor\n"); + sc->sc_data_iface_no = data_ifcno = + umodem_get_caps(uaa, sc->sc_ctl_iface_no, &sc->sc_cm_cap, &sc->sc_acm_cap); + + if (data_ifcno == -1) { + device_printf(sc->sc_dev,"%s: no pointer to data interface\n"); goto bad; } - sc->sc_data_iface_no = data_ifcno = cmd->bDataInterface; device_printf(sc->sc_dev, "data interface %d, has %sCM over data, has %sbreak\n", @@ -530,27 +526,50 @@ ucom_status_change(&sc->sc_ucom); } -void -umodem_get_caps(usbd_device_handle dev, int *cm, int *acm) +static int +umodem_get_caps(struct usb_attach_arg *uaa, int ctl_iface_no, int *cm, int *acm) { usb_cdc_cm_descriptor_t *cmd; usb_cdc_acm_descriptor_t *cad; + usb_cdc_union_descriptor_t *cud; + usbd_device_handle dev = uaa->device; + usbd_interface_handle iface; + int iface_no = 0; *cm = *acm = 0; - cmd = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); + cmd = umodem_get_desc(dev, NULL, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); if (cmd == NULL) { DPRINTF(("umodem_get_desc: no CM desc\n")); - return; + } else { + *cm = cmd->bmCapabilities; } - *cm = cmd->bmCapabilities; - cad = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM); + cad = umodem_get_desc(dev, NULL, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM); if (cad == NULL) { DPRINTF(("umodem_get_desc: no ACM desc\n")); - return; + } else { + *acm = cad->bmCapabilities; + } + + cud = NULL; + while ((cud = umodem_get_desc(dev, (usb_descriptor_t *)cud, + UDESC_CS_INTERFACE, UDESCSUB_CDC_UNION))) + { + iface_no = cud->bSlaveInterface[0]; + if (ctl_iface_no == -1) + break; + + iface = umodem_get_interface(uaa,iface_no); + if (ctl_iface_no == cud->bMasterInterface && + usbd_get_interface_descriptor(iface)->bNumEndpoints >= 2) + break; + } + if (cud == NULL) { + DPRINTF(("umodem_get_caps: no UNION desc\n")); } - *acm = cad->bmCapabilities; + + return cmd ? cmd->bDataInterface : cud ? iface_no : -1; } void @@ -566,6 +585,23 @@ *msr = sc->sc_msr; } +static usbd_interface_handle +umodem_get_interface(struct usb_attach_arg *uaa, int ifcno) +{ + int i; + usb_interface_descriptor_t *id; + + for (i = 0; i < uaa->nifaces; i++) { + if (uaa->ifaces[i] != NULL) { + id = usbd_get_interface_descriptor(uaa->ifaces[i]); + if (id != NULL && id->bInterfaceNumber == ifcno) { + return uaa->ifaces[i]; + } + } + } + return NULL; +} + int umodem_param(void *addr, int portno, struct termios *t) { @@ -756,14 +792,17 @@ return (USBD_NORMAL_COMPLETION); } -void * -umodem_get_desc(usbd_device_handle dev, int type, int subtype) +static void * +umodem_get_desc(usbd_device_handle dev, usb_descriptor_t *restart, int type, int subtype) { usb_descriptor_t *desc; usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev); uByte *p = (uByte *)cd; uByte *end = p + UGETW(cd->wTotalLength); + if (restart) + p = (uByte *)(restart) + restart->bLength; + while (p < end) { desc = (usb_descriptor_t *)p; if (desc->bDescriptorType == type && >Release-Note: >Audit-Trail: >Unformatted: