haiku_usb_backend.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. /*
  2. * Haiku Backend for libusb
  3. * Copyright © 2014 Akshay Jaggi <akshay1994.leo@gmail.com>
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, or (at your option) any later version.
  9. *
  10. * This library 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 GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. */
  19. #include <unistd.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <new>
  23. #include <vector>
  24. #include "haiku_usb.h"
  25. static int _errno_to_libusb(int status)
  26. {
  27. return status;
  28. }
  29. USBTransfer::USBTransfer(struct usbi_transfer *itransfer, USBDevice *device)
  30. {
  31. fUsbiTransfer = itransfer;
  32. fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
  33. fUSBDevice = device;
  34. fCancelled = false;
  35. }
  36. USBTransfer::~USBTransfer()
  37. {
  38. }
  39. struct usbi_transfer *
  40. USBTransfer::UsbiTransfer()
  41. {
  42. return fUsbiTransfer;
  43. }
  44. void
  45. USBTransfer::SetCancelled()
  46. {
  47. fCancelled = true;
  48. }
  49. bool
  50. USBTransfer::IsCancelled()
  51. {
  52. return fCancelled;
  53. }
  54. void
  55. USBTransfer::Do(int fRawFD)
  56. {
  57. switch (fLibusbTransfer->type) {
  58. case LIBUSB_TRANSFER_TYPE_CONTROL:
  59. {
  60. struct libusb_control_setup *setup = (struct libusb_control_setup *)fLibusbTransfer->buffer;
  61. usb_raw_command command;
  62. command.control.request_type = setup->bmRequestType;
  63. command.control.request = setup->bRequest;
  64. command.control.value = setup->wValue;
  65. command.control.index = setup->wIndex;
  66. command.control.length = setup->wLength;
  67. command.control.data = fLibusbTransfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
  68. if (fCancelled)
  69. break;
  70. if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
  71. command.control.status != B_USB_RAW_STATUS_SUCCESS) {
  72. fUsbiTransfer->transferred = -1;
  73. usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed control transfer");
  74. break;
  75. }
  76. fUsbiTransfer->transferred = command.control.length;
  77. }
  78. break;
  79. case LIBUSB_TRANSFER_TYPE_BULK:
  80. case LIBUSB_TRANSFER_TYPE_INTERRUPT:
  81. {
  82. usb_raw_command command;
  83. command.transfer.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
  84. command.transfer.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
  85. command.transfer.data = fLibusbTransfer->buffer;
  86. command.transfer.length = fLibusbTransfer->length;
  87. if (fCancelled)
  88. break;
  89. if (fLibusbTransfer->type == LIBUSB_TRANSFER_TYPE_BULK) {
  90. if (ioctl(fRawFD, B_USB_RAW_COMMAND_BULK_TRANSFER, &command, sizeof(command)) ||
  91. command.transfer.status != B_USB_RAW_STATUS_SUCCESS) {
  92. fUsbiTransfer->transferred = -1;
  93. usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed bulk transfer");
  94. break;
  95. }
  96. }
  97. else {
  98. if (ioctl(fRawFD, B_USB_RAW_COMMAND_INTERRUPT_TRANSFER, &command, sizeof(command)) ||
  99. command.transfer.status != B_USB_RAW_STATUS_SUCCESS) {
  100. fUsbiTransfer->transferred = -1;
  101. usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed interrupt transfer");
  102. break;
  103. }
  104. }
  105. fUsbiTransfer->transferred = command.transfer.length;
  106. }
  107. break;
  108. // IsochronousTransfers not tested
  109. case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
  110. {
  111. usb_raw_command command;
  112. command.isochronous.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
  113. command.isochronous.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
  114. command.isochronous.data = fLibusbTransfer->buffer;
  115. command.isochronous.length = fLibusbTransfer->length;
  116. command.isochronous.packet_count = fLibusbTransfer->num_iso_packets;
  117. int i;
  118. usb_iso_packet_descriptor *packetDescriptors = new usb_iso_packet_descriptor[fLibusbTransfer->num_iso_packets];
  119. for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
  120. if ((fLibusbTransfer->iso_packet_desc[i]).length > (unsigned int)INT16_MAX) {
  121. fUsbiTransfer->transferred = -1;
  122. usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
  123. break;
  124. }
  125. packetDescriptors[i].request_length = (int16)(fLibusbTransfer->iso_packet_desc[i]).length;
  126. }
  127. if (i < fLibusbTransfer->num_iso_packets)
  128. break; // TODO Handle this error
  129. command.isochronous.packet_descriptors = packetDescriptors;
  130. if (fCancelled)
  131. break;
  132. if (ioctl(fRawFD, B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER, &command, sizeof(command)) ||
  133. command.isochronous.status != B_USB_RAW_STATUS_SUCCESS) {
  134. fUsbiTransfer->transferred = -1;
  135. usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
  136. break;
  137. }
  138. for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
  139. (fLibusbTransfer->iso_packet_desc[i]).actual_length = packetDescriptors[i].actual_length;
  140. switch (packetDescriptors[i].status) {
  141. case B_OK:
  142. (fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_COMPLETED;
  143. break;
  144. default:
  145. (fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_ERROR;
  146. break;
  147. }
  148. }
  149. delete[] packetDescriptors;
  150. // Do we put the length of transfer here, for isochronous transfers?
  151. fUsbiTransfer->transferred = command.transfer.length;
  152. }
  153. break;
  154. default:
  155. usbi_err(TRANSFER_CTX(fLibusbTransfer), "Unknown type of transfer");
  156. }
  157. }
  158. bool
  159. USBDeviceHandle::InitCheck()
  160. {
  161. return fInitCheck;
  162. }
  163. status_t
  164. USBDeviceHandle::TransfersThread(void *self)
  165. {
  166. USBDeviceHandle *handle = (USBDeviceHandle *)self;
  167. handle->TransfersWorker();
  168. return B_OK;
  169. }
  170. void
  171. USBDeviceHandle::TransfersWorker()
  172. {
  173. while (true) {
  174. status_t status = acquire_sem(fTransfersSem);
  175. if (status == B_BAD_SEM_ID)
  176. break;
  177. if (status == B_INTERRUPTED)
  178. continue;
  179. fTransfersLock.Lock();
  180. USBTransfer *fPendingTransfer = (USBTransfer *) fTransfers.RemoveItem((int32)0);
  181. fTransfersLock.Unlock();
  182. fPendingTransfer->Do(fRawFD);
  183. usbi_signal_transfer_completion(fPendingTransfer->UsbiTransfer());
  184. }
  185. }
  186. status_t
  187. USBDeviceHandle::SubmitTransfer(struct usbi_transfer *itransfer)
  188. {
  189. USBTransfer *transfer = new USBTransfer(itransfer, fUSBDevice);
  190. *((USBTransfer **)usbi_get_transfer_priv(itransfer)) = transfer;
  191. BAutolock locker(fTransfersLock);
  192. fTransfers.AddItem(transfer);
  193. release_sem(fTransfersSem);
  194. return LIBUSB_SUCCESS;
  195. }
  196. status_t
  197. USBDeviceHandle::CancelTransfer(USBTransfer *transfer)
  198. {
  199. transfer->SetCancelled();
  200. fTransfersLock.Lock();
  201. bool removed = fTransfers.RemoveItem(transfer);
  202. fTransfersLock.Unlock();
  203. if (removed)
  204. usbi_signal_transfer_completion(transfer->UsbiTransfer());
  205. return LIBUSB_SUCCESS;
  206. }
  207. USBDeviceHandle::USBDeviceHandle(USBDevice *dev)
  208. :
  209. fUSBDevice(dev),
  210. fClaimedInterfaces(0),
  211. fTransfersThread(-1),
  212. fInitCheck(false)
  213. {
  214. fRawFD = open(dev->Location(), O_RDWR | O_CLOEXEC);
  215. if (fRawFD < 0) {
  216. usbi_err(NULL,"failed to open device");
  217. return;
  218. }
  219. fTransfersSem = create_sem(0, "Transfers Queue Sem");
  220. fTransfersThread = spawn_thread(TransfersThread, "Transfer Worker", B_NORMAL_PRIORITY, this);
  221. resume_thread(fTransfersThread);
  222. fInitCheck = true;
  223. }
  224. USBDeviceHandle::~USBDeviceHandle()
  225. {
  226. if (fRawFD > 0)
  227. close(fRawFD);
  228. for (int i = 0; i < 32; i++) {
  229. if (fClaimedInterfaces & (1U << i))
  230. ReleaseInterface(i);
  231. }
  232. delete_sem(fTransfersSem);
  233. if (fTransfersThread > 0)
  234. wait_for_thread(fTransfersThread, NULL);
  235. }
  236. int
  237. USBDeviceHandle::ClaimInterface(uint8 inumber)
  238. {
  239. int status = fUSBDevice->ClaimInterface(inumber);
  240. if (status == LIBUSB_SUCCESS)
  241. fClaimedInterfaces |= (1U << inumber);
  242. return status;
  243. }
  244. int
  245. USBDeviceHandle::ReleaseInterface(uint8 inumber)
  246. {
  247. fUSBDevice->ReleaseInterface(inumber);
  248. fClaimedInterfaces &= ~(1U << inumber);
  249. return LIBUSB_SUCCESS;
  250. }
  251. int
  252. USBDeviceHandle::SetConfiguration(uint8 config)
  253. {
  254. int config_index = fUSBDevice->CheckInterfacesFree(config);
  255. if (config_index == LIBUSB_ERROR_BUSY || config_index == LIBUSB_ERROR_NOT_FOUND)
  256. return config_index;
  257. usb_raw_command command;
  258. command.config.config_index = config_index;
  259. if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_CONFIGURATION, &command, sizeof(command)) ||
  260. command.config.status != B_USB_RAW_STATUS_SUCCESS) {
  261. return _errno_to_libusb(command.config.status);
  262. }
  263. fUSBDevice->SetActiveConfiguration((uint8)config_index);
  264. return LIBUSB_SUCCESS;
  265. }
  266. int
  267. USBDeviceHandle::SetAltSetting(uint8 inumber, uint8 alt)
  268. {
  269. usb_raw_command command;
  270. command.alternate.config_index = fUSBDevice->ActiveConfigurationIndex();
  271. command.alternate.interface_index = inumber;
  272. if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX, &command, sizeof(command)) ||
  273. command.alternate.status != B_USB_RAW_STATUS_SUCCESS) {
  274. usbi_err(NULL, "Error retrieving active alternate interface");
  275. return _errno_to_libusb(command.alternate.status);
  276. }
  277. if (command.alternate.alternate_info == (uint32)alt) {
  278. usbi_dbg(NULL, "Setting alternate interface successful");
  279. return LIBUSB_SUCCESS;
  280. }
  281. command.alternate.alternate_info = alt;
  282. if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_ALT_INTERFACE, &command, sizeof(command)) ||
  283. command.alternate.status != B_USB_RAW_STATUS_SUCCESS) { //IF IOCTL FAILS DEVICE DISCONNECTED PROBABLY
  284. usbi_err(NULL, "Error setting alternate interface");
  285. return _errno_to_libusb(command.alternate.status);
  286. }
  287. usbi_dbg(NULL, "Setting alternate interface successful");
  288. return LIBUSB_SUCCESS;
  289. }
  290. int
  291. USBDeviceHandle::ClearHalt(uint8 endpoint)
  292. {
  293. usb_raw_command command;
  294. command.control.request_type = USB_REQTYPE_ENDPOINT_OUT;
  295. command.control.request = USB_REQUEST_CLEAR_FEATURE;
  296. command.control.value = USB_FEATURE_ENDPOINT_HALT;
  297. command.control.index = endpoint;
  298. command.control.length = 0;
  299. if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
  300. command.control.status != B_USB_RAW_STATUS_SUCCESS) {
  301. return _errno_to_libusb(command.control.status);
  302. }
  303. return LIBUSB_SUCCESS;
  304. }
  305. USBDevice::USBDevice(const char *path)
  306. :
  307. fClaimedInterfaces(0),
  308. fConfigurationDescriptors(NULL),
  309. fActiveConfiguration(0), //0?
  310. fPath(NULL),
  311. fEndpointToIndex(NULL),
  312. fEndpointToInterface(NULL),
  313. fInitCheck(false)
  314. {
  315. fPath=strdup(path);
  316. Initialise();
  317. }
  318. USBDevice::~USBDevice()
  319. {
  320. free(fPath);
  321. if (fConfigurationDescriptors) {
  322. for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
  323. if (fConfigurationDescriptors[i])
  324. delete fConfigurationDescriptors[i];
  325. }
  326. delete[] fConfigurationDescriptors;
  327. }
  328. if (fEndpointToIndex)
  329. delete[] fEndpointToIndex;
  330. if (fEndpointToInterface)
  331. delete[] fEndpointToInterface;
  332. }
  333. bool
  334. USBDevice::InitCheck()
  335. {
  336. return fInitCheck;
  337. }
  338. const char *
  339. USBDevice::Location() const
  340. {
  341. return fPath;
  342. }
  343. uint8
  344. USBDevice::CountConfigurations() const
  345. {
  346. return fDeviceDescriptor.num_configurations;
  347. }
  348. const usb_device_descriptor *
  349. USBDevice::Descriptor() const
  350. {
  351. return &fDeviceDescriptor;
  352. }
  353. const usb_configuration_descriptor *
  354. USBDevice::ConfigurationDescriptor(uint8 index) const
  355. {
  356. if (index > CountConfigurations())
  357. return NULL;
  358. return (usb_configuration_descriptor *) fConfigurationDescriptors[index];
  359. }
  360. const usb_configuration_descriptor *
  361. USBDevice::ActiveConfiguration() const
  362. {
  363. return (usb_configuration_descriptor *) fConfigurationDescriptors[fActiveConfiguration];
  364. }
  365. uint8
  366. USBDevice::ActiveConfigurationIndex() const
  367. {
  368. return fActiveConfiguration;
  369. }
  370. int USBDevice::ClaimInterface(uint8 interface)
  371. {
  372. if (interface > ActiveConfiguration()->number_interfaces)
  373. return LIBUSB_ERROR_NOT_FOUND;
  374. if (fClaimedInterfaces & (1U << interface))
  375. return LIBUSB_ERROR_BUSY;
  376. fClaimedInterfaces |= (1U << interface);
  377. return LIBUSB_SUCCESS;
  378. }
  379. int USBDevice::ReleaseInterface(uint8 interface)
  380. {
  381. fClaimedInterfaces &= ~(1U << interface);
  382. return LIBUSB_SUCCESS;
  383. }
  384. int
  385. USBDevice::CheckInterfacesFree(uint8 config)
  386. {
  387. if (fConfigToIndex.count(config) == 0)
  388. return LIBUSB_ERROR_NOT_FOUND;
  389. if (fClaimedInterfaces == 0)
  390. return fConfigToIndex[config];
  391. return LIBUSB_ERROR_BUSY;
  392. }
  393. void
  394. USBDevice::SetActiveConfiguration(uint8 config_index)
  395. {
  396. fActiveConfiguration = config_index;
  397. }
  398. uint8
  399. USBDevice::EndpointToIndex(uint8 address) const
  400. {
  401. return fEndpointToIndex[fActiveConfiguration][address];
  402. }
  403. uint8
  404. USBDevice::EndpointToInterface(uint8 address) const
  405. {
  406. return fEndpointToInterface[fActiveConfiguration][address];
  407. }
  408. int
  409. USBDevice::Initialise() //Do we need more error checking, etc? How to report?
  410. {
  411. int fRawFD = open(fPath, O_RDWR | O_CLOEXEC);
  412. if (fRawFD < 0)
  413. return B_ERROR;
  414. usb_raw_command command;
  415. command.device.descriptor = &fDeviceDescriptor;
  416. if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR, &command, sizeof(command)) ||
  417. command.device.status != B_USB_RAW_STATUS_SUCCESS) {
  418. close(fRawFD);
  419. return B_ERROR;
  420. }
  421. fConfigurationDescriptors = new(std::nothrow) unsigned char *[fDeviceDescriptor.num_configurations];
  422. fEndpointToIndex = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
  423. fEndpointToInterface = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
  424. for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
  425. usb_configuration_descriptor tmp_config;
  426. command.config.descriptor = &tmp_config;
  427. command.config.config_index = i;
  428. if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR, &command, sizeof(command)) ||
  429. command.config.status != B_USB_RAW_STATUS_SUCCESS) {
  430. usbi_err(NULL, "failed retrieving configuration descriptor");
  431. close(fRawFD);
  432. return B_ERROR;
  433. }
  434. fConfigToIndex[tmp_config.configuration_value] = i;
  435. fConfigurationDescriptors[i] = new(std::nothrow) unsigned char[tmp_config.total_length];
  436. command.config_etc.descriptor = (usb_configuration_descriptor*)fConfigurationDescriptors[i];
  437. command.config_etc.length = tmp_config.total_length;
  438. command.config_etc.config_index = i;
  439. if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC, &command, sizeof(command)) ||
  440. command.config_etc.status != B_USB_RAW_STATUS_SUCCESS) {
  441. usbi_err(NULL, "failed retrieving full configuration descriptor");
  442. close(fRawFD);
  443. return B_ERROR;
  444. }
  445. for (uint8 j = 0; j < tmp_config.number_interfaces; j++) {
  446. command.alternate.config_index = i;
  447. command.alternate.interface_index = j;
  448. if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command, sizeof(command)) ||
  449. command.config.status != B_USB_RAW_STATUS_SUCCESS) {
  450. usbi_err(NULL, "failed retrieving number of alternate interfaces");
  451. close(fRawFD);
  452. return B_ERROR;
  453. }
  454. uint8 num_alternate = (uint8)command.alternate.alternate_info;
  455. for (uint8 k = 0; k < num_alternate; k++) {
  456. usb_interface_descriptor tmp_interface;
  457. command.interface_etc.config_index = i;
  458. command.interface_etc.interface_index = j;
  459. command.interface_etc.alternate_index = k;
  460. command.interface_etc.descriptor = &tmp_interface;
  461. if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC, &command, sizeof(command)) ||
  462. command.config.status != B_USB_RAW_STATUS_SUCCESS) {
  463. usbi_err(NULL, "failed retrieving interface descriptor");
  464. close(fRawFD);
  465. return B_ERROR;
  466. }
  467. for (uint8 l = 0; l < tmp_interface.num_endpoints; l++) {
  468. usb_endpoint_descriptor tmp_endpoint;
  469. command.endpoint_etc.config_index = i;
  470. command.endpoint_etc.interface_index = j;
  471. command.endpoint_etc.alternate_index = k;
  472. command.endpoint_etc.endpoint_index = l;
  473. command.endpoint_etc.descriptor = &tmp_endpoint;
  474. if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC, &command, sizeof(command)) ||
  475. command.config.status != B_USB_RAW_STATUS_SUCCESS) {
  476. usbi_err(NULL, "failed retrieving endpoint descriptor");
  477. close(fRawFD);
  478. return B_ERROR;
  479. }
  480. fEndpointToIndex[i][tmp_endpoint.endpoint_address] = l;
  481. fEndpointToInterface[i][tmp_endpoint.endpoint_address] = j;
  482. }
  483. }
  484. }
  485. }
  486. close(fRawFD);
  487. fInitCheck = true;
  488. return B_OK;
  489. }