aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKevin Lloyd <klloyd@sierrawireless.com>2008-07-10 17:14:57 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-08-13 20:32:51 -0400
commit32fe5e393455d87db4988af03915634304870fb4 (patch)
tree79040d3b0f6d6adcf0fa764b4d935d1d77c7a80c /drivers
parent0585e4dfe5670d3ccb77bf86551a657699e9e52e (diff)
USB Storage Sierra: TRU-Install feature update
This patch upgrades the support for the Sierra Wireless TRU-Install feature (i.e. zeroCD) to allow for future support of Linux enabled TRU-Install devices. By default all devices that do not have a Linux enabled TRU-Install device (i.e. the device does not have a Linux package on the virtual CD partition) will be switched into "modem mode." Devices that do contain a Linux package in the TRU-Install virtual CD will be allowed to enumerate as a CD-Rom so that either (a) a user can install the packaged software or (b) a user-space application (e.g. udev) can switch it to modem mode. This patch does allow for manual override by adding a usb-storage module parameter 'swi_tru_install' which can force the modem into either mode regardless of what packages it contains. Signed-off-by: Kevin Lloyd <klloyd@sierrawireless.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/storage/Kconfig12
-rw-r--r--drivers/usb/storage/Makefile1
-rw-r--r--drivers/usb/storage/sierra_ms.c207
-rw-r--r--drivers/usb/storage/sierra_ms.h4
-rw-r--r--drivers/usb/storage/unusual_devs.h6
-rw-r--r--drivers/usb/storage/usb.c3
6 files changed, 231 insertions, 2 deletions
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index 3d9249632ae1..c76034672c18 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -146,6 +146,18 @@ config USB_STORAGE_KARMA
146 on the resulting scsi device node returns the Karma to normal 146 on the resulting scsi device node returns the Karma to normal
147 operation. 147 operation.
148 148
149config USB_STORAGE_SIERRA
150 bool "Sierra Wireless TRU-Install Feature Support"
151 depends on USB_STORAGE
152 help
153 Say Y here to include additional code to support Sierra Wireless
154 products with the TRU-Install feature (e.g., AC597E, AC881U).
155
156 This code switches the Sierra Wireless device from being in
157 Mass Storage mode to Modem mode. It also has the ability to
158 support host software upgrades should full Linux support be added
159 to TRU-Install.
160
149config USB_STORAGE_CYPRESS_ATACB 161config USB_STORAGE_CYPRESS_ATACB
150 bool "SAT emulation on Cypress USB/ATA Bridge with ATACB" 162 bool "SAT emulation on Cypress USB/ATA Bridge with ATACB"
151 depends on USB_STORAGE 163 depends on USB_STORAGE
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
index 4c596c766c53..bc3415b475c9 100644
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -21,6 +21,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
21usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA) += alauda.o 21usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA) += alauda.o
22usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o 22usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o
23usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA) += karma.o 23usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA) += karma.o
24usb-storage-obj-$(CONFIG_USB_STORAGE_SIERRA) += sierra_ms.o
24usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o 25usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o
25 26
26usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ 27usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c
new file mode 100644
index 000000000000..4359a2cb42df
--- /dev/null
+++ b/drivers/usb/storage/sierra_ms.c
@@ -0,0 +1,207 @@
1#include <scsi/scsi.h>
2#include <scsi/scsi_host.h>
3#include <scsi/scsi_cmnd.h>
4#include <scsi/scsi_device.h>
5#include <linux/usb.h>
6
7#include "usb.h"
8#include "transport.h"
9#include "protocol.h"
10#include "scsiglue.h"
11#include "sierra_ms.h"
12#include "debug.h"
13
14#define SWIMS_USB_REQUEST_SetSwocMode 0x0B
15#define SWIMS_USB_REQUEST_GetSwocInfo 0x0A
16#define SWIMS_USB_INDEX_SetMode 0x0000
17#define SWIMS_SET_MODE_Modem 0x0001
18
19#define TRU_NORMAL 0x01
20#define TRU_FORCE_MS 0x02
21#define TRU_FORCE_MODEM 0x03
22
23static unsigned int swi_tru_install = 1;
24module_param(swi_tru_install, uint, S_IRUGO | S_IWUSR);
25MODULE_PARM_DESC(swi_tru_install, "TRU-Install mode (1=Full Logic (def),"
26 " 2=Force CD-Rom, 3=Force Modem)");
27
28struct swoc_info {
29 __u8 rev;
30 __u8 reserved[8];
31 __u16 LinuxSKU;
32 __u16 LinuxVer;
33 __u8 reserved2[47];
34} __attribute__((__packed__));
35
36static bool containsFullLinuxPackage(struct swoc_info *swocInfo)
37{
38 if ((swocInfo->LinuxSKU >= 0x2100 && swocInfo->LinuxSKU <= 0x2FFF) ||
39 (swocInfo->LinuxSKU >= 0x7100 && swocInfo->LinuxSKU <= 0x7FFF))
40 return true;
41 else
42 return false;
43}
44
45static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode)
46{
47 int result;
48 US_DEBUGP("SWIMS: %s", "DEVICE MODE SWITCH\n");
49 result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
50 SWIMS_USB_REQUEST_SetSwocMode, /* __u8 request */
51 USB_TYPE_VENDOR | USB_DIR_OUT, /* __u8 request type */
52 eSWocMode, /* __u16 value */
53 0x0000, /* __u16 index */
54 NULL, /* void *data */
55 0, /* __u16 size */
56 USB_CTRL_SET_TIMEOUT); /* int timeout */
57 return result;
58}
59
60
61static int sierra_get_swoc_info(struct usb_device *udev,
62 struct swoc_info *swocInfo)
63{
64 int result;
65
66 US_DEBUGP("SWIMS: Attempting to get TRU-Install info.\n");
67
68 result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
69 SWIMS_USB_REQUEST_GetSwocInfo, /* __u8 request */
70 USB_TYPE_VENDOR | USB_DIR_IN, /* __u8 request type */
71 0, /* __u16 value */
72 0, /* __u16 index */
73 (void *) swocInfo, /* void *data */
74 sizeof(struct swoc_info), /* __u16 size */
75 USB_CTRL_SET_TIMEOUT); /* int timeout */
76
77 swocInfo->LinuxSKU = le16_to_cpu(swocInfo->LinuxSKU);
78 swocInfo->LinuxVer = le16_to_cpu(swocInfo->LinuxVer);
79 return result;
80}
81
82static void debug_swoc(struct swoc_info *swocInfo)
83{
84 US_DEBUGP("SWIMS: SWoC Rev: %02d \n", swocInfo->rev);
85 US_DEBUGP("SWIMS: Linux SKU: %04X \n", swocInfo->LinuxSKU);
86 US_DEBUGP("SWIMS: Linux Version: %04X \n", swocInfo->LinuxVer);
87}
88
89
90static ssize_t show_truinst(struct device *dev, struct device_attribute *attr,
91 char *buf)
92{
93 struct swoc_info *swocInfo;
94 struct usb_interface *intf = to_usb_interface(dev);
95 struct usb_device *udev = interface_to_usbdev(intf);
96 int result;
97 if (swi_tru_install == TRU_FORCE_MS) {
98 result = snprintf(buf, PAGE_SIZE, "Forced Mass Storage\n");
99 } else {
100 swocInfo = kmalloc(sizeof(struct swoc_info), GFP_KERNEL);
101 if (!swocInfo) {
102 US_DEBUGP("SWIMS: Allocation failure\n");
103 snprintf(buf, PAGE_SIZE, "Error\n");
104 return -ENOMEM;
105 }
106 result = sierra_get_swoc_info(udev, swocInfo);
107 if (result < 0) {
108 US_DEBUGP("SWIMS: failed SWoC query\n");
109 kfree(swocInfo);
110 snprintf(buf, PAGE_SIZE, "Error\n");
111 return -EIO;
112 }
113 debug_swoc(swocInfo);
114 result = snprintf(buf, PAGE_SIZE,
115 "REV=%02d SKU=%04X VER=%04X\n",
116 swocInfo->rev,
117 swocInfo->LinuxSKU,
118 swocInfo->LinuxVer);
119 kfree(swocInfo);
120 }
121 return result;
122}
123static DEVICE_ATTR(truinst, S_IWUGO | S_IRUGO, show_truinst, NULL);
124
125int sierra_ms_init(struct us_data *us)
126{
127 int result, retries;
128 signed long delay_t;
129 struct swoc_info *swocInfo;
130 struct usb_device *udev;
131 struct Scsi_Host *sh;
132 struct scsi_device *sd;
133
134 delay_t = 2;
135 retries = 3;
136 result = 0;
137 udev = us->pusb_dev;
138
139 sh = us_to_host(us);
140 sd = scsi_get_host_dev(sh);
141
142 US_DEBUGP("SWIMS: sierra_ms_init called\n");
143
144 /* Force Modem mode */
145 if (swi_tru_install == TRU_FORCE_MODEM) {
146 US_DEBUGP("SWIMS: %s", "Forcing Modem Mode\n");
147 result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
148 if (result < 0)
149 US_DEBUGP("SWIMS: Failed to switch to modem mode.\n");
150 return -EIO;
151 }
152 /* Force Mass Storage mode (keep CD-Rom) */
153 else if (swi_tru_install == TRU_FORCE_MS) {
154 US_DEBUGP("SWIMS: %s", "Forcing Mass Storage Mode\n");
155 goto complete;
156 }
157 /* Normal TRU-Install Logic */
158 else {
159 US_DEBUGP("SWIMS: %s", "Normal SWoC Logic\n");
160
161 swocInfo = kmalloc(sizeof(struct swoc_info),
162 GFP_KERNEL);
163 if (!swocInfo) {
164 US_DEBUGP("SWIMS: %s", "Allocation failure\n");
165 return -ENOMEM;
166 }
167
168 retries = 3;
169 do {
170 retries--;
171 result = sierra_get_swoc_info(udev, swocInfo);
172 if (result < 0) {
173 US_DEBUGP("SWIMS: %s", "Failed SWoC query\n");
174 schedule_timeout_uninterruptible(2*HZ);
175 }
176 } while (retries && result < 0);
177
178 if (result < 0) {
179 US_DEBUGP("SWIMS: %s",
180 "Completely failed SWoC query\n");
181 kfree(swocInfo);
182 return -EIO;
183 }
184
185 debug_swoc(swocInfo);
186
187 /* If there is not Linux software on the TRU-Install device
188 * then switch to modem mode
189 */
190 if (!containsFullLinuxPackage(swocInfo)) {
191 US_DEBUGP("SWIMS: %s",
192 "Switching to Modem Mode\n");
193 result = sierra_set_ms_mode(udev,
194 SWIMS_SET_MODE_Modem);
195 if (result < 0)
196 US_DEBUGP("SWIMS: Failed to switch modem\n");
197 kfree(swocInfo);
198 return -EIO;
199 }
200 kfree(swocInfo);
201 }
202complete:
203 result = device_create_file(&us->pusb_intf->dev, &dev_attr_truinst);
204
205 return USB_STOR_TRANSPORT_GOOD;
206}
207
diff --git a/drivers/usb/storage/sierra_ms.h b/drivers/usb/storage/sierra_ms.h
new file mode 100644
index 000000000000..bb48634ac1fc
--- /dev/null
+++ b/drivers/usb/storage/sierra_ms.h
@@ -0,0 +1,4 @@
1#ifndef _SIERRA_MS_H_
2#define _SIERRA_MS_H_
3extern int sierra_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 11249bf5d74f..927572377f32 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1569,6 +1569,7 @@ UNUSUAL_DEV( 0x10d6, 0x2200, 0x0100, 0x0100,
1569 US_SC_DEVICE, US_PR_DEVICE, NULL, 1569 US_SC_DEVICE, US_PR_DEVICE, NULL,
1570 0), 1570 0),
1571 1571
1572#ifdef CONFIG_USB_STORAGE_SIERRA
1572/* Reported by Kevin Lloyd <linux@sierrawireless.com> 1573/* Reported by Kevin Lloyd <linux@sierrawireless.com>
1573 * Entry is needed for the initializer function override, 1574 * Entry is needed for the initializer function override,
1574 * which instructs the device to load as a modem 1575 * which instructs the device to load as a modem
@@ -1577,8 +1578,9 @@ UNUSUAL_DEV( 0x10d6, 0x2200, 0x0100, 0x0100,
1577UNUSUAL_DEV( 0x1199, 0x0fff, 0x0000, 0x9999, 1578UNUSUAL_DEV( 0x1199, 0x0fff, 0x0000, 0x9999,
1578 "Sierra Wireless", 1579 "Sierra Wireless",
1579 "USB MMC Storage", 1580 "USB MMC Storage",
1580 US_SC_DEVICE, US_PR_DEVICE, NULL, 1581 US_SC_DEVICE, US_PR_DEVICE, sierra_ms_init,
1581 US_FL_IGNORE_DEVICE), 1582 0),
1583#endif
1582 1584
1583/* Reported by Jaco Kroon <jaco@kroon.co.za> 1585/* Reported by Jaco Kroon <jaco@kroon.co.za>
1584 * The usb-storage module found on the Digitech GNX4 (and supposedly other 1586 * The usb-storage module found on the Digitech GNX4 (and supposedly other
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index bfea851be985..73679aa506de 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -102,6 +102,9 @@
102#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB 102#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
103#include "cypress_atacb.h" 103#include "cypress_atacb.h"
104#endif 104#endif
105#ifdef CONFIG_USB_STORAGE_SIERRA
106#include "sierra_ms.h"
107#endif
105 108
106/* Some informational data */ 109/* Some informational data */
107MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); 110MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");