usb/117185: [umodem] [patch] Add support for UNION interface
descriptor
Alexey Dokuchaev
danfe at nsu.ru
Wed Jul 16 13:00:12 UTC 2008
The following reply was made to PR usb/117185; it has been noted by GNATS.
From: Alexey Dokuchaev <danfe at nsu.ru>
To: bug-followup at FreeBSD.org, eugen at grosbein.pp.ru
Cc: imp at bsdimp.com
Subject: Re: usb/117185: [umodem] [patch] Add support for UNION interface descriptor
Date: Wed, 16 Jul 2008 19:00:17 +0700
--YiEDa0DAkWCtVeE4
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Just confirmed to fix my Nokia E60 on 6-STABLE (had to change the patch
slightly to fit 6.x codebase).
P.S. Warner, you mentioned that you were going to take a look at NetBSD
(which this patch originates from) changes and merge the fix (usb/91546,
obsolete now). Could you possibly take a look now? People say this
code had been pretty stable for them for several months by now.
Provided 6.x is also covered, I look forward for a merge. Thanks.
--YiEDa0DAkWCtVeE4
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="umodem-nokia-releng6.patch"
--- umodem.c.orig 2008-07-16 12:01:22.000000000 +0700
+++ umodem.c 2008-07-16 12:43:32.000000000 +0700
@@ -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 &&
--YiEDa0DAkWCtVeE4--
More information about the freebsd-usb
mailing list