• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Haiku Backend for libusb
3  * Copyright © 2014 Akshay Jaggi <akshay1994.leo@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
haiku_init(struct libusb_context * ctx)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
haiku_exit(void)41 haiku_exit(void)
42 {
43 	if (atomic_add(&gInitCount, -1) == 1)
44 		gUsbRoster.Stop();
45 }
46 
47 static int
haiku_open(struct libusb_device_handle * dev_handle)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
haiku_close(struct libusb_device_handle * dev_handle)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
haiku_get_device_descriptor(struct libusb_device * device,unsigned char * buffer,int * host_endian)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
haiku_get_active_config_descriptor(struct libusb_device * device,unsigned char * buffer,size_t len,int * host_endian)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
haiku_get_config_descriptor(struct libusb_device * device,uint8_t config_index,unsigned char * buffer,size_t len,int * host_endian)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
haiku_set_configuration(struct libusb_device_handle * dev_handle,int config)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
haiku_claim_interface(struct libusb_device_handle * dev_handle,int interface_number)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
haiku_set_altsetting(struct libusb_device_handle * dev_handle,int interface_number,int altsetting)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
haiku_release_interface(struct libusb_device_handle * dev_handle,int interface_number)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
haiku_submit_transfer(struct usbi_transfer * itransfer)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
haiku_cancel_transfer(struct usbi_transfer * itransfer)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
haiku_clear_transfer_priv(struct usbi_transfer * itransfer)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
haiku_handle_transfer_completion(struct usbi_transfer * itransfer)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
haiku_clock_gettime(int clkid,struct timespec * tp)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