Hi,
On 4/7/06, Noah Schwartz <[EMAIL PROTECTED]> wrote:
> > Anyway, for now, just apply the patch that I sent to this list. Note
> > that you probably have to do some badgering with it because I
> > accidentally sent the patch out in quoted printable format, which
> > means that a few lines were split (only the diff headers I think), and
> > that all tabs were replaced by 8 spaces (so a search 'n replace will
> > fix that for you).
>
> Could you possibly send a version without formatting issues? I seem to be
> having some difficulty applying the patch.
Here's the second revision of the original patch. Going to submit it
upstream today.
Regards,
Ole André
diff -Naurp linux-2.6.16.2-orig/drivers/usb/net/cdc_ether.c linux-2.6.16.2/drivers/usb/net/cdc_ether.c
--- linux-2.6.16.2-orig/drivers/usb/net/cdc_ether.c 2006-04-07 19:56:47.000000000 +0300
+++ linux-2.6.16.2/drivers/usb/net/cdc_ether.c 2006-04-10 01:03:10.000000000 +0300
@@ -72,7 +72,8 @@ int usbnet_generic_cdc_bind(struct usbne
/* this assumes that if there's a non-RNDIS vendor variant
* of cdc-acm, it'll fail RNDIS requests cleanly.
*/
- rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
+ rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff ||
+ intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_MISC);
memset(info, 0, sizeof *info);
info->control = intf;
@@ -172,6 +173,61 @@ next_desc:
buf += buf [0];
}
+ /* Windows Mobile 5 based RNDIS devices lack the CDC descriptors,
+ * so to work around this without changing too much of the overall
+ * logic we fake those headers here.
+ */
+ if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_MISC) {
+ struct usb_cdc_header_desc *h = NULL;
+ struct usb_cdc_union_desc *u = NULL;
+
+ dev_dbg(&intf->dev, "taking WM5 workaround path\n");
+
+ /* allocate and fill the missing structures */
+ h = kmalloc(sizeof(struct usb_cdc_header_desc), GFP_KERNEL);
+ u = kmalloc(sizeof(struct usb_cdc_union_desc), GFP_KERNEL);
+ if (!h || !u) {
+ if (h)
+ kfree(h);
+ if (u)
+ kfree(u);
+
+ return -ENOMEM;
+ }
+
+ info->header = h;
+
+ h->bLength = sizeof(struct usb_cdc_header_desc);
+ h->bDescriptorType = USB_DT_CS_INTERFACE;
+ h->bDescriptorSubType = USB_CDC_HEADER_TYPE;
+
+ h->bcdCDC = 0;
+
+ info->u = u;
+
+ u->bLength = sizeof(struct usb_cdc_union_desc);
+ u->bDescriptorType = USB_DT_CS_INTERFACE;
+ u->bDescriptorSubType = USB_CDC_UNION_TYPE;
+
+ u->bMasterInterface0 = 0;
+ u->bSlaveInterface0 = 1;
+
+ /* initialize */
+ info->control = usb_ifnum_to_if(dev->udev,
+ info->u->bMasterInterface0);
+ info->data = usb_ifnum_to_if(dev->udev,
+ info->u->bSlaveInterface0);
+ if (!info->control || !info->data) {
+ dev_dbg(&intf->dev,
+ "master #%u/%p slave #%u/%p\n",
+ info->u->bMasterInterface0,
+ info->control,
+ info->u->bSlaveInterface0,
+ info->data);
+ goto bad_desc;
+ }
+ }
+
if (!info->header || !info->u || (!rndis && !info->ether)) {
dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
info->header ? "" : "header ",
@@ -229,6 +285,17 @@ void usbnet_cdc_unbind(struct usbnet *de
struct cdc_state *info = (void *) &dev->data;
struct usb_driver *driver = driver_of(intf);
+ /* clean up resources allocated by the Windows Mobile 5
+ * RNDIS workaround ...
+ */
+ if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_MISC) {
+ if (info->header)
+ kfree(info->header);
+
+ if (info->u)
+ kfree(info->u);
+ }
+
/* disconnect master --> disconnect slave */
if (intf == info->control && info->data) {
/* ensure immediate exit from usbnet_disconnect */
diff -Naurp linux-2.6.16.2-orig/drivers/usb/net/rndis_host.c linux-2.6.16.2/drivers/usb/net/rndis_host.c
--- linux-2.6.16.2-orig/drivers/usb/net/rndis_host.c 2006-04-07 19:56:47.000000000 +0300
+++ linux-2.6.16.2/drivers/usb/net/rndis_host.c 2006-04-10 00:55:29.000000000 +0300
@@ -377,6 +377,7 @@ static int rndis_bind(struct usbnet *dev
struct rndis_set_c *set_c;
} u;
u32 tmp;
+ char *p;
/* we can't rely on i/o from stack working, or stack allocation */
u.buf = kmalloc(1024, GFP_KERNEL);
@@ -409,11 +410,18 @@ fail:
dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
1 << le32_to_cpu(u.init_c->packet_alignment));
- /* get designated host ethernet address */
- memset(u.get, 0, sizeof *u.get);
+ /* get designated host ethernet address
+ *
+ * adding a payload exactly the same size as the expected
+ * response' payload is a requirement added by MSFT as of
+ * post-RNDIS 1.0
+ */
+ memset(u.get, 0, sizeof *u.get + 48);
u.get->msg_type = RNDIS_MSG_QUERY;
- u.get->msg_len = ccpu2(sizeof *u.get);
+ u.get->msg_len = ccpu2(sizeof *u.get + 48);
u.get->oid = OID_802_3_PERMANENT_ADDRESS;
+ u.get->len = ccpu2(48);
+ u.get->offset = ccpu2(20);
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
@@ -575,10 +583,14 @@ static const struct driver_info rndis_in
/*-------------------------------------------------------------------------*/
+#define WM5_SUB_CLASS 0x01
+#define WM5_PROTOCOL 0x01
+
static const struct usb_device_id products [] = {
{
/* RNDIS is MSFT's un-official variant of CDC ACM */
USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
+ USB_INTERFACE_INFO(USB_CLASS_MISC, WM5_SUB_CLASS, WM5_PROTOCOL),
.driver_info = (unsigned long) &rndis_info,
},
{ }, // END
diff -Naurp linux-2.6.16.2-orig/include/linux/usb_ch9.h linux-2.6.16.2/include/linux/usb_ch9.h
--- linux-2.6.16.2-orig/include/linux/usb_ch9.h 2006-04-07 19:56:47.000000000 +0300
+++ linux-2.6.16.2/include/linux/usb_ch9.h 2006-04-10 00:22:01.000000000 +0300
@@ -217,6 +217,7 @@ struct usb_device_descriptor {
#define USB_CLASS_CONTENT_SEC 0x0d /* content security */
#define USB_CLASS_VIDEO 0x0e
#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
+#define USB_CLASS_MISC 0xef
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff