| 1 | |
| 2 | |
| 3 | * CDC Ethernet based networking peripherals
|
| 4 | * Copyright (C) 2003-2005 by David Brownell
|
| 5 | * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
|
| 6 |
|
| 7 |
|
| 8 | |
| 9 | |
| 10 |
|
| 11 | #include <linux/module.h>
|
| 12 | #include <linux/netdevice.h>
|
| 13 | #include <linux/etherdevice.h>
|
| 14 | #include <linux/ethtool.h>
|
| 15 | #include <linux/workqueue.h>
|
| 16 | #include <linux/mii.h>
|
| 17 | #include <linux/usb.h>
|
| 18 | #include <linux/usb/cdc.h>
|
| 19 | #include <linux/usb/usbnet.h>
|
| 20 |
|
| 21 |
|
| 22 | #if IS_ENABLED(CONFIG_USB_NET_RNDIS_HOST)
|
| 23 |
|
| 24 | static int is_rndis(struct usb_interface_descriptor *desc)
|
| 25 | {
|
| 26 | return (desc->bInterfaceClass == USB_CLASS_COMM &&
|
| 27 | desc->bInterfaceSubClass == 2 &&
|
| 28 | desc->bInterfaceProtocol == 0xff);
|
| 29 | }
|
| 30 |
|
| 31 | static int is_activesync(struct usb_interface_descriptor *desc)
|
| 32 | {
|
| 33 | return (desc->bInterfaceClass == USB_CLASS_MISC &&
|
| 34 | desc->bInterfaceSubClass == 1 &&
|
| 35 | desc->bInterfaceProtocol == 1);
|
| 36 | }
|
| 37 |
|
| 38 | static int is_wireless_rndis(struct usb_interface_descriptor *desc)
|
| 39 | {
|
| 40 | return (desc->bInterfaceClass == USB_CLASS_WIRELESS_CONTROLLER &&
|
| 41 | desc->bInterfaceSubClass == 1 &&
|
| 42 | desc->bInterfaceProtocol == 3);
|
| 43 | }
|
| 44 |
|
| 45 | static int is_novatel_rndis(struct usb_interface_descriptor *desc)
|
| 46 | {
|
| 47 | return (desc->bInterfaceClass == USB_CLASS_MISC &&
|
| 48 | desc->bInterfaceSubClass == 4 &&
|
| 49 | desc->bInterfaceProtocol == 1);
|
| 50 | }
|
| 51 |
|
| 52 | #else
|
| 53 |
|
| 54 | #define is_rndis(desc) 0
|
| 55 | #define is_activesync(desc) 0
|
| 56 | #define is_wireless_rndis(desc) 0
|
| 57 | #define is_novatel_rndis(desc) 0
|
| 58 |
|
| 59 | #endif
|
| 60 |
|
| 61 | static const u8 mbm_guid[16] = {
|
| 62 | 0xa3, 0x17, 0xa8, 0x8b, 0x04, 0x5e, 0x4f, 0x01,
|
| 63 | 0xa6, 0x07, 0xc0, 0xff, 0xcb, 0x7e, 0x39, 0x2a,
|
| 64 | };
|
| 65 |
|
| 66 | void usbnet_cdc_update_filter(struct usbnet *dev)
|
| 67 | {
|
| 68 | struct net_device *net = dev->net;
|
| 69 |
|
| 70 | u16 cdc_filter = USB_CDC_PACKET_TYPE_DIRECTED
|
| 71 | | USB_CDC_PACKET_TYPE_BROADCAST;
|
| 72 |
|
| 73 | |
| 74 | * the hassle so we just roughly care about snooping and if any
|
| 75 | * multicast is requested, we take every multicast
|
| 76 |
|
| 77 | if (net->flags & IFF_PROMISC)
|
| 78 | cdc_filter |= USB_CDC_PACKET_TYPE_PROMISCUOUS;
|
| 79 | if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI))
|
| 80 | cdc_filter |= USB_CDC_PACKET_TYPE_ALL_MULTICAST;
|
| 81 |
|
| 82 | usb_control_msg(dev->udev,
|
| 83 | usb_sndctrlpipe(dev->udev, 0),
|
| 84 | USB_CDC_SET_ETHERNET_PACKET_FILTER,
|
| 85 | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
| 86 | cdc_filter,
|
| 87 | dev->intf->cur_altsetting->desc.bInterfaceNumber,
|
| 88 | NULL,
|
| 89 | 0,
|
| 90 | USB_CTRL_SET_TIMEOUT
|
| 91 | );
|
| 92 | }
|
| 93 | EXPORT_SYMBOL_GPL(usbnet_cdc_update_filter);
|
| 94 |
|
| 95 |
|
| 96 | static const struct ethtool_ops cdc_ether_ethtool_ops = {
|
| 97 | .get_link = usbnet_get_link,
|
| 98 | .nway_reset = usbnet_nway_reset,
|
| 99 | .get_drvinfo = usbnet_get_drvinfo,
|
| 100 | .get_msglevel = usbnet_get_msglevel,
|
| 101 | .set_msglevel = usbnet_set_msglevel,
|
| 102 | .get_ts_info = ethtool_op_get_ts_info,
|
| 103 | .get_link_ksettings = usbnet_get_link_ksettings_internal,
|
| 104 | .set_link_ksettings = NULL,
|
| 105 | };
|
| 106 |
|
| 107 | |
| 108 | * endpoints, activates data interface (if needed), maybe sets MTU.
|
| 109 | * all pure cdc, except for certain firmware workarounds, and knowing
|
| 110 | * that rndis uses one different rule.
|
| 111 |
|
| 112 | int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
|
| 113 | {
|
| 114 | u8 *buf = intf->cur_altsetting->extra;
|
| 115 | int len = intf->cur_altsetting->extralen;
|
| 116 | struct usb_interface_descriptor *d;
|
| 117 | struct cdc_state *info = (void *) &dev->data;
|
| 118 | int status = -ENODEV;
|
| 119 | int rndis;
|
| 120 | bool android_rndis_quirk = false;
|
| 121 | struct usb_driver *driver = driver_of(intf);
|
| 122 | struct usb_cdc_parsed_header header;
|
| 123 |
|
| 124 | if (sizeof(dev->data) < sizeof(*info))
|
| 125 | return -EDOM;
|
| 126 |
|
| 127 | |
| 128 | * cope with firmware which stores them in the wrong place
|
| 129 |
|
| 130 | if (len == 0 && dev->udev->actconfig->extralen) {
|
| 131 | |
| 132 | * from a Broadcom design) put CDC descriptors here
|
| 133 |
|
| 134 | buf = dev->udev->actconfig->extra;
|
| 135 | len = dev->udev->actconfig->extralen;
|
| 136 | dev_dbg(&intf->dev, "CDC descriptors on config\n");
|
| 137 | }
|
| 138 |
|
| 139 | |
| 140 | * been seen on some 2Wire Inc RNDIS-ish products.
|
| 141 |
|
| 142 | if (len == 0) {
|
| 143 | struct usb_host_endpoint *hep;
|
| 144 |
|
| 145 | hep = intf->cur_altsetting->endpoint;
|
| 146 | if (hep) {
|
| 147 | buf = hep->extra;
|
| 148 | len = hep->extralen;
|
| 149 | }
|
| 150 | if (len)
|
| 151 | dev_dbg(&intf->dev,
|
| 152 | "CDC descriptors on endpoint\n");
|
| 153 | }
|
| 154 |
|
| 155 | |
| 156 | * of cdc-acm, it'll fail RNDIS requests cleanly.
|
| 157 |
|
| 158 | rndis = (is_rndis(&intf->cur_altsetting->desc) ||
|
| 159 | is_activesync(&intf->cur_altsetting->desc) ||
|
| 160 | is_wireless_rndis(&intf->cur_altsetting->desc) ||
|
| 161 | is_novatel_rndis(&intf->cur_altsetting->desc));
|
| 162 |
|
| 163 | memset(info, 0, sizeof(*info));
|
| 164 | info->control = intf;
|
| 165 |
|
| 166 | cdc_parse_cdc_header(&header, intf, buf, len);
|
| 167 |
|
| 168 | info->u = header.usb_cdc_union_desc;
|
| 169 | info->header = header.usb_cdc_header_desc;
|
| 170 | info->ether = header.usb_cdc_ether_desc;
|
| 171 | if (!info->u) {
|
| 172 | if (rndis) {
|
| 173 | goto skip;
|
| 174 | } else {
|
| 175 |
|
| 176 | dev_err(&dev->udev->dev, "No union descriptors\n");
|
| 177 | goto bad_desc;
|
| 178 | }
|
| 179 | }
|
| 180 | |
| 181 | * probed with) and a slave/data interface; union
|
| 182 | * descriptors sort this all out.
|
| 183 |
|
| 184 | info->control = usb_ifnum_to_if(dev->udev, info->u->bMasterInterface0);
|
| 185 | info->data = usb_ifnum_to_if(dev->udev, info->u->bSlaveInterface0);
|
| 186 | if (!info->control || !info->data) {
|
| 187 | dev_dbg(&intf->dev,
|
| 188 | "master #%u/%p slave #%u/%p\n",
|
| 189 | info->u->bMasterInterface0,
|
| 190 | info->control,
|
| 191 | info->u->bSlaveInterface0,
|
| 192 | info->data);
|
| 193 |
|
| 194 | if (rndis) {
|
| 195 | android_rndis_quirk = true;
|
| 196 | goto skip;
|
| 197 | }
|
| 198 | dev_err(&intf->dev, "bad CDC descriptors\n");
|
| 199 | goto bad_desc;
|
| 200 | }
|
| 201 | if (info->control != intf) {
|
| 202 | |
| 203 | * interchanges master and slave interface.
|
| 204 |
|
| 205 | if (info->data == intf) {
|
| 206 | info->data = info->control;
|
| 207 | info->control = intf;
|
| 208 | } else {
|
| 209 | dev_err(&intf->dev, "bogus CDC Union\n");
|
| 210 | goto bad_desc;
|
| 211 | }
|
| 212 | }
|
| 213 |
|
| 214 |
|
| 215 | if (info->control == info->data)
|
| 216 | goto skip;
|
| 217 |
|
| 218 |
|
| 219 | d = &info->data->cur_altsetting->desc;
|
| 220 | if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {
|
| 221 | dev_err(&intf->dev, "slave class %u\n", d->bInterfaceClass);
|
| 222 | goto bad_desc;
|
| 223 | }
|
| 224 | skip:
|
| 225 | |
| 226 | * RNDIS. But some Wireless class RNDIS functions use
|
| 227 | * bmCapabilities for their own purpose. The failsafe is
|
| 228 | * therefore applied only to Communication class RNDIS
|
| 229 | * functions. The rndis test is redundant, but a cheap
|
| 230 | * optimization.
|
| 231 |
|
| 232 | if (rndis && is_rndis(&intf->cur_altsetting->desc) &&
|
| 233 | header.usb_cdc_acm_descriptor &&
|
| 234 | header.usb_cdc_acm_descriptor->bmCapabilities) {
|
| 235 | dev_err(&intf->dev,
|
| 236 | "ACM capabilities %02x, not really RNDIS?\n",
|
| 237 | header.usb_cdc_acm_descriptor->bmCapabilities);
|
| 238 | goto bad_desc;
|
| 239 | }
|
| 240 |
|
| 241 | if (header.usb_cdc_ether_desc && info->ether->wMaxSegmentSize) {
|
| 242 | dev->hard_mtu = le16_to_cpu(info->ether->wMaxSegmentSize);
|
| 243 | |
| 244 | * side link address we were given.
|
| 245 |
|
| 246 | }
|
| 247 |
|
| 248 | if (header.usb_cdc_mdlm_desc &&
|
| 249 | memcmp(header.usb_cdc_mdlm_desc->bGUID, mbm_guid, 16)) {
|
| 250 | dev_err(&intf->dev, "GUID doesn't match\n");
|
| 251 | goto bad_desc;
|
| 252 | }
|
| 253 |
|
| 254 | if (header.usb_cdc_mdlm_detail_desc &&
|
| 255 | header.usb_cdc_mdlm_detail_desc->bLength <
|
| 256 | (sizeof(struct usb_cdc_mdlm_detail_desc) + 1)) {
|
| 257 | dev_err(&intf->dev, "Descriptor too short\n");
|
| 258 | goto bad_desc;
|
| 259 | }
|
| 260 |
|
| 261 |
|
| 262 |
|
| 263 | |
| 264 | * CDC descriptors, so we'll hard-wire the interfaces and not check
|
| 265 | * for descriptors.
|
| 266 | *
|
| 267 | * Some Android RNDIS devices have a CDC Union descriptor pointing
|
| 268 | * to non-existing interfaces. Ignore that and attempt the same
|
| 269 | * hard-wired 0 and 1 interfaces.
|
| 270 |
|
| 271 | if (rndis && (!info->u || android_rndis_quirk)) {
|
| 272 | info->control = usb_ifnum_to_if(dev->udev, 0);
|
| 273 | info->data = usb_ifnum_to_if(dev->udev, 1);
|
| 274 | if (!info->control || !info->data || info->control != intf) {
|
| 275 | dev_err(&intf->dev,
|
| 276 | "rndis: master #0/%p slave #1/%p\n",
|
| 277 | info->control,
|
| 278 | info->data);
|
| 279 | goto bad_desc;
|
| 280 | }
|
| 281 |
|
| 282 | } else if (!info->header || (!rndis && !info->ether)) {
|
| 283 | dev_err(&intf->dev, "missing cdc %s%s%sdescriptor\n",
|
| 284 | info->header ? "" : "header ",
|
| 285 | info->u ? "" : "union ",
|
| 286 | info->ether ? "" : "ether ");
|
| 287 | goto bad_desc;
|
| 288 | }
|
| 289 |
|
| 290 | |
| 291 | * network traffic can't flow until an altsetting is enabled.
|
| 292 |
|
| 293 | if (info->data != info->control) {
|
| 294 | status = usb_driver_claim_interface(driver, info->data, dev);
|
| 295 | if (status < 0) {
|
| 296 | dev_err(&intf->dev, "Second interface unclaimable\n");
|
| 297 | goto bad_desc;
|
| 298 | }
|
| 299 | }
|
| 300 | status = usbnet_get_endpoints(dev, info->data);
|
| 301 | if (status < 0) {
|
| 302 | dev_dbg(&intf->dev, "Mandatory endpoints missing\n");
|
| 303 | goto bail_out_and_release;
|
| 304 | }
|
| 305 |
|
| 306 |
|
| 307 | if (info->data != info->control)
|
| 308 | dev->status = NULL;
|
| 309 | if (info->control->cur_altsetting->desc.bNumEndpoints == 1) {
|
| 310 | struct usb_endpoint_descriptor *desc;
|
| 311 |
|
| 312 | dev->status = &info->control->cur_altsetting->endpoint[0];
|
| 313 | desc = &dev->status->desc;
|
| 314 | if (!usb_endpoint_is_int_in(desc) ||
|
| 315 | (le16_to_cpu(desc->wMaxPacketSize)
|
| 316 | < sizeof(struct usb_cdc_notification)) ||
|
| 317 | !desc->bInterval) {
|
| 318 | dev_dbg(&intf->dev, "bad notification endpoint\n");
|
| 319 | dev->status = NULL;
|
| 320 | }
|
| 321 | }
|
| 322 | if (rndis && !dev->status) {
|
| 323 | dev_err(&intf->dev, "missing RNDIS status endpoint\n");
|
| 324 | status = -ENODEV;
|
| 325 | goto bail_out_and_release;
|
| 326 | }
|
| 327 |
|
| 328 |
|
| 329 | dev->net->ethtool_ops = &cdc_ether_ethtool_ops;
|
| 330 |
|
| 331 | return 0;
|
| 332 |
|
| 333 | bail_out_and_release:
|
| 334 | usb_set_intfdata(info->data, NULL);
|
| 335 | if (info->data != info->control)
|
| 336 | usb_driver_release_interface(driver, info->data);
|
| 337 | bad_desc:
|
| 338 | return status;
|
| 339 | }
|
| 340 | EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind);
|
| 341 |
|
| 342 |
|
| 343 | |
| 344 | * correctly
|
| 345 |
|
| 346 | int usbnet_ether_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
|
| 347 | {
|
| 348 | int rv;
|
| 349 |
|
| 350 | rv = usbnet_generic_cdc_bind(dev, intf);
|
| 351 | if (rv < 0)
|
| 352 | goto bail_out;
|
| 353 |
|
| 354 | |
| 355 | * the packet filter is not reset. There are devices that
|
| 356 | * don't do reset all the way. So the packet filter should
|
| 357 | * be set to a sane initial value.
|
| 358 |
|
| 359 | usbnet_cdc_update_filter(dev);
|
| 360 |
|
| 361 | bail_out:
|
| 362 | return rv;
|
| 363 | }
|
| 364 | EXPORT_SYMBOL_GPL(usbnet_ether_cdc_bind);
|
| 365 |
|
| 366 | void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
|
| 367 | {
|
| 368 | struct cdc_state *info = (void *) &dev->data;
|
| 369 | struct usb_driver *driver = driver_of(intf);
|
| 370 |
|
| 371 |
|
| 372 | if (info->data == info->control)
|
| 373 | return;
|
| 374 |
|
| 375 |
|
| 376 | if (intf == info->control && info->data) {
|
| 377 |
|
| 378 | usb_set_intfdata(info->data, NULL);
|
| 379 | usb_driver_release_interface(driver, info->data);
|
| 380 | info->data = NULL;
|
| 381 | }
|
| 382 |
|
| 383 |
|
| 384 | else if (intf == info->data && info->control) {
|
| 385 |
|
| 386 | usb_set_intfdata(info->control, NULL);
|
| 387 | usb_driver_release_interface(driver, info->control);
|
| 388 | info->control = NULL;
|
| 389 | }
|
| 390 | }
|
| 391 | EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
|
| 392 |
|
| 393 | |
| 394 | *
|
| 395 | * Takes two interfaces. The DATA interface is inactive till an altsetting
|
| 396 | * is selected. Configuration data includes class descriptors. There's
|
| 397 | * an optional status endpoint on the control interface.
|
| 398 | *
|
| 399 | * This should interop with whatever the 2.4 "CDCEther.c" driver
|
| 400 | * (by Brad Hards) talked with, with more functionality.
|
| 401 |
|
| 402 |
|
| 403 | static void speed_change(struct usbnet *dev, __le32 *speeds)
|
| 404 | {
|
| 405 | dev->tx_speed = __le32_to_cpu(speeds[0]);
|
| 406 | dev->rx_speed = __le32_to_cpu(speeds[1]);
|
| 407 | }
|
| 408 |
|
| 409 | void usbnet_cdc_status(struct usbnet *dev, struct urb *urb)
|
| 410 | {
|
| 411 | struct usb_cdc_notification *event;
|
| 412 |
|
| 413 | if (urb->actual_length < sizeof(*event))
|
| 414 | return;
|
| 415 |
|
| 416 |
|
| 417 | if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
|
| 418 | speed_change(dev, (__le32 *) urb->transfer_buffer);
|
| 419 | return;
|
| 420 | }
|
| 421 |
|
| 422 | event = urb->transfer_buffer;
|
| 423 | switch (event->bNotificationType) {
|
| 424 | case USB_CDC_NOTIFY_NETWORK_CONNECTION:
|
| 425 | netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n",
|
| 426 | event->wValue ? "on" : "off");
|
| 427 | if (netif_carrier_ok(dev->net) != !!event->wValue)
|
| 428 | usbnet_link_change(dev, !!event->wValue, 0);
|
| 429 | break;
|
| 430 | case USB_CDC_NOTIFY_SPEED_CHANGE:
|
| 431 | netif_dbg(dev, timer, dev->net, "CDC: speed change (len %d)\n",
|
| 432 | urb->actual_length);
|
| 433 | if (urb->actual_length != (sizeof(*event) + 8))
|
| 434 | set_bit(EVENT_STS_SPLIT, &dev->flags);
|
| 435 | else
|
| 436 | speed_change(dev, (__le32 *) &event[1]);
|
| 437 | break;
|
| 438 | |
| 439 | * but there are no standard formats for the response data.
|
| 440 |
|
| 441 | default:
|
| 442 | netdev_err(dev->net, "CDC: unexpected notification %02x!\n",
|
| 443 | event->bNotificationType);
|
| 444 | break;
|
| 445 | }
|
| 446 | }
|
| 447 | EXPORT_SYMBOL_GPL(usbnet_cdc_status);
|
| 448 |
|
| 449 | int usbnet_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
|
| 450 | {
|
| 451 | int status;
|
| 452 | struct cdc_state *info = (void *) &dev->data;
|
| 453 |
|
| 454 | BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data)
|
| 455 | < sizeof(struct cdc_state)));
|
| 456 |
|
| 457 | status = usbnet_ether_cdc_bind(dev, intf);
|
| 458 | if (status < 0)
|
| 459 | return status;
|
| 460 |
|
| 461 | status = usbnet_get_ethernet_addr(dev, info->ether->iMACAddress);
|
| 462 | if (status < 0) {
|
| 463 | usb_set_intfdata(info->data, NULL);
|
| 464 | usb_driver_release_interface(driver_of(intf), info->data);
|
| 465 | return status;
|
| 466 | }
|
| 467 |
|
| 468 | return 0;
|
| 469 | }
|
| 470 | EXPORT_SYMBOL_GPL(usbnet_cdc_bind);
|
| 471 |
|
| 472 | static int usbnet_cdc_zte_bind(struct usbnet *dev, struct usb_interface *intf)
|
| 473 | {
|
| 474 | int status = usbnet_cdc_bind(dev, intf);
|
| 475 |
|
| 476 | if (!status && (dev->net->dev_addr[0] & 0x02))
|
| 477 | eth_hw_addr_random(dev->net);
|
| 478 |
|
| 479 | return status;
|
| 480 | }
|
| 481 |
|
| 482 | |
| 483 | *
|
| 484 | * A firmware bug observed on some devices (ZTE MF823/831/910) is that the
|
| 485 | * device sends packets with a static, bogus, random MAC address (event if
|
| 486 | * device MAC address has been updated). Always set MAC address to that of the
|
| 487 | * device.
|
| 488 |
|
| 489 | int usbnet_cdc_zte_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
| 490 | {
|
| 491 | if (skb->len < ETH_HLEN || !(skb->data[0] & 0x02))
|
| 492 | return 1;
|
| 493 |
|
| 494 | skb_reset_mac_header(skb);
|
| 495 | ether_addr_copy(eth_hdr(skb)->h_dest, dev->net->dev_addr);
|
| 496 |
|
| 497 | return 1;
|
| 498 | }
|
| 499 | EXPORT_SYMBOL_GPL(usbnet_cdc_zte_rx_fixup);
|
| 500 |
|
| 501 | |
| 502 | *
|
| 503 | * Some devices (ZTE MF823/831/910) export two carrier on notifications when
|
| 504 | * connected. This causes the link state to be incorrect. Work around this by
|
| 505 | * always setting the state to off, then on.
|
| 506 |
|
| 507 | static void usbnet_cdc_zte_status(struct usbnet *dev, struct urb *urb)
|
| 508 | {
|
| 509 | struct usb_cdc_notification *event;
|
| 510 |
|
| 511 | if (urb->actual_length < sizeof(*event))
|
| 512 | return;
|
| 513 |
|
| 514 | event = urb->transfer_buffer;
|
| 515 |
|
| 516 | if (event->bNotificationType != USB_CDC_NOTIFY_NETWORK_CONNECTION) {
|
| 517 | usbnet_cdc_status(dev, urb);
|
| 518 | return;
|
| 519 | }
|
| 520 |
|
| 521 | netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n",
|
| 522 | event->wValue ? "on" : "off");
|
| 523 |
|
| 524 | if (event->wValue &&
|
| 525 | netif_carrier_ok(dev->net))
|
| 526 | netif_carrier_off(dev->net);
|
| 527 |
|
| 528 | usbnet_link_change(dev, !!event->wValue, 0);
|
| 529 | }
|
| 530 |
|
| 531 | static const struct driver_info cdc_info = {
|
| 532 | .description = "CDC Ethernet Device",
|
| 533 | .flags = FLAG_ETHER | FLAG_POINTTOPOINT,
|
| 534 | .bind = usbnet_cdc_bind,
|
| 535 | .unbind = usbnet_cdc_unbind,
|
| 536 | .status = usbnet_cdc_status,
|
| 537 | .set_rx_mode = usbnet_cdc_update_filter,
|
| 538 | .manage_power = usbnet_manage_power,
|
| 539 | };
|
| 540 |
|
| 541 | static const struct driver_info ami_bmc_info = {
|
| 542 | .description = "AMI BMC USB Ethernet",
|
| 543 | .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_LINK_INTR,
|
| 544 | .bind = usbnet_cdc_bind,
|
| 545 | .unbind = usbnet_cdc_unbind,
|
| 546 | .status = usbnet_cdc_status,
|
| 547 | .set_rx_mode = usbnet_cdc_update_filter,
|
| 548 | .manage_power = usbnet_manage_power,
|
| 549 | };
|
| 550 |
|
| 551 | static const struct driver_info zte_cdc_info = {
|
| 552 | .description = "ZTE CDC Ethernet Device",
|
| 553 | .flags = FLAG_ETHER | FLAG_POINTTOPOINT,
|
| 554 | .bind = usbnet_cdc_zte_bind,
|
| 555 | .unbind = usbnet_cdc_unbind,
|
| 556 | .status = usbnet_cdc_zte_status,
|
| 557 | .set_rx_mode = usbnet_cdc_update_filter,
|
| 558 | .manage_power = usbnet_manage_power,
|
| 559 | .rx_fixup = usbnet_cdc_zte_rx_fixup,
|
| 560 | };
|
| 561 |
|
| 562 | static const struct driver_info wwan_info = {
|
| 563 | .description = "Mobile Broadband Network Device",
|
| 564 | .flags = FLAG_WWAN,
|
| 565 | .bind = usbnet_cdc_bind,
|
| 566 | .unbind = usbnet_cdc_unbind,
|
| 567 | .status = usbnet_cdc_status,
|
| 568 | .set_rx_mode = usbnet_cdc_update_filter,
|
| 569 | .manage_power = usbnet_manage_power,
|
| 570 | };
|
| 571 |
|
| 572 |
|
| 573 |
|
| 574 | #define HUAWEI_VENDOR_ID 0x12D1
|
| 575 | #define NOVATEL_VENDOR_ID 0x1410
|
| 576 | #define ZTE_VENDOR_ID 0x19D2
|
| 577 | #define DELL_VENDOR_ID 0x413C
|
| 578 | #define REALTEK_VENDOR_ID 0x0bda
|
| 579 | #define SAMSUNG_VENDOR_ID 0x04e8
|
| 580 | #define LENOVO_VENDOR_ID 0x17ef
|
| 581 | #define LINKSYS_VENDOR_ID 0x13b1
|
| 582 | #define NVIDIA_VENDOR_ID 0x0955
|
| 583 | #define HP_VENDOR_ID 0x03f0
|
| 584 | #define MICROSOFT_VENDOR_ID 0x045e
|
| 585 | #define UBLOX_VENDOR_ID 0x1546
|
| 586 | #define TPLINK_VENDOR_ID 0x2357
|
| 587 | #define AQUANTIA_VENDOR_ID 0x2eca
|
| 588 | #define ASIX_VENDOR_ID 0x0b95
|
| 589 |
|
| 590 | static const struct usb_device_id products[] = {
|
| 591 | |
| 592 | *
|
| 593 | * First blacklist any products that are egregiously nonconformant
|
| 594 | * with the CDC Ethernet specs. Minor braindamage we cope with; when
|
| 595 | * they're not even trying, needing a separate driver is only the first
|
| 596 | * of the differences to show up.
|
| 597 |
|
| 598 |
|
| 599 | #define ZAURUS_MASTER_INTERFACE \
|
| 600 | .bInterfaceClass = USB_CLASS_COMM, \
|
| 601 | .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \
|
| 602 | .bInterfaceProtocol = USB_CDC_PROTO_NONE
|
| 603 |
|
| 604 | #define ZAURUS_FAKE_INTERFACE \
|
| 605 | .bInterfaceClass = USB_CLASS_COMM, \
|
| 606 | .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM, \
|
| 607 | .bInterfaceProtocol = USB_CDC_PROTO_NONE
|
| 608 |
|
| 609 | |
| 610 | * wire-incompatible with true CDC Ethernet implementations.
|
| 611 | * (And, it seems, needlessly so...)
|
| 612 |
|
| 613 | {
|
| 614 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 615 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 616 | .idVendor = 0x04DD,
|
| 617 | .idProduct = 0x8004,
|
| 618 | ZAURUS_MASTER_INTERFACE,
|
| 619 | .driver_info = 0,
|
| 620 | },
|
| 621 |
|
| 622 | |
| 623 | * (later models especially) may have shipped only with firmware
|
| 624 | * advertising false "CDC MDLM" compatibility ... but we're not
|
| 625 | * clear which models did that, so for now let's assume the worst.
|
| 626 |
|
| 627 | {
|
| 628 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 629 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 630 | .idVendor = 0x04DD,
|
| 631 | .idProduct = 0x8005,
|
| 632 | ZAURUS_MASTER_INTERFACE,
|
| 633 | .driver_info = 0,
|
| 634 | }, {
|
| 635 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 636 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 637 | .idVendor = 0x04DD,
|
| 638 | .idProduct = 0x8005,
|
| 639 | ZAURUS_FAKE_INTERFACE,
|
| 640 | .driver_info = 0,
|
| 641 | }, {
|
| 642 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 643 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 644 | .idVendor = 0x04DD,
|
| 645 | .idProduct = 0x8006,
|
| 646 | ZAURUS_MASTER_INTERFACE,
|
| 647 | .driver_info = 0,
|
| 648 | }, {
|
| 649 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 650 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 651 | .idVendor = 0x04DD,
|
| 652 | .idProduct = 0x8006,
|
| 653 | ZAURUS_FAKE_INTERFACE,
|
| 654 | .driver_info = 0,
|
| 655 | }, {
|
| 656 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 657 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 658 | .idVendor = 0x04DD,
|
| 659 | .idProduct = 0x8007,
|
| 660 | ZAURUS_MASTER_INTERFACE,
|
| 661 | .driver_info = 0,
|
| 662 | }, {
|
| 663 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 664 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 665 | .idVendor = 0x04DD,
|
| 666 | .idProduct = 0x8007,
|
| 667 | ZAURUS_FAKE_INTERFACE,
|
| 668 | .driver_info = 0,
|
| 669 | }, {
|
| 670 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 671 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 672 | .idVendor = 0x04DD,
|
| 673 | .idProduct = 0x9031,
|
| 674 | ZAURUS_MASTER_INTERFACE,
|
| 675 | .driver_info = 0,
|
| 676 | }, {
|
| 677 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 678 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 679 | .idVendor = 0x04DD,
|
| 680 | .idProduct = 0x9032,
|
| 681 | ZAURUS_MASTER_INTERFACE,
|
| 682 | .driver_info = 0,
|
| 683 | }, {
|
| 684 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 685 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 686 | .idVendor = 0x04DD,
|
| 687 | .idProduct = 0x9032,
|
| 688 | ZAURUS_FAKE_INTERFACE,
|
| 689 | .driver_info = 0,
|
| 690 | }, {
|
| 691 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 692 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 693 | .idVendor = 0x04DD,
|
| 694 |
|
| 695 | .idProduct = 0x9050,
|
| 696 | ZAURUS_MASTER_INTERFACE,
|
| 697 | .driver_info = 0,
|
| 698 | },
|
| 699 |
|
| 700 | |
| 701 | * R-1000 uses a FreeScale i.MXL cpu (ARMv4T)
|
| 702 |
|
| 703 | {
|
| 704 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 705 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 706 | .idVendor = 0x07B4,
|
| 707 | .idProduct = 0x0F02,
|
| 708 | ZAURUS_MASTER_INTERFACE,
|
| 709 | .driver_info = 0,
|
| 710 | },
|
| 711 |
|
| 712 |
|
| 713 | {
|
| 714 | USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM,
|
| 715 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 716 | .driver_info = 0,
|
| 717 | },
|
| 718 |
|
| 719 |
|
| 720 | {
|
| 721 | USB_DEVICE_AND_INTERFACE_INFO(0x046d, 0xc11f, USB_CLASS_COMM,
|
| 722 | USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
|
| 723 | .driver_info = 0,
|
| 724 | },
|
| 725 |
|
| 726 |
|
| 727 | {
|
| 728 | USB_DEVICE_AND_INTERFACE_INFO(NOVATEL_VENDOR_ID, 0xB001, USB_CLASS_COMM,
|
| 729 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 730 | .driver_info = 0,
|
| 731 | },
|
| 732 |
|
| 733 |
|
| 734 | {
|
| 735 | USB_DEVICE_AND_INTERFACE_INFO(NOVATEL_VENDOR_ID, 0x9010, USB_CLASS_COMM,
|
| 736 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 737 | .driver_info = 0,
|
| 738 | },
|
| 739 |
|
| 740 |
|
| 741 | {
|
| 742 | USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x8195, USB_CLASS_COMM,
|
| 743 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 744 | .driver_info = 0,
|
| 745 | },
|
| 746 |
|
| 747 |
|
| 748 | {
|
| 749 | USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x8196, USB_CLASS_COMM,
|
| 750 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 751 | .driver_info = 0,
|
| 752 | },
|
| 753 |
|
| 754 |
|
| 755 | {
|
| 756 | USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x819b, USB_CLASS_COMM,
|
| 757 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 758 | .driver_info = 0,
|
| 759 | },
|
| 760 |
|
| 761 |
|
| 762 | {
|
| 763 | USB_DEVICE_AND_INTERFACE_INFO(NOVATEL_VENDOR_ID, 0x9011, USB_CLASS_COMM,
|
| 764 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 765 | .driver_info = 0,
|
| 766 | },
|
| 767 |
|
| 768 |
|
| 769 | {
|
| 770 | USB_DEVICE_AND_INTERFACE_INFO(HP_VENDOR_ID, 0x421d, USB_CLASS_COMM,
|
| 771 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 772 | .driver_info = 0,
|
| 773 | },
|
| 774 |
|
| 775 |
|
| 776 | {
|
| 777 | USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a, USB_CLASS_COMM,
|
| 778 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 779 | .driver_info = 0,
|
| 780 | },
|
| 781 |
|
| 782 |
|
| 783 | {
|
| 784 | USB_DEVICE_INTERFACE_NUMBER(HUAWEI_VENDOR_ID, 0x14ac, 1),
|
| 785 | .driver_info = 0,
|
| 786 | },
|
| 787 |
|
| 788 |
|
| 789 | {
|
| 790 | USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM,
|
| 791 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 792 | .driver_info = 0,
|
| 793 | },
|
| 794 |
|
| 795 |
|
| 796 | {
|
| 797 | USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x721e, USB_CLASS_COMM,
|
| 798 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 799 | .driver_info = 0,
|
| 800 | },
|
| 801 |
|
| 802 |
|
| 803 | {
|
| 804 | USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0xa359, USB_CLASS_COMM,
|
| 805 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 806 | .driver_info = 0,
|
| 807 | },
|
| 808 |
|
| 809 |
|
| 810 | {
|
| 811 | USB_DEVICE_AND_INTERFACE_INFO(AQUANTIA_VENDOR_ID, 0xc101,
|
| 812 | USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
|
| 813 | USB_CDC_PROTO_NONE),
|
| 814 | .driver_info = 0,
|
| 815 | },
|
| 816 |
|
| 817 |
|
| 818 | {
|
| 819 | USB_DEVICE_AND_INTERFACE_INFO(ASIX_VENDOR_ID, 0x2790, USB_CLASS_COMM,
|
| 820 | USB_CDC_SUBCLASS_ETHERNET,
|
| 821 | USB_CDC_PROTO_NONE),
|
| 822 | .driver_info = 0,
|
| 823 | },
|
| 824 |
|
| 825 |
|
| 826 | {
|
| 827 | USB_DEVICE_AND_INTERFACE_INFO(ASIX_VENDOR_ID, 0x2791, USB_CLASS_COMM,
|
| 828 | USB_CDC_SUBCLASS_ETHERNET,
|
| 829 | USB_CDC_PROTO_NONE),
|
| 830 | .driver_info = 0,
|
| 831 | },
|
| 832 |
|
| 833 |
|
| 834 | {
|
| 835 | USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0xe05a, USB_CLASS_COMM,
|
| 836 | USB_CDC_SUBCLASS_ETHERNET,
|
| 837 | USB_CDC_PROTO_NONE),
|
| 838 | .driver_info = 0,
|
| 839 | },
|
| 840 |
|
| 841 |
|
| 842 | {
|
| 843 | USB_DEVICE_AND_INTERFACE_INFO(0x1c04, 0x0015, USB_CLASS_COMM,
|
| 844 | USB_CDC_SUBCLASS_ETHERNET,
|
| 845 | USB_CDC_PROTO_NONE),
|
| 846 | .driver_info = 0,
|
| 847 | },
|
| 848 |
|
| 849 | |
| 850 | *
|
| 851 | * CDC Ether uses two interfaces, not necessarily consecutive.
|
| 852 | * We match the main interface, ignoring the optional device
|
| 853 | * class so we could handle devices that aren't exclusively
|
| 854 | * CDC ether.
|
| 855 | *
|
| 856 | * NOTE: this match must come AFTER entries blacklisting devices
|
| 857 | * because of bugs/quirks in a given product (like Zaurus, above).
|
| 858 |
|
| 859 | {
|
| 860 |
|
| 861 | USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1003, USB_CLASS_COMM,
|
| 862 | USB_CDC_SUBCLASS_ETHERNET,
|
| 863 | USB_CDC_PROTO_NONE),
|
| 864 | .driver_info = (unsigned long)&wwan_info,
|
| 865 | }, {
|
| 866 |
|
| 867 | USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1015, USB_CLASS_COMM,
|
| 868 | USB_CDC_SUBCLASS_ETHERNET,
|
| 869 | USB_CDC_PROTO_NONE),
|
| 870 | .driver_info = (unsigned long)&wwan_info,
|
| 871 | }, {
|
| 872 |
|
| 873 | USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1173, USB_CLASS_COMM,
|
| 874 | USB_CDC_SUBCLASS_ETHERNET,
|
| 875 | USB_CDC_PROTO_NONE),
|
| 876 | .driver_info = (unsigned long)&wwan_info,
|
| 877 | }, {
|
| 878 |
|
| 879 | USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1177, USB_CLASS_COMM,
|
| 880 | USB_CDC_SUBCLASS_ETHERNET,
|
| 881 | USB_CDC_PROTO_NONE),
|
| 882 | .driver_info = (unsigned long)&wwan_info,
|
| 883 | }, {
|
| 884 |
|
| 885 | USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1181, USB_CLASS_COMM,
|
| 886 | USB_CDC_SUBCLASS_ETHERNET,
|
| 887 | USB_CDC_PROTO_NONE),
|
| 888 | .driver_info = (unsigned long)&wwan_info,
|
| 889 | }, {
|
| 890 |
|
| 891 | USB_VENDOR_AND_INTERFACE_INFO(0x1bc7, USB_CLASS_COMM,
|
| 892 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 893 | .driver_info = (kernel_ulong_t) &wwan_info,
|
| 894 | }, {
|
| 895 |
|
| 896 | USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x81ba, USB_CLASS_COMM,
|
| 897 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
| 898 | .driver_info = (kernel_ulong_t)&wwan_info,
|
| 899 | }, {
|
| 900 |
|
| 901 | USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x15c1, USB_CLASS_COMM,
|
| 902 | USB_CDC_SUBCLASS_ETHERNET,
|
| 903 | USB_CDC_PROTO_NONE),
|
| 904 | .driver_info = (unsigned long)&wwan_info,
|
| 905 | }, {
|
| 906 |
|
| 907 | USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, USB_CLASS_COMM,
|
| 908 | USB_CDC_SUBCLASS_ETHERNET,
|
| 909 | USB_CDC_PROTO_NONE),
|
| 910 | .driver_info = (unsigned long)&zte_cdc_info,
|
| 911 | }, {
|
| 912 |
|
| 913 | USB_DEVICE_AND_INTERFACE_INFO(UBLOX_VENDOR_ID, 0x1143, USB_CLASS_COMM,
|
| 914 | USB_CDC_SUBCLASS_ETHERNET,
|
| 915 | USB_CDC_PROTO_NONE),
|
| 916 | .driver_info = (unsigned long)&wwan_info,
|
| 917 | }, {
|
| 918 |
|
| 919 | USB_DEVICE_AND_INTERFACE_INFO(UBLOX_VENDOR_ID, 0x1104, USB_CLASS_COMM,
|
| 920 | USB_CDC_SUBCLASS_ETHERNET,
|
| 921 | USB_CDC_PROTO_NONE),
|
| 922 | .driver_info = (unsigned long)&wwan_info,
|
| 923 | }, {
|
| 924 |
|
| 925 | USB_DEVICE_AND_INTERFACE_INFO(UBLOX_VENDOR_ID, 0x1313, USB_CLASS_COMM,
|
| 926 | USB_CDC_SUBCLASS_ETHERNET,
|
| 927 | USB_CDC_PROTO_NONE),
|
| 928 | .driver_info = (unsigned long)&wwan_info,
|
| 929 | }, {
|
| 930 |
|
| 931 | USB_DEVICE_AND_INTERFACE_INFO(UBLOX_VENDOR_ID, 0x1343, USB_CLASS_COMM,
|
| 932 | USB_CDC_SUBCLASS_ETHERNET,
|
| 933 | USB_CDC_PROTO_NONE),
|
| 934 | .driver_info = (unsigned long)&wwan_info,
|
| 935 | }, {
|
| 936 |
|
| 937 | USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0061, USB_CLASS_COMM,
|
| 938 | USB_CDC_SUBCLASS_ETHERNET,
|
| 939 | USB_CDC_PROTO_NONE),
|
| 940 | .driver_info = (unsigned long)&wwan_info,
|
| 941 | }, {
|
| 942 |
|
| 943 | USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0055, USB_CLASS_COMM,
|
| 944 | USB_CDC_SUBCLASS_ETHERNET,
|
| 945 | USB_CDC_PROTO_NONE),
|
| 946 | .driver_info = (unsigned long)&wwan_info,
|
| 947 | }, {
|
| 948 |
|
| 949 | USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x005b, USB_CLASS_COMM,
|
| 950 | USB_CDC_SUBCLASS_ETHERNET,
|
| 951 | USB_CDC_PROTO_NONE),
|
| 952 | .driver_info = (unsigned long)&wwan_info,
|
| 953 | }, {
|
| 954 |
|
| 955 | USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0069, USB_CLASS_COMM,
|
| 956 | USB_CDC_SUBCLASS_ETHERNET,
|
| 957 | USB_CDC_PROTO_NONE),
|
| 958 | .driver_info = (unsigned long)&wwan_info,
|
| 959 | }, {
|
| 960 |
|
| 961 | USB_DEVICE_AND_INTERFACE_INFO(0x046b, 0xffb0, USB_CLASS_COMM,
|
| 962 | USB_CDC_SUBCLASS_ETHERNET,
|
| 963 | USB_CDC_PROTO_NONE),
|
| 964 | .driver_info = (unsigned long)&ami_bmc_info,
|
| 965 | }, {
|
| 966 | USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
|
| 967 | USB_CDC_PROTO_NONE),
|
| 968 | .driver_info = (unsigned long) &cdc_info,
|
| 969 | }, {
|
| 970 | USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM,
|
| 971 | USB_CDC_PROTO_NONE),
|
| 972 | .driver_info = (unsigned long)&wwan_info,
|
| 973 |
|
| 974 | }, {
|
| 975 |
|
| 976 | USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_COMM,
|
| 977 | USB_CDC_SUBCLASS_ETHERNET, 255),
|
| 978 | .driver_info = (unsigned long)&wwan_info,
|
| 979 | },
|
| 980 | { },
|
| 981 | };
|
| 982 | MODULE_DEVICE_TABLE(usb, products);
|
| 983 |
|
| 984 | static struct usb_driver cdc_driver = {
|
| 985 | .name = "cdc_ether",
|
| 986 | .id_table = products,
|
| 987 | .probe = usbnet_probe,
|
| 988 | .disconnect = usbnet_disconnect,
|
| 989 | .suspend = usbnet_suspend,
|
| 990 | .resume = usbnet_resume,
|
| 991 | .reset_resume = usbnet_resume,
|
| 992 | .supports_autosuspend = 1,
|
| 993 | .disable_hub_initiated_lpm = 1,
|
| 994 | };
|
| 995 |
|
| 996 | module_usb_driver(cdc_driver);
|
| 997 |
|
| 998 | MODULE_AUTHOR("David Brownell");
|
| 999 | MODULE_DESCRIPTION("USB CDC Ethernet devices");
|
| 1000 | MODULE_LICENSE("GPL");
|