aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2008-12-14 12:39:22 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-07 13:00:09 -0500
commit281b064f237205053ef1874ffc77b9211265af4c (patch)
tree0a5c9efd36c71fef29eb75cc22dc0ecf43f6e60a /drivers/usb/storage
parent49367d8f1d9f26482cf7089489e90f0afd0a942c (diff)
USB: unusual dev for Option N.V. ZeroCD modems
Many newer Option mobile broadband devices initially provide a usb-storage "driver CD" device that's pretty useless on Linux since any software on it most likely wouldn't be compatible with your kernel or distro anyway. Thus, by default just kill the driver CD device by sending the SCSI 'rezero' command, but allow override of the default behavior via usb-storage module parameter so users can keep the ZeroCD device if they really want to. Inspired by the Sierra TruInstall patch. Signed-off-by: Dan Williams <dcbw@redhat.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Cc: Peter Henn <p.henn@option.com Cc: Denis Joseph Barrow <D.Barow@option.com> Cc: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r--drivers/usb/storage/Makefile2
-rw-r--r--drivers/usb/storage/option_ms.c147
-rw-r--r--drivers/usb/storage/option_ms.h4
-rw-r--r--drivers/usb/storage/unusual_devs.h24
-rw-r--r--drivers/usb/storage/usb.c1
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
23usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o 23usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o
24 24
25usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ 25usb-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
28ifneq ($(CONFIG_USB_LIBUSUAL),) 28ifneq ($(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
33static unsigned int option_zero_cd = ZCD_FORCE_MODEM;
34module_param(option_zero_cd, uint, S_IRUGO | S_IWUSR);
35MODULE_PARM_DESC(option_zero_cd, "ZeroCD mode (1=Force Modem (default),"
36 " 2=Allow CD-Rom");
37
38#define RESPONSE_LEN 1024
39
40static 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
74out:
75 kfree(buffer);
76 return result;
77}
78
79int 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_
3extern 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 */
994UNUSUAL_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
989UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001, 1001UNUSUAL_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 */
1495UNUSUAL_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 */
105MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); 106MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");