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
27 #include <sys/queue.h>
28 #include <sys/types.h>
39 #include "libusb20_desc.h"
40 #include "libusb20_int.h"
42 #include <dev/usb/usb.h>
43 #include <dev/usb/usb_ioctl.h>
44 #include <dev/usb/usb_mfunc.h>
45 #include <dev/usb/usb_error.h>
46 #include <dev/usb/usb_revision.h>
48 static libusb20_init_backend_t ugen20_init_backend;
49 static libusb20_open_device_t ugen20_open_device;
50 static libusb20_close_device_t ugen20_close_device;
51 static libusb20_get_backend_name_t ugen20_get_backend_name;
52 static libusb20_exit_backend_t ugen20_exit_backend;
53 static libusb20_bus_set_owner_t ugen20_bus_set_owner;
54 static libusb20_bus_get_owner_t ugen20_bus_get_owner;
55 static libusb20_bus_set_perm_t ugen20_bus_set_perm;
56 static libusb20_bus_get_perm_t ugen20_bus_get_perm;
57 static libusb20_dev_get_iface_owner_t ugen20_dev_get_iface_owner;
58 static libusb20_dev_get_iface_perm_t ugen20_dev_get_iface_perm;
59 static libusb20_dev_get_owner_t ugen20_dev_get_owner;
60 static libusb20_dev_get_perm_t ugen20_dev_get_perm;
61 static libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc;
62 static libusb20_dev_get_info_t ugen20_dev_get_info;
63 static libusb20_dev_set_iface_owner_t ugen20_dev_set_iface_owner;
64 static libusb20_dev_set_iface_perm_t ugen20_dev_set_iface_perm;
65 static libusb20_dev_set_owner_t ugen20_dev_set_owner;
66 static libusb20_dev_set_perm_t ugen20_dev_set_perm;
67 static libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk;
68 static libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name;
69 static libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk;
70 static libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk;
71 static libusb20_root_set_owner_t ugen20_root_set_owner;
72 static libusb20_root_get_owner_t ugen20_root_get_owner;
73 static libusb20_root_set_perm_t ugen20_root_set_perm;
74 static libusb20_root_get_perm_t ugen20_root_get_perm;
75 static libusb20_root_set_template_t ugen20_root_set_template;
76 static libusb20_root_get_template_t ugen20_root_get_template;
78 const struct libusb20_backend_methods libusb20_ugen20_backend = {
79 LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
82 /* USB device specific */
83 static libusb20_get_config_desc_full_t ugen20_get_config_desc_full;
84 static libusb20_get_config_index_t ugen20_get_config_index;
85 static libusb20_set_config_index_t ugen20_set_config_index;
86 static libusb20_claim_interface_t ugen20_claim_interface;
87 static libusb20_release_interface_t ugen20_release_interface;
88 static libusb20_set_alt_index_t ugen20_set_alt_index;
89 static libusb20_reset_device_t ugen20_reset_device;
90 static libusb20_set_power_mode_t ugen20_set_power_mode;
91 static libusb20_get_power_mode_t ugen20_get_power_mode;
92 static libusb20_kernel_driver_active_t ugen20_kernel_driver_active;
93 static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver;
94 static libusb20_do_request_sync_t ugen20_do_request_sync;
95 static libusb20_process_t ugen20_process;
97 /* USB transfer specific */
98 static libusb20_tr_open_t ugen20_tr_open;
99 static libusb20_tr_close_t ugen20_tr_close;
100 static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync;
101 static libusb20_tr_submit_t ugen20_tr_submit;
102 static libusb20_tr_cancel_async_t ugen20_tr_cancel_async;
104 static const struct libusb20_device_methods libusb20_ugen20_device_methods = {
105 LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20)
109 ugen20_get_backend_name(void)
111 return ("FreeBSD UGEN 2.0");
115 ugen20_path_convert_one(const char **pp)
122 while ((*ptr >= '0') && (*ptr <= '9')) {
124 temp += (*ptr - '0');
125 if (temp >= 1000000) {
126 /* catch overflow early */
142 ugen20_enumerate(struct libusb20_device *pdev, const char *id)
144 const char *tmp = id;
145 struct usb2_device_descriptor ddesc;
146 struct usb2_device_info devinfo;
152 pdev->bus_number = ugen20_path_convert_one(&tmp);
153 pdev->device_address = ugen20_path_convert_one(&tmp);
155 snprintf(buf, sizeof(buf), "/dev/ugen%u.%u",
156 pdev->bus_number, pdev->device_address);
158 f = open(buf, O_RDWR);
160 return (LIBUSB20_ERROR_OTHER);
162 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
163 error = LIBUSB20_ERROR_OTHER;
166 /* store when the device was plugged */
167 pdev->session_data.plugtime = plugtime;
169 if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) {
170 error = LIBUSB20_ERROR_OTHER;
173 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
175 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
177 if (pdev->ddesc.bNumConfigurations == 0) {
178 error = LIBUSB20_ERROR_OTHER;
180 } else if (pdev->ddesc.bNumConfigurations >= 8) {
181 error = LIBUSB20_ERROR_OTHER;
184 if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) {
185 error = LIBUSB20_ERROR_OTHER;
188 switch (devinfo.udi_mode) {
189 case USB_MODE_DEVICE:
190 pdev->usb_mode = LIBUSB20_MODE_DEVICE;
193 pdev->usb_mode = LIBUSB20_MODE_HOST;
197 switch (devinfo.udi_speed) {
199 pdev->usb_speed = LIBUSB20_SPEED_LOW;
202 pdev->usb_speed = LIBUSB20_SPEED_FULL;
205 pdev->usb_speed = LIBUSB20_SPEED_HIGH;
207 case USB_SPEED_VARIABLE:
208 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
210 case USB_SPEED_SUPER:
211 pdev->usb_speed = LIBUSB20_SPEED_SUPER;
214 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
218 /* generate a nice description for printout */
220 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
221 "ugen%u.%u: <%s %s> at usbus%u", pdev->bus_number,
222 pdev->device_address, devinfo.udi_product,
223 devinfo.udi_vendor, pdev->bus_number);
231 struct ugen20_urd_state {
232 struct usb2_read_dir urd;
239 uint8_t dummy_zero[1];
243 ugen20_readdir(struct ugen20_urd_state *st)
247 if (st->ptr == NULL) {
248 st->urd.urd_startentry += st->nparsed;
249 st->urd.urd_data = st->buf;
250 st->urd.urd_maxlen = sizeof(st->buf);
253 if (ioctl(st->f, USB_READ_DIR, &st->urd)) {
258 if (st->ptr[0] == 0) {
266 st->src = (void *)(st->ptr + 1);
267 st->dst = st->src + strlen(st->src) + 1;
268 st->ptr = st->ptr + st->ptr[0];
271 if ((st->ptr < st->buf) ||
272 (st->ptr > st->dummy_zero)) {
280 ugen20_init_backend(struct libusb20_backend *pbe)
282 struct ugen20_urd_state state;
283 struct libusb20_device *pdev;
285 memset(&state, 0, sizeof(state));
287 state.f = open("/dev/usb", O_RDONLY);
289 return (LIBUSB20_ERROR_OTHER);
291 while (ugen20_readdir(&state) == 0) {
293 if ((state.src[0] != 'u') ||
294 (state.src[1] != 'g') ||
295 (state.src[2] != 'e') ||
296 (state.src[3] != 'n')) {
299 pdev = libusb20_dev_alloc();
303 if (ugen20_enumerate(pdev, state.src + 4)) {
304 libusb20_dev_free(pdev);
307 /* put the device on the backend list */
308 libusb20_be_enqueue_device(pbe, pdev);
311 return (0); /* success */
315 ugen20_tr_release(struct libusb20_device *pdev)
317 struct usb2_fs_uninit fs_uninit;
319 if (pdev->nTransfer == 0) {
322 /* release all pending USB transfers */
323 if (pdev->privBeData != NULL) {
324 memset(&fs_uninit, 0, sizeof(fs_uninit));
325 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
326 /* ignore any errors of this kind */
333 ugen20_tr_renew(struct libusb20_device *pdev)
335 struct usb2_fs_init fs_init;
336 struct usb2_fs_endpoint *pfse;
339 uint16_t nMaxTransfer;
341 nMaxTransfer = pdev->nTransfer;
344 if (nMaxTransfer == 0) {
347 size = nMaxTransfer * sizeof(*pfse);
349 if (pdev->privBeData == NULL) {
352 error = LIBUSB20_ERROR_NO_MEM;
355 pdev->privBeData = pfse;
357 /* reset endpoint data */
358 memset(pdev->privBeData, 0, size);
360 memset(&fs_init, 0, sizeof(fs_init));
362 fs_init.pEndpoints = pdev->privBeData;
363 fs_init.ep_index_max = nMaxTransfer;
365 if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) {
366 error = LIBUSB20_ERROR_OTHER;
374 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
382 snprintf(buf, sizeof(buf), "/dev/ugen%u.%u",
383 pdev->bus_number, pdev->device_address);
386 * We need two file handles, one for the control endpoint and one
387 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
390 g = open(buf, O_RDWR);
392 return (LIBUSB20_ERROR_NO_DEVICE);
394 f = open(buf, O_RDWR);
397 return (LIBUSB20_ERROR_NO_DEVICE);
399 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
400 error = LIBUSB20_ERROR_OTHER;
403 /* check that the correct device is still plugged */
404 if (pdev->session_data.plugtime != plugtime) {
405 error = LIBUSB20_ERROR_NO_DEVICE;
408 /* need to set this before "tr_renew()" */
412 /* renew all USB transfers */
413 error = ugen20_tr_renew(pdev);
418 pdev->methods = &libusb20_ugen20_device_methods;
422 if (pdev->privBeData) {
423 /* cleanup after "tr_renew()" */
424 free(pdev->privBeData);
425 pdev->privBeData = NULL;
428 pdev->file_ctrl = -1;
436 ugen20_close_device(struct libusb20_device *pdev)
438 struct usb2_fs_uninit fs_uninit;
440 if (pdev->privBeData) {
441 memset(&fs_uninit, 0, sizeof(fs_uninit));
442 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
443 /* ignore this error */
445 free(pdev->privBeData);
448 pdev->privBeData = NULL;
450 close(pdev->file_ctrl);
452 pdev->file_ctrl = -1;
453 return (0); /* success */
457 ugen20_exit_backend(struct libusb20_backend *pbe)
459 return; /* nothing to do */
463 ugen20_get_config_desc_full(struct libusb20_device *pdev,
464 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
466 struct usb2_gen_descriptor gen_desc;
467 struct usb2_config_descriptor cdesc;
472 memset(&gen_desc, 0, sizeof(gen_desc));
474 gen_desc.ugd_data = &cdesc;
475 gen_desc.ugd_maxlen = sizeof(cdesc);
476 gen_desc.ugd_config_index = cfg_index;
478 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
480 return (LIBUSB20_ERROR_OTHER);
482 len = UGETW(cdesc.wTotalLength);
483 if (len < sizeof(cdesc)) {
484 /* corrupt descriptor */
485 return (LIBUSB20_ERROR_OTHER);
489 return (LIBUSB20_ERROR_NO_MEM);
491 gen_desc.ugd_data = ptr;
492 gen_desc.ugd_maxlen = len;
494 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
497 return (LIBUSB20_ERROR_OTHER);
499 /* make sure that the device doesn't fool us */
500 memcpy(ptr, &cdesc, sizeof(cdesc));
505 return (0); /* success */
509 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
513 if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) {
514 return (LIBUSB20_ERROR_OTHER);
522 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
524 int temp = cfg_index;
526 /* release all active USB transfers */
527 ugen20_tr_release(pdev);
529 if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) {
530 return (LIBUSB20_ERROR_OTHER);
532 return (ugen20_tr_renew(pdev));
536 ugen20_claim_interface(struct libusb20_device *pdev, uint8_t iface_index)
538 int temp = iface_index;
540 if (ioctl(pdev->file_ctrl, USB_CLAIM_INTERFACE, &temp)) {
541 return (LIBUSB20_ERROR_OTHER);
547 ugen20_release_interface(struct libusb20_device *pdev, uint8_t iface_index)
549 int temp = iface_index;
551 if (ioctl(pdev->file_ctrl, USB_RELEASE_INTERFACE, &temp)) {
552 return (LIBUSB20_ERROR_OTHER);
558 ugen20_set_alt_index(struct libusb20_device *pdev,
559 uint8_t iface_index, uint8_t alt_index)
561 struct usb2_alt_interface alt_iface;
563 memset(&alt_iface, 0, sizeof(alt_iface));
565 alt_iface.uai_interface_index = iface_index;
566 alt_iface.uai_alt_index = alt_index;
568 /* release all active USB transfers */
569 ugen20_tr_release(pdev);
571 if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) {
572 return (LIBUSB20_ERROR_OTHER);
574 return (ugen20_tr_renew(pdev));
578 ugen20_reset_device(struct libusb20_device *pdev)
582 /* release all active USB transfers */
583 ugen20_tr_release(pdev);
585 if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) {
586 return (LIBUSB20_ERROR_OTHER);
588 return (ugen20_tr_renew(pdev));
592 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
596 switch (power_mode) {
597 case LIBUSB20_POWER_OFF:
598 temp = USB_POWER_MODE_OFF;
600 case LIBUSB20_POWER_ON:
601 temp = USB_POWER_MODE_ON;
603 case LIBUSB20_POWER_SAVE:
604 temp = USB_POWER_MODE_SAVE;
606 case LIBUSB20_POWER_SUSPEND:
607 temp = USB_POWER_MODE_SUSPEND;
609 case LIBUSB20_POWER_RESUME:
610 temp = USB_POWER_MODE_RESUME;
613 return (LIBUSB20_ERROR_INVALID_PARAM);
615 if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) {
616 return (LIBUSB20_ERROR_OTHER);
622 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
626 if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) {
627 return (LIBUSB20_ERROR_OTHER);
630 case USB_POWER_MODE_OFF:
631 temp = LIBUSB20_POWER_OFF;
633 case USB_POWER_MODE_ON:
634 temp = LIBUSB20_POWER_ON;
636 case USB_POWER_MODE_SAVE:
637 temp = LIBUSB20_POWER_SAVE;
639 case USB_POWER_MODE_SUSPEND:
640 temp = LIBUSB20_POWER_SUSPEND;
642 case USB_POWER_MODE_RESUME:
643 temp = LIBUSB20_POWER_RESUME;
646 temp = LIBUSB20_POWER_ON;
650 return (0); /* success */
654 ugen20_kernel_driver_active(struct libusb20_device *pdev,
657 int temp = iface_index;
659 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) {
660 return (LIBUSB20_ERROR_OTHER);
662 return (0); /* kernel driver is active */
666 ugen20_detach_kernel_driver(struct libusb20_device *pdev,
669 int temp = iface_index;
671 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) {
672 return (LIBUSB20_ERROR_OTHER);
674 return (0); /* kernel driver is active */
678 ugen20_do_request_sync(struct libusb20_device *pdev,
679 struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
680 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
682 struct usb2_ctl_request req;
684 memset(&req, 0, sizeof(req));
687 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
688 req.ucr_flags |= USB_SHORT_XFER_OK;
690 if (libusb20_me_encode(&req.ucr_request,
691 sizeof(req.ucr_request), setup)) {
694 if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) {
695 return (LIBUSB20_ERROR_OTHER);
698 /* get actual length */
699 *pactlen = req.ucr_actlen;
701 return (0); /* kernel driver is active */
705 ugen20_process(struct libusb20_device *pdev)
707 struct usb2_fs_complete temp;
708 struct usb2_fs_endpoint *fsep;
709 struct libusb20_transfer *xfer;
713 if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) {
714 if (errno == EBUSY) {
717 /* device detached */
718 return (LIBUSB20_ERROR_OTHER);
721 fsep = pdev->privBeData;
722 xfer = pdev->pTransfer;
723 fsep += temp.ep_index;
724 xfer += temp.ep_index;
726 /* update transfer status */
728 if (fsep->status == 0) {
729 xfer->aFrames = fsep->aFrames;
730 xfer->timeComplete = fsep->isoc_time_complete;
731 xfer->status = LIBUSB20_TRANSFER_COMPLETED;
732 } else if (fsep->status == USB_ERR_CANCELLED) {
734 xfer->timeComplete = 0;
735 xfer->status = LIBUSB20_TRANSFER_CANCELLED;
736 } else if (fsep->status == USB_ERR_STALLED) {
738 xfer->timeComplete = 0;
739 xfer->status = LIBUSB20_TRANSFER_STALL;
740 } else if (fsep->status == USB_ERR_TIMEOUT) {
742 xfer->timeComplete = 0;
743 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
746 xfer->timeComplete = 0;
747 xfer->status = LIBUSB20_TRANSFER_ERROR;
749 libusb20_tr_callback_wrapper(xfer);
751 return (0); /* done */
755 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
756 uint32_t MaxFrameCount, uint8_t ep_no)
758 struct usb2_fs_open temp;
759 struct usb2_fs_endpoint *fsep;
761 memset(&temp, 0, sizeof(temp));
763 fsep = xfer->pdev->privBeData;
764 fsep += xfer->trIndex;
766 temp.max_bufsize = MaxBufSize;
767 temp.max_frames = MaxFrameCount;
768 temp.ep_index = xfer->trIndex;
771 if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) {
772 return (LIBUSB20_ERROR_INVALID_PARAM);
774 /* maximums might have changed - update */
775 xfer->maxFrames = temp.max_frames;
777 /* "max_bufsize" should be multiple of "max_packet_length" */
778 xfer->maxTotalLength = temp.max_bufsize;
779 xfer->maxPacketLen = temp.max_packet_length;
781 /* setup buffer and length lists */
782 fsep->ppBuffer = xfer->ppBuffer;/* zero copy */
783 fsep->pLength = xfer->pLength; /* zero copy */
785 return (0); /* success */
789 ugen20_tr_close(struct libusb20_transfer *xfer)
791 struct usb2_fs_close temp;
793 memset(&temp, 0, sizeof(temp));
795 temp.ep_index = xfer->trIndex;
797 if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) {
798 return (LIBUSB20_ERROR_INVALID_PARAM);
800 return (0); /* success */
804 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
806 struct usb2_fs_clear_stall_sync temp;
808 memset(&temp, 0, sizeof(temp));
810 /* if the transfer is active, an error will be returned */
812 temp.ep_index = xfer->trIndex;
814 if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) {
815 return (LIBUSB20_ERROR_INVALID_PARAM);
817 return (0); /* success */
821 ugen20_tr_submit(struct libusb20_transfer *xfer)
823 struct usb2_fs_start temp;
824 struct usb2_fs_endpoint *fsep;
826 memset(&temp, 0, sizeof(temp));
828 fsep = xfer->pdev->privBeData;
829 fsep += xfer->trIndex;
831 fsep->nFrames = xfer->nFrames;
833 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
834 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
836 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
837 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
839 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
840 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
842 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
843 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
845 fsep->timeout = xfer->timeout;
847 temp.ep_index = xfer->trIndex;
849 if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) {
850 /* ignore any errors - should never happen */
852 return; /* success */
856 ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
858 struct usb2_fs_stop temp;
860 memset(&temp, 0, sizeof(temp));
862 temp.ep_index = xfer->trIndex;
864 if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) {
865 /* ignore any errors - should never happen */
871 ugen20_be_ioctl(uint32_t cmd, void *data)
876 f = open("/dev/usb", O_RDONLY);
878 return (LIBUSB20_ERROR_OTHER);
879 error = ioctl(f, cmd, data);
881 if (errno == EPERM) {
882 error = LIBUSB20_ERROR_ACCESS;
884 error = LIBUSB20_ERROR_OTHER;
892 ugen20_be_do_perm(uint32_t get_cmd, uint32_t set_cmd, uint8_t bus,
893 uint8_t dev, uint8_t iface, uid_t *uid,
894 gid_t *gid, mode_t *mode)
896 struct usb2_dev_perm perm;
899 memset(&perm, 0, sizeof(perm));
901 perm.bus_index = bus;
902 perm.dev_index = dev;
903 perm.iface_index = iface;
905 error = ugen20_be_ioctl(get_cmd, &perm);
913 *gid = perm.group_id;
921 perm.group_id = *gid;
925 return (ugen20_be_ioctl(set_cmd, &perm));
929 ugen20_bus_set_owner(struct libusb20_backend *pbe,
930 uint8_t bus, uid_t user, gid_t group)
932 return (ugen20_be_do_perm(USB_GET_BUS_PERM, USB_SET_BUS_PERM,
933 bus, 0, 0, &user, &group, NULL));
937 ugen20_bus_get_owner(struct libusb20_backend *pbe, uint8_t bus,
938 uid_t *user, gid_t *group)
940 return (ugen20_be_do_perm(USB_GET_BUS_PERM, 0,
941 bus, 0, 0, user, group, NULL));
945 ugen20_bus_set_perm(struct libusb20_backend *pbe,
946 uint8_t bus, mode_t mode)
948 return (ugen20_be_do_perm(USB_GET_BUS_PERM, USB_SET_BUS_PERM,
949 bus, 0, 0, NULL, NULL, &mode));
953 ugen20_bus_get_perm(struct libusb20_backend *pbe,
954 uint8_t bus, mode_t *mode)
956 return (ugen20_be_do_perm(USB_GET_BUS_PERM, 0,
957 bus, 0, 0, NULL, NULL, mode));
961 ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
962 uint8_t iface_index, char *buf, uint8_t len)
964 struct usb2_gen_descriptor ugd;
966 memset(&ugd, 0, sizeof(ugd));
969 ugd.ugd_maxlen = len;
970 ugd.ugd_iface_index = iface_index;
972 if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) {
973 return (LIBUSB20_ERROR_INVALID_PARAM);
979 ugen20_dev_get_info(struct libusb20_device *pdev,
980 struct usb2_device_info *pinfo)
982 if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) {
983 return (LIBUSB20_ERROR_INVALID_PARAM);
989 ugen20_dev_get_iface_owner(struct libusb20_device *pdev,
990 uint8_t iface_index, uid_t *user, gid_t *group)
992 return (ugen20_be_do_perm(USB_GET_IFACE_PERM, 0,
993 pdev->bus_number, pdev->device_address, iface_index,
998 ugen20_dev_get_iface_perm(struct libusb20_device *pdev,
999 uint8_t iface_index, mode_t *mode)
1001 return (ugen20_be_do_perm(USB_GET_IFACE_PERM, 0,
1002 pdev->bus_number, pdev->device_address, iface_index,
1007 ugen20_dev_get_owner(struct libusb20_device *pdev,
1008 uid_t *user, gid_t *group)
1010 return (ugen20_be_do_perm(USB_GET_DEVICE_PERM, 0,
1011 pdev->bus_number, pdev->device_address, 0,
1012 user, group, NULL));
1016 ugen20_dev_get_perm(struct libusb20_device *pdev, mode_t *mode)
1018 return (ugen20_be_do_perm(USB_GET_DEVICE_PERM, 0,
1019 pdev->bus_number, pdev->device_address, 0,
1024 ugen20_dev_set_iface_owner(struct libusb20_device *pdev,
1025 uint8_t iface_index, uid_t user, gid_t group)
1027 return (ugen20_be_do_perm(USB_GET_IFACE_PERM, USB_SET_IFACE_PERM,
1028 pdev->bus_number, pdev->device_address, iface_index,
1029 &user, &group, NULL));
1033 ugen20_dev_set_iface_perm(struct libusb20_device *pdev,
1034 uint8_t iface_index, mode_t mode)
1036 return (ugen20_be_do_perm(USB_GET_IFACE_PERM, USB_SET_IFACE_PERM,
1037 pdev->bus_number, pdev->device_address, iface_index,
1038 NULL, NULL, &mode));
1042 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
1043 uint16_t quirk_index, struct libusb20_quirk *pq)
1045 struct usb2_gen_quirk q;
1048 memset(&q, 0, sizeof(q));
1050 q.index = quirk_index;
1052 error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q);
1055 if (errno == EINVAL) {
1056 return (LIBUSB20_ERROR_NOT_FOUND);
1061 pq->bcdDeviceLow = q.bcdDeviceLow;
1062 pq->bcdDeviceHigh = q.bcdDeviceHigh;
1063 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
1069 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
1070 struct libusb20_quirk *pq)
1072 struct usb2_gen_quirk q;
1075 memset(&q, 0, sizeof(q));
1077 q.index = quirk_index;
1079 error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q);
1082 if (errno == EINVAL) {
1083 return (LIBUSB20_ERROR_NOT_FOUND);
1086 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
1092 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
1093 struct libusb20_quirk *pq)
1095 struct usb2_gen_quirk q;
1098 memset(&q, 0, sizeof(q));
1102 q.bcdDeviceLow = pq->bcdDeviceLow;
1103 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1104 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1106 error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q);
1108 if (errno == ENOMEM) {
1109 return (LIBUSB20_ERROR_NO_MEM);
1116 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
1117 struct libusb20_quirk *pq)
1119 struct usb2_gen_quirk q;
1122 memset(&q, 0, sizeof(q));
1126 q.bcdDeviceLow = pq->bcdDeviceLow;
1127 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1128 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1130 error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q);
1132 if (errno == EINVAL) {
1133 return (LIBUSB20_ERROR_NOT_FOUND);
1140 ugen20_dev_set_owner(struct libusb20_device *pdev,
1141 uid_t user, gid_t group)
1143 return (ugen20_be_do_perm(USB_GET_DEVICE_PERM, USB_SET_DEVICE_PERM,
1144 pdev->bus_number, pdev->device_address, 0,
1145 &user, &group, NULL));
1149 ugen20_dev_set_perm(struct libusb20_device *pdev, mode_t mode)
1151 return (ugen20_be_do_perm(USB_GET_DEVICE_PERM, USB_SET_DEVICE_PERM,
1152 pdev->bus_number, pdev->device_address, 0,
1153 NULL, NULL, &mode));
1157 ugen20_root_set_owner(struct libusb20_backend *pbe,
1158 uid_t user, gid_t group)
1160 return (ugen20_be_do_perm(USB_GET_ROOT_PERM, USB_SET_ROOT_PERM, 0, 0, 0,
1161 &user, &group, NULL));
1165 ugen20_root_get_owner(struct libusb20_backend *pbe, uid_t *user, gid_t *group)
1167 return (ugen20_be_do_perm(USB_GET_ROOT_PERM, 0, 0, 0, 0,
1168 user, group, NULL));
1172 ugen20_root_set_perm(struct libusb20_backend *pbe, mode_t mode)
1174 return (ugen20_be_do_perm(USB_GET_ROOT_PERM, USB_SET_ROOT_PERM, 0, 0, 0,
1175 NULL, NULL, &mode));
1179 ugen20_root_get_perm(struct libusb20_backend *pbe, mode_t *mode)
1181 return (ugen20_be_do_perm(USB_GET_ROOT_PERM, 0, 0, 0, 0,
1186 ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
1188 return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp));
1192 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
1194 return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp));