blob: 7c0b05a3655432b78e3c1bee5dbee4cd9e5883ec [file] [log] [blame]
Greg Kroah-Hartman5fd54ac2017-11-03 11:28:30 +01001// SPDX-License-Identifier: GPL-2.0+
Dan Williams281b0642008-12-14 12:39:22 -05002/*
3 * Driver for Option High Speed Mobile Devices.
4 *
5 * (c) 2008 Dan Williams <dcbw@redhat.com>
6 *
7 * Inspiration taken from sierra_ms.c by Kevin Lloyd <klloyd@sierrawireless.com>
Dan Williams281b0642008-12-14 12:39:22 -05008 */
9
10#include <linux/usb.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090011#include <linux/slab.h>
Paul Gortmaker6eb0de82011-07-03 16:09:31 -040012#include <linux/module.h>
Dan Williams281b0642008-12-14 12:39:22 -050013
14#include "usb.h"
15#include "transport.h"
16#include "option_ms.h"
17#include "debug.h"
18
19#define ZCD_FORCE_MODEM 0x01
20#define ZCD_ALLOW_MS 0x02
21
22static unsigned int option_zero_cd = ZCD_FORCE_MODEM;
23module_param(option_zero_cd, uint, S_IRUGO | S_IWUSR);
24MODULE_PARM_DESC(option_zero_cd, "ZeroCD mode (1=Force Modem (default),"
25 " 2=Allow CD-Rom");
26
27#define RESPONSE_LEN 1024
28
Josua Dietze32ebbe72009-05-24 23:21:42 +020029static int option_rezero(struct us_data *us)
Dan Williams281b0642008-12-14 12:39:22 -050030{
Colin Ian King38502ef2017-09-12 12:38:35 +010031 static const unsigned char rezero_msg[] = {
Dan Williams281b0642008-12-14 12:39:22 -050032 0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12,
33 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x01,
34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
36 };
37 char *buffer;
38 int result;
39
Joe Perches191648d2013-04-19 11:44:00 -070040 usb_stor_dbg(us, "Option MS: %s\n", "DEVICE MODE SWITCH");
Dan Williams281b0642008-12-14 12:39:22 -050041
42 buffer = kzalloc(RESPONSE_LEN, GFP_KERNEL);
43 if (buffer == NULL)
44 return USB_STOR_TRANSPORT_ERROR;
45
Josua Dietze32ebbe72009-05-24 23:21:42 +020046 memcpy(buffer, rezero_msg, sizeof(rezero_msg));
Dan Williams281b0642008-12-14 12:39:22 -050047 result = usb_stor_bulk_transfer_buf(us,
Josua Dietze32ebbe72009-05-24 23:21:42 +020048 us->send_bulk_pipe,
49 buffer, sizeof(rezero_msg), NULL);
Dan Williams281b0642008-12-14 12:39:22 -050050 if (result != USB_STOR_XFER_GOOD) {
51 result = USB_STOR_XFER_ERROR;
52 goto out;
53 }
54
Felipe Balbif0183a32016-04-18 13:09:11 +030055 /*
56 * Some of the devices need to be asked for a response, but we don't
Dan Williams281b0642008-12-14 12:39:22 -050057 * care what that response is.
58 */
Josua Dietze32ebbe72009-05-24 23:21:42 +020059 usb_stor_bulk_transfer_buf(us,
60 us->recv_bulk_pipe,
Dan Williams281b0642008-12-14 12:39:22 -050061 buffer, RESPONSE_LEN, NULL);
Josua Dietze32ebbe72009-05-24 23:21:42 +020062
63 /* Read the CSW */
64 usb_stor_bulk_transfer_buf(us,
65 us->recv_bulk_pipe,
66 buffer, 13, NULL);
67
Dan Williams281b0642008-12-14 12:39:22 -050068 result = USB_STOR_XFER_GOOD;
69
70out:
71 kfree(buffer);
72 return result;
73}
74
Josua Dietze32ebbe72009-05-24 23:21:42 +020075static int option_inquiry(struct us_data *us)
76{
Colin Ian King38502ef2017-09-12 12:38:35 +010077 static const unsigned char inquiry_msg[] = {
Josua Dietze32ebbe72009-05-24 23:21:42 +020078 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
79 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12,
80 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
82 };
83 char *buffer;
84 int result;
85
Joe Perches191648d2013-04-19 11:44:00 -070086 usb_stor_dbg(us, "Option MS: %s\n", "device inquiry for vendor name");
Josua Dietze32ebbe72009-05-24 23:21:42 +020087
88 buffer = kzalloc(0x24, GFP_KERNEL);
89 if (buffer == NULL)
90 return USB_STOR_TRANSPORT_ERROR;
91
92 memcpy(buffer, inquiry_msg, sizeof(inquiry_msg));
93 result = usb_stor_bulk_transfer_buf(us,
94 us->send_bulk_pipe,
95 buffer, sizeof(inquiry_msg), NULL);
96 if (result != USB_STOR_XFER_GOOD) {
97 result = USB_STOR_XFER_ERROR;
98 goto out;
99 }
100
101 result = usb_stor_bulk_transfer_buf(us,
102 us->recv_bulk_pipe,
103 buffer, 0x24, NULL);
104 if (result != USB_STOR_XFER_GOOD) {
105 result = USB_STOR_XFER_ERROR;
106 goto out;
107 }
108
109 result = memcmp(buffer+8, "Option", 6);
110
Jonathan McDowell2ab21782009-07-05 12:29:51 +0100111 if (result != 0)
112 result = memcmp(buffer+8, "ZCOPTION", 8);
113
Josua Dietze32ebbe72009-05-24 23:21:42 +0200114 /* Read the CSW */
115 usb_stor_bulk_transfer_buf(us,
116 us->recv_bulk_pipe,
117 buffer, 13, NULL);
118
119out:
120 kfree(buffer);
121 return result;
122}
123
124
Dan Williams281b0642008-12-14 12:39:22 -0500125int option_ms_init(struct us_data *us)
126{
Josua Dietze32ebbe72009-05-24 23:21:42 +0200127 int result;
Dan Williams281b0642008-12-14 12:39:22 -0500128
Joe Perches191648d2013-04-19 11:44:00 -0700129 usb_stor_dbg(us, "Option MS: %s\n", "option_ms_init called");
Dan Williams281b0642008-12-14 12:39:22 -0500130
Felipe Balbif0183a32016-04-18 13:09:11 +0300131 /*
132 * Additional test for vendor information via INQUIRY,
Josua Dietze32ebbe72009-05-24 23:21:42 +0200133 * because some vendor/product IDs are ambiguous
134 */
135 result = option_inquiry(us);
136 if (result != 0) {
Joe Perches191648d2013-04-19 11:44:00 -0700137 usb_stor_dbg(us, "Option MS: %s\n",
138 "vendor is not Option or not determinable, no action taken");
Alan Sternbe475d902009-05-21 17:37:58 -0400139 return 0;
Josua Dietze32ebbe72009-05-24 23:21:42 +0200140 } else
Joe Perches191648d2013-04-19 11:44:00 -0700141 usb_stor_dbg(us, "Option MS: %s\n",
142 "this is a genuine Option device, proceeding");
Dan Williams281b0642008-12-14 12:39:22 -0500143
144 /* Force Modem mode */
145 if (option_zero_cd == ZCD_FORCE_MODEM) {
Joe Perches191648d2013-04-19 11:44:00 -0700146 usb_stor_dbg(us, "Option MS: %s\n", "Forcing Modem Mode");
Josua Dietze32ebbe72009-05-24 23:21:42 +0200147 result = option_rezero(us);
Dan Williams281b0642008-12-14 12:39:22 -0500148 if (result != USB_STOR_XFER_GOOD)
Joe Perches191648d2013-04-19 11:44:00 -0700149 usb_stor_dbg(us, "Option MS: %s\n",
150 "Failed to switch to modem mode");
Dan Williams281b0642008-12-14 12:39:22 -0500151 return -EIO;
152 } else if (option_zero_cd == ZCD_ALLOW_MS) {
153 /* Allow Mass Storage mode (keep CD-Rom) */
Joe Perches191648d2013-04-19 11:44:00 -0700154 usb_stor_dbg(us, "Option MS: %s\n",
155 "Allowing Mass Storage Mode if device requests it");
Dan Williams281b0642008-12-14 12:39:22 -0500156 }
157
Alan Sternbe475d902009-05-21 17:37:58 -0400158 return 0;
Dan Williams281b0642008-12-14 12:39:22 -0500159}
160