Skip to content

Commit

Permalink
[PATCH] zd1211rw: Convert installer CDROM device into WLAN device
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Daniel Drake authored and John W. Linville committed Aug 14, 2006
1 parent 4ceb7e9 commit a1030e9
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 0 deletions.
59 changes: 59 additions & 0 deletions drivers/net/wireless/zd1211rw/zd_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{}
};

Expand Down Expand Up @@ -951,6 +953,55 @@ static void print_id(struct usb_device *udev)
#define print_id(udev) do { } while (0)
#endif

static int eject_installer(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_host_interface *iface_desc = &intf->altsetting[0];
struct usb_endpoint_descriptor *endpoint;
unsigned char *cmd;
u8 bulk_out_ep;
int r;

/* Find bulk out endpoint */
endpoint = &iface_desc->endpoint[1].desc;
if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT &&
(endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_BULK) {
bulk_out_ep = endpoint->bEndpointAddress;
} else {
dev_err(&udev->dev,
"zd1211rw: Could not find bulk out endpoint\n");
return -ENODEV;
}

cmd = kzalloc(31, GFP_KERNEL);
if (cmd == NULL)
return -ENODEV;

/* USB bulk command block */
cmd[0] = 0x55; /* bulk command signature */
cmd[1] = 0x53; /* bulk command signature */
cmd[2] = 0x42; /* bulk command signature */
cmd[3] = 0x43; /* bulk command signature */
cmd[14] = 6; /* command length */

cmd[15] = 0x1b; /* SCSI command: START STOP UNIT */
cmd[19] = 0x2; /* eject disc */

dev_info(&udev->dev, "Ejecting virtual installer media...\n");
r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep),
cmd, 31, NULL, 2000);
kfree(cmd);
if (r)
return r;

/* At this point, the device disconnects and reconnects with the real
* ID numbers. */

usb_set_intfdata(intf, NULL);
return 0;
}

static int probe(struct usb_interface *intf, const struct usb_device_id *id)
{
int r;
Expand All @@ -959,6 +1010,9 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)

print_id(udev);

if (id->driver_info & DEVICE_INSTALLER)
return eject_installer(intf);

switch (udev->speed) {
case USB_SPEED_LOW:
case USB_SPEED_FULL:
Expand Down Expand Up @@ -1024,6 +1078,11 @@ static void disconnect(struct usb_interface *intf)
struct zd_mac *mac = zd_netdev_mac(netdev);
struct zd_usb *usb = &mac->chip.usb;

/* Either something really bad happened, or we're just dealing with
* a DEVICE_INSTALLER. */
if (netdev == NULL)
return;

dev_dbg_f(zd_usb_dev(usb), "\n");

zd_netdev_disconnect(netdev);
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/zd1211rw/zd_usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
enum devicetype {
DEVICE_ZD1211 = 0,
DEVICE_ZD1211B = 1,
DEVICE_INSTALLER = 2,
};

enum endpoints {
Expand Down

0 comments on commit a1030e9

Please sign in to comment.