aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/zd1211rw
diff options
context:
space:
mode:
authorDaniel Drake <dsd@gentoo.org>2006-08-13 07:15:29 -0400
committerJohn W. Linville <linville@tuxdriver.com>2006-08-14 15:43:23 -0400
commita1030e92c1507eb4a3c15d0a7d62987f671b609c (patch)
tree96bdf0831b6a71bbf43fd6ad28f1186a9b408b0c /drivers/net/wireless/zd1211rw
parent4ceb7e9936dae67d6c553a4954fa410a99b3ea16 (diff)
[PATCH] zd1211rw: Convert installer CDROM device into WLAN device
Some devices identify themselves as a virtual USB CDROM drive. The virtual CD includes the windows driver. We aren't interested in this, so we eject the virtual CDROM and then the real wireless device appears. Patch fixed over the earlier version to not leak cmd, thanks to Michael Buesch for spotting that. Signed-off-by: Daniel Drake <dsd@gentoo.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/zd1211rw')
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c59
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h1
2 files changed, 60 insertions, 0 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 347ebc17bd74..83e23c320ece 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -48,6 +48,8 @@ static struct usb_device_id usb_ids[] = {
48 { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, 48 { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
49 { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, 49 { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
50 { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, 50 { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
51 /* "Driverless" devices that need ejecting */
52 { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
51 {} 53 {}
52}; 54};
53 55
@@ -951,6 +953,55 @@ static void print_id(struct usb_device *udev)
951#define print_id(udev) do { } while (0) 953#define print_id(udev) do { } while (0)
952#endif 954#endif
953 955
956static int eject_installer(struct usb_interface *intf)
957{
958 struct usb_device *udev = interface_to_usbdev(intf);
959 struct usb_host_interface *iface_desc = &intf->altsetting[0];
960 struct usb_endpoint_descriptor *endpoint;
961 unsigned char *cmd;
962 u8 bulk_out_ep;
963 int r;
964
965 /* Find bulk out endpoint */
966 endpoint = &iface_desc->endpoint[1].desc;
967 if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT &&
968 (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
969 USB_ENDPOINT_XFER_BULK) {
970 bulk_out_ep = endpoint->bEndpointAddress;
971 } else {
972 dev_err(&udev->dev,
973 "zd1211rw: Could not find bulk out endpoint\n");
974 return -ENODEV;
975 }
976
977 cmd = kzalloc(31, GFP_KERNEL);
978 if (cmd == NULL)
979 return -ENODEV;
980
981 /* USB bulk command block */
982 cmd[0] = 0x55; /* bulk command signature */
983 cmd[1] = 0x53; /* bulk command signature */
984 cmd[2] = 0x42; /* bulk command signature */
985 cmd[3] = 0x43; /* bulk command signature */
986 cmd[14] = 6; /* command length */
987
988 cmd[15] = 0x1b; /* SCSI command: START STOP UNIT */
989 cmd[19] = 0x2; /* eject disc */
990
991 dev_info(&udev->dev, "Ejecting virtual installer media...\n");
992 r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep),
993 cmd, 31, NULL, 2000);
994 kfree(cmd);
995 if (r)
996 return r;
997
998 /* At this point, the device disconnects and reconnects with the real
999 * ID numbers. */
1000
1001 usb_set_intfdata(intf, NULL);
1002 return 0;
1003}
1004
954static int probe(struct usb_interface *intf, const struct usb_device_id *id) 1005static int probe(struct usb_interface *intf, const struct usb_device_id *id)
955{ 1006{
956 int r; 1007 int r;
@@ -959,6 +1010,9 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
959 1010
960 print_id(udev); 1011 print_id(udev);
961 1012
1013 if (id->driver_info & DEVICE_INSTALLER)
1014 return eject_installer(intf);
1015
962 switch (udev->speed) { 1016 switch (udev->speed) {
963 case USB_SPEED_LOW: 1017 case USB_SPEED_LOW:
964 case USB_SPEED_FULL: 1018 case USB_SPEED_FULL:
@@ -1024,6 +1078,11 @@ static void disconnect(struct usb_interface *intf)
1024 struct zd_mac *mac = zd_netdev_mac(netdev); 1078 struct zd_mac *mac = zd_netdev_mac(netdev);
1025 struct zd_usb *usb = &mac->chip.usb; 1079 struct zd_usb *usb = &mac->chip.usb;
1026 1080
1081 /* Either something really bad happened, or we're just dealing with
1082 * a DEVICE_INSTALLER. */
1083 if (netdev == NULL)
1084 return;
1085
1027 dev_dbg_f(zd_usb_dev(usb), "\n"); 1086 dev_dbg_f(zd_usb_dev(usb), "\n");
1028 1087
1029 zd_netdev_disconnect(netdev); 1088 zd_netdev_disconnect(netdev);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index d6420283bd5a..92746f76239a 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -30,6 +30,7 @@
30enum devicetype { 30enum devicetype {
31 DEVICE_ZD1211 = 0, 31 DEVICE_ZD1211 = 0,
32 DEVICE_ZD1211B = 1, 32 DEVICE_ZD1211B = 1,
33 DEVICE_INSTALLER = 2,
33}; 34};
34 35
35enum endpoints { 36enum endpoints {