mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-14 08:25:09 +02:00
![Léo Lam](/assets/img/avatar_default.png)
Now has support for isochronous transfers in the WinUSB backend, which may or may not work better than the UsbDk backend.
254 lines
7.4 KiB
C++
254 lines
7.4 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_get_config_descriptor(struct libusb_device *, uint8_t,
|
|
unsigned char *, size_t, int *);
|
|
|
|
static int
|
|
haiku_init(struct libusb_context *ctx)
|
|
{
|
|
if (atomic_add(&gInitCount, 1) == 0)
|
|
return gUsbRoster.Start();
|
|
return LIBUSB_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
haiku_exit(struct libusb_context *ctx)
|
|
{
|
|
UNUSED(ctx);
|
|
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);
|
|
return haiku_get_config_descriptor(device, dev->ActiveConfigurationIndex(), buffer, len, host_endian);
|
|
}
|
|
|
|
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 usbi_backend = {
|
|
.name = "Haiku usbfs",
|
|
.caps = 0,
|
|
.init = haiku_init,
|
|
.exit = haiku_exit,
|
|
.set_option = NULL,
|
|
.get_device_list = NULL,
|
|
.hotplug_poll = NULL,
|
|
.wrap_sys_device = 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
|
|
|
|
.context_priv_size = 0,
|
|
.device_priv_size = sizeof(USBDevice *),
|
|
.device_handle_priv_size = sizeof(USBDeviceHandle *),
|
|
.transfer_priv_size = sizeof(USBTransfer *),
|
|
};
|