Branch data Line data Source code
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 : : #include <linux/slab.h>
25 : : #include <linux/module.h>
26 : :
27 : : #include "usb.h"
28 : : #include "transport.h"
29 : : #include "option_ms.h"
30 : : #include "debug.h"
31 : :
32 : : #define ZCD_FORCE_MODEM 0x01
33 : : #define ZCD_ALLOW_MS 0x02
34 : :
35 : : static unsigned int option_zero_cd = ZCD_FORCE_MODEM;
36 : : module_param(option_zero_cd, uint, S_IRUGO | S_IWUSR);
37 : : MODULE_PARM_DESC(option_zero_cd, "ZeroCD mode (1=Force Modem (default),"
38 : : " 2=Allow CD-Rom");
39 : :
40 : : #define RESPONSE_LEN 1024
41 : :
42 : 0 : static int option_rezero(struct us_data *us)
43 : : {
44 : 0 : const unsigned char rezero_msg[] = {
45 : : 0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12,
46 : : 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x01,
47 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
49 : : };
50 : : char *buffer;
51 : : int result;
52 : :
53 : : usb_stor_dbg(us, "Option MS: %s\n", "DEVICE MODE SWITCH");
54 : :
55 : : buffer = kzalloc(RESPONSE_LEN, GFP_KERNEL);
56 [ # # ]: 0 : if (buffer == NULL)
57 : : return USB_STOR_TRANSPORT_ERROR;
58 : :
59 : 0 : memcpy(buffer, rezero_msg, sizeof(rezero_msg));
60 : 0 : result = usb_stor_bulk_transfer_buf(us,
61 : : us->send_bulk_pipe,
62 : : buffer, sizeof(rezero_msg), NULL);
63 [ # # ]: 0 : if (result != USB_STOR_XFER_GOOD) {
64 : : result = USB_STOR_XFER_ERROR;
65 : : goto out;
66 : : }
67 : :
68 : : /* Some of the devices need to be asked for a response, but we don't
69 : : * care what that response is.
70 : : */
71 : 0 : usb_stor_bulk_transfer_buf(us,
72 : : us->recv_bulk_pipe,
73 : : buffer, RESPONSE_LEN, NULL);
74 : :
75 : : /* Read the CSW */
76 : 0 : usb_stor_bulk_transfer_buf(us,
77 : : us->recv_bulk_pipe,
78 : : buffer, 13, NULL);
79 : :
80 : : result = USB_STOR_XFER_GOOD;
81 : :
82 : : out:
83 : 0 : kfree(buffer);
84 : 0 : return result;
85 : : }
86 : :
87 : 0 : static int option_inquiry(struct us_data *us)
88 : : {
89 : 0 : const unsigned char inquiry_msg[] = {
90 : : 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
91 : : 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12,
92 : : 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
93 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
94 : : };
95 : : char *buffer;
96 : : int result;
97 : :
98 : : usb_stor_dbg(us, "Option MS: %s\n", "device inquiry for vendor name");
99 : :
100 : : buffer = kzalloc(0x24, GFP_KERNEL);
101 [ # # ]: 0 : if (buffer == NULL)
102 : : return USB_STOR_TRANSPORT_ERROR;
103 : :
104 : 0 : memcpy(buffer, inquiry_msg, sizeof(inquiry_msg));
105 : 0 : result = usb_stor_bulk_transfer_buf(us,
106 : : us->send_bulk_pipe,
107 : : buffer, sizeof(inquiry_msg), NULL);
108 [ # # ]: 0 : if (result != USB_STOR_XFER_GOOD) {
109 : : result = USB_STOR_XFER_ERROR;
110 : : goto out;
111 : : }
112 : :
113 : 0 : result = usb_stor_bulk_transfer_buf(us,
114 : : us->recv_bulk_pipe,
115 : : buffer, 0x24, NULL);
116 [ # # ]: 0 : if (result != USB_STOR_XFER_GOOD) {
117 : : result = USB_STOR_XFER_ERROR;
118 : : goto out;
119 : : }
120 : :
121 : 0 : result = memcmp(buffer+8, "Option", 6);
122 : :
123 [ # # ]: 0 : if (result != 0)
124 : 0 : result = memcmp(buffer+8, "ZCOPTION", 8);
125 : :
126 : : /* Read the CSW */
127 : 0 : usb_stor_bulk_transfer_buf(us,
128 : : us->recv_bulk_pipe,
129 : : buffer, 13, NULL);
130 : :
131 : : out:
132 : 0 : kfree(buffer);
133 : 0 : return result;
134 : : }
135 : :
136 : :
137 : 0 : int option_ms_init(struct us_data *us)
138 : : {
139 : : int result;
140 : :
141 : : usb_stor_dbg(us, "Option MS: %s\n", "option_ms_init called");
142 : :
143 : : /* Additional test for vendor information via INQUIRY,
144 : : * because some vendor/product IDs are ambiguous
145 : : */
146 : 0 : result = option_inquiry(us);
147 [ # # ]: 0 : if (result != 0) {
148 : : usb_stor_dbg(us, "Option MS: %s\n",
149 : : "vendor is not Option or not determinable, no action taken");
150 : : return 0;
151 : : } else
152 : : usb_stor_dbg(us, "Option MS: %s\n",
153 : : "this is a genuine Option device, proceeding");
154 : :
155 : : /* Force Modem mode */
156 [ # # ]: 0 : if (option_zero_cd == ZCD_FORCE_MODEM) {
157 : : usb_stor_dbg(us, "Option MS: %s\n", "Forcing Modem Mode");
158 : 0 : result = option_rezero(us);
159 : : if (result != USB_STOR_XFER_GOOD)
160 : : usb_stor_dbg(us, "Option MS: %s\n",
161 : : "Failed to switch to modem mode");
162 : 0 : return -EIO;
163 : : } else if (option_zero_cd == ZCD_ALLOW_MS) {
164 : : /* Allow Mass Storage mode (keep CD-Rom) */
165 : : usb_stor_dbg(us, "Option MS: %s\n",
166 : : "Allowing Mass Storage Mode if device requests it");
167 : : }
168 : :
169 : : return 0;
170 : : }
171 : :
|