diff options
Diffstat (limited to 'drivers/net/wireless/zd1211rw')
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_usb.c | 59 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_usb.h | 1 |
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 | ||
956 | static 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 | |||
954 | static int probe(struct usb_interface *intf, const struct usb_device_id *id) | 1005 | static 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 @@ | |||
30 | enum devicetype { | 30 | enum 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 | ||
35 | enum endpoints { | 36 | enum endpoints { |