sierra_ms.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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 "usb.h"
  7. #include "transport.h"
  8. #include "protocol.h"
  9. #include "scsiglue.h"
  10. #include "sierra_ms.h"
  11. #include "debug.h"
  12. #define SWIMS_USB_REQUEST_SetSwocMode 0x0B
  13. #define SWIMS_USB_REQUEST_GetSwocInfo 0x0A
  14. #define SWIMS_USB_INDEX_SetMode 0x0000
  15. #define SWIMS_SET_MODE_Modem 0x0001
  16. #define TRU_NORMAL 0x01
  17. #define TRU_FORCE_MS 0x02
  18. #define TRU_FORCE_MODEM 0x03
  19. static unsigned int swi_tru_install = 1;
  20. module_param(swi_tru_install, uint, S_IRUGO | S_IWUSR);
  21. MODULE_PARM_DESC(swi_tru_install, "TRU-Install mode (1=Full Logic (def),"
  22. " 2=Force CD-Rom, 3=Force Modem)");
  23. struct swoc_info {
  24. __u8 rev;
  25. __u8 reserved[8];
  26. __u16 LinuxSKU;
  27. __u16 LinuxVer;
  28. __u8 reserved2[47];
  29. } __attribute__((__packed__));
  30. static bool containsFullLinuxPackage(struct swoc_info *swocInfo)
  31. {
  32. if ((swocInfo->LinuxSKU >= 0x2100 && swocInfo->LinuxSKU <= 0x2FFF) ||
  33. (swocInfo->LinuxSKU >= 0x7100 && swocInfo->LinuxSKU <= 0x7FFF))
  34. return true;
  35. else
  36. return false;
  37. }
  38. static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode)
  39. {
  40. int result;
  41. US_DEBUGP("SWIMS: %s", "DEVICE MODE SWITCH\n");
  42. result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
  43. SWIMS_USB_REQUEST_SetSwocMode, /* __u8 request */
  44. USB_TYPE_VENDOR | USB_DIR_OUT, /* __u8 request type */
  45. eSWocMode, /* __u16 value */
  46. 0x0000, /* __u16 index */
  47. NULL, /* void *data */
  48. 0, /* __u16 size */
  49. USB_CTRL_SET_TIMEOUT); /* int timeout */
  50. return result;
  51. }
  52. static int sierra_get_swoc_info(struct usb_device *udev,
  53. struct swoc_info *swocInfo)
  54. {
  55. int result;
  56. US_DEBUGP("SWIMS: Attempting to get TRU-Install info.\n");
  57. result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
  58. SWIMS_USB_REQUEST_GetSwocInfo, /* __u8 request */
  59. USB_TYPE_VENDOR | USB_DIR_IN, /* __u8 request type */
  60. 0, /* __u16 value */
  61. 0, /* __u16 index */
  62. (void *) swocInfo, /* void *data */
  63. sizeof(struct swoc_info), /* __u16 size */
  64. USB_CTRL_SET_TIMEOUT); /* int timeout */
  65. swocInfo->LinuxSKU = le16_to_cpu(swocInfo->LinuxSKU);
  66. swocInfo->LinuxVer = le16_to_cpu(swocInfo->LinuxVer);
  67. return result;
  68. }
  69. static void debug_swoc(struct swoc_info *swocInfo)
  70. {
  71. US_DEBUGP("SWIMS: SWoC Rev: %02d \n", swocInfo->rev);
  72. US_DEBUGP("SWIMS: Linux SKU: %04X \n", swocInfo->LinuxSKU);
  73. US_DEBUGP("SWIMS: Linux Version: %04X \n", swocInfo->LinuxVer);
  74. }
  75. static ssize_t show_truinst(struct device *dev, struct device_attribute *attr,
  76. char *buf)
  77. {
  78. struct swoc_info *swocInfo;
  79. struct usb_interface *intf = to_usb_interface(dev);
  80. struct usb_device *udev = interface_to_usbdev(intf);
  81. int result;
  82. if (swi_tru_install == TRU_FORCE_MS) {
  83. result = snprintf(buf, PAGE_SIZE, "Forced Mass Storage\n");
  84. } else {
  85. swocInfo = kmalloc(sizeof(struct swoc_info), GFP_KERNEL);
  86. if (!swocInfo) {
  87. US_DEBUGP("SWIMS: Allocation failure\n");
  88. snprintf(buf, PAGE_SIZE, "Error\n");
  89. return -ENOMEM;
  90. }
  91. result = sierra_get_swoc_info(udev, swocInfo);
  92. if (result < 0) {
  93. US_DEBUGP("SWIMS: failed SWoC query\n");
  94. kfree(swocInfo);
  95. snprintf(buf, PAGE_SIZE, "Error\n");
  96. return -EIO;
  97. }
  98. debug_swoc(swocInfo);
  99. result = snprintf(buf, PAGE_SIZE,
  100. "REV=%02d SKU=%04X VER=%04X\n",
  101. swocInfo->rev,
  102. swocInfo->LinuxSKU,
  103. swocInfo->LinuxVer);
  104. kfree(swocInfo);
  105. }
  106. return result;
  107. }
  108. static DEVICE_ATTR(truinst, S_IWUGO | S_IRUGO, show_truinst, NULL);
  109. int sierra_ms_init(struct us_data *us)
  110. {
  111. int result, retries;
  112. signed long delay_t;
  113. struct swoc_info *swocInfo;
  114. struct usb_device *udev;
  115. struct Scsi_Host *sh;
  116. struct scsi_device *sd;
  117. delay_t = 2;
  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. }