| 1 | |
| 2 | |
| 3 | * Copyright (C) 2002 Pavel Machek <[email protected]>
|
| 4 | * Copyright (C) 2002-2005 by David Brownell
|
| 5 |
|
| 6 |
|
| 7 | |
| 8 | |
| 9 |
|
| 10 | #include <linux/module.h>
|
| 11 | #include <linux/netdevice.h>
|
| 12 | #include <linux/ethtool.h>
|
| 13 | #include <linux/workqueue.h>
|
| 14 | #include <linux/mii.h>
|
| 15 | #include <linux/crc32.h>
|
| 16 | #include <linux/usb.h>
|
| 17 | #include <linux/usb/cdc.h>
|
| 18 | #include <linux/usb/usbnet.h>
|
| 19 |
|
| 20 |
|
| 21 | |
| 22 | * All known Zaurii lie about their standards conformance. At least
|
| 23 | * the earliest SA-1100 models lie by saying they support CDC Ethernet.
|
| 24 | * Some later models (especially PXA-25x and PXA-27x based ones) lie
|
| 25 | * and say they support CDC MDLM (for access to cell phone modems).
|
| 26 | *
|
| 27 | * There are non-Zaurus products that use these same protocols too.
|
| 28 | *
|
| 29 | * The annoying thing is that at the same time Sharp was developing
|
| 30 | * that annoying standards-breaking software, the Linux community had
|
| 31 | * a simple "CDC Subset" working reliably on the same SA-1100 hardware.
|
| 32 | * That is, the same functionality but not violating standards.
|
| 33 | *
|
| 34 | * The CDC Ethernet nonconformance points are troublesome to hosts
|
| 35 | * with a true CDC Ethernet implementation:
|
| 36 | * - Framing appends a CRC, which the spec says drivers "must not" do;
|
| 37 | * - Transfers data in altsetting zero, instead of altsetting 1;
|
| 38 | * - All these peripherals use the same ethernet address.
|
| 39 | *
|
| 40 | * The CDC MDLM nonconformance is less immediately troublesome, since all
|
| 41 | * MDLM implementations are quasi-proprietary anyway.
|
| 42 |
|
| 43 |
|
| 44 | static struct sk_buff *
|
| 45 | zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
|
| 46 | {
|
| 47 | int padlen;
|
| 48 | struct sk_buff *skb2;
|
| 49 |
|
| 50 | padlen = 2;
|
| 51 | if (!skb_cloned(skb)) {
|
| 52 | int tailroom = skb_tailroom(skb);
|
| 53 | if ((padlen + 4) <= tailroom)
|
| 54 | goto done;
|
| 55 | }
|
| 56 | skb2 = skb_copy_expand(skb, 0, 4 + padlen, flags);
|
| 57 | dev_kfree_skb_any(skb);
|
| 58 | skb = skb2;
|
| 59 | if (skb) {
|
| 60 | u32 fcs;
|
| 61 | done:
|
| 62 | fcs = crc32_le(~0, skb->data, skb->len);
|
| 63 | fcs = ~fcs;
|
| 64 |
|
| 65 | skb_put_u8(skb, fcs & 0xff);
|
| 66 | skb_put_u8(skb, (fcs >> 8) & 0xff);
|
| 67 | skb_put_u8(skb, (fcs >> 16) & 0xff);
|
| 68 | skb_put_u8(skb, (fcs >> 24) & 0xff);
|
| 69 | }
|
| 70 | return skb;
|
| 71 | }
|
| 72 |
|
| 73 | static int zaurus_bind(struct usbnet *dev, struct usb_interface *intf)
|
| 74 | {
|
| 75 | |
| 76 | * TRAILERS (!) with 4 bytes CRC, and maybe 2 pad bytes.
|
| 77 |
|
| 78 | dev->net->hard_header_len += 6;
|
| 79 | dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu;
|
| 80 | return usbnet_generic_cdc_bind(dev, intf);
|
| 81 | }
|
| 82 |
|
| 83 |
|
| 84 | static int always_connected (struct usbnet *dev)
|
| 85 | {
|
| 86 | return 0;
|
| 87 | }
|
| 88 |
|
| 89 | static const struct driver_info zaurus_sl5x00_info = {
|
| 90 | .description = "Sharp Zaurus SL-5x00",
|
| 91 | .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z,
|
| 92 | .check_connect = always_connected,
|
| 93 | .bind = zaurus_bind,
|
| 94 | .unbind = usbnet_cdc_unbind,
|
| 95 | .tx_fixup = zaurus_tx_fixup,
|
| 96 | };
|
| 97 | #define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info)
|
| 98 |
|
| 99 | static const struct driver_info zaurus_pxa_info = {
|
| 100 | .description = "Sharp Zaurus, PXA-2xx based",
|
| 101 | .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z,
|
| 102 | .check_connect = always_connected,
|
| 103 | .bind = zaurus_bind,
|
| 104 | .unbind = usbnet_cdc_unbind,
|
| 105 | .tx_fixup = zaurus_tx_fixup,
|
| 106 | };
|
| 107 | #define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info)
|
| 108 |
|
| 109 | static const struct driver_info olympus_mxl_info = {
|
| 110 | .description = "Olympus R1000",
|
| 111 | .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z,
|
| 112 | .check_connect = always_connected,
|
| 113 | .bind = zaurus_bind,
|
| 114 | .unbind = usbnet_cdc_unbind,
|
| 115 | .tx_fixup = zaurus_tx_fixup,
|
| 116 | };
|
| 117 | #define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info)
|
| 118 |
|
| 119 |
|
| 120 | |
| 121 | * CDC MDLM conformance. They aren't conformant: data endpoints live
|
| 122 | * in the control interface, there's no data interface, and it's not used
|
| 123 | * to talk to a cell phone radio. But at least we can detect these two
|
| 124 | * pseudo-classes, rather than growing this product list with entries for
|
| 125 | * each new nonconformant product (sigh).
|
| 126 |
|
| 127 | static const u8 safe_guid[16] = {
|
| 128 | 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
|
| 129 | 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
|
| 130 | };
|
| 131 | static const u8 blan_guid[16] = {
|
| 132 | 0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70,
|
| 133 | 0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37,
|
| 134 | };
|
| 135 |
|
| 136 | static int blan_mdlm_bind(struct usbnet *dev, struct usb_interface *intf)
|
| 137 | {
|
| 138 | u8 *buf = intf->cur_altsetting->extra;
|
| 139 | int len = intf->cur_altsetting->extralen;
|
| 140 | struct usb_cdc_mdlm_desc *desc = NULL;
|
| 141 | struct usb_cdc_mdlm_detail_desc *detail = NULL;
|
| 142 |
|
| 143 | while (len > 3) {
|
| 144 | if (buf [1] != USB_DT_CS_INTERFACE)
|
| 145 | goto next_desc;
|
| 146 |
|
| 147 | |
| 148 | * "BLAN" (or "SAFE") descriptor.
|
| 149 |
|
| 150 | switch (buf [2]) {
|
| 151 | case USB_CDC_MDLM_TYPE:
|
| 152 | if (desc) {
|
| 153 | dev_dbg(&intf->dev, "extra MDLM\n");
|
| 154 | goto bad_desc;
|
| 155 | }
|
| 156 | desc = (void *) buf;
|
| 157 | if (desc->bLength != sizeof *desc) {
|
| 158 | dev_dbg(&intf->dev, "MDLM len %u\n",
|
| 159 | desc->bLength);
|
| 160 | goto bad_desc;
|
| 161 | }
|
| 162 |
|
| 163 | if (memcmp(&desc->bGUID, blan_guid, 16) &&
|
| 164 | memcmp(&desc->bGUID, safe_guid, 16)) {
|
| 165 |
|
| 166 | dev_dbg(&intf->dev, "MDLM guid\n");
|
| 167 | goto bad_desc;
|
| 168 | }
|
| 169 | break;
|
| 170 | case USB_CDC_MDLM_DETAIL_TYPE:
|
| 171 | if (detail) {
|
| 172 | dev_dbg(&intf->dev, "extra MDLM detail\n");
|
| 173 | goto bad_desc;
|
| 174 | }
|
| 175 | detail = (void *) buf;
|
| 176 | switch (detail->bGuidDescriptorType) {
|
| 177 | case 0:
|
| 178 | if (detail->bLength != (sizeof *detail + 2))
|
| 179 | goto bad_detail;
|
| 180 | break;
|
| 181 | case 1:
|
| 182 | if (detail->bLength != (sizeof *detail + 3))
|
| 183 | goto bad_detail;
|
| 184 | break;
|
| 185 | default:
|
| 186 | goto bad_detail;
|
| 187 | }
|
| 188 |
|
| 189 | |
| 190 | * find it soon, there are some data bytes here:
|
| 191 | * - bmNetworkCapabilities (unused)
|
| 192 | * - bmDataCapabilities (bits, see below)
|
| 193 | * - bPad (ignored, for PADAFTER -- BLAN-only)
|
| 194 | * bits are:
|
| 195 | * - 0x01 -- Zaurus framing (add CRC)
|
| 196 | * - 0x02 -- PADBEFORE (CRC includes some padding)
|
| 197 | * - 0x04 -- PADAFTER (some padding after CRC)
|
| 198 | * - 0x08 -- "fermat" packet mangling (for hw bugs)
|
| 199 | * the PADBEFORE appears not to matter; we interop
|
| 200 | * with devices that use it and those that don't.
|
| 201 |
|
| 202 | if ((detail->bDetailData[1] & ~0x02) != 0x01) {
|
| 203 | |
| 204 | * but framing is minidriver-coupled for now.
|
| 205 |
|
| 206 | bad_detail:
|
| 207 | dev_dbg(&intf->dev,
|
| 208 | "bad MDLM detail, %d %d %d\n",
|
| 209 | detail->bLength,
|
| 210 | detail->bDetailData[0],
|
| 211 | detail->bDetailData[2]);
|
| 212 | goto bad_desc;
|
| 213 | }
|
| 214 |
|
| 215 |
|
| 216 | dev->net->hard_header_len += 6;
|
| 217 | dev->rx_urb_size = dev->net->hard_header_len
|
| 218 | + dev->net->mtu;
|
| 219 | break;
|
| 220 | }
|
| 221 | next_desc:
|
| 222 | len -= buf [0];
|
| 223 | buf += buf [0];
|
| 224 | }
|
| 225 |
|
| 226 | if (!desc || !detail) {
|
| 227 | dev_dbg(&intf->dev, "missing cdc mdlm %s%sdescriptor\n",
|
| 228 | desc ? "" : "func ",
|
| 229 | detail ? "" : "detail ");
|
| 230 | goto bad_desc;
|
| 231 | }
|
| 232 |
|
| 233 | |
| 234 | * rely on the Ethernet address it provides since not all vendors
|
| 235 | * bother to make it unique. Likewise there's no point in tracking
|
| 236 | * of the CDC event notifications.
|
| 237 |
|
| 238 | return usbnet_get_endpoints(dev, intf);
|
| 239 |
|
| 240 | bad_desc:
|
| 241 | dev_info(&dev->udev->dev, "unsupported MDLM descriptors\n");
|
| 242 | return -ENODEV;
|
| 243 | }
|
| 244 |
|
| 245 | static const struct driver_info bogus_mdlm_info = {
|
| 246 | .description = "pseudo-MDLM (BLAN) device",
|
| 247 | .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z,
|
| 248 | .check_connect = always_connected,
|
| 249 | .tx_fixup = zaurus_tx_fixup,
|
| 250 | .bind = blan_mdlm_bind,
|
| 251 | };
|
| 252 |
|
| 253 | static const struct usb_device_id products [] = {
|
| 254 | #define ZAURUS_MASTER_INTERFACE \
|
| 255 | .bInterfaceClass = USB_CLASS_COMM, \
|
| 256 | .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \
|
| 257 | .bInterfaceProtocol = USB_CDC_PROTO_NONE
|
| 258 |
|
| 259 | #define ZAURUS_FAKE_INTERFACE \
|
| 260 | .bInterfaceClass = USB_CLASS_COMM, \
|
| 261 | .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM, \
|
| 262 | .bInterfaceProtocol = USB_CDC_PROTO_NONE
|
| 263 |
|
| 264 |
|
| 265 | {
|
| 266 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 267 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 268 | .idVendor = 0x04DD,
|
| 269 | .idProduct = 0x8004,
|
| 270 | ZAURUS_MASTER_INTERFACE,
|
| 271 | .driver_info = ZAURUS_STRONGARM_INFO,
|
| 272 | },
|
| 273 |
|
| 274 | |
| 275 | * more devices that claim to be CDC Ethernet, make sure they get
|
| 276 | * added to the blacklist in cdc_ether too.
|
| 277 | *
|
| 278 | * NOTE: OpenZaurus versions with 2.6 kernels won't use these entries,
|
| 279 | * unlike the older ones with 2.4 "embedix" kernels.
|
| 280 |
|
| 281 | {
|
| 282 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 283 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 284 | .idVendor = 0x04DD,
|
| 285 | .idProduct = 0x8005,
|
| 286 | ZAURUS_MASTER_INTERFACE,
|
| 287 | .driver_info = ZAURUS_PXA_INFO,
|
| 288 | }, {
|
| 289 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 290 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 291 | .idVendor = 0x04DD,
|
| 292 | .idProduct = 0x8005,
|
| 293 | ZAURUS_FAKE_INTERFACE,
|
| 294 | .driver_info = (unsigned long)&bogus_mdlm_info,
|
| 295 | }, {
|
| 296 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 297 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 298 | .idVendor = 0x04DD,
|
| 299 | .idProduct = 0x8006,
|
| 300 | ZAURUS_MASTER_INTERFACE,
|
| 301 | .driver_info = ZAURUS_PXA_INFO,
|
| 302 | }, {
|
| 303 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 304 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 305 | .idVendor = 0x04DD,
|
| 306 | .idProduct = 0x8006,
|
| 307 | ZAURUS_FAKE_INTERFACE,
|
| 308 | .driver_info = (unsigned long)&bogus_mdlm_info,
|
| 309 | }, {
|
| 310 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 311 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 312 | .idVendor = 0x04DD,
|
| 313 | .idProduct = 0x8007,
|
| 314 | ZAURUS_MASTER_INTERFACE,
|
| 315 | .driver_info = ZAURUS_PXA_INFO,
|
| 316 | }, {
|
| 317 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 318 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 319 | .idVendor = 0x04DD,
|
| 320 | .idProduct = 0x8007,
|
| 321 | ZAURUS_FAKE_INTERFACE,
|
| 322 | .driver_info = (unsigned long)&bogus_mdlm_info,
|
| 323 | }, {
|
| 324 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 325 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 326 | .idVendor = 0x04DD,
|
| 327 | .idProduct = 0x9031,
|
| 328 | ZAURUS_MASTER_INTERFACE,
|
| 329 | .driver_info = ZAURUS_PXA_INFO,
|
| 330 | }, {
|
| 331 |
|
| 332 | USB_DEVICE_AND_INTERFACE_INFO(0x04DD, 0x9031, USB_CLASS_COMM,
|
| 333 | USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
|
| 334 | .driver_info = (unsigned long) &bogus_mdlm_info,
|
| 335 | }, {
|
| 336 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 337 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 338 | .idVendor = 0x04DD,
|
| 339 | .idProduct = 0x9032,
|
| 340 | ZAURUS_MASTER_INTERFACE,
|
| 341 | .driver_info = ZAURUS_PXA_INFO,
|
| 342 | }, {
|
| 343 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 344 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 345 | .idVendor = 0x04DD,
|
| 346 | .idProduct = 0x9032,
|
| 347 | ZAURUS_FAKE_INTERFACE,
|
| 348 | .driver_info = (unsigned long)&bogus_mdlm_info,
|
| 349 | }, {
|
| 350 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 351 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 352 | .idVendor = 0x04DD,
|
| 353 |
|
| 354 | .idProduct = 0x9050,
|
| 355 | ZAURUS_MASTER_INTERFACE,
|
| 356 | .driver_info = ZAURUS_PXA_INFO,
|
| 357 | },
|
| 358 | {
|
| 359 |
|
| 360 | USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6027, USB_CLASS_COMM,
|
| 361 | USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
|
| 362 | .driver_info = (unsigned long) &bogus_mdlm_info,
|
| 363 | }, {
|
| 364 |
|
| 365 | USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6425, USB_CLASS_COMM,
|
| 366 | USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
|
| 367 | .driver_info = (unsigned long) &bogus_mdlm_info,
|
| 368 | },
|
| 369 |
|
| 370 | |
| 371 | * R-1000 uses a FreeScale i.MXL cpu (ARMv4T)
|
| 372 |
|
| 373 | {
|
| 374 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
|
| 375 | | USB_DEVICE_ID_MATCH_DEVICE,
|
| 376 | .idVendor = 0x07B4,
|
| 377 | .idProduct = 0x0F02,
|
| 378 | ZAURUS_MASTER_INTERFACE,
|
| 379 | .driver_info = OLYMPUS_MXL_INFO,
|
| 380 | },
|
| 381 |
|
| 382 |
|
| 383 | {
|
| 384 | USB_DEVICE_AND_INTERFACE_INFO(0x046d, 0xc11f, USB_CLASS_COMM,
|
| 385 | USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
|
| 386 | .driver_info = (unsigned long) &bogus_mdlm_info,
|
| 387 | },
|
| 388 | { }, |
| 389 | };
|
| 390 | MODULE_DEVICE_TABLE(usb, products);
|
| 391 |
|
| 392 | static struct usb_driver zaurus_driver = {
|
| 393 | .name = "zaurus",
|
| 394 | .id_table = products,
|
| 395 | .probe = usbnet_probe,
|
| 396 | .disconnect = usbnet_disconnect,
|
| 397 | .suspend = usbnet_suspend,
|
| 398 | .resume = usbnet_resume,
|
| 399 | .disable_hub_initiated_lpm = 1,
|
| 400 | };
|
| 401 |
|
| 402 | module_usb_driver(zaurus_driver);
|
| 403 |
|
| 404 | MODULE_AUTHOR("Pavel Machek, David Brownell");
|
| 405 | MODULE_DESCRIPTION("Sharp Zaurus PDA, and compatible products");
|
| 406 | MODULE_LICENSE("GPL");
|