root/drivers/usb/storage/sierra_ms.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. containsFullLinuxPackage
  2. sierra_set_ms_mode
  3. sierra_get_swoc_info
  4. debug_swoc
  5. truinst_show
  6. sierra_ms_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <scsi/scsi.h>
   3 #include <scsi/scsi_host.h>
   4 #include <scsi/scsi_cmnd.h>
   5 #include <scsi/scsi_device.h>
   6 #include <linux/usb.h>
   7 #include <linux/module.h>
   8 #include <linux/slab.h>
   9 
  10 #include "usb.h"
  11 #include "transport.h"
  12 #include "protocol.h"
  13 #include "scsiglue.h"
  14 #include "sierra_ms.h"
  15 #include "debug.h"
  16 
  17 #define SWIMS_USB_REQUEST_SetSwocMode   0x0B
  18 #define SWIMS_USB_REQUEST_GetSwocInfo   0x0A
  19 #define SWIMS_USB_INDEX_SetMode         0x0000
  20 #define SWIMS_SET_MODE_Modem            0x0001
  21 
  22 #define TRU_NORMAL                      0x01
  23 #define TRU_FORCE_MS                    0x02
  24 #define TRU_FORCE_MODEM                 0x03
  25 
  26 static unsigned int swi_tru_install = 1;
  27 module_param(swi_tru_install, uint, S_IRUGO | S_IWUSR);
  28 MODULE_PARM_DESC(swi_tru_install, "TRU-Install mode (1=Full Logic (def),"
  29                  " 2=Force CD-Rom, 3=Force Modem)");
  30 
  31 struct swoc_info {
  32         __u8 rev;
  33         __u8 reserved[8];
  34         __u16 LinuxSKU;
  35         __u16 LinuxVer;
  36         __u8 reserved2[47];
  37 } __attribute__((__packed__));
  38 
  39 static bool containsFullLinuxPackage(struct swoc_info *swocInfo)
  40 {
  41         if ((swocInfo->LinuxSKU >= 0x2100 && swocInfo->LinuxSKU <= 0x2FFF) ||
  42            (swocInfo->LinuxSKU >= 0x7100 && swocInfo->LinuxSKU <= 0x7FFF))
  43                 return true;
  44         else
  45                 return false;
  46 }
  47 
  48 static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode)
  49 {
  50         int result;
  51         dev_dbg(&udev->dev, "SWIMS: %s", "DEVICE MODE SWITCH\n");
  52         result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
  53                         SWIMS_USB_REQUEST_SetSwocMode,  /* __u8 request      */
  54                         USB_TYPE_VENDOR | USB_DIR_OUT,  /* __u8 request type */
  55                         eSWocMode,                      /* __u16 value       */
  56                         0x0000,                         /* __u16 index       */
  57                         NULL,                           /* void *data        */
  58                         0,                              /* __u16 size        */
  59                         USB_CTRL_SET_TIMEOUT);          /* int timeout       */
  60         return result;
  61 }
  62 
  63 
  64 static int sierra_get_swoc_info(struct usb_device *udev,
  65                                 struct swoc_info *swocInfo)
  66 {
  67         int result;
  68 
  69         dev_dbg(&udev->dev, "SWIMS: Attempting to get TRU-Install info\n");
  70 
  71         result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
  72                         SWIMS_USB_REQUEST_GetSwocInfo,  /* __u8 request      */
  73                         USB_TYPE_VENDOR | USB_DIR_IN,   /* __u8 request type */
  74                         0,                              /* __u16 value       */
  75                         0,                              /* __u16 index       */
  76                         (void *) swocInfo,              /* void *data        */
  77                         sizeof(struct swoc_info),       /* __u16 size        */
  78                         USB_CTRL_SET_TIMEOUT);          /* int timeout       */
  79 
  80         swocInfo->LinuxSKU = le16_to_cpu(swocInfo->LinuxSKU);
  81         swocInfo->LinuxVer = le16_to_cpu(swocInfo->LinuxVer);
  82         return result;
  83 }
  84 
  85 static void debug_swoc(const struct device *dev, struct swoc_info *swocInfo)
  86 {
  87         dev_dbg(dev, "SWIMS: SWoC Rev: %02d\n", swocInfo->rev);
  88         dev_dbg(dev, "SWIMS: Linux SKU: %04X\n", swocInfo->LinuxSKU);
  89         dev_dbg(dev, "SWIMS: Linux Version: %04X\n", swocInfo->LinuxVer);
  90 }
  91 
  92 
  93 static ssize_t truinst_show(struct device *dev, struct device_attribute *attr,
  94                         char *buf)
  95 {
  96         struct swoc_info *swocInfo;
  97         struct usb_interface *intf = to_usb_interface(dev);
  98         struct usb_device *udev = interface_to_usbdev(intf);
  99         int result;
 100         if (swi_tru_install == TRU_FORCE_MS) {
 101                 result = snprintf(buf, PAGE_SIZE, "Forced Mass Storage\n");
 102         } else {
 103                 swocInfo = kmalloc(sizeof(struct swoc_info), GFP_KERNEL);
 104                 if (!swocInfo) {
 105                         snprintf(buf, PAGE_SIZE, "Error\n");
 106                         return -ENOMEM;
 107                 }
 108                 result = sierra_get_swoc_info(udev, swocInfo);
 109                 if (result < 0) {
 110                         dev_dbg(dev, "SWIMS: failed SWoC query\n");
 111                         kfree(swocInfo);
 112                         snprintf(buf, PAGE_SIZE, "Error\n");
 113                         return -EIO;
 114                 }
 115                 debug_swoc(dev, swocInfo);
 116                 result = snprintf(buf, PAGE_SIZE,
 117                         "REV=%02d SKU=%04X VER=%04X\n",
 118                         swocInfo->rev,
 119                         swocInfo->LinuxSKU,
 120                         swocInfo->LinuxVer);
 121                 kfree(swocInfo);
 122         }
 123         return result;
 124 }
 125 static DEVICE_ATTR_RO(truinst);
 126 
 127 int sierra_ms_init(struct us_data *us)
 128 {
 129         int result, retries;
 130         struct swoc_info *swocInfo;
 131         struct usb_device *udev;
 132         struct Scsi_Host *sh;
 133 
 134         retries = 3;
 135         result = 0;
 136         udev = us->pusb_dev;
 137 
 138         sh = us_to_host(us);
 139         scsi_get_host_dev(sh);
 140 
 141         /* Force Modem mode */
 142         if (swi_tru_install == TRU_FORCE_MODEM) {
 143                 usb_stor_dbg(us, "SWIMS: Forcing Modem Mode\n");
 144                 result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
 145                 if (result < 0)
 146                         usb_stor_dbg(us, "SWIMS: Failed to switch to modem mode\n");
 147                 return -EIO;
 148         }
 149         /* Force Mass Storage mode (keep CD-Rom) */
 150         else if (swi_tru_install == TRU_FORCE_MS) {
 151                 usb_stor_dbg(us, "SWIMS: Forcing Mass Storage Mode\n");
 152                 goto complete;
 153         }
 154         /* Normal TRU-Install Logic */
 155         else {
 156                 usb_stor_dbg(us, "SWIMS: Normal SWoC Logic\n");
 157 
 158                 swocInfo = kmalloc(sizeof(struct swoc_info),
 159                                 GFP_KERNEL);
 160                 if (!swocInfo)
 161                         return -ENOMEM;
 162 
 163                 retries = 3;
 164                 do {
 165                         retries--;
 166                         result = sierra_get_swoc_info(udev, swocInfo);
 167                         if (result < 0) {
 168                                 usb_stor_dbg(us, "SWIMS: Failed SWoC query\n");
 169                                 schedule_timeout_uninterruptible(2*HZ);
 170                         }
 171                 } while (retries && result < 0);
 172 
 173                 if (result < 0) {
 174                         usb_stor_dbg(us, "SWIMS: Completely failed SWoC query\n");
 175                         kfree(swocInfo);
 176                         return -EIO;
 177                 }
 178 
 179                 debug_swoc(&us->pusb_dev->dev, swocInfo);
 180 
 181                 /*
 182                  * If there is not Linux software on the TRU-Install device
 183                  * then switch to modem mode
 184                  */
 185                 if (!containsFullLinuxPackage(swocInfo)) {
 186                         usb_stor_dbg(us, "SWIMS: Switching to Modem Mode\n");
 187                         result = sierra_set_ms_mode(udev,
 188                                 SWIMS_SET_MODE_Modem);
 189                         if (result < 0)
 190                                 usb_stor_dbg(us, "SWIMS: Failed to switch modem\n");
 191                         kfree(swocInfo);
 192                         return -EIO;
 193                 }
 194                 kfree(swocInfo);
 195         }
 196 complete:
 197         return device_create_file(&us->pusb_intf->dev, &dev_attr_truinst);
 198 }
 199 

/* [<][>][^][v][top][bottom][index][help] */