123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532 |
- /*
- * Haiku Backend for libusb
- * Copyright © 2014 Akshay Jaggi <akshay1994.leo@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <new>
- #include <vector>
- #include "haiku_usb.h"
- static int _errno_to_libusb(int status)
- {
- return status;
- }
- USBTransfer::USBTransfer(struct usbi_transfer *itransfer, USBDevice *device)
- {
- fUsbiTransfer = itransfer;
- fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- fUSBDevice = device;
- fCancelled = false;
- }
- USBTransfer::~USBTransfer()
- {
- }
- struct usbi_transfer *
- USBTransfer::UsbiTransfer()
- {
- return fUsbiTransfer;
- }
- void
- USBTransfer::SetCancelled()
- {
- fCancelled = true;
- }
- bool
- USBTransfer::IsCancelled()
- {
- return fCancelled;
- }
- void
- USBTransfer::Do(int fRawFD)
- {
- switch (fLibusbTransfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- {
- struct libusb_control_setup *setup = (struct libusb_control_setup *)fLibusbTransfer->buffer;
- usb_raw_command command;
- command.control.request_type = setup->bmRequestType;
- command.control.request = setup->bRequest;
- command.control.value = setup->wValue;
- command.control.index = setup->wIndex;
- command.control.length = setup->wLength;
- command.control.data = fLibusbTransfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
- if (fCancelled)
- break;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
- command.control.status != B_USB_RAW_STATUS_SUCCESS) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed control transfer");
- break;
- }
- fUsbiTransfer->transferred = command.control.length;
- }
- break;
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- {
- usb_raw_command command;
- command.transfer.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
- command.transfer.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
- command.transfer.data = fLibusbTransfer->buffer;
- command.transfer.length = fLibusbTransfer->length;
- if (fCancelled)
- break;
- if (fLibusbTransfer->type == LIBUSB_TRANSFER_TYPE_BULK) {
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_BULK_TRANSFER, &command, sizeof(command)) ||
- command.transfer.status != B_USB_RAW_STATUS_SUCCESS) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed bulk transfer");
- break;
- }
- }
- else {
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_INTERRUPT_TRANSFER, &command, sizeof(command)) ||
- command.transfer.status != B_USB_RAW_STATUS_SUCCESS) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed interrupt transfer");
- break;
- }
- }
- fUsbiTransfer->transferred = command.transfer.length;
- }
- break;
- // IsochronousTransfers not tested
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- {
- usb_raw_command command;
- command.isochronous.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
- command.isochronous.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
- command.isochronous.data = fLibusbTransfer->buffer;
- command.isochronous.length = fLibusbTransfer->length;
- command.isochronous.packet_count = fLibusbTransfer->num_iso_packets;
- int i;
- usb_iso_packet_descriptor *packetDescriptors = new usb_iso_packet_descriptor[fLibusbTransfer->num_iso_packets];
- for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
- if ((fLibusbTransfer->iso_packet_desc[i]).length > (unsigned int)INT16_MAX) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
- break;
- }
- packetDescriptors[i].request_length = (int16)(fLibusbTransfer->iso_packet_desc[i]).length;
- }
- if (i < fLibusbTransfer->num_iso_packets)
- break; // TODO Handle this error
- command.isochronous.packet_descriptors = packetDescriptors;
- if (fCancelled)
- break;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER, &command, sizeof(command)) ||
- command.isochronous.status != B_USB_RAW_STATUS_SUCCESS) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
- break;
- }
- for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
- (fLibusbTransfer->iso_packet_desc[i]).actual_length = packetDescriptors[i].actual_length;
- switch (packetDescriptors[i].status) {
- case B_OK:
- (fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_COMPLETED;
- break;
- default:
- (fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_ERROR;
- break;
- }
- }
- delete[] packetDescriptors;
- // Do we put the length of transfer here, for isochronous transfers?
- fUsbiTransfer->transferred = command.transfer.length;
- }
- break;
- default:
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "Unknown type of transfer");
- }
- }
- bool
- USBDeviceHandle::InitCheck()
- {
- return fInitCheck;
- }
- status_t
- USBDeviceHandle::TransfersThread(void *self)
- {
- USBDeviceHandle *handle = (USBDeviceHandle *)self;
- handle->TransfersWorker();
- return B_OK;
- }
- void
- USBDeviceHandle::TransfersWorker()
- {
- while (true) {
- status_t status = acquire_sem(fTransfersSem);
- if (status == B_BAD_SEM_ID)
- break;
- if (status == B_INTERRUPTED)
- continue;
- fTransfersLock.Lock();
- USBTransfer *fPendingTransfer = (USBTransfer *) fTransfers.RemoveItem((int32)0);
- fTransfersLock.Unlock();
- fPendingTransfer->Do(fRawFD);
- usbi_signal_transfer_completion(fPendingTransfer->UsbiTransfer());
- }
- }
- status_t
- USBDeviceHandle::SubmitTransfer(struct usbi_transfer *itransfer)
- {
- USBTransfer *transfer = new USBTransfer(itransfer, fUSBDevice);
- *((USBTransfer **)usbi_get_transfer_priv(itransfer)) = transfer;
- BAutolock locker(fTransfersLock);
- fTransfers.AddItem(transfer);
- release_sem(fTransfersSem);
- return LIBUSB_SUCCESS;
- }
- status_t
- USBDeviceHandle::CancelTransfer(USBTransfer *transfer)
- {
- transfer->SetCancelled();
- fTransfersLock.Lock();
- bool removed = fTransfers.RemoveItem(transfer);
- fTransfersLock.Unlock();
- if (removed)
- usbi_signal_transfer_completion(transfer->UsbiTransfer());
- return LIBUSB_SUCCESS;
- }
- USBDeviceHandle::USBDeviceHandle(USBDevice *dev)
- :
- fUSBDevice(dev),
- fClaimedInterfaces(0),
- fTransfersThread(-1),
- fInitCheck(false)
- {
- fRawFD = open(dev->Location(), O_RDWR | O_CLOEXEC);
- if (fRawFD < 0) {
- usbi_err(NULL,"failed to open device");
- return;
- }
- fTransfersSem = create_sem(0, "Transfers Queue Sem");
- fTransfersThread = spawn_thread(TransfersThread, "Transfer Worker", B_NORMAL_PRIORITY, this);
- resume_thread(fTransfersThread);
- fInitCheck = true;
- }
- USBDeviceHandle::~USBDeviceHandle()
- {
- if (fRawFD > 0)
- close(fRawFD);
- for (int i = 0; i < 32; i++) {
- if (fClaimedInterfaces & (1U << i))
- ReleaseInterface(i);
- }
- delete_sem(fTransfersSem);
- if (fTransfersThread > 0)
- wait_for_thread(fTransfersThread, NULL);
- }
- int
- USBDeviceHandle::ClaimInterface(uint8 inumber)
- {
- int status = fUSBDevice->ClaimInterface(inumber);
- if (status == LIBUSB_SUCCESS)
- fClaimedInterfaces |= (1U << inumber);
- return status;
- }
- int
- USBDeviceHandle::ReleaseInterface(uint8 inumber)
- {
- fUSBDevice->ReleaseInterface(inumber);
- fClaimedInterfaces &= ~(1U << inumber);
- return LIBUSB_SUCCESS;
- }
- int
- USBDeviceHandle::SetConfiguration(uint8 config)
- {
- int config_index = fUSBDevice->CheckInterfacesFree(config);
- if (config_index == LIBUSB_ERROR_BUSY || config_index == LIBUSB_ERROR_NOT_FOUND)
- return config_index;
- usb_raw_command command;
- command.config.config_index = config_index;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_CONFIGURATION, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- return _errno_to_libusb(command.config.status);
- }
- fUSBDevice->SetActiveConfiguration((uint8)config_index);
- return LIBUSB_SUCCESS;
- }
- int
- USBDeviceHandle::SetAltSetting(uint8 inumber, uint8 alt)
- {
- usb_raw_command command;
- command.alternate.config_index = fUSBDevice->ActiveConfigurationIndex();
- command.alternate.interface_index = inumber;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX, &command, sizeof(command)) ||
- command.alternate.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "Error retrieving active alternate interface");
- return _errno_to_libusb(command.alternate.status);
- }
- if (command.alternate.alternate_info == (uint32)alt) {
- usbi_dbg(NULL, "Setting alternate interface successful");
- return LIBUSB_SUCCESS;
- }
- command.alternate.alternate_info = alt;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_ALT_INTERFACE, &command, sizeof(command)) ||
- command.alternate.status != B_USB_RAW_STATUS_SUCCESS) { //IF IOCTL FAILS DEVICE DISCONNECTED PROBABLY
- usbi_err(NULL, "Error setting alternate interface");
- return _errno_to_libusb(command.alternate.status);
- }
- usbi_dbg(NULL, "Setting alternate interface successful");
- return LIBUSB_SUCCESS;
- }
- int
- USBDeviceHandle::ClearHalt(uint8 endpoint)
- {
- usb_raw_command command;
- command.control.request_type = USB_REQTYPE_ENDPOINT_OUT;
- command.control.request = USB_REQUEST_CLEAR_FEATURE;
- command.control.value = USB_FEATURE_ENDPOINT_HALT;
- command.control.index = endpoint;
- command.control.length = 0;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
- command.control.status != B_USB_RAW_STATUS_SUCCESS) {
- return _errno_to_libusb(command.control.status);
- }
- return LIBUSB_SUCCESS;
- }
- USBDevice::USBDevice(const char *path)
- :
- fClaimedInterfaces(0),
- fConfigurationDescriptors(NULL),
- fActiveConfiguration(0), //0?
- fPath(NULL),
- fEndpointToIndex(NULL),
- fEndpointToInterface(NULL),
- fInitCheck(false)
- {
- fPath=strdup(path);
- Initialise();
- }
- USBDevice::~USBDevice()
- {
- free(fPath);
- if (fConfigurationDescriptors) {
- for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
- if (fConfigurationDescriptors[i])
- delete fConfigurationDescriptors[i];
- }
- delete[] fConfigurationDescriptors;
- }
- if (fEndpointToIndex)
- delete[] fEndpointToIndex;
- if (fEndpointToInterface)
- delete[] fEndpointToInterface;
- }
- bool
- USBDevice::InitCheck()
- {
- return fInitCheck;
- }
- const char *
- USBDevice::Location() const
- {
- return fPath;
- }
- uint8
- USBDevice::CountConfigurations() const
- {
- return fDeviceDescriptor.num_configurations;
- }
- const usb_device_descriptor *
- USBDevice::Descriptor() const
- {
- return &fDeviceDescriptor;
- }
- const usb_configuration_descriptor *
- USBDevice::ConfigurationDescriptor(uint8 index) const
- {
- if (index > CountConfigurations())
- return NULL;
- return (usb_configuration_descriptor *) fConfigurationDescriptors[index];
- }
- const usb_configuration_descriptor *
- USBDevice::ActiveConfiguration() const
- {
- return (usb_configuration_descriptor *) fConfigurationDescriptors[fActiveConfiguration];
- }
- uint8
- USBDevice::ActiveConfigurationIndex() const
- {
- return fActiveConfiguration;
- }
- int USBDevice::ClaimInterface(uint8 interface)
- {
- if (interface > ActiveConfiguration()->number_interfaces)
- return LIBUSB_ERROR_NOT_FOUND;
- if (fClaimedInterfaces & (1U << interface))
- return LIBUSB_ERROR_BUSY;
- fClaimedInterfaces |= (1U << interface);
- return LIBUSB_SUCCESS;
- }
- int USBDevice::ReleaseInterface(uint8 interface)
- {
- fClaimedInterfaces &= ~(1U << interface);
- return LIBUSB_SUCCESS;
- }
- int
- USBDevice::CheckInterfacesFree(uint8 config)
- {
- if (fConfigToIndex.count(config) == 0)
- return LIBUSB_ERROR_NOT_FOUND;
- if (fClaimedInterfaces == 0)
- return fConfigToIndex[config];
- return LIBUSB_ERROR_BUSY;
- }
- void
- USBDevice::SetActiveConfiguration(uint8 config_index)
- {
- fActiveConfiguration = config_index;
- }
- uint8
- USBDevice::EndpointToIndex(uint8 address) const
- {
- return fEndpointToIndex[fActiveConfiguration][address];
- }
- uint8
- USBDevice::EndpointToInterface(uint8 address) const
- {
- return fEndpointToInterface[fActiveConfiguration][address];
- }
- int
- USBDevice::Initialise() //Do we need more error checking, etc? How to report?
- {
- int fRawFD = open(fPath, O_RDWR | O_CLOEXEC);
- if (fRawFD < 0)
- return B_ERROR;
- usb_raw_command command;
- command.device.descriptor = &fDeviceDescriptor;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR, &command, sizeof(command)) ||
- command.device.status != B_USB_RAW_STATUS_SUCCESS) {
- close(fRawFD);
- return B_ERROR;
- }
- fConfigurationDescriptors = new(std::nothrow) unsigned char *[fDeviceDescriptor.num_configurations];
- fEndpointToIndex = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
- fEndpointToInterface = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
- for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
- usb_configuration_descriptor tmp_config;
- command.config.descriptor = &tmp_config;
- command.config.config_index = i;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving configuration descriptor");
- close(fRawFD);
- return B_ERROR;
- }
- fConfigToIndex[tmp_config.configuration_value] = i;
- fConfigurationDescriptors[i] = new(std::nothrow) unsigned char[tmp_config.total_length];
- command.config_etc.descriptor = (usb_configuration_descriptor*)fConfigurationDescriptors[i];
- command.config_etc.length = tmp_config.total_length;
- command.config_etc.config_index = i;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC, &command, sizeof(command)) ||
- command.config_etc.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving full configuration descriptor");
- close(fRawFD);
- return B_ERROR;
- }
- for (uint8 j = 0; j < tmp_config.number_interfaces; j++) {
- command.alternate.config_index = i;
- command.alternate.interface_index = j;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving number of alternate interfaces");
- close(fRawFD);
- return B_ERROR;
- }
- uint8 num_alternate = (uint8)command.alternate.alternate_info;
- for (uint8 k = 0; k < num_alternate; k++) {
- usb_interface_descriptor tmp_interface;
- command.interface_etc.config_index = i;
- command.interface_etc.interface_index = j;
- command.interface_etc.alternate_index = k;
- command.interface_etc.descriptor = &tmp_interface;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving interface descriptor");
- close(fRawFD);
- return B_ERROR;
- }
- for (uint8 l = 0; l < tmp_interface.num_endpoints; l++) {
- usb_endpoint_descriptor tmp_endpoint;
- command.endpoint_etc.config_index = i;
- command.endpoint_etc.interface_index = j;
- command.endpoint_etc.alternate_index = k;
- command.endpoint_etc.endpoint_index = l;
- command.endpoint_etc.descriptor = &tmp_endpoint;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving endpoint descriptor");
- close(fRawFD);
- return B_ERROR;
- }
- fEndpointToIndex[i][tmp_endpoint.endpoint_address] = l;
- fEndpointToInterface[i][tmp_endpoint.endpoint_address] = j;
- }
- }
- }
- }
- close(fRawFD);
- fInitCheck = true;
- return B_OK;
- }
|