]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/usb/net/cdc_ether.c
[PATCH] remove many unneeded #includes of sched.h
[net-next-2.6.git] / drivers / usb / net / cdc_ether.c
index 82ce0358d9a3e5f13e44a76089c319e28622b662..5a21f06bf8a54fab20e2bb70dd0f599b4be910c2 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * CDC Ethernet based networking peripherals
  * Copyright (C) 2003-2005 by David Brownell
+ * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,7 +22,6 @@
 // #define     VERBOSE                 // more; success messages
 
 #include <linux/module.h>
-#include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include "usbnet.h"
 
 
+#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+       return desc->bInterfaceClass == USB_CLASS_COMM
+               && desc->bInterfaceSubClass == 2
+               && desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+       return desc->bInterfaceClass == USB_CLASS_MISC
+               && desc->bInterfaceSubClass == 1
+               && desc->bInterfaceProtocol == 1;
+}
+
+#else
+
+#define is_rndis(desc)         0
+#define is_activesync(desc)    0
+
+#endif
+
 /*
  * probes control interface, claims data interface, collects the bulk
  * endpoints, activates data interface (if needed), maybe sets MTU.
@@ -71,7 +94,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
        /* 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 = is_rndis(&intf->cur_altsetting->desc)
+               || is_activesync(&intf->cur_altsetting->desc);
 
        memset(info, 0, sizeof *info);
        info->control = intf;
@@ -99,6 +123,23 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                                goto bad_desc;
                        }
                        break;
+               case USB_CDC_ACM_TYPE:
+                       /* paranoia:  disambiguate a "real" vendor-specific
+                        * modem interface from an RNDIS non-modem.
+                        */
+                       if (rndis) {
+                               struct usb_cdc_acm_descriptor *d;
+
+                               d = (void *) buf;
+                               if (d->bmCapabilities) {
+                                       dev_dbg(&intf->dev,
+                                               "ACM capabilities %02x, "
+                                               "not really RNDIS?\n",
+                                               d->bmCapabilities);
+                                       goto bad_desc;
+                               }
+                       }
+                       break;
                case USB_CDC_UNION_TYPE:
                        if (info->u) {
                                dev_dbg(&intf->dev, "extra CDC union\n");
@@ -171,7 +212,21 @@ next_desc:
                buf += buf [0];
        }
 
-       if (!info->header || !info->u || (!rndis && !info->ether)) {
+       /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
+        * so we'll hard-wire the interfaces and not check for descriptors.
+        */
+       if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
+               info->control = usb_ifnum_to_if(dev->udev, 0);
+               info->data = usb_ifnum_to_if(dev->udev, 1);
+               if (!info->control || !info->data) {
+                       dev_dbg(&intf->dev,
+                               "activesync: master #0/%p slave #1/%p\n",
+                               info->control,
+                               info->data);
+                       goto bad_desc;
+               }
+
+       } else if (!info->header || !info->u || (!rndis && !info->ether)) {
                dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
                        info->header ? "" : "header ",
                        info->u ? "" : "union ",
@@ -200,8 +255,7 @@ next_desc:
 
                dev->status = &info->control->cur_altsetting->endpoint [0];
                desc = &dev->status->desc;
-               if (desc->bmAttributes != USB_ENDPOINT_XFER_INT
-                               || !(desc->bEndpointAddress & USB_DIR_IN)
+               if (!usb_endpoint_is_int_in(desc)
                                || (le16_to_cpu(desc->wMaxPacketSize)
                                        < sizeof(struct usb_cdc_notification))
                                || !desc->bInterval) {
@@ -498,7 +552,7 @@ static struct usb_driver cdc_driver = {
 
 static int __init cdc_init(void)
 {
-       BUG_ON((sizeof(((struct usbnet *)0)->data)
+       BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data)
                        < sizeof(struct cdc_state)));
 
        return usb_register(&cdc_driver);