The following reply was made to PR usb/91546; it has been noted by GNATS.

From: Eugene Grosbein <[EMAIL PROTECTED]>
To: [EMAIL PROTECTED]
Cc: [EMAIL PROTECTED], "M. Warner Losh" <[EMAIL PROTECTED]>
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 &&
 
_______________________________________________
freebsd-usb@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-usb
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to