Home | History | Annotate | Download | only in os
      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