u3_scsi_usb.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /**
  2. * u3-tool - U3 USB stick manager
  3. * Copyright (C) 2007 Daviedev, daviedev@users.sourceforge.net
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. */
  19. #if HAVE_CONFIG_H
  20. # include "config.h"
  21. #endif
  22. #ifdef SUBSYS_LIBUSB
  23. #include "u3_scsi.h"
  24. #include "u3_error.h"
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <sys/ioctl.h>
  28. #include <fcntl.h>
  29. #include <string.h>
  30. #include <unistd.h>
  31. #include <usb.h>
  32. #include <errno.h>
  33. #include <regex.h>
  34. // USB maximum packet length
  35. #define USB_MAX_PACKET_LEN 256
  36. // USB command block wrapper length
  37. #define U3_CBWCB_LEN 12
  38. // USB MSC command/status wrapper signatures
  39. #define CBW_SIGNATURE 0x43425355
  40. #define CSW_SIGNATURE 0x53425355
  41. // USB MSC command block wrapper data direction bits
  42. #define CBW_DATA_IN 0x80
  43. #define CBW_DATA_OUT 0x00
  44. #define CBW_DATA_NONE 0x00
  45. #define CBW_FLAG_DIRECTION 0x80
  46. #define U3_DEVICE_TIMEOUT 20000 //2000 millisecs == 2 seconds
  47. #define U3_DEV_LIST_LENGTH 4
  48. uint16_t u3_dev_list[U3_DEV_LIST_LENGTH][2] = {
  49. { 0x08ec, 0x0020 }, // Verbatim Store 'N Go
  50. { 0x0781, 0x5406 }, // Sandisk Cruzer Micro
  51. { 0x0781, 0x5408 }, // Sandisk Cruzer Titanium
  52. { 0x0781, 0x550a }, // Sandisk Cruzer Pattern
  53. };
  54. struct u3_usb_handle {
  55. usb_dev_handle *handle;
  56. int interface_num;
  57. int ep_out;
  58. int ep_in;
  59. };
  60. typedef struct u3_usb_handle u3_usb_handle_t;
  61. struct usb_msc_cbw {
  62. uint32_t dCBWSignature;
  63. uint32_t dCBWTag;
  64. uint32_t dCBWDataTransferLength;
  65. uint8_t bmCBWFlags;
  66. uint8_t bCBWLUN;
  67. uint8_t bCBWCBLength;
  68. uint8_t CBWCB[16];
  69. } __attribute__ ((packed));
  70. struct usb_msc_csw {
  71. uint32_t dCSWSignature;
  72. uint32_t dCSWTag;
  73. uint32_t dCSWDataResidue;
  74. uint8_t bCSWStatus;
  75. } __attribute__ ((packed));
  76. const char *u3_subsystem_name = "libusb";
  77. const char *u3_subsystem_help = "'scan' to automatically use the first detected U3 device, or 'vid:pid' if not detected";
  78. struct usb_device *
  79. locate_u3_device(uint16_t vid, uint16_t pid)
  80. {
  81. struct usb_bus *bus;
  82. struct usb_device *dev;
  83. // rescan busses and devices
  84. usb_find_busses();
  85. usb_find_devices();
  86. for (bus = usb_get_busses(); bus; bus = bus->next) {
  87. for (dev = bus->devices; dev; dev = dev->next) {
  88. if (dev->descriptor.idVendor == vid &&
  89. (dev->descriptor.idProduct == pid))
  90. {
  91. return dev;
  92. }
  93. }
  94. }
  95. return NULL;
  96. }
  97. int u3_open(u3_handle_t *device, const char *which)
  98. {
  99. uint16_t vid, pid;
  100. regex_t vid_pid_regex;
  101. struct usb_device *u3_device;
  102. u3_usb_handle_t *handle_wrapper;
  103. struct usb_config_descriptor *config_desc;
  104. struct usb_interface_descriptor *interface_desc;
  105. struct usb_endpoint_descriptor *endpoint_desc;
  106. int err;
  107. char errbuf[U3_MAX_ERROR_LEN];
  108. int i;
  109. // init
  110. u3_set_error(device, "");
  111. err = regcomp(&vid_pid_regex, "[::xdigit::]*:[::xdigit::]*", 0);
  112. if (err != 0) {
  113. regerror(err, &vid_pid_regex, errbuf, U3_MAX_ERROR_LEN);
  114. u3_set_error(device, "Failed constructing 'vid:pid' regular "
  115. "expression: %s", errbuf);
  116. return U3_FAILURE;
  117. }
  118. usb_init();
  119. if (debug)
  120. usb_set_debug(255);
  121. // Find device
  122. if (regexec(&vid_pid_regex, which, 0, 0, 0) == 0) {
  123. char *seperator=0;
  124. vid = strtoul(which, &seperator, 16);
  125. pid = strtoul(seperator+1, &seperator, 16);
  126. u3_device = locate_u3_device(vid, pid);
  127. } else if (strcmp(which, "scan") == 0) {
  128. i = 0;
  129. u3_device = NULL;
  130. while (u3_device == NULL && i < U3_DEV_LIST_LENGTH) {
  131. u3_device = locate_u3_device(u3_dev_list[i][0],
  132. u3_dev_list[i][1]);
  133. i++;
  134. }
  135. // } else if (regexec(&serial_regex, which, 0, 0, 0) == 0) {
  136. //TODO: search for a specific serial number
  137. } else {
  138. u3_set_error(device, "Unknown device name '%s', try 'scan' "
  139. "for first available device", which);
  140. return U3_FAILURE;
  141. }
  142. regfree(&vid_pid_regex);
  143. if (u3_device == NULL) {
  144. u3_set_error(device, "Could not locate the U3 device '%s', "
  145. "try 'scan' for first available device", which);
  146. return U3_FAILURE;
  147. }
  148. // Open device
  149. handle_wrapper = (u3_usb_handle_t *) malloc(sizeof(u3_usb_handle_t));
  150. if (handle_wrapper == NULL) {
  151. u3_set_error(device, "Failed allocate memory!!");
  152. return U3_FAILURE;
  153. }
  154. handle_wrapper->handle = usb_open(u3_device);
  155. // Set configuration
  156. if (u3_device->descriptor.bNumConfigurations != 1) {
  157. u3_set_error(device,
  158. "Multiple USB configuration not supported");
  159. goto open_fail;
  160. }
  161. config_desc = u3_device->config;
  162. usb_set_configuration(handle_wrapper->handle,
  163. config_desc->bConfigurationValue);
  164. // Claim device
  165. if (config_desc->bNumInterfaces != 1) {
  166. u3_set_error(device, "Multiple USB configuration interfaces "
  167. "not supported");
  168. goto open_fail;
  169. }
  170. if (config_desc->interface->num_altsetting != 1) {
  171. u3_set_error(device, "Multiple USB configuration interface "
  172. " alt. settings not supported");
  173. goto open_fail;
  174. }
  175. interface_desc = config_desc->interface->altsetting;
  176. handle_wrapper->interface_num = interface_desc->bInterfaceNumber;
  177. if ((err=usb_claim_interface(handle_wrapper->handle,
  178. handle_wrapper->interface_num)) != 0)
  179. {
  180. if (err == -EBUSY) {
  181. // Don't try to detach driver on Linux, this can cause
  182. // data loss and leaves the device in a unspecified
  183. // state. The user should 'unbind' the driver through
  184. // sysfs, or unload the usb-storage driver.
  185. u3_set_error(device, "Failed to claim device: Device is busy");
  186. goto open_fail;
  187. } else {
  188. u3_set_error(device, "Failed to claim device: %s", usb_strerror());
  189. goto open_fail;
  190. }
  191. }
  192. // Set alt. setting
  193. usb_set_altinterface(handle_wrapper->handle,
  194. interface_desc->bAlternateSetting);
  195. // Find the correct endpoints
  196. if (interface_desc->bNumEndpoints != 2) {
  197. u3_set_error(device, "Not exactly two usb endpoints defined,"
  198. " unsupported.");
  199. goto claimed_fail;
  200. }
  201. endpoint_desc = interface_desc->endpoint;
  202. if (endpoint_desc[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
  203. handle_wrapper->ep_in = endpoint_desc[0].bEndpointAddress;
  204. handle_wrapper->ep_out = endpoint_desc[1].bEndpointAddress;
  205. } else {
  206. handle_wrapper->ep_out = endpoint_desc[0].bEndpointAddress;
  207. handle_wrapper->ep_in = endpoint_desc[1].bEndpointAddress;
  208. }
  209. if (!((handle_wrapper->ep_in & USB_ENDPOINT_DIR_MASK) ^
  210. (handle_wrapper->ep_out & USB_ENDPOINT_DIR_MASK)))
  211. {
  212. u3_set_error(device, "Both usb endpoints in same direction!");
  213. goto claimed_fail;
  214. }
  215. device->dev = handle_wrapper;
  216. return U3_SUCCESS;
  217. claimed_fail:
  218. usb_release_interface(handle_wrapper->handle,
  219. handle_wrapper->interface_num);
  220. open_fail:
  221. usb_close(handle_wrapper->handle);
  222. free(handle_wrapper);
  223. return U3_FAILURE;
  224. }
  225. void u3_close(u3_handle_t *device)
  226. {
  227. u3_usb_handle_t *handle_wrapper = (u3_usb_handle_t *) device->dev;
  228. usb_release_interface(handle_wrapper->handle,
  229. handle_wrapper->interface_num);
  230. usb_close(handle_wrapper->handle);
  231. free(handle_wrapper);
  232. }
  233. int u3_send_cmd(u3_handle_t *device, uint8_t cmd[U3_CMD_LEN],
  234. int dxfer_direction, int dxfer_length, uint8_t *dxfer_data,
  235. uint8_t *status)
  236. {
  237. u3_usb_handle_t *handle_wrapper = (u3_usb_handle_t *) device->dev;
  238. struct usb_msc_cbw cbw;
  239. struct usb_msc_csw csw;
  240. // translate dxfer_direction
  241. switch (dxfer_direction) {
  242. case U3_DATA_TO_DEV:
  243. dxfer_direction = CBW_DATA_OUT;
  244. break;
  245. case U3_DATA_FROM_DEV:
  246. dxfer_direction = CBW_DATA_IN;
  247. break;
  248. case U3_DATA_NONE:
  249. default:
  250. dxfer_direction = CBW_DATA_NONE;
  251. dxfer_length = 0;
  252. break;
  253. }
  254. // Prepare command
  255. memset(&cbw, 0, sizeof(cbw));
  256. cbw.dCBWSignature = CBW_SIGNATURE;
  257. cbw.dCBWDataTransferLength = dxfer_length;
  258. cbw.bmCBWFlags |= (dxfer_direction & CBW_FLAG_DIRECTION);
  259. cbw.bCBWCBLength = U3_CBWCB_LEN;
  260. memcpy(&(cbw.CBWCB), cmd, U3_CBWCB_LEN);
  261. // send command
  262. if (usb_bulk_write(handle_wrapper->handle, handle_wrapper->ep_out,
  263. (char *) &cbw, sizeof(cbw), U3_DEVICE_TIMEOUT)
  264. != sizeof(cbw))
  265. {
  266. u3_set_error(device, "Failed executing scsi command: "
  267. "Could not write command block to device");
  268. return U3_FAILURE;
  269. }
  270. // read/write extra command data
  271. if (dxfer_direction == CBW_DATA_OUT) {
  272. int bytes_send = 0;
  273. while (bytes_send < dxfer_length) {
  274. int plen;
  275. plen = dxfer_length - bytes_send;
  276. if (plen > USB_MAX_PACKET_LEN)
  277. plen = USB_MAX_PACKET_LEN;
  278. if (usb_bulk_write(handle_wrapper->handle,
  279. handle_wrapper->ep_out,
  280. (char *) dxfer_data+bytes_send, plen,
  281. U3_DEVICE_TIMEOUT) != plen)
  282. {
  283. u3_set_error(device, "Failed executing scsi command: "
  284. "Could not write data to device");
  285. return U3_FAILURE;
  286. }
  287. bytes_send += plen;
  288. }
  289. } else if (dxfer_direction == CBW_DATA_IN) {
  290. if (usb_bulk_read(handle_wrapper->handle, handle_wrapper->ep_in,
  291. (char *) dxfer_data, dxfer_length,
  292. U3_DEVICE_TIMEOUT) != dxfer_length)
  293. {
  294. u3_set_error(device, "Failed executing scsi command: "
  295. "Could not read data from device");
  296. return U3_FAILURE;
  297. }
  298. }
  299. // read command status
  300. if (usb_bulk_read(handle_wrapper->handle, handle_wrapper->ep_in,
  301. (char *) &csw, sizeof(csw), U3_DEVICE_TIMEOUT)
  302. != sizeof(csw))
  303. {
  304. u3_set_error(device, "Failed executing scsi command: "
  305. "Could not read command status from device");
  306. return U3_FAILURE;
  307. }
  308. *status = csw.bCSWStatus;
  309. return U3_SUCCESS;
  310. }
  311. #endif //SUBSYS_LIBUSB