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