diff options
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r-- | drivers/usb/storage/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/storage/option_ms.c | 147 | ||||
-rw-r--r-- | drivers/usb/storage/option_ms.h | 4 | ||||
-rw-r--r-- | drivers/usb/storage/unusual_devs.h | 24 | ||||
-rw-r--r-- | drivers/usb/storage/usb.c | 1 |
5 files changed, 177 insertions, 1 deletions
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile index facf610f1683..b32069313390 100644 --- a/drivers/usb/storage/Makefile +++ b/drivers/usb/storage/Makefile | |||
@@ -23,7 +23,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA) += karma.o | |||
23 | usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o | 23 | usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o |
24 | 24 | ||
25 | usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ | 25 | usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ |
26 | initializers.o sierra_ms.o $(usb-storage-obj-y) | 26 | initializers.o sierra_ms.o option_ms.o $(usb-storage-obj-y) |
27 | 27 | ||
28 | ifneq ($(CONFIG_USB_LIBUSUAL),) | 28 | ifneq ($(CONFIG_USB_LIBUSUAL),) |
29 | obj-$(CONFIG_USB) += libusual.o | 29 | obj-$(CONFIG_USB) += libusual.o |
diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c new file mode 100644 index 000000000000..353f922939a4 --- /dev/null +++ b/drivers/usb/storage/option_ms.c | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * Driver for Option High Speed Mobile Devices. | ||
3 | * | ||
4 | * (c) 2008 Dan Williams <dcbw@redhat.com> | ||
5 | * | ||
6 | * Inspiration taken from sierra_ms.c by Kevin Lloyd <klloyd@sierrawireless.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/usb.h> | ||
24 | |||
25 | #include "usb.h" | ||
26 | #include "transport.h" | ||
27 | #include "option_ms.h" | ||
28 | #include "debug.h" | ||
29 | |||
30 | #define ZCD_FORCE_MODEM 0x01 | ||
31 | #define ZCD_ALLOW_MS 0x02 | ||
32 | |||
33 | static unsigned int option_zero_cd = ZCD_FORCE_MODEM; | ||
34 | module_param(option_zero_cd, uint, S_IRUGO | S_IWUSR); | ||
35 | MODULE_PARM_DESC(option_zero_cd, "ZeroCD mode (1=Force Modem (default)," | ||
36 | " 2=Allow CD-Rom"); | ||
37 | |||
38 | #define RESPONSE_LEN 1024 | ||
39 | |||
40 | static int option_rezero(struct us_data *us, int ep_in, int ep_out) | ||
41 | { | ||
42 | const unsigned char rezero_msg[] = { | ||
43 | 0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12, | ||
44 | 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x01, | ||
45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
47 | }; | ||
48 | char *buffer; | ||
49 | int result; | ||
50 | |||
51 | US_DEBUGP("Option MS: %s", "DEVICE MODE SWITCH\n"); | ||
52 | |||
53 | buffer = kzalloc(RESPONSE_LEN, GFP_KERNEL); | ||
54 | if (buffer == NULL) | ||
55 | return USB_STOR_TRANSPORT_ERROR; | ||
56 | |||
57 | memcpy(buffer, rezero_msg, sizeof (rezero_msg)); | ||
58 | result = usb_stor_bulk_transfer_buf(us, | ||
59 | usb_sndbulkpipe(us->pusb_dev, ep_out), | ||
60 | buffer, sizeof (rezero_msg), NULL); | ||
61 | if (result != USB_STOR_XFER_GOOD) { | ||
62 | result = USB_STOR_XFER_ERROR; | ||
63 | goto out; | ||
64 | } | ||
65 | |||
66 | /* Some of the devices need to be asked for a response, but we don't | ||
67 | * care what that response is. | ||
68 | */ | ||
69 | result = usb_stor_bulk_transfer_buf(us, | ||
70 | usb_sndbulkpipe(us->pusb_dev, ep_out), | ||
71 | buffer, RESPONSE_LEN, NULL); | ||
72 | result = USB_STOR_XFER_GOOD; | ||
73 | |||
74 | out: | ||
75 | kfree(buffer); | ||
76 | return result; | ||
77 | } | ||
78 | |||
79 | int option_ms_init(struct us_data *us) | ||
80 | { | ||
81 | struct usb_device *udev; | ||
82 | struct usb_interface *intf; | ||
83 | struct usb_host_interface *iface_desc; | ||
84 | struct usb_endpoint_descriptor *endpoint = NULL; | ||
85 | u8 ep_in = 0, ep_out = 0; | ||
86 | int ep_in_size = 0, ep_out_size = 0; | ||
87 | int i, result; | ||
88 | |||
89 | udev = us->pusb_dev; | ||
90 | intf = us->pusb_intf; | ||
91 | |||
92 | /* Ensure it's really a ZeroCD device; devices that are already | ||
93 | * in modem mode return 0xFF for class, subclass, and protocol. | ||
94 | */ | ||
95 | if (udev->descriptor.bDeviceClass != 0 || | ||
96 | udev->descriptor.bDeviceSubClass != 0 || | ||
97 | udev->descriptor.bDeviceProtocol != 0) | ||
98 | return USB_STOR_TRANSPORT_GOOD; | ||
99 | |||
100 | US_DEBUGP("Option MS: option_ms_init called\n"); | ||
101 | |||
102 | /* Find the right mass storage interface */ | ||
103 | iface_desc = intf->cur_altsetting; | ||
104 | if (iface_desc->desc.bInterfaceClass != 0x8 || | ||
105 | iface_desc->desc.bInterfaceSubClass != 0x6 || | ||
106 | iface_desc->desc.bInterfaceProtocol != 0x50) { | ||
107 | US_DEBUGP("Option MS: mass storage interface not found, no action " | ||
108 | "required\n"); | ||
109 | return USB_STOR_TRANSPORT_GOOD; | ||
110 | } | ||
111 | |||
112 | /* Find the mass storage bulk endpoints */ | ||
113 | for (i = 0; i < iface_desc->desc.bNumEndpoints && (!ep_in_size || !ep_out_size); ++i) { | ||
114 | endpoint = &iface_desc->endpoint[i].desc; | ||
115 | |||
116 | if (usb_endpoint_is_bulk_in(endpoint)) { | ||
117 | ep_in = usb_endpoint_num(endpoint); | ||
118 | ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize); | ||
119 | } else if (usb_endpoint_is_bulk_out(endpoint)) { | ||
120 | ep_out = usb_endpoint_num(endpoint); | ||
121 | ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | /* Can't find the mass storage endpoints */ | ||
126 | if (!ep_in_size || !ep_out_size) { | ||
127 | US_DEBUGP("Option MS: mass storage endpoints not found, no action " | ||
128 | "required\n"); | ||
129 | return USB_STOR_TRANSPORT_GOOD; | ||
130 | } | ||
131 | |||
132 | /* Force Modem mode */ | ||
133 | if (option_zero_cd == ZCD_FORCE_MODEM) { | ||
134 | US_DEBUGP("Option MS: %s", "Forcing Modem Mode\n"); | ||
135 | result = option_rezero(us, ep_in, ep_out); | ||
136 | if (result != USB_STOR_XFER_GOOD) | ||
137 | US_DEBUGP("Option MS: Failed to switch to modem mode.\n"); | ||
138 | return -EIO; | ||
139 | } else if (option_zero_cd == ZCD_ALLOW_MS) { | ||
140 | /* Allow Mass Storage mode (keep CD-Rom) */ | ||
141 | US_DEBUGP("Option MS: %s", "Allowing Mass Storage Mode if device" | ||
142 | " requests it\n"); | ||
143 | } | ||
144 | |||
145 | return USB_STOR_TRANSPORT_GOOD; | ||
146 | } | ||
147 | |||
diff --git a/drivers/usb/storage/option_ms.h b/drivers/usb/storage/option_ms.h new file mode 100644 index 000000000000..b6e448cab039 --- /dev/null +++ b/drivers/usb/storage/option_ms.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef _OPTION_MS_H_ | ||
2 | #define _OPTION_MS_H_ | ||
3 | extern int option_ms_init(struct us_data *us); | ||
4 | #endif | ||
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 0fd42a0c794f..0330ed53ec1c 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h | |||
@@ -985,6 +985,18 @@ UNUSUAL_DEV( 0x05ac, 0x120a, 0x0000, 0x9999, | |||
985 | US_SC_DEVICE, US_PR_DEVICE, NULL, | 985 | US_SC_DEVICE, US_PR_DEVICE, NULL, |
986 | US_FL_FIX_CAPACITY ), | 986 | US_FL_FIX_CAPACITY ), |
987 | 987 | ||
988 | /* Reported by Dan Williams <dcbw@redhat.com> | ||
989 | * Option N.V. mobile broadband modems | ||
990 | * Ignore driver CD mode and force into modem mode by default. | ||
991 | */ | ||
992 | |||
993 | /* Globetrotter HSDPA; mass storage shows up as Qualcomm for vendor */ | ||
994 | UNUSUAL_DEV( 0x05c6, 0x1000, 0x0000, 0x9999, | ||
995 | "Option N.V.", | ||
996 | "Mass Storage", | ||
997 | US_SC_DEVICE, US_PR_DEVICE, option_ms_init, | ||
998 | 0), | ||
999 | |||
988 | #ifdef CONFIG_USB_STORAGE_JUMPSHOT | 1000 | #ifdef CONFIG_USB_STORAGE_JUMPSHOT |
989 | UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001, | 1001 | UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001, |
990 | "Lexar", | 1002 | "Lexar", |
@@ -1474,6 +1486,18 @@ UNUSUAL_DEV( 0x0ace, 0x20ff, 0x0101, 0x0101, | |||
1474 | US_SC_DEVICE, US_PR_DEVICE, NULL, | 1486 | US_SC_DEVICE, US_PR_DEVICE, NULL, |
1475 | US_FL_IGNORE_DEVICE ), | 1487 | US_FL_IGNORE_DEVICE ), |
1476 | 1488 | ||
1489 | /* Reported by Dan Williams <dcbw@redhat.com> | ||
1490 | * Option N.V. mobile broadband modems | ||
1491 | * Ignore driver CD mode and force into modem mode by default. | ||
1492 | */ | ||
1493 | |||
1494 | /* iCON 225 */ | ||
1495 | UNUSUAL_DEV( 0x0af0, 0x6971, 0x0000, 0x9999, | ||
1496 | "Option N.V.", | ||
1497 | "Mass Storage", | ||
1498 | US_SC_DEVICE, US_PR_DEVICE, option_ms_init, | ||
1499 | 0), | ||
1500 | |||
1477 | /* Reported by F. Aben <f.aben@option.com> | 1501 | /* Reported by F. Aben <f.aben@option.com> |
1478 | * This device (wrongly) has a vendor-specific device descriptor. | 1502 | * This device (wrongly) has a vendor-specific device descriptor. |
1479 | * The entry is needed so usb-storage can bind to it's mass-storage | 1503 | * The entry is needed so usb-storage can bind to it's mass-storage |
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index b25c448d5eb7..ce0b580db5ea 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c | |||
@@ -100,6 +100,7 @@ | |||
100 | #include "cypress_atacb.h" | 100 | #include "cypress_atacb.h" |
101 | #endif | 101 | #endif |
102 | #include "sierra_ms.h" | 102 | #include "sierra_ms.h" |
103 | #include "option_ms.h" | ||
103 | 104 | ||
104 | /* Some informational data */ | 105 | /* Some informational data */ |
105 | MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); | 106 | MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); |