Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Driver for Option High Speed Mobile Devices.
0004  *
0005  *   (c) 2008 Dan Williams <dcbw@redhat.com>
0006  *
0007  * Inspiration taken from sierra_ms.c by Kevin Lloyd <klloyd@sierrawireless.com>
0008  */
0009 
0010 #include <linux/usb.h>
0011 #include <linux/slab.h>
0012 #include <linux/module.h>
0013 
0014 #include "usb.h"
0015 #include "transport.h"
0016 #include "option_ms.h"
0017 #include "debug.h"
0018 
0019 #define ZCD_FORCE_MODEM         0x01
0020 #define ZCD_ALLOW_MS            0x02
0021 
0022 static unsigned int option_zero_cd = ZCD_FORCE_MODEM;
0023 module_param(option_zero_cd, uint, S_IRUGO | S_IWUSR);
0024 MODULE_PARM_DESC(option_zero_cd, "ZeroCD mode (1=Force Modem (default),"
0025          " 2=Allow CD-Rom");
0026 
0027 #define RESPONSE_LEN 1024
0028 
0029 static int option_rezero(struct us_data *us)
0030 {
0031     static const unsigned char rezero_msg[] = {
0032       0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12,
0033       0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x01,
0034       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0035       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0036     };
0037     char *buffer;
0038     int result;
0039 
0040     usb_stor_dbg(us, "Option MS: %s\n", "DEVICE MODE SWITCH");
0041 
0042     buffer = kzalloc(RESPONSE_LEN, GFP_KERNEL);
0043     if (buffer == NULL)
0044         return USB_STOR_TRANSPORT_ERROR;
0045 
0046     memcpy(buffer, rezero_msg, sizeof(rezero_msg));
0047     result = usb_stor_bulk_transfer_buf(us,
0048             us->send_bulk_pipe,
0049             buffer, sizeof(rezero_msg), NULL);
0050     if (result != USB_STOR_XFER_GOOD) {
0051         result = USB_STOR_XFER_ERROR;
0052         goto out;
0053     }
0054 
0055     /*
0056      * Some of the devices need to be asked for a response, but we don't
0057      * care what that response is.
0058      */
0059     usb_stor_bulk_transfer_buf(us,
0060             us->recv_bulk_pipe,
0061             buffer, RESPONSE_LEN, NULL);
0062 
0063     /* Read the CSW */
0064     usb_stor_bulk_transfer_buf(us,
0065             us->recv_bulk_pipe,
0066             buffer, 13, NULL);
0067 
0068     result = USB_STOR_XFER_GOOD;
0069 
0070 out:
0071     kfree(buffer);
0072     return result;
0073 }
0074 
0075 static int option_inquiry(struct us_data *us)
0076 {
0077     static const unsigned char inquiry_msg[] = {
0078       0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
0079       0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12,
0080       0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
0081       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0082     };
0083     char *buffer;
0084     int result;
0085 
0086     usb_stor_dbg(us, "Option MS: %s\n", "device inquiry for vendor name");
0087 
0088     buffer = kzalloc(0x24, GFP_KERNEL);
0089     if (buffer == NULL)
0090         return USB_STOR_TRANSPORT_ERROR;
0091 
0092     memcpy(buffer, inquiry_msg, sizeof(inquiry_msg));
0093     result = usb_stor_bulk_transfer_buf(us,
0094             us->send_bulk_pipe,
0095             buffer, sizeof(inquiry_msg), NULL);
0096     if (result != USB_STOR_XFER_GOOD) {
0097         result = USB_STOR_XFER_ERROR;
0098         goto out;
0099     }
0100 
0101     result = usb_stor_bulk_transfer_buf(us,
0102             us->recv_bulk_pipe,
0103             buffer, 0x24, NULL);
0104     if (result != USB_STOR_XFER_GOOD) {
0105         result = USB_STOR_XFER_ERROR;
0106         goto out;
0107     }
0108 
0109     result = memcmp(buffer+8, "Option", 6);
0110 
0111     if (result != 0)
0112         result = memcmp(buffer+8, "ZCOPTION", 8);
0113 
0114     /* Read the CSW */
0115     usb_stor_bulk_transfer_buf(us,
0116             us->recv_bulk_pipe,
0117             buffer, 13, NULL);
0118 
0119 out:
0120     kfree(buffer);
0121     return result;
0122 }
0123 
0124 
0125 int option_ms_init(struct us_data *us)
0126 {
0127     int result;
0128 
0129     usb_stor_dbg(us, "Option MS: %s\n", "option_ms_init called");
0130 
0131     /*
0132      * Additional test for vendor information via INQUIRY,
0133      * because some vendor/product IDs are ambiguous
0134      */
0135     result = option_inquiry(us);
0136     if (result != 0) {
0137         usb_stor_dbg(us, "Option MS: %s\n",
0138                  "vendor is not Option or not determinable, no action taken");
0139         return 0;
0140     } else
0141         usb_stor_dbg(us, "Option MS: %s\n",
0142                  "this is a genuine Option device, proceeding");
0143 
0144     /* Force Modem mode */
0145     if (option_zero_cd == ZCD_FORCE_MODEM) {
0146         usb_stor_dbg(us, "Option MS: %s\n", "Forcing Modem Mode");
0147         result = option_rezero(us);
0148         if (result != USB_STOR_XFER_GOOD)
0149             usb_stor_dbg(us, "Option MS: %s\n",
0150                      "Failed to switch to modem mode");
0151         return -EIO;
0152     } else if (option_zero_cd == ZCD_ALLOW_MS) {
0153         /* Allow Mass Storage mode (keep CD-Rom) */
0154         usb_stor_dbg(us, "Option MS: %s\n",
0155                  "Allowing Mass Storage Mode if device requests it");
0156     }
0157 
0158     return 0;
0159 }
0160