sierra_ms.c 5.4 KB

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