xref: /aosp_15_r20/external/libusb/libusb/os/haiku_usb_backend.cpp (revision 86b64dcb59b3a0b37502ecd56e119234366a6f7e)
1 /*
2  * Haiku Backend for libusb
3  * Copyright © 2014 Akshay Jaggi <[email protected]>
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 
_errno_to_libusb(int status)29 static int _errno_to_libusb(int status)
30 {
31 	return status;
32 }
33 
USBTransfer(struct usbi_transfer * itransfer,USBDevice * device)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 
~USBTransfer()42 USBTransfer::~USBTransfer()
43 {
44 }
45 
46 struct usbi_transfer *
UsbiTransfer()47 USBTransfer::UsbiTransfer()
48 {
49 	return fUsbiTransfer;
50 }
51 
52 void
SetCancelled()53 USBTransfer::SetCancelled()
54 {
55 	fCancelled = true;
56 }
57 
58 bool
IsCancelled()59 USBTransfer::IsCancelled()
60 {
61 	return fCancelled;
62 }
63 
64 void
Do(int fRawFD)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 ((fLibusbTransfer->iso_packet_desc[i]).length > (unsigned int)INT16_MAX) {
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
InitCheck()170 USBDeviceHandle::InitCheck()
171 {
172 	return fInitCheck;
173 }
174 
175 status_t
TransfersThread(void * self)176 USBDeviceHandle::TransfersThread(void *self)
177 {
178 	USBDeviceHandle *handle = (USBDeviceHandle *)self;
179 	handle->TransfersWorker();
180 	return B_OK;
181 }
182 
183 void
TransfersWorker()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
SubmitTransfer(struct usbi_transfer * itransfer)201 USBDeviceHandle::SubmitTransfer(struct usbi_transfer *itransfer)
202 {
203 	USBTransfer *transfer = new USBTransfer(itransfer, fUSBDevice);
204 	*((USBTransfer **)usbi_get_transfer_priv(itransfer)) = transfer;
205 	BAutolock locker(fTransfersLock);
206 	fTransfers.AddItem(transfer);
207 	release_sem(fTransfersSem);
208 	return LIBUSB_SUCCESS;
209 }
210 
211 status_t
CancelTransfer(USBTransfer * transfer)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 
USBDeviceHandle(USBDevice * dev)223 USBDeviceHandle::USBDeviceHandle(USBDevice *dev)
224 	:
225 	fUSBDevice(dev),
226 	fClaimedInterfaces(0),
227 	fTransfersThread(-1),
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 
~USBDeviceHandle()241 USBDeviceHandle::~USBDeviceHandle()
242 {
243 	if (fRawFD > 0)
244 		close(fRawFD);
245 	for (int i = 0; i < 32; i++) {
246 		if (fClaimedInterfaces & (1U << i))
247 			ReleaseInterface(i);
248 	}
249 	delete_sem(fTransfersSem);
250 	if (fTransfersThread > 0)
251 		wait_for_thread(fTransfersThread, NULL);
252 }
253 
254 int
ClaimInterface(uint8 inumber)255 USBDeviceHandle::ClaimInterface(uint8 inumber)
256 {
257 	int status = fUSBDevice->ClaimInterface(inumber);
258 	if (status == LIBUSB_SUCCESS)
259 		fClaimedInterfaces |= (1U << inumber);
260 	return status;
261 }
262 
263 int
ReleaseInterface(uint8 inumber)264 USBDeviceHandle::ReleaseInterface(uint8 inumber)
265 {
266 	fUSBDevice->ReleaseInterface(inumber);
267 	fClaimedInterfaces &= ~(1U << inumber);
268 	return LIBUSB_SUCCESS;
269 }
270 
271 int
SetConfiguration(uint8 config)272 USBDeviceHandle::SetConfiguration(uint8 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((uint8)config_index);
284 	return LIBUSB_SUCCESS;
285 }
286 
287 int
SetAltSetting(uint8 inumber,uint8 alt)288 USBDeviceHandle::SetAltSetting(uint8 inumber, uint8 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 == (uint32)alt) {
299 		usbi_dbg(NULL, "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 DISCONNECTED PROBABLY
305 		usbi_err(NULL, "Error setting alternate interface");
306 		return _errno_to_libusb(command.alternate.status);
307 	}
308 	usbi_dbg(NULL, "Setting alternate interface successful");
309 	return LIBUSB_SUCCESS;
310 }
311 
312 int
ClearHalt(uint8 endpoint)313 USBDeviceHandle::ClearHalt(uint8 endpoint)
314 {
315 	usb_raw_command command;
316 	command.control.request_type = USB_REQTYPE_ENDPOINT_OUT;
317 	command.control.request = USB_REQUEST_CLEAR_FEATURE;
318 	command.control.value = USB_FEATURE_ENDPOINT_HALT;
319 	command.control.index = endpoint;
320 	command.control.length = 0;
321 
322 	if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
323 			command.control.status != B_USB_RAW_STATUS_SUCCESS) {
324 		return _errno_to_libusb(command.control.status);
325 	}
326 	return LIBUSB_SUCCESS;
327 }
328 
329 
USBDevice(const char * path)330 USBDevice::USBDevice(const char *path)
331 	:
332 	fClaimedInterfaces(0),
333 	fConfigurationDescriptors(NULL),
334 	fActiveConfiguration(0),	//0?
335 	fPath(NULL),
336 	fEndpointToIndex(NULL),
337 	fEndpointToInterface(NULL),
338 	fInitCheck(false)
339 {
340 	fPath=strdup(path);
341 	Initialise();
342 }
343 
~USBDevice()344 USBDevice::~USBDevice()
345 {
346 	free(fPath);
347 	if (fConfigurationDescriptors) {
348 		for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
349 			if (fConfigurationDescriptors[i])
350 				delete fConfigurationDescriptors[i];
351 		}
352 		delete[] fConfigurationDescriptors;
353 	}
354 	if (fEndpointToIndex)
355 		delete[] fEndpointToIndex;
356 	if (fEndpointToInterface)
357 		delete[] fEndpointToInterface;
358 }
359 
360 bool
InitCheck()361 USBDevice::InitCheck()
362 {
363 	return fInitCheck;
364 }
365 
366 const char *
Location() const367 USBDevice::Location() const
368 {
369 	return fPath;
370 }
371 
372 uint8
CountConfigurations() const373 USBDevice::CountConfigurations() const
374 {
375 	return fDeviceDescriptor.num_configurations;
376 }
377 
378 const usb_device_descriptor *
Descriptor() const379 USBDevice::Descriptor() const
380 {
381 	return &fDeviceDescriptor;
382 }
383 
384 const usb_configuration_descriptor *
ConfigurationDescriptor(uint8 index) const385 USBDevice::ConfigurationDescriptor(uint8 index) const
386 {
387 	if (index > CountConfigurations())
388 		return NULL;
389 	return (usb_configuration_descriptor *) fConfigurationDescriptors[index];
390 }
391 
392 const usb_configuration_descriptor *
ActiveConfiguration() const393 USBDevice::ActiveConfiguration() const
394 {
395 	return (usb_configuration_descriptor *) fConfigurationDescriptors[fActiveConfiguration];
396 }
397 
398 uint8
ActiveConfigurationIndex() const399 USBDevice::ActiveConfigurationIndex() const
400 {
401 	return fActiveConfiguration;
402 }
403 
ClaimInterface(uint8 interface)404 int USBDevice::ClaimInterface(uint8 interface)
405 {
406 	if (interface > ActiveConfiguration()->number_interfaces)
407 		return LIBUSB_ERROR_NOT_FOUND;
408 	if (fClaimedInterfaces & (1U << interface))
409 		return LIBUSB_ERROR_BUSY;
410 	fClaimedInterfaces |= (1U << interface);
411 	return LIBUSB_SUCCESS;
412 }
413 
ReleaseInterface(uint8 interface)414 int USBDevice::ReleaseInterface(uint8 interface)
415 {
416 	fClaimedInterfaces &= ~(1U << interface);
417 	return LIBUSB_SUCCESS;
418 }
419 
420 int
CheckInterfacesFree(uint8 config)421 USBDevice::CheckInterfacesFree(uint8 config)
422 {
423 	if (fConfigToIndex.count(config) == 0)
424 		return LIBUSB_ERROR_NOT_FOUND;
425 	if (fClaimedInterfaces == 0)
426 		return fConfigToIndex[config];
427 	return LIBUSB_ERROR_BUSY;
428 }
429 
430 void
SetActiveConfiguration(uint8 config_index)431 USBDevice::SetActiveConfiguration(uint8 config_index)
432 {
433 	fActiveConfiguration = config_index;
434 }
435 
436 uint8
EndpointToIndex(uint8 address) const437 USBDevice::EndpointToIndex(uint8 address) const
438 {
439 	return fEndpointToIndex[fActiveConfiguration][address];
440 }
441 
442 uint8
EndpointToInterface(uint8 address) const443 USBDevice::EndpointToInterface(uint8 address) const
444 {
445 	return fEndpointToInterface[fActiveConfiguration][address];
446 }
447 
448 int
Initialise()449 USBDevice::Initialise()		//Do we need more error checking, etc? How to report?
450 {
451 	int fRawFD = open(fPath, O_RDWR | O_CLOEXEC);
452 	if (fRawFD < 0)
453 		return B_ERROR;
454 	usb_raw_command command;
455 	command.device.descriptor = &fDeviceDescriptor;
456 	if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR, &command, sizeof(command)) ||
457 			command.device.status != B_USB_RAW_STATUS_SUCCESS) {
458 		close(fRawFD);
459 		return B_ERROR;
460 	}
461 
462 	fConfigurationDescriptors = new(std::nothrow) unsigned char *[fDeviceDescriptor.num_configurations];
463 	fEndpointToIndex = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
464 	fEndpointToInterface = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
465 	for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
466 		usb_configuration_descriptor tmp_config;
467 		command.config.descriptor = &tmp_config;
468 		command.config.config_index = i;
469 		if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR, &command, sizeof(command)) ||
470 				command.config.status != B_USB_RAW_STATUS_SUCCESS) {
471 			usbi_err(NULL, "failed retrieving configuration descriptor");
472 			close(fRawFD);
473 			return B_ERROR;
474 		}
475 		fConfigToIndex[tmp_config.configuration_value] = i;
476 		fConfigurationDescriptors[i] = new(std::nothrow) unsigned char[tmp_config.total_length];
477 
478 		command.config_etc.descriptor = (usb_configuration_descriptor*)fConfigurationDescriptors[i];
479 		command.config_etc.length = tmp_config.total_length;
480 		command.config_etc.config_index = i;
481 		if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC, &command, sizeof(command)) ||
482 				command.config_etc.status != B_USB_RAW_STATUS_SUCCESS) {
483 			usbi_err(NULL, "failed retrieving full configuration descriptor");
484 			close(fRawFD);
485 			return B_ERROR;
486 		}
487 
488 		for (uint8 j = 0; j < tmp_config.number_interfaces; j++) {
489 			command.alternate.config_index = i;
490 			command.alternate.interface_index = j;
491 			if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command, sizeof(command)) ||
492 					command.config.status != B_USB_RAW_STATUS_SUCCESS) {
493 				usbi_err(NULL, "failed retrieving number of alternate interfaces");
494 				close(fRawFD);
495 				return B_ERROR;
496 			}
497 			uint8 num_alternate = (uint8)command.alternate.alternate_info;
498 			for (uint8 k = 0; k < num_alternate; k++) {
499 				usb_interface_descriptor tmp_interface;
500 				command.interface_etc.config_index = i;
501 				command.interface_etc.interface_index = j;
502 				command.interface_etc.alternate_index = k;
503 				command.interface_etc.descriptor = &tmp_interface;
504 				if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC, &command, sizeof(command)) ||
505 						command.config.status != B_USB_RAW_STATUS_SUCCESS) {
506 					usbi_err(NULL, "failed retrieving interface descriptor");
507 					close(fRawFD);
508 					return B_ERROR;
509 				}
510 				for (uint8 l = 0; l < tmp_interface.num_endpoints; l++) {
511 					usb_endpoint_descriptor tmp_endpoint;
512 					command.endpoint_etc.config_index = i;
513 					command.endpoint_etc.interface_index = j;
514 					command.endpoint_etc.alternate_index = k;
515 					command.endpoint_etc.endpoint_index = l;
516 					command.endpoint_etc.descriptor = &tmp_endpoint;
517 					if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC, &command, sizeof(command)) ||
518 							command.config.status != B_USB_RAW_STATUS_SUCCESS) {
519 						usbi_err(NULL, "failed retrieving endpoint descriptor");
520 						close(fRawFD);
521 						return B_ERROR;
522 					}
523 					fEndpointToIndex[i][tmp_endpoint.endpoint_address] = l;
524 					fEndpointToInterface[i][tmp_endpoint.endpoint_address] = j;
525 				}
526 			}
527 		}
528 	}
529 	close(fRawFD);
530 	fInitCheck = true;
531 	return B_OK;
532 }
533