diff options
author | Sujith Manoharan <Sujith.Manoharan@atheros.com> | 2011-02-20 21:17:52 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-02-23 16:25:25 -0500 |
commit | 36bcce430657e6fece0e8dd91557f35dbb69ec67 (patch) | |
tree | cfd67c41f810b96b738994eb1206578ed2a880ef /drivers/net/wireless/ath | |
parent | 85c9205c79c794a6eea0c7217db93b4c637f136e (diff) |
ath9k_htc: Handle storage devices
Some AR7010 based devices are recognized as storage media.
Sending a CD-EJECT command to the device will 'convert' it into
a WLAN device. Do this within the driver itself, removing the
dependancy on an external program (usb_modeswitch).
Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hif_usb.c | 74 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/reg.h | 1 |
2 files changed, 69 insertions, 6 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 5ab3084eb9cb..fde54446973f 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c | |||
@@ -52,6 +52,9 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { | |||
52 | { USB_DEVICE(0x083A, 0xA704), | 52 | { USB_DEVICE(0x083A, 0xA704), |
53 | .driver_info = AR9280_USB }, /* SMC Networks */ | 53 | .driver_info = AR9280_USB }, /* SMC Networks */ |
54 | 54 | ||
55 | { USB_DEVICE(0x0cf3, 0x20ff), | ||
56 | .driver_info = STORAGE_DEVICE }, | ||
57 | |||
55 | { }, | 58 | { }, |
56 | }; | 59 | }; |
57 | 60 | ||
@@ -934,6 +937,61 @@ static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev) | |||
934 | release_firmware(hif_dev->firmware); | 937 | release_firmware(hif_dev->firmware); |
935 | } | 938 | } |
936 | 939 | ||
940 | /* | ||
941 | * An exact copy of the function from zd1211rw. | ||
942 | */ | ||
943 | static int send_eject_command(struct usb_interface *interface) | ||
944 | { | ||
945 | struct usb_device *udev = interface_to_usbdev(interface); | ||
946 | struct usb_host_interface *iface_desc = &interface->altsetting[0]; | ||
947 | struct usb_endpoint_descriptor *endpoint; | ||
948 | unsigned char *cmd; | ||
949 | u8 bulk_out_ep; | ||
950 | int r; | ||
951 | |||
952 | /* Find bulk out endpoint */ | ||
953 | for (r = 1; r >= 0; r--) { | ||
954 | endpoint = &iface_desc->endpoint[r].desc; | ||
955 | if (usb_endpoint_dir_out(endpoint) && | ||
956 | usb_endpoint_xfer_bulk(endpoint)) { | ||
957 | bulk_out_ep = endpoint->bEndpointAddress; | ||
958 | break; | ||
959 | } | ||
960 | } | ||
961 | if (r == -1) { | ||
962 | dev_err(&udev->dev, | ||
963 | "ath9k_htc: Could not find bulk out endpoint\n"); | ||
964 | return -ENODEV; | ||
965 | } | ||
966 | |||
967 | cmd = kzalloc(31, GFP_KERNEL); | ||
968 | if (cmd == NULL) | ||
969 | return -ENODEV; | ||
970 | |||
971 | /* USB bulk command block */ | ||
972 | cmd[0] = 0x55; /* bulk command signature */ | ||
973 | cmd[1] = 0x53; /* bulk command signature */ | ||
974 | cmd[2] = 0x42; /* bulk command signature */ | ||
975 | cmd[3] = 0x43; /* bulk command signature */ | ||
976 | cmd[14] = 6; /* command length */ | ||
977 | |||
978 | cmd[15] = 0x1b; /* SCSI command: START STOP UNIT */ | ||
979 | cmd[19] = 0x2; /* eject disc */ | ||
980 | |||
981 | dev_info(&udev->dev, "Ejecting storage device...\n"); | ||
982 | r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep), | ||
983 | cmd, 31, NULL, 2000); | ||
984 | kfree(cmd); | ||
985 | if (r) | ||
986 | return r; | ||
987 | |||
988 | /* At this point, the device disconnects and reconnects with the real | ||
989 | * ID numbers. */ | ||
990 | |||
991 | usb_set_intfdata(interface, NULL); | ||
992 | return 0; | ||
993 | } | ||
994 | |||
937 | static int ath9k_hif_usb_probe(struct usb_interface *interface, | 995 | static int ath9k_hif_usb_probe(struct usb_interface *interface, |
938 | const struct usb_device_id *id) | 996 | const struct usb_device_id *id) |
939 | { | 997 | { |
@@ -941,6 +999,9 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, | |||
941 | struct hif_device_usb *hif_dev; | 999 | struct hif_device_usb *hif_dev; |
942 | int ret = 0; | 1000 | int ret = 0; |
943 | 1001 | ||
1002 | if (id->driver_info == STORAGE_DEVICE) | ||
1003 | return send_eject_command(interface); | ||
1004 | |||
944 | hif_dev = kzalloc(sizeof(struct hif_device_usb), GFP_KERNEL); | 1005 | hif_dev = kzalloc(sizeof(struct hif_device_usb), GFP_KERNEL); |
945 | if (!hif_dev) { | 1006 | if (!hif_dev) { |
946 | ret = -ENOMEM; | 1007 | ret = -ENOMEM; |
@@ -1027,12 +1088,13 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface) | |||
1027 | struct hif_device_usb *hif_dev = usb_get_intfdata(interface); | 1088 | struct hif_device_usb *hif_dev = usb_get_intfdata(interface); |
1028 | bool unplugged = (udev->state == USB_STATE_NOTATTACHED) ? true : false; | 1089 | bool unplugged = (udev->state == USB_STATE_NOTATTACHED) ? true : false; |
1029 | 1090 | ||
1030 | if (hif_dev) { | 1091 | if (!hif_dev) |
1031 | ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged); | 1092 | return; |
1032 | ath9k_htc_hw_free(hif_dev->htc_handle); | 1093 | |
1033 | ath9k_hif_usb_dev_deinit(hif_dev); | 1094 | ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged); |
1034 | usb_set_intfdata(interface, NULL); | 1095 | ath9k_htc_hw_free(hif_dev->htc_handle); |
1035 | } | 1096 | ath9k_hif_usb_dev_deinit(hif_dev); |
1097 | usb_set_intfdata(interface, NULL); | ||
1036 | 1098 | ||
1037 | if (!unplugged && (hif_dev->flags & HIF_USB_START)) | 1099 | if (!unplugged && (hif_dev->flags & HIF_USB_START)) |
1038 | ath9k_hif_usb_reboot(udev); | 1100 | ath9k_hif_usb_reboot(udev); |
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 64b226a78b2e..8fa8acfde62e 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h | |||
@@ -878,6 +878,7 @@ | |||
878 | enum ath_usb_dev { | 878 | enum ath_usb_dev { |
879 | AR9280_USB = 1, /* AR7010 + AR9280, UB94 */ | 879 | AR9280_USB = 1, /* AR7010 + AR9280, UB94 */ |
880 | AR9287_USB = 2, /* AR7010 + AR9287, UB95 */ | 880 | AR9287_USB = 2, /* AR7010 + AR9287, UB95 */ |
881 | STORAGE_DEVICE = 3, | ||
881 | }; | 882 | }; |
882 | 883 | ||
883 | #define AR_DEVID_7010(_ah) \ | 884 | #define AR_DEVID_7010(_ah) \ |