Fix issue 1) not recognizes some usb device, 2) reconnect when ffmpeg encoder error
[rtmpclient.git] / app / src / main / jni / libusb-1.0.22 / libusb / os / haiku_usb_backend.cpp
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 int _errno_to_libusb(int status)
30 {
31         return status;
32 }
33
34 USBTransfer::USBTransfer(struct usbi_transfer *itransfer, USBDevice *device)
35 {
36         fUsbiTransfer = itransfer;
37         fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
38         fUSBDevice = device;
39         fCancelled = false;
40 }
41
42 USBTransfer::~USBTransfer()
43 {
44 }
45
46 struct usbi_transfer *
47 USBTransfer::UsbiTransfer()
48 {
49         return fUsbiTransfer;
50 }
51
52 void
53 USBTransfer::SetCancelled()
54 {
55         fCancelled = true;
56 }
57
58 bool
59 USBTransfer::IsCancelled()
60 {
61         return fCancelled;
62 }
63
64 void
65 USBTransfer::Do(int fRawFD)
66 {
67         switch (fLibusbTransfer->type) {
68                 case LIBUSB_TRANSFER_TYPE_CONTROL:
69                 {
70                         struct libusb_control_setup *setup = (struct libusb_control_setup *)fLibusbTransfer->buffer;
71                         usb_raw_command command;
72                         command.control.request_type = setup->bmRequestType;
73                         command.control.request = setup->bRequest;
74                         command.control.value = setup->wValue;
75                         command.control.index = setup->wIndex;
76                         command.control.length = setup->wLength;
77                         command.control.data = fLibusbTransfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
78                         if (fCancelled)
79                                 break;
80                         if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
81                                         command.control.status != B_USB_RAW_STATUS_SUCCESS) {
82                                 fUsbiTransfer->transferred = -1;
83                                 usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed control transfer");
84                                 break;
85                         }
86                         fUsbiTransfer->transferred = command.control.length;
87                 }
88                 break;
89                 case LIBUSB_TRANSFER_TYPE_BULK:
90                 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
91                 {
92                         usb_raw_command command;
93                         command.transfer.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
94                         command.transfer.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
95                         command.transfer.data = fLibusbTransfer->buffer;
96                         command.transfer.length = fLibusbTransfer->length;
97                         if (fCancelled)
98                                 break;
99                         if (fLibusbTransfer->type == LIBUSB_TRANSFER_TYPE_BULK) {
100                                 if (ioctl(fRawFD, B_USB_RAW_COMMAND_BULK_TRANSFER, &command, sizeof(command)) ||
101                                                 command.transfer.status != B_USB_RAW_STATUS_SUCCESS) {
102                                         fUsbiTransfer->transferred = -1;
103                                         usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed bulk transfer");
104                                         break;
105                                 }
106                         }
107                         else {
108                                 if (ioctl(fRawFD, B_USB_RAW_COMMAND_INTERRUPT_TRANSFER, &command, sizeof(command)) ||
109                                                 command.transfer.status != B_USB_RAW_STATUS_SUCCESS) {
110                                         fUsbiTransfer->transferred = -1;
111                                         usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed interrupt transfer");
112                                         break;
113                                 }
114                         }
115                         fUsbiTransfer->transferred = command.transfer.length;
116                 }
117                 break;
118                 // IsochronousTransfers not tested
119                 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
120                 {
121                         usb_raw_command command;
122                         command.isochronous.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
123                         command.isochronous.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
124                         command.isochronous.data = fLibusbTransfer->buffer;
125                         command.isochronous.length = fLibusbTransfer->length;
126                         command.isochronous.packet_count = fLibusbTransfer->num_iso_packets;
127                         int i;
128                         usb_iso_packet_descriptor *packetDescriptors = new usb_iso_packet_descriptor[fLibusbTransfer->num_iso_packets];
129                         for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
130                                 if ((int16)(fLibusbTransfer->iso_packet_desc[i]).length != (fLibusbTransfer->iso_packet_desc[i]).length) {
131                                         fUsbiTransfer->transferred = -1;
132                                         usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
133                                         break;
134                                 }
135                                 packetDescriptors[i].request_length = (int16)(fLibusbTransfer->iso_packet_desc[i]).length;
136                         }
137                         if (i < fLibusbTransfer->num_iso_packets)
138                                 break;  // TODO Handle this error
139                         command.isochronous.packet_descriptors = packetDescriptors;
140                         if (fCancelled)
141                                 break;
142                         if (ioctl(fRawFD, B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER, &command, sizeof(command)) ||
143                                         command.isochronous.status != B_USB_RAW_STATUS_SUCCESS) {
144                                 fUsbiTransfer->transferred = -1;
145                                 usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
146                                 break;
147                         }
148                         for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
149                                 (fLibusbTransfer->iso_packet_desc[i]).actual_length = packetDescriptors[i].actual_length;
150                                 switch (packetDescriptors[i].status) {
151                                         case B_OK:
152                                                 (fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_COMPLETED;
153                                                 break;
154                                         default:
155                                                 (fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_ERROR;
156                                                 break;
157                                 }
158                         }
159                         delete[] packetDescriptors;
160                         // Do we put the length of transfer here, for isochronous transfers?
161                         fUsbiTransfer->transferred = command.transfer.length;
162                 }
163                 break;
164                 default:
165                         usbi_err(TRANSFER_CTX(fLibusbTransfer), "Unknown type of transfer");
166         }
167 }
168
169 bool
170 USBDeviceHandle::InitCheck()
171 {
172         return fInitCheck;
173 }
174
175 status_t
176 USBDeviceHandle::TransfersThread(void *self)
177 {
178         USBDeviceHandle *handle = (USBDeviceHandle *)self;
179         handle->TransfersWorker();
180         return B_OK;
181 }
182
183 void
184 USBDeviceHandle::TransfersWorker()
185 {
186         while (true) {
187                 status_t status = acquire_sem(fTransfersSem);
188                 if (status == B_BAD_SEM_ID)
189                         break;
190                 if (status == B_INTERRUPTED)
191                         continue;
192                 fTransfersLock.Lock();
193                 USBTransfer *fPendingTransfer = (USBTransfer *) fTransfers.RemoveItem((int32)0);
194                 fTransfersLock.Unlock();
195                 fPendingTransfer->Do(fRawFD);
196                 usbi_signal_transfer_completion(fPendingTransfer->UsbiTransfer());
197         }
198 }
199
200 status_t
201 USBDeviceHandle::SubmitTransfer(struct usbi_transfer *itransfer)
202 {
203         USBTransfer *transfer = new USBTransfer(itransfer, fUSBDevice);
204         *((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = transfer;
205         BAutolock locker(fTransfersLock);
206         fTransfers.AddItem(transfer);
207         release_sem(fTransfersSem);
208         return LIBUSB_SUCCESS;
209 }
210
211 status_t
212 USBDeviceHandle::CancelTransfer(USBTransfer *transfer)
213 {
214         transfer->SetCancelled();
215         fTransfersLock.Lock();
216         bool removed = fTransfers.RemoveItem(transfer);
217         fTransfersLock.Unlock();
218         if(removed)
219                 usbi_signal_transfer_completion(transfer->UsbiTransfer());
220         return LIBUSB_SUCCESS;
221 }
222
223 USBDeviceHandle::USBDeviceHandle(USBDevice *dev)
224         :
225         fTransfersThread(-1),
226         fUSBDevice(dev),
227         fClaimedInterfaces(0),
228         fInitCheck(false)
229 {
230         fRawFD = open(dev->Location(), O_RDWR | O_CLOEXEC);
231         if (fRawFD < 0) {
232                 usbi_err(NULL,"failed to open device");
233                 return;
234         }
235         fTransfersSem = create_sem(0, "Transfers Queue Sem");
236         fTransfersThread = spawn_thread(TransfersThread, "Transfer Worker", B_NORMAL_PRIORITY, this);
237         resume_thread(fTransfersThread);
238         fInitCheck = true;
239 }
240
241 USBDeviceHandle::~USBDeviceHandle()
242 {
243         if (fRawFD > 0)
244                 close(fRawFD);
245         for(int i = 0; i < 32; i++) {
246                 if (fClaimedInterfaces & (1 << i))
247                         ReleaseInterface(i);
248         }
249         delete_sem(fTransfersSem);
250         if (fTransfersThread > 0)
251                 wait_for_thread(fTransfersThread, NULL);
252 }
253
254 int
255 USBDeviceHandle::ClaimInterface(int inumber)
256 {
257         int status = fUSBDevice->ClaimInterface(inumber);
258         if (status == LIBUSB_SUCCESS)
259                 fClaimedInterfaces |= (1 << inumber);
260         return status;
261 }
262
263 int
264 USBDeviceHandle::ReleaseInterface(int inumber)
265 {
266         fUSBDevice->ReleaseInterface(inumber);
267         fClaimedInterfaces &= ~(1 << inumber);
268         return LIBUSB_SUCCESS;
269 }
270
271 int
272 USBDeviceHandle::SetConfiguration(int config)
273 {
274         int config_index = fUSBDevice->CheckInterfacesFree(config);
275         if(config_index == LIBUSB_ERROR_BUSY || config_index == LIBUSB_ERROR_NOT_FOUND)
276                 return config_index;
277         usb_raw_command command;
278         command.config.config_index = config_index;
279         if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_CONFIGURATION, &command, sizeof(command)) ||
280                         command.config.status != B_USB_RAW_STATUS_SUCCESS) {
281                 return _errno_to_libusb(command.config.status);
282         }
283         fUSBDevice->SetActiveConfiguration(config_index);
284         return LIBUSB_SUCCESS;
285 }
286
287 int
288 USBDeviceHandle::SetAltSetting(int inumber, int alt)
289 {
290         usb_raw_command command;
291         command.alternate.config_index = fUSBDevice->ActiveConfigurationIndex();
292         command.alternate.interface_index = inumber;
293         if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX, &command, sizeof(command)) ||
294                         command.alternate.status != B_USB_RAW_STATUS_SUCCESS) {
295                 usbi_err(NULL, "Error retrieving active alternate interface");
296                 return _errno_to_libusb(command.alternate.status);
297         }
298         if (command.alternate.alternate_info == alt) {
299                 usbi_dbg("Setting alternate interface successful");
300                 return LIBUSB_SUCCESS;
301         }
302         command.alternate.alternate_info = alt;
303         if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_ALT_INTERFACE, &command, sizeof(command)) ||
304                         command.alternate.status != B_USB_RAW_STATUS_SUCCESS) { //IF IOCTL FAILS DEVICE DISONNECTED PROBABLY
305                 usbi_err(NULL, "Error setting alternate interface");
306                 return _errno_to_libusb(command.alternate.status);
307         }
308         usbi_dbg("Setting alternate interface successful");
309         return LIBUSB_SUCCESS;
310 }
311
312
313 USBDevice::USBDevice(const char *path)
314         :
315         fPath(NULL),
316         fActiveConfiguration(0),        //0?
317         fConfigurationDescriptors(NULL),
318         fClaimedInterfaces(0),
319         fEndpointToIndex(NULL),
320         fEndpointToInterface(NULL),
321         fInitCheck(false)
322 {
323         fPath=strdup(path);
324         Initialise();
325 }
326
327 USBDevice::~USBDevice()
328 {
329         free(fPath);
330         if (fConfigurationDescriptors) {
331                 for(int i = 0; i < fDeviceDescriptor.num_configurations; i++) {
332                         if (fConfigurationDescriptors[i])
333                                 delete fConfigurationDescriptors[i];
334                 }
335                 delete[] fConfigurationDescriptors;
336         }
337         if (fEndpointToIndex)
338                 delete[] fEndpointToIndex;
339         if (fEndpointToInterface)
340                 delete[] fEndpointToInterface;
341 }
342
343 bool
344 USBDevice::InitCheck()
345 {
346         return fInitCheck;
347 }
348
349 const char *
350 USBDevice::Location() const
351 {
352         return fPath;
353 }
354
355 uint8
356 USBDevice::CountConfigurations() const
357 {
358         return fDeviceDescriptor.num_configurations;
359 }
360
361 const usb_device_descriptor *
362 USBDevice::Descriptor() const
363 {
364         return &fDeviceDescriptor;
365 }
366
367 const usb_configuration_descriptor *
368 USBDevice::ConfigurationDescriptor(uint32 index) const
369 {
370         if (index > CountConfigurations())
371                 return NULL;
372         return (usb_configuration_descriptor *) fConfigurationDescriptors[index];
373 }
374
375 const usb_configuration_descriptor *
376 USBDevice::ActiveConfiguration() const
377 {
378         return (usb_configuration_descriptor *) fConfigurationDescriptors[fActiveConfiguration];
379 }
380
381 int
382 USBDevice::ActiveConfigurationIndex() const
383 {
384         return fActiveConfiguration;
385 }
386
387 int USBDevice::ClaimInterface(int interface)
388 {
389         if (interface > ActiveConfiguration()->number_interfaces)
390                 return LIBUSB_ERROR_NOT_FOUND;
391         if (fClaimedInterfaces & (1 << interface))
392                 return LIBUSB_ERROR_BUSY;
393         fClaimedInterfaces |= (1 << interface);
394         return LIBUSB_SUCCESS;
395 }
396
397 int USBDevice::ReleaseInterface(int interface)
398 {
399         fClaimedInterfaces &= ~(1 << interface);
400         return LIBUSB_SUCCESS;
401 }
402
403 int
404 USBDevice::CheckInterfacesFree(int config)
405 {
406         if (fConfigToIndex.count(config) == 0)
407                 return LIBUSB_ERROR_NOT_FOUND;
408         if (fClaimedInterfaces == 0)
409                 return fConfigToIndex[(uint8)config];
410         return LIBUSB_ERROR_BUSY;
411 }
412
413 int
414 USBDevice::SetActiveConfiguration(int config_index)
415 {
416         fActiveConfiguration = config_index;
417         return LIBUSB_SUCCESS;
418 }
419
420 uint8
421 USBDevice::EndpointToIndex(uint8 address) const
422 {
423         return fEndpointToIndex[fActiveConfiguration][address];
424 }
425
426 uint8
427 USBDevice::EndpointToInterface(uint8 address) const
428 {
429         return fEndpointToInterface[fActiveConfiguration][address];
430 }
431
432 int
433 USBDevice::Initialise()         //Do we need more error checking, etc? How to report?
434 {
435         int fRawFD = open(fPath, O_RDWR | O_CLOEXEC);
436         if (fRawFD < 0)
437                 return B_ERROR;
438         usb_raw_command command;
439         command.device.descriptor = &fDeviceDescriptor;
440         if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR, &command, sizeof(command)) ||
441                         command.device.status != B_USB_RAW_STATUS_SUCCESS) {
442                 close(fRawFD);
443                 return B_ERROR;
444         }
445
446         fConfigurationDescriptors = new(std::nothrow) unsigned char *[fDeviceDescriptor.num_configurations];
447         fEndpointToIndex = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
448         fEndpointToInterface = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
449         for (int i = 0; i < fDeviceDescriptor.num_configurations; i++) {
450                 usb_configuration_descriptor tmp_config;
451                 command.config.descriptor = &tmp_config;
452                 command.config.config_index = i;
453                 if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR, &command, sizeof(command)) ||
454                                 command.config.status != B_USB_RAW_STATUS_SUCCESS) {
455                         usbi_err(NULL, "failed retrieving configuration descriptor");
456                         close(fRawFD);
457                         return B_ERROR;
458                 }
459                 fConfigToIndex[tmp_config.configuration_value] = i;
460                 fConfigurationDescriptors[i] = new(std::nothrow) unsigned char[tmp_config.total_length];
461                 command.control.request_type = 128;
462                 command.control.request = 6;
463                 command.control.value = (2 << 8) | i;
464                 command.control.index = 0;
465                 command.control.length = tmp_config.total_length;
466                 command.control.data = fConfigurationDescriptors[i];
467                 if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
468                                 command.control.status!=B_USB_RAW_STATUS_SUCCESS) {
469                         usbi_err(NULL, "failed retrieving full configuration descriptor");
470                         close(fRawFD);
471                         return B_ERROR;
472                 }
473                 for (int j = 0; j < tmp_config.number_interfaces; j++) {
474                         command.alternate.config_index = i;
475                         command.alternate.interface_index = j;
476                         if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command, sizeof(command)) ||
477                                         command.config.status != B_USB_RAW_STATUS_SUCCESS) {
478                                 usbi_err(NULL, "failed retrieving number of alternate interfaces");
479                                 close(fRawFD);
480                                 return B_ERROR;
481                         }
482                         int num_alternate = command.alternate.alternate_info;
483                         for (int k = 0; k < num_alternate; k++) {
484                                 usb_interface_descriptor tmp_interface;
485                                 command.interface_etc.config_index = i;
486                                 command.interface_etc.interface_index = j;
487                                 command.interface_etc.alternate_index = k;
488                                 command.interface_etc.descriptor = &tmp_interface;
489                                 if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC, &command, sizeof(command)) ||
490                                                 command.config.status != B_USB_RAW_STATUS_SUCCESS) {
491                                         usbi_err(NULL, "failed retrieving interface descriptor");
492                                         close(fRawFD);
493                                         return B_ERROR;
494                                 }
495                                 for (int l = 0; l < tmp_interface.num_endpoints; l++) {
496                                         usb_endpoint_descriptor tmp_endpoint;
497                                         command.endpoint_etc.config_index = i;
498                                         command.endpoint_etc.interface_index = j;
499                                         command.endpoint_etc.alternate_index = k;
500                                         command.endpoint_etc.endpoint_index = l;
501                                         command.endpoint_etc.descriptor = &tmp_endpoint;
502                                         if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC, &command, sizeof(command)) ||
503                                                         command.config.status != B_USB_RAW_STATUS_SUCCESS) {
504                                                 usbi_err(NULL, "failed retrieving endpoint descriptor");
505                                                 close(fRawFD);
506                                                 return B_ERROR;
507                                         }
508                                         fEndpointToIndex[i][tmp_endpoint.endpoint_address] = l;
509                                         fEndpointToInterface[i][tmp_endpoint.endpoint_address] = j;
510                                 }
511                         }
512                 }
513         }
514         close(fRawFD);
515         fInitCheck = true;
516         return B_OK;
517 }