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