dolphin/Externals/libusb/libusb/os/haiku_usb_raw.cpp
Léo Lam 04db41adf3 Externals: Update libusb to version 1.0.21
1.0.21 adds a usbdk backend, which may be helpful as it could be
used in the future to work around the missing isochronous transfer
support for WinUSB backends.

Here is the full changelog (from libusb).

2016-10-01: v1.0.21:
* Core: Refactor code related to transfer flags and timeout handling
* Darwin: Ignore root hub simulation devices
* Darwin: Improved support for OS X El Capitan
* Darwin: Work around devices with buggy endpoint descriptors
* Darwin: Do not use objc_registerThreadWithCollector after its deprecation
* Darwin: Use C11 atomics on 10.12+ as the OS atomics are now deprecated
* Linux: Support preallocating kernel memory for zerocopy USB
* Linux: Deal with receiving POLLERR before all transfers have completed
* Solaris: Add solaris backend
* Windows: Add Visual Studio 2015 support
* Windows: Add usbdk backend
* Prevent attempts to recursively handle events
* Fix race condition in handle_timeout()
* Allow transferred argument to be optional in bulk APIs
* Various other bug fixes and improvements
2016-11-20 18:11:42 +01:00

251 lines
7.5 KiB
C++

/*
* 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"
USBRoster gUsbRoster;
int32 gInitCount = 0;
static int
haiku_init(struct libusb_context *ctx)
{
if (atomic_add(&gInitCount, 1) == 0)
return gUsbRoster.Start();
return LIBUSB_SUCCESS;
}
static void
haiku_exit(void)
{
if (atomic_add(&gInitCount, -1) == 1)
gUsbRoster.Stop();
}
static int
haiku_open(struct libusb_device_handle *dev_handle)
{
USBDevice *dev = *((USBDevice **)dev_handle->dev->os_priv);
USBDeviceHandle *handle = new(std::nothrow) USBDeviceHandle(dev);
if (handle == NULL)
return LIBUSB_ERROR_NO_MEM;
if (handle->InitCheck() == false) {
delete handle;
return LIBUSB_ERROR_NO_DEVICE;
}
*((USBDeviceHandle **)dev_handle->os_priv) = handle;
return LIBUSB_SUCCESS;
}
static void
haiku_close(struct libusb_device_handle *dev_handle)
{
USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
if (handle == NULL)
return;
delete handle;
*((USBDeviceHandle **)dev_handle->os_priv) = NULL;
}
static int
haiku_get_device_descriptor(struct libusb_device *device, unsigned char *buffer, int *host_endian)
{
USBDevice *dev = *((USBDevice **)device->os_priv);
memcpy(buffer, dev->Descriptor(), DEVICE_DESC_LENGTH);
*host_endian = 0;
return LIBUSB_SUCCESS;
}
static int
haiku_get_active_config_descriptor(struct libusb_device *device, unsigned char *buffer, size_t len, int *host_endian)
{
USBDevice *dev = *((USBDevice **)device->os_priv);
const usb_configuration_descriptor *act_config = dev->ActiveConfiguration();
if (len > act_config->total_length)
return LIBUSB_ERROR_OVERFLOW;
memcpy(buffer, act_config, len);
*host_endian = 0;
return LIBUSB_SUCCESS;
}
static int
haiku_get_config_descriptor(struct libusb_device *device, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
{
USBDevice *dev = *((USBDevice **)device->os_priv);
const usb_configuration_descriptor *config = dev->ConfigurationDescriptor(config_index);
if (config == NULL) {
usbi_err(DEVICE_CTX(device), "failed getting configuration descriptor");
return LIBUSB_ERROR_INVALID_PARAM;
}
if (len > config->total_length)
len = config->total_length;
memcpy(buffer, config, len);
*host_endian = 0;
return len;
}
static int
haiku_set_configuration(struct libusb_device_handle *dev_handle, int config)
{
USBDeviceHandle *handle= *((USBDeviceHandle **)dev_handle->os_priv);
return handle->SetConfiguration(config);
}
static int
haiku_claim_interface(struct libusb_device_handle *dev_handle, int interface_number)
{
USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
return handle->ClaimInterface(interface_number);
}
static int
haiku_set_altsetting(struct libusb_device_handle *dev_handle, int interface_number, int altsetting)
{
USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
return handle->SetAltSetting(interface_number, altsetting);
}
static int
haiku_release_interface(struct libusb_device_handle *dev_handle, int interface_number)
{
USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
haiku_set_altsetting(dev_handle,interface_number, 0);
return handle->ReleaseInterface(interface_number);
}
static int
haiku_submit_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)fLibusbTransfer->dev_handle->os_priv);
return fDeviceHandle->SubmitTransfer(itransfer);
}
static int
haiku_cancel_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)fLibusbTransfer->dev_handle->os_priv);
return fDeviceHandle->CancelTransfer(*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)));
}
static void
haiku_clear_transfer_priv(struct usbi_transfer *itransfer)
{
USBTransfer *transfer = *((USBTransfer **)usbi_transfer_get_os_priv(itransfer));
delete transfer;
*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL;
}
static int
haiku_handle_transfer_completion(struct usbi_transfer *itransfer)
{
USBTransfer *transfer = *((USBTransfer **)usbi_transfer_get_os_priv(itransfer));
usbi_mutex_lock(&itransfer->lock);
if (transfer->IsCancelled()) {
delete transfer;
*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL;
usbi_mutex_unlock(&itransfer->lock);
if (itransfer->transferred < 0)
itransfer->transferred = 0;
return usbi_handle_transfer_cancellation(itransfer);
}
libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED;
if (itransfer->transferred < 0) {
usbi_err(ITRANSFER_CTX(itransfer), "error in transfer");
status = LIBUSB_TRANSFER_ERROR;
itransfer->transferred = 0;
}
delete transfer;
*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL;
usbi_mutex_unlock(&itransfer->lock);
return usbi_handle_transfer_completion(itransfer, status);
}
static int
haiku_clock_gettime(int clkid, struct timespec *tp)
{
if (clkid == USBI_CLOCK_REALTIME)
return clock_gettime(CLOCK_REALTIME, tp);
if (clkid == USBI_CLOCK_MONOTONIC)
return clock_gettime(CLOCK_MONOTONIC, tp);
return LIBUSB_ERROR_INVALID_PARAM;
}
const struct usbi_os_backend haiku_usb_raw_backend = {
/*.name =*/ "Haiku usbfs",
/*.caps =*/ 0,
/*.init =*/ haiku_init,
/*.exit =*/ haiku_exit,
/*.get_device_list =*/ NULL,
/*.hotplug_poll =*/ NULL,
/*.open =*/ haiku_open,
/*.close =*/ haiku_close,
/*.get_device_descriptor =*/ haiku_get_device_descriptor,
/*.get_active_config_descriptor =*/ haiku_get_active_config_descriptor,
/*.get_config_descriptor =*/ haiku_get_config_descriptor,
/*.get_config_descriptor_by_value =*/ NULL,
/*.get_configuration =*/ NULL,
/*.set_configuration =*/ haiku_set_configuration,
/*.claim_interface =*/ haiku_claim_interface,
/*.release_interface =*/ haiku_release_interface,
/*.set_interface_altsetting =*/ haiku_set_altsetting,
/*.clear_halt =*/ NULL,
/*.reset_device =*/ NULL,
/*.alloc_streams =*/ NULL,
/*.free_streams =*/ NULL,
/*.dev_mem_alloc =*/ NULL,
/*.dev_mem_free =*/ NULL,
/*.kernel_driver_active =*/ NULL,
/*.detach_kernel_driver =*/ NULL,
/*.attach_kernel_driver =*/ NULL,
/*.destroy_device =*/ NULL,
/*.submit_transfer =*/ haiku_submit_transfer,
/*.cancel_transfer =*/ haiku_cancel_transfer,
/*.clear_transfer_priv =*/ haiku_clear_transfer_priv,
/*.handle_events =*/ NULL,
/*.handle_transfer_completion =*/ haiku_handle_transfer_completion,
/*.clock_gettime =*/ haiku_clock_gettime,
#ifdef USBI_TIMERFD_AVAILABLE
/*.get_timerfd_clockid =*/ NULL,
#endif
/*.device_priv_size =*/ sizeof(USBDevice *),
/*.device_handle_priv_size =*/ sizeof(USBDeviceHandle *),
/*.transfer_priv_size =*/ sizeof(USBTransfer *),
};