From owner-freebsd-usb@FreeBSD.ORG Sun Nov 25 08:20:03 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 55E3816A418 for ; Sun, 25 Nov 2007 08:20:03 +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 314EE13C465 for ; Sun, 25 Nov 2007 08:20:03 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.2/8.14.2) with ESMTP id lAP8K2Cr045187 for ; Sun, 25 Nov 2007 08:20:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.2/8.14.1/Submit) id lAP8K24k045179; Sun, 25 Nov 2007 08:20:02 GMT (envelope-from gnats) Date: Sun, 25 Nov 2007 08:20:02 GMT Message-Id: <200711250820.lAP8K24k045179@freefall.freebsd.org> To: freebsd-usb@FreeBSD.org From: Eugene Grosbein Cc: Subject: Re: usb/117185: [patch] [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, 25 Nov 2007 08:20:03 -0000 The following reply was made to PR usb/117185; it has been noted by GNATS. From: Eugene Grosbein To: bug-followup@freebsd.org Cc: Heikki Suonsivu Subject: Re: usb/117185: [patch] [umodem] Add support for UNION interface descriptor Date: Sun, 25 Nov 2007 15:17:26 +0700 > The patch does not seem to compile. Removing the offending %s lets it > compile. Triggering this may require -O2. Yes, thank you. It seems I've sent wrong (unfinished) version of patch, sorry; right one that I really use follows (see below). > When starting pppd on boot, there seems to be some hick-ups, not getting > phone to respond, etc. After replugging the phone it starts to work, > but this is undesirable when trying to build unattended operation. > Usb bus does not seem to get proper reset at any time, is there any way > to enforce it? This problem seems to happen with Nokia 9300. When the > phone is replugged when the system is up and running, it seems to work >better. I'd not compile ucom(4) and umodem(4) drivers into a kernel in such case, rather kldload them manually just before starting of pppd. This also gives a possibility to "reset usb" by unloading/reloading modules. Or, you may try to load these modules with loader(8) - perhaps, drivers will behave better. Btw, it seems to me as hardware/motherboard/phone problem - you may also try to use other USB ports or USB controller. > I also noticethat if pppd is started without delay on boot, it gets > sighup from where, triggering loss of connection to both Nokia phones I > have tried. If 30 second delay is added before starting pppd, the > system gets up and running, and then ppp seems to work fine without > getting extra hups. The kernel sends SIGHUP at the moment of switching to multi-user mode to all processes that did not daemonize properly to this moment. I've already seen reports about this problem with pppd for recent versions of FreeBSD. For 4.x, there was no such problem. Someone (c) needs to dig this problem in more details. Now the patch for RELENG_7: --- 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,"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 &&