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 USBRoster gUsbRoster;
     30 int32 gInitCount = 0;
     31 
     32 static int
     33 haiku_init(struct libusb_context *ctx)
     34 {
     35 	if (atomic_add(&gInitCount, 1) == 0)
     36 		return gUsbRoster.Start();
     37 	return LIBUSB_SUCCESS;
     38 }
     39 
     40 static void
     41 haiku_exit(void)
     42 {
     43 	if (atomic_add(&gInitCount, -1) == 1)
     44 		gUsbRoster.Stop();
     45 }
     46 
     47 static int
     48 haiku_open(struct libusb_device_handle *dev_handle)
     49 {
     50 	USBDevice *dev = *((USBDevice **)dev_handle->dev->os_priv);
     51 	USBDeviceHandle *handle = new(std::nothrow) USBDeviceHandle(dev);
     52 	if (handle == NULL)
     53 		return LIBUSB_ERROR_NO_MEM;
     54 	if (handle->InitCheck() == false) {
     55 		delete handle;
     56 		return LIBUSB_ERROR_NO_DEVICE;
     57 	}
     58 	*((USBDeviceHandle **)dev_handle->os_priv) = handle;
     59 	return LIBUSB_SUCCESS;
     60 }
     61 
     62 static void
     63 haiku_close(struct libusb_device_handle *dev_handle)
     64 {
     65 	USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
     66 	if (handle == NULL)
     67 		return;
     68 	delete handle;
     69 	*((USBDeviceHandle **)dev_handle->os_priv) = NULL;
     70 }
     71 
     72 static int
     73 haiku_get_device_descriptor(struct libusb_device *device, unsigned char *buffer, int *host_endian)
     74 {
     75 	USBDevice *dev = *((USBDevice **)device->os_priv);
     76 	memcpy(buffer, dev->Descriptor(), DEVICE_DESC_LENGTH);
     77 	*host_endian = 0;
     78 	return LIBUSB_SUCCESS;
     79 }
     80 
     81 static int
     82 haiku_get_active_config_descriptor(struct libusb_device *device, unsigned char *buffer, size_t len, int *host_endian)
     83 {
     84 	USBDevice *dev = *((USBDevice **)device->os_priv);
     85 	const usb_configuration_descriptor *act_config = dev->ActiveConfiguration();
     86 	if (len > act_config->total_length)
     87 		return LIBUSB_ERROR_OVERFLOW;
     88 	memcpy(buffer, act_config, len);
     89 	*host_endian = 0;
     90 	return LIBUSB_SUCCESS;
     91 }
     92 
     93 static int
     94 haiku_get_config_descriptor(struct libusb_device *device, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
     95 {
     96 	USBDevice *dev = *((USBDevice **)device->os_priv);
     97 	const usb_configuration_descriptor *config = dev->ConfigurationDescriptor(config_index);
     98 	if (config == NULL) {
     99 		usbi_err(DEVICE_CTX(device), "failed getting configuration descriptor");
    100 		return LIBUSB_ERROR_INVALID_PARAM;
    101 	}
    102 	if (len > config->total_length)
    103 		len = config->total_length;
    104 	memcpy(buffer, config, len);
    105 	*host_endian = 0;
    106 	return len;
    107 }
    108 
    109 static int
    110 haiku_set_configuration(struct libusb_device_handle *dev_handle, int config)
    111 {
    112 	USBDeviceHandle *handle= *((USBDeviceHandle **)dev_handle->os_priv);
    113 	return handle->SetConfiguration(config);
    114 }
    115 
    116 static int
    117 haiku_claim_interface(struct libusb_device_handle *dev_handle, int interface_number)
    118 {
    119 	USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
    120 	return handle->ClaimInterface(interface_number);
    121 }
    122 
    123 static int
    124 haiku_set_altsetting(struct libusb_device_handle *dev_handle, int interface_number, int altsetting)
    125 {
    126 	USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
    127 	return handle->SetAltSetting(interface_number, altsetting);
    128 }
    129 
    130 static int
    131 haiku_release_interface(struct libusb_device_handle *dev_handle, int interface_number)
    132 {
    133 	USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
    134 	haiku_set_altsetting(dev_handle,interface_number, 0);
    135 	return handle->ReleaseInterface(interface_number);
    136 }
    137 
    138 static int
    139 haiku_submit_transfer(struct usbi_transfer *itransfer)
    140 {
    141 	struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
    142 	USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)fLibusbTransfer->dev_handle->os_priv);
    143 	return fDeviceHandle->SubmitTransfer(itransfer);
    144 }
    145 
    146 static int
    147 haiku_cancel_transfer(struct usbi_transfer *itransfer)
    148 {
    149 	struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
    150 	USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)fLibusbTransfer->dev_handle->os_priv);
    151 	return fDeviceHandle->CancelTransfer(*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)));
    152 }
    153 
    154 static void
    155 haiku_clear_transfer_priv(struct usbi_transfer *itransfer)
    156 {
    157 	USBTransfer *transfer = *((USBTransfer **)usbi_transfer_get_os_priv(itransfer));
    158 	delete transfer;
    159 	*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL;
    160 }
    161 
    162 static int
    163 haiku_handle_transfer_completion(struct usbi_transfer *itransfer)
    164 {
    165 	USBTransfer *transfer = *((USBTransfer **)usbi_transfer_get_os_priv(itransfer));
    166 
    167 	usbi_mutex_lock(&itransfer->lock);
    168 	if (transfer->IsCancelled()) {
    169 		delete transfer;
    170 		*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL;
    171 		usbi_mutex_unlock(&itransfer->lock);
    172 		if (itransfer->transferred < 0)
    173 			itransfer->transferred = 0;
    174 		return usbi_handle_transfer_cancellation(itransfer);
    175 	}
    176 	libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED;
    177 	if (itransfer->transferred < 0) {
    178 		usbi_err(ITRANSFER_CTX(itransfer), "error in transfer");
    179 		status = LIBUSB_TRANSFER_ERROR;
    180 		itransfer->transferred = 0;
    181 	}
    182 	delete transfer;
    183 	*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL;
    184 	usbi_mutex_unlock(&itransfer->lock);
    185 	return usbi_handle_transfer_completion(itransfer, status);
    186 }
    187 
    188 static int
    189 haiku_clock_gettime(int clkid, struct timespec *tp)
    190 {
    191 	if (clkid == USBI_CLOCK_REALTIME)
    192 		return clock_gettime(CLOCK_REALTIME, tp);
    193 	if (clkid == USBI_CLOCK_MONOTONIC)
    194 		return clock_gettime(CLOCK_MONOTONIC, tp);
    195 	return LIBUSB_ERROR_INVALID_PARAM;
    196 }
    197 
    198 const struct usbi_os_backend haiku_usb_raw_backend = {
    199 	/*.name =*/ "Haiku usbfs",
    200 	/*.caps =*/ 0,
    201 	/*.init =*/ haiku_init,
    202 	/*.exit =*/ haiku_exit,
    203 	/*.get_device_list =*/ NULL,
    204 	/*.hotplug_poll =*/ NULL,
    205 	/*.open =*/ haiku_open,
    206 	/*.close =*/ haiku_close,
    207 	/*.get_device_descriptor =*/ haiku_get_device_descriptor,
    208 	/*.get_active_config_descriptor =*/ haiku_get_active_config_descriptor,
    209 	/*.get_config_descriptor =*/ haiku_get_config_descriptor,
    210 	/*.get_config_descriptor_by_value =*/ NULL,
    211 
    212 
    213 	/*.get_configuration =*/ NULL,
    214 	/*.set_configuration =*/ haiku_set_configuration,
    215 	/*.claim_interface =*/ haiku_claim_interface,
    216 	/*.release_interface =*/ haiku_release_interface,
    217 
    218 	/*.set_interface_altsetting =*/ haiku_set_altsetting,
    219 	/*.clear_halt =*/ NULL,
    220 	/*.reset_device =*/ NULL,
    221 
    222 	/*.alloc_streams =*/ NULL,
    223 	/*.free_streams =*/ NULL,
    224 
    225 	/*.dev_mem_alloc =*/ NULL,
    226 	/*.dev_mem_free =*/ NULL,
    227 
    228 	/*.kernel_driver_active =*/ NULL,
    229 	/*.detach_kernel_driver =*/ NULL,
    230 	/*.attach_kernel_driver =*/ NULL,
    231 
    232 	/*.destroy_device =*/ NULL,
    233 
    234 	/*.submit_transfer =*/ haiku_submit_transfer,
    235 	/*.cancel_transfer =*/ haiku_cancel_transfer,
    236 	/*.clear_transfer_priv =*/ haiku_clear_transfer_priv,
    237 
    238 	/*.handle_events =*/ NULL,
    239 	/*.handle_transfer_completion =*/ haiku_handle_transfer_completion,
    240 
    241 	/*.clock_gettime =*/ haiku_clock_gettime,
    242 
    243 #ifdef USBI_TIMERFD_AVAILABLE
    244 	/*.get_timerfd_clockid =*/ NULL,
    245 #endif
    246 
    247 	/*.device_priv_size =*/ sizeof(USBDevice *),
    248 	/*.device_handle_priv_size =*/ sizeof(USBDeviceHandle *),
    249 	/*.transfer_priv_size =*/ sizeof(USBTransfer *),
    250 };
    251