Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 28 Sep 2007 13:30:07 GMT
From:      Eugene Grosbein <eugen@kuzbass.ru>
To:        freebsd-usb@FreeBSD.org
Subject:   Re: usb/91546: [umodem] [patch] Nokia 6630 mobile phone does not work
Message-ID:  <200709281330.l8SDU7oH098742@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR usb/91546; it has been noted by GNATS.

From: Eugene Grosbein <eugen@kuzbass.ru>
To: bug-followup@freebsd.org
Cc: usb@freebsd.org, "M. Warner Losh" <imp@bsdimp.com>
Subject: Re: usb/91546: [umodem] [patch] Nokia 6630 mobile phone does not work
Date: Fri, 28 Sep 2007 21:25:30 +0800

 Hi!
 
 Here is the patch allowing to work with Nokia E50 (and hopefully others)
 as USB modem through device /dev/cuaU0 or like.
 
 This is basically the same code from NetBSD with one addition.
 The code from NetBSD allows to use UNION interface descriptor
 instead of CM descriptor but takes the first UNION descriptor it finds.
 That does not work for modern devices having lots of UNION descriptors,
 where needed is not first.
 
 The code uses umodem_get_desc() function to fine UNION,
 so I made it restartable with additional parameter.
 To start search from the beginning, the caller passes NULL,
 or it may pass the descriptor returned by umodem_get_desc() and
 it continues the search from the next descriptor.
 
 The function umodem_get_caps() obtains additional parameters
 and one of them is device control interface. It ignores any UNION
 which master interface is not device control interface and that
 has not at lease two endpoints (we need bulk in and out).
 So, it successfully finds needed descriptor in my case,
 attaches the device and it works.
 
 
 --- sys/dev/usb/umodem.c.orig	2007-09-26 21:22:37.000000000 +0800
 +++ sys/dev/usb/umodem.c	2007-09-28 21:01:06.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);
 @@ -261,10 +262,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;
 @@ -276,7 +274,6 @@
  	usbd_device_handle dev = uaa->device;
  	usb_interface_descriptor_t *id;
  	usb_endpoint_descriptor_t *ed;
 -	usb_cdc_cm_descriptor_t *cmd;
  	char *devinfo = NULL;
  	const char *devname;
  	usbd_status err;
 @@ -304,15 +301,14 @@
  	  id->bInterfaceClass, id->bInterfaceSubClass);
  	sc->sc_ctl_iface_no = id->bInterfaceNumber;
  
 -	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) {
 -		printf("%s: no CM descriptor\n", devname);
 +	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) {
 +		printf("%s: no pointer to data interface\n", devname);
  		goto bad;
  	}
 -	sc->sc_data_iface_no = data_ifcno = cmd->bDataInterface;
  
  	printf("%s: data interface %d, has %sCM over data, has %sbreak\n",
  	       devname, data_ifcno,
 @@ -550,27 +546,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;
  	}
 -	*acm = cad->bmCapabilities;
 +	if (cud == NULL) {
 +		DPRINTF(("umodem_get_caps: no UNION desc\n"));
 +	}
 +	
 +	return cmd ? cmd->bDataInterface : cud ? iface_no : -1;
  }
  
  void
 @@ -586,6 +605,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)
  {
 @@ -776,14 +812,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 &&
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200709281330.l8SDU7oH098742>