3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/queue.h>
35 #include "libusb20_desc.h"
36 #include "libusb20_int.h"
41 return (LIBUSB20_ERROR_NOT_SUPPORTED);
51 dummy_callback(struct libusb20_transfer *xfer)
54 switch (libusb20_tr_get_status(xfer)) {
55 case LIBUSB20_TRANSFER_START:
56 libusb20_tr_submit(xfer);
59 /* complete or error */
65 #define dummy_get_config_desc_full (void *)dummy_int
66 #define dummy_get_config_index (void *)dummy_int
67 #define dummy_set_config_index (void *)dummy_int
68 #define dummy_claim_interface (void *)dummy_int
69 #define dummy_release_interface (void *)dummy_int
70 #define dummy_set_alt_index (void *)dummy_int
71 #define dummy_reset_device (void *)dummy_int
72 #define dummy_set_power_mode (void *)dummy_int
73 #define dummy_get_power_mode (void *)dummy_int
74 #define dummy_kernel_driver_active (void *)dummy_int
75 #define dummy_detach_kernel_driver (void *)dummy_int
76 #define dummy_do_request_sync (void *)dummy_int
77 #define dummy_tr_open (void *)dummy_int
78 #define dummy_tr_close (void *)dummy_int
79 #define dummy_tr_clear_stall_sync (void *)dummy_int
80 #define dummy_process (void *)dummy_int
82 #define dummy_tr_submit (void *)dummy_void
83 #define dummy_tr_cancel_async (void *)dummy_void
85 static const struct libusb20_device_methods libusb20_dummy_methods = {
86 LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy)
90 libusb20_tr_callback_wrapper(struct libusb20_transfer *xfer)
96 if (!xfer->is_pending) {
97 xfer->status = LIBUSB20_TRANSFER_START;
102 (xfer->callback) (xfer);
104 if (xfer->is_restart) {
105 xfer->is_restart = 0;
108 if (xfer->is_draining &&
109 (!xfer->is_pending)) {
110 xfer->is_draining = 0;
111 xfer->status = LIBUSB20_TRANSFER_DRAINED;
112 (xfer->callback) (xfer);
118 libusb20_tr_close(struct libusb20_transfer *xfer)
122 if (!xfer->is_opened) {
123 return (LIBUSB20_ERROR_OTHER);
125 error = (xfer->pdev->methods->tr_close) (xfer);
130 if (xfer->ppBuffer) {
131 free(xfer->ppBuffer);
133 /* clear some fields */
136 xfer->maxTotalLength = 0;
137 xfer->maxPacketLen = 0;
142 libusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
143 uint32_t MaxFrameCount, uint8_t ep_no)
148 if (xfer->is_opened) {
149 return (LIBUSB20_ERROR_BUSY);
151 if (MaxFrameCount == 0) {
152 return (LIBUSB20_ERROR_INVALID_PARAM);
154 xfer->maxFrames = MaxFrameCount;
156 size = MaxFrameCount * sizeof(xfer->pLength[0]);
157 xfer->pLength = malloc(size);
158 if (xfer->pLength == NULL) {
159 return (LIBUSB20_ERROR_NO_MEM);
161 memset(xfer->pLength, 0, size);
163 size = MaxFrameCount * sizeof(xfer->ppBuffer[0]);
164 xfer->ppBuffer = malloc(size);
165 if (xfer->ppBuffer == NULL) {
167 return (LIBUSB20_ERROR_NO_MEM);
169 memset(xfer->ppBuffer, 0, size);
171 error = (xfer->pdev->methods->tr_open) (xfer, MaxBufSize,
172 MaxFrameCount, ep_no);
175 free(xfer->ppBuffer);
183 struct libusb20_transfer *
184 libusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex)
186 if (trIndex >= pdev->nTransfer) {
189 return (pdev->pTransfer + trIndex);
193 libusb20_tr_get_actual_frames(struct libusb20_transfer *xfer)
195 return (xfer->aFrames);
199 libusb20_tr_get_time_complete(struct libusb20_transfer *xfer)
201 return (xfer->timeComplete);
205 libusb20_tr_get_actual_length(struct libusb20_transfer *xfer)
210 for (x = 0; x != xfer->aFrames; x++) {
211 actlen += xfer->pLength[x];
217 libusb20_tr_get_max_frames(struct libusb20_transfer *xfer)
219 return (xfer->maxFrames);
223 libusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer)
226 * Special Case NOTE: If the packet multiplier is non-zero for
227 * High Speed USB, the value returned is equal to
228 * "wMaxPacketSize * multiplier" !
230 return (xfer->maxPacketLen);
234 libusb20_tr_get_max_total_length(struct libusb20_transfer *xfer)
236 return (xfer->maxTotalLength);
240 libusb20_tr_get_status(struct libusb20_transfer *xfer)
242 return (xfer->status);
246 libusb20_tr_pending(struct libusb20_transfer *xfer)
248 return (xfer->is_pending);
252 libusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer)
254 return (xfer->priv_sc0);
258 libusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer)
260 return (xfer->priv_sc1);
264 libusb20_tr_stop(struct libusb20_transfer *xfer)
266 if (!xfer->is_pending) {
267 /* transfer not pending */
270 if (xfer->is_cancel) {
271 /* already cancelling */
274 xfer->is_cancel = 1; /* we are cancelling */
276 (xfer->pdev->methods->tr_cancel_async) (xfer);
281 libusb20_tr_drain(struct libusb20_transfer *xfer)
283 /* make sure that we are cancelling */
284 libusb20_tr_stop(xfer);
286 if (xfer->is_pending) {
287 xfer->is_draining = 1;
293 libusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
295 (xfer->pdev->methods->tr_clear_stall_sync) (xfer);
300 libusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex)
302 xfer->ppBuffer[frIndex] = buffer;
307 libusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb)
314 libusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags)
321 libusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex)
323 xfer->pLength[frIndex] = length;
328 libusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0)
330 xfer->priv_sc0 = sc0;
335 libusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1)
337 xfer->priv_sc1 = sc1;
342 libusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout)
344 xfer->timeout = timeout;
349 libusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames)
351 if (nFrames > xfer->maxFrames) {
352 /* should not happen */
353 nFrames = xfer->maxFrames;
355 xfer->nFrames = nFrames;
360 libusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
362 xfer->ppBuffer[0] = pBuf;
363 xfer->pLength[0] = length;
364 xfer->timeout = timeout;
370 libusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout)
374 xfer->ppBuffer[0] = psetup;
375 xfer->pLength[0] = 8; /* fixed */
376 xfer->timeout = timeout;
378 len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8);
382 xfer->ppBuffer[1] = pBuf;
383 xfer->pLength[1] = len;
391 libusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
393 xfer->ppBuffer[0] = pBuf;
394 xfer->pLength[0] = length;
395 xfer->timeout = timeout;
401 libusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex)
403 if (frIndex >= xfer->maxFrames) {
404 /* should not happen */
407 xfer->ppBuffer[frIndex] = pBuf;
408 xfer->pLength[frIndex] = length;
413 libusb20_tr_submit(struct libusb20_transfer *xfer)
415 if (xfer->is_pending) {
416 /* should not happen */
419 xfer->is_pending = 1; /* we are pending */
420 xfer->is_cancel = 0; /* not cancelling */
421 xfer->is_restart = 0; /* not restarting */
423 (xfer->pdev->methods->tr_submit) (xfer);
428 libusb20_tr_start(struct libusb20_transfer *xfer)
430 if (xfer->is_pending) {
431 if (xfer->is_cancel) {
432 /* cancelling - restart */
433 xfer->is_restart = 1;
435 /* transfer not pending */
438 /* get into the callback */
439 libusb20_tr_callback_wrapper(xfer);
443 /* USB device operations */
446 libusb20_dev_claim_interface(struct libusb20_device *pdev, uint8_t ifaceIndex)
450 if (ifaceIndex >= 32) {
451 error = LIBUSB20_ERROR_INVALID_PARAM;
452 } else if (pdev->claimed_interfaces & (1 << ifaceIndex)) {
453 error = LIBUSB20_ERROR_NOT_FOUND;
455 error = (pdev->methods->claim_interface) (pdev, ifaceIndex);
458 pdev->claimed_interfaces |= (1 << ifaceIndex);
464 libusb20_dev_close(struct libusb20_device *pdev)
466 struct libusb20_transfer *xfer;
470 if (!pdev->is_opened) {
471 return (LIBUSB20_ERROR_OTHER);
473 for (x = 0; x != pdev->nTransfer; x++) {
474 xfer = pdev->pTransfer + x;
476 libusb20_tr_drain(xfer);
479 if (pdev->pTransfer != NULL) {
480 free(pdev->pTransfer);
481 pdev->pTransfer = NULL;
483 error = (pdev->beMethods->close_device) (pdev);
485 pdev->methods = &libusb20_dummy_methods;
489 pdev->claimed_interfaces = 0;
495 libusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex)
499 error = (pdev->methods->detach_kernel_driver) (pdev, ifaceIndex);
503 struct LIBUSB20_DEVICE_DESC_DECODED *
504 libusb20_dev_get_device_desc(struct libusb20_device *pdev)
506 return (&(pdev->ddesc));
510 libusb20_dev_get_fd(struct libusb20_device *pdev)
516 libusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex)
520 error = (pdev->methods->kernel_driver_active) (pdev, ifaceIndex);
525 libusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax)
527 struct libusb20_transfer *xfer;
532 if (pdev->is_opened) {
533 return (LIBUSB20_ERROR_BUSY);
535 if (nTransferMax >= 256) {
536 return (LIBUSB20_ERROR_INVALID_PARAM);
537 } else if (nTransferMax != 0) {
538 size = sizeof(pdev->pTransfer[0]) * nTransferMax;
539 pdev->pTransfer = malloc(size);
540 if (pdev->pTransfer == NULL) {
541 return (LIBUSB20_ERROR_NO_MEM);
543 memset(pdev->pTransfer, 0, size);
545 /* initialise all transfers */
546 for (x = 0; x != nTransferMax; x++) {
548 xfer = pdev->pTransfer + x;
552 xfer->callback = &dummy_callback;
555 /* set "nTransfer" early */
556 pdev->nTransfer = nTransferMax;
558 error = (pdev->beMethods->open_device) (pdev, nTransferMax);
561 if (pdev->pTransfer != NULL) {
562 free(pdev->pTransfer);
563 pdev->pTransfer = NULL;
566 pdev->file_ctrl = -1;
575 libusb20_dev_release_interface(struct libusb20_device *pdev, uint8_t ifaceIndex)
579 if (ifaceIndex >= 32) {
580 error = LIBUSB20_ERROR_INVALID_PARAM;
581 } else if (!(pdev->claimed_interfaces & (1 << ifaceIndex))) {
582 error = LIBUSB20_ERROR_NOT_FOUND;
584 error = (pdev->methods->release_interface) (pdev, ifaceIndex);
587 pdev->claimed_interfaces &= ~(1 << ifaceIndex);
593 libusb20_dev_reset(struct libusb20_device *pdev)
597 error = (pdev->methods->reset_device) (pdev);
602 libusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
606 error = (pdev->methods->set_power_mode) (pdev, power_mode);
611 libusb20_dev_get_power_mode(struct libusb20_device *pdev)
616 error = (pdev->methods->get_power_mode) (pdev, &power_mode);
618 power_mode = LIBUSB20_POWER_ON; /* fake power mode */
623 libusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex)
627 error = (pdev->methods->set_alt_index) (pdev, ifaceIndex, altIndex);
632 libusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex)
636 error = (pdev->methods->set_config_index) (pdev, configIndex);
641 libusb20_dev_request_sync(struct libusb20_device *pdev,
642 struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data,
643 uint16_t *pactlen, uint32_t timeout, uint8_t flags)
647 error = (pdev->methods->do_request_sync) (pdev,
648 setup, data, pactlen, timeout, flags);
653 libusb20_dev_req_string_sync(struct libusb20_device *pdev,
654 uint8_t str_index, uint16_t langid, void *ptr, uint16_t len)
656 struct LIBUSB20_CONTROL_SETUP_DECODED req;
661 return (LIBUSB20_ERROR_INVALID_PARAM);
663 LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
666 * We need to read the USB string in two steps else some USB
667 * devices will complain.
670 LIBUSB20_REQUEST_TYPE_STANDARD |
671 LIBUSB20_RECIPIENT_DEVICE |
672 LIBUSB20_ENDPOINT_IN;
673 req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR;
674 req.wValue = (LIBUSB20_DT_STRING << 8) | str_index;
676 req.wLength = 4; /* bytes */
678 error = libusb20_dev_request_sync(pdev, &req,
679 ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
683 req.wLength = *(uint8_t *)ptr; /* bytes */
684 if (req.wLength > len) {
685 /* partial string read */
688 error = libusb20_dev_request_sync(pdev, &req,
689 ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
694 if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) {
695 return (LIBUSB20_ERROR_OTHER);
697 return (0); /* success */
701 libusb20_dev_req_string_simple_sync(struct libusb20_device *pdev,
702 uint8_t str_index, void *ptr, uint16_t len)
713 /* the following code derives from the FreeBSD USB kernel */
715 if ((len < 1) || (ptr == NULL)) {
716 /* too short buffer */
717 return (LIBUSB20_ERROR_INVALID_PARAM);
719 error = libusb20_dev_req_string_sync(pdev,
720 0, 0, temp, sizeof(temp));
722 *(uint8_t *)ptr = 0; /* zero terminate */
725 langid = temp[2] | (temp[3] << 8);
727 error = libusb20_dev_req_string_sync(pdev, str_index,
728 langid, temp, sizeof(temp));
730 *(uint8_t *)ptr = 0; /* zero terminate */
734 /* string length is too short */
735 *(uint8_t *)ptr = 0; /* zero terminate */
736 return (LIBUSB20_ERROR_OTHER);
738 /* reserve one byte for terminating zero */
741 /* find maximum length */
742 n = (temp[0] / 2) - 1;
746 /* reset swap state */
749 /* setup output buffer pointer */
752 /* convert and filter */
753 for (i = 0; (i != n); i++) {
754 c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8);
756 /* convert from Unicode, handle buggy strings */
757 if (((c & 0xff00) == 0) && (swap & 1)) {
758 /* Little Endian, default */
761 } else if (((c & 0x00ff) == 0) && (swap & 2)) {
766 /* skip invalid character */
770 * Filter by default - we don't allow greater and less than
771 * signs because they might confuse the dmesg printouts!
773 if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) {
774 /* skip invalid character */
779 *buf = 0; /* zero terminate string */
784 struct libusb20_config *
785 libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex)
787 struct libusb20_config *retval = NULL;
793 if (!pdev->is_opened) {
794 error = libusb20_dev_open(pdev, 0);
802 error = (pdev->methods->get_config_desc_full) (pdev,
803 &ptr, &len, configIndex);
808 /* parse new config descriptor */
809 retval = libusb20_parse_config_desc(ptr);
811 /* free config descriptor */
816 error = libusb20_dev_close(pdev);
821 struct libusb20_device *
822 libusb20_dev_alloc(void)
824 struct libusb20_device *pdev;
826 pdev = malloc(sizeof(*pdev));
830 memset(pdev, 0, sizeof(*pdev));
833 pdev->file_ctrl = -1;
834 pdev->methods = &libusb20_dummy_methods;
839 libusb20_dev_get_config_index(struct libusb20_device *pdev)
845 if (!pdev->is_opened) {
846 error = libusb20_dev_open(pdev, 0);
856 error = (pdev->methods->get_config_index) (pdev, &cfg_index);
858 cfg_index = 0 - 1; /* current config index */
861 if (libusb20_dev_close(pdev)) {
869 libusb20_dev_get_mode(struct libusb20_device *pdev)
871 return (pdev->usb_mode);
875 libusb20_dev_get_speed(struct libusb20_device *pdev)
877 return (pdev->usb_speed);
880 /* if this function returns an error, the device is gone */
882 libusb20_dev_process(struct libusb20_device *pdev)
886 error = (pdev->methods->process) (pdev);
891 libusb20_dev_wait_process(struct libusb20_device *pdev, int timeout)
893 struct pollfd pfd[1];
895 if (!pdev->is_opened) {
898 pfd[0].fd = pdev->file;
899 pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
902 if (poll(pfd, 1, timeout)) {
903 /* ignore any error */
909 libusb20_dev_free(struct libusb20_device *pdev)
915 if (pdev->is_opened) {
916 if (libusb20_dev_close(pdev)) {
917 /* ignore any errors */
925 libusb20_dev_get_backend_name(struct libusb20_device *pdev)
927 return ((pdev->beMethods->get_backend_name) ());
931 libusb20_dev_get_desc(struct libusb20_device *pdev)
933 return (pdev->usb_desc);
937 libusb20_dev_set_debug(struct libusb20_device *pdev, int debug)
944 libusb20_dev_get_debug(struct libusb20_device *pdev)
946 return (pdev->debug);
950 libusb20_dev_get_address(struct libusb20_device *pdev)
952 return (pdev->device_address);
956 libusb20_dev_get_bus_number(struct libusb20_device *pdev)
958 return (pdev->bus_number);
962 libusb20_dev_set_owner(struct libusb20_device *pdev, uid_t user, gid_t group)
964 return ((pdev->beMethods->dev_set_owner) (pdev, user, group));
968 libusb20_dev_set_perm(struct libusb20_device *pdev, mode_t mode)
970 return ((pdev->beMethods->dev_set_perm) (pdev, mode));
974 libusb20_dev_set_iface_owner(struct libusb20_device *pdev, uint8_t iface_index, uid_t user, gid_t group)
976 return ((pdev->beMethods->dev_set_iface_owner) (pdev, iface_index, user, group));
980 libusb20_dev_set_iface_perm(struct libusb20_device *pdev, uint8_t iface_index, mode_t mode)
982 return ((pdev->beMethods->dev_set_iface_perm) (pdev, iface_index, mode));
986 libusb20_dev_get_owner(struct libusb20_device *pdev, uid_t *user, gid_t *group)
996 return ((pdev->beMethods->dev_get_owner) (pdev, user, group));
1000 libusb20_dev_get_perm(struct libusb20_device *pdev, mode_t *mode)
1006 return ((pdev->beMethods->dev_get_perm) (pdev, mode));
1010 libusb20_dev_get_iface_owner(struct libusb20_device *pdev, uint8_t iface_index, uid_t *user, gid_t *group)
1020 return ((pdev->beMethods->dev_get_iface_owner) (pdev, iface_index, user, group));
1024 libusb20_dev_get_iface_perm(struct libusb20_device *pdev, uint8_t iface_index, mode_t *mode)
1030 return ((pdev->beMethods->dev_get_iface_perm) (pdev, iface_index, mode));
1033 /* USB bus operations */
1036 libusb20_bus_set_owner(struct libusb20_backend *pbe, uint8_t bus, uid_t user, gid_t group)
1038 return ((pbe->methods->bus_set_owner) (pbe, bus, user, group));
1042 libusb20_bus_set_perm(struct libusb20_backend *pbe, uint8_t bus, mode_t mode)
1044 return ((pbe->methods->bus_set_perm) (pbe, bus, mode));
1048 libusb20_bus_get_owner(struct libusb20_backend *pbe, uint8_t bus, uid_t *user, gid_t *group)
1057 return ((pbe->methods->bus_get_owner) (pbe, bus, user, group));
1061 libusb20_bus_get_perm(struct libusb20_backend *pbe, uint8_t bus, mode_t *mode)
1067 return ((pbe->methods->bus_get_perm) (pbe, bus, mode));
1070 /* USB backend operations */
1073 libusb20_be_get_dev_quirk(struct libusb20_backend *pbe,
1074 uint16_t quirk_index, struct libusb20_quirk *pq)
1076 return ((pbe->methods->root_get_dev_quirk) (pbe, quirk_index, pq));
1080 libusb20_be_get_quirk_name(struct libusb20_backend *pbe,
1081 uint16_t quirk_index, struct libusb20_quirk *pq)
1083 return ((pbe->methods->root_get_quirk_name) (pbe, quirk_index, pq));
1087 libusb20_be_add_dev_quirk(struct libusb20_backend *pbe,
1088 struct libusb20_quirk *pq)
1090 return ((pbe->methods->root_add_dev_quirk) (pbe, pq));
1094 libusb20_be_remove_dev_quirk(struct libusb20_backend *pbe,
1095 struct libusb20_quirk *pq)
1097 return ((pbe->methods->root_remove_dev_quirk) (pbe, pq));
1101 libusb20_be_set_owner(struct libusb20_backend *pbe, uid_t user, gid_t group)
1103 return ((pbe->methods->root_set_owner) (pbe, user, group));
1107 libusb20_be_set_perm(struct libusb20_backend *pbe, mode_t mode)
1109 return ((pbe->methods->root_set_perm) (pbe, mode));
1113 libusb20_be_get_owner(struct libusb20_backend *pbe, uid_t *user, gid_t *group)
1122 return ((pbe->methods->root_get_owner) (pbe, user, group));
1126 libusb20_be_get_perm(struct libusb20_backend *pbe, mode_t *mode)
1132 return ((pbe->methods->root_get_perm) (pbe, mode));
1135 struct libusb20_device *
1136 libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1140 } else if (pdev == NULL) {
1141 pdev = TAILQ_FIRST(&(pbe->usb_devs));
1143 pdev = TAILQ_NEXT(pdev, dev_entry);
1148 struct libusb20_backend *
1149 libusb20_be_alloc(const struct libusb20_backend_methods *methods)
1151 struct libusb20_backend *pbe;
1153 pbe = malloc(sizeof(*pbe));
1157 memset(pbe, 0, sizeof(*pbe));
1159 TAILQ_INIT(&(pbe->usb_devs));
1161 pbe->methods = methods; /* set backend methods */
1163 /* do the initial device scan */
1164 if (pbe->methods->init_backend) {
1165 (pbe->methods->init_backend) (pbe);
1170 struct libusb20_backend *
1171 libusb20_be_alloc_linux(void)
1173 struct libusb20_backend *pbe;
1176 pbe = libusb20_be_alloc(&libusb20_linux_backend);
1183 struct libusb20_backend *
1184 libusb20_be_alloc_ugen20(void)
1186 struct libusb20_backend *pbe;
1189 pbe = libusb20_be_alloc(&libusb20_ugen20_backend);
1196 struct libusb20_backend *
1197 libusb20_be_alloc_default(void)
1199 struct libusb20_backend *pbe;
1201 pbe = libusb20_be_alloc_linux();
1205 pbe = libusb20_be_alloc_ugen20();
1209 return (NULL); /* no backend found */
1213 libusb20_be_free(struct libusb20_backend *pbe)
1215 struct libusb20_device *pdev;
1221 while ((pdev = libusb20_be_device_foreach(pbe, NULL))) {
1222 libusb20_be_dequeue_device(pbe, pdev);
1223 libusb20_dev_free(pdev);
1225 if (pbe->methods->exit_backend) {
1226 (pbe->methods->exit_backend) (pbe);
1232 libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1234 pdev->beMethods = pbe->methods; /* copy backend methods */
1235 TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry);
1240 libusb20_be_dequeue_device(struct libusb20_backend *pbe,
1241 struct libusb20_device *pdev)
1243 TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry);