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>
38 #include "libusb20_desc.h"
39 #include "libusb20_int.h"
41 #include <dev/usb/usb.h>
42 #include <dev/usb/usbdi.h>
43 #include <dev/usb/usb_ioctl.h>
45 static libusb20_init_backend_t ugen20_init_backend;
46 static libusb20_open_device_t ugen20_open_device;
47 static libusb20_close_device_t ugen20_close_device;
48 static libusb20_get_backend_name_t ugen20_get_backend_name;
49 static libusb20_exit_backend_t ugen20_exit_backend;
50 static libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc;
51 static libusb20_dev_get_info_t ugen20_dev_get_info;
52 static libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk;
53 static libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name;
54 static libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk;
55 static libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk;
56 static libusb20_root_set_template_t ugen20_root_set_template;
57 static libusb20_root_get_template_t ugen20_root_get_template;
59 const struct libusb20_backend_methods libusb20_ugen20_backend = {
60 LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
63 /* USB device specific */
64 static libusb20_get_config_desc_full_t ugen20_get_config_desc_full;
65 static libusb20_get_config_index_t ugen20_get_config_index;
66 static libusb20_set_config_index_t ugen20_set_config_index;
67 static libusb20_set_alt_index_t ugen20_set_alt_index;
68 static libusb20_reset_device_t ugen20_reset_device;
69 static libusb20_check_connected_t ugen20_check_connected;
70 static libusb20_set_power_mode_t ugen20_set_power_mode;
71 static libusb20_get_power_mode_t ugen20_get_power_mode;
72 static libusb20_get_port_path_t ugen20_get_port_path;
73 static libusb20_get_power_usage_t ugen20_get_power_usage;
74 static libusb20_kernel_driver_active_t ugen20_kernel_driver_active;
75 static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver;
76 static libusb20_do_request_sync_t ugen20_do_request_sync;
77 static libusb20_process_t ugen20_process;
79 /* USB transfer specific */
80 static libusb20_tr_open_t ugen20_tr_open;
81 static libusb20_tr_close_t ugen20_tr_close;
82 static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync;
83 static libusb20_tr_submit_t ugen20_tr_submit;
84 static libusb20_tr_cancel_async_t ugen20_tr_cancel_async;
86 static const struct libusb20_device_methods libusb20_ugen20_device_methods = {
87 LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20)
91 ugen20_get_backend_name(void)
93 return ("FreeBSD UGEN 2.0");
97 ugen20_path_convert_one(const char **pp)
104 while ((*ptr >= '0') && (*ptr <= '9')) {
106 temp += (*ptr - '0');
107 if (temp >= 1000000) {
108 /* catch overflow early */
124 ugen20_enumerate(struct libusb20_device *pdev, const char *id)
126 const char *tmp = id;
127 struct usb_device_descriptor ddesc;
128 struct usb_device_info devinfo;
134 pdev->bus_number = ugen20_path_convert_one(&tmp);
135 pdev->device_address = ugen20_path_convert_one(&tmp);
137 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
138 pdev->bus_number, pdev->device_address);
140 f = open(buf, O_RDWR);
142 return (LIBUSB20_ERROR_OTHER);
144 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
145 error = LIBUSB20_ERROR_OTHER;
148 /* store when the device was plugged */
149 pdev->session_data.plugtime = plugtime;
151 if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) {
152 error = LIBUSB20_ERROR_OTHER;
155 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
157 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
159 if (pdev->ddesc.bNumConfigurations == 0) {
160 error = LIBUSB20_ERROR_OTHER;
162 } else if (pdev->ddesc.bNumConfigurations >= 8) {
163 error = LIBUSB20_ERROR_OTHER;
166 if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) {
167 error = LIBUSB20_ERROR_OTHER;
170 switch (devinfo.udi_mode) {
171 case USB_MODE_DEVICE:
172 pdev->usb_mode = LIBUSB20_MODE_DEVICE;
175 pdev->usb_mode = LIBUSB20_MODE_HOST;
179 switch (devinfo.udi_speed) {
181 pdev->usb_speed = LIBUSB20_SPEED_LOW;
184 pdev->usb_speed = LIBUSB20_SPEED_FULL;
187 pdev->usb_speed = LIBUSB20_SPEED_HIGH;
189 case USB_SPEED_VARIABLE:
190 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
192 case USB_SPEED_SUPER:
193 pdev->usb_speed = LIBUSB20_SPEED_SUPER;
196 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
200 /* get parent HUB index and port */
202 pdev->parent_address = devinfo.udi_hubindex;
203 pdev->parent_port = devinfo.udi_hubport;
205 /* generate a nice description for printout */
207 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
208 USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
209 pdev->device_address, devinfo.udi_product,
210 devinfo.udi_vendor, pdev->bus_number);
218 struct ugen20_urd_state {
219 struct usb_read_dir urd;
226 uint8_t dummy_zero[1];
230 ugen20_readdir(struct ugen20_urd_state *st)
234 if (st->ptr == NULL) {
235 st->urd.urd_startentry += st->nparsed;
236 st->urd.urd_data = libusb20_pass_ptr(st->buf);
237 st->urd.urd_maxlen = sizeof(st->buf);
240 if (ioctl(st->f, USB_READ_DIR, &st->urd)) {
245 if (st->ptr[0] == 0) {
253 st->src = (void *)(st->ptr + 1);
254 st->dst = st->src + strlen(st->src) + 1;
255 st->ptr = st->ptr + st->ptr[0];
258 if ((st->ptr < st->buf) ||
259 (st->ptr > st->dummy_zero)) {
267 ugen20_init_backend(struct libusb20_backend *pbe)
269 struct ugen20_urd_state state;
270 struct libusb20_device *pdev;
272 memset(&state, 0, sizeof(state));
274 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
276 return (LIBUSB20_ERROR_OTHER);
278 while (ugen20_readdir(&state) == 0) {
280 if ((state.src[0] != 'u') ||
281 (state.src[1] != 'g') ||
282 (state.src[2] != 'e') ||
283 (state.src[3] != 'n')) {
286 pdev = libusb20_dev_alloc();
290 if (ugen20_enumerate(pdev, state.src + 4)) {
291 libusb20_dev_free(pdev);
294 /* put the device on the backend list */
295 libusb20_be_enqueue_device(pbe, pdev);
298 return (0); /* success */
302 ugen20_tr_release(struct libusb20_device *pdev)
304 struct usb_fs_uninit fs_uninit;
306 if (pdev->nTransfer == 0) {
309 /* release all pending USB transfers */
310 if (pdev->privBeData != NULL) {
311 memset(&fs_uninit, 0, sizeof(fs_uninit));
312 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
313 /* ignore any errors of this kind */
320 ugen20_tr_renew(struct libusb20_device *pdev)
322 struct usb_fs_init fs_init;
323 struct usb_fs_endpoint *pfse;
326 uint16_t nMaxTransfer;
328 nMaxTransfer = pdev->nTransfer;
331 if (nMaxTransfer == 0) {
334 size = nMaxTransfer * sizeof(*pfse);
336 if (pdev->privBeData == NULL) {
339 error = LIBUSB20_ERROR_NO_MEM;
342 pdev->privBeData = pfse;
344 /* reset endpoint data */
345 memset(pdev->privBeData, 0, size);
347 memset(&fs_init, 0, sizeof(fs_init));
349 fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData);
350 fs_init.ep_index_max = nMaxTransfer;
352 if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) {
353 error = LIBUSB20_ERROR_OTHER;
361 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
369 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
370 pdev->bus_number, pdev->device_address);
373 * We need two file handles, one for the control endpoint and one
374 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
377 g = open(buf, O_RDWR);
379 return (LIBUSB20_ERROR_NO_DEVICE);
381 f = open(buf, O_RDWR);
384 return (LIBUSB20_ERROR_NO_DEVICE);
386 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
387 error = LIBUSB20_ERROR_OTHER;
390 /* check that the correct device is still plugged */
391 if (pdev->session_data.plugtime != plugtime) {
392 error = LIBUSB20_ERROR_NO_DEVICE;
395 /* need to set this before "tr_renew()" */
399 /* renew all USB transfers */
400 error = ugen20_tr_renew(pdev);
405 pdev->methods = &libusb20_ugen20_device_methods;
409 if (pdev->privBeData) {
410 /* cleanup after "tr_renew()" */
411 free(pdev->privBeData);
412 pdev->privBeData = NULL;
415 pdev->file_ctrl = -1;
423 ugen20_close_device(struct libusb20_device *pdev)
425 struct usb_fs_uninit fs_uninit;
427 if (pdev->privBeData) {
428 memset(&fs_uninit, 0, sizeof(fs_uninit));
429 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
430 /* ignore this error */
432 free(pdev->privBeData);
435 pdev->privBeData = NULL;
437 close(pdev->file_ctrl);
439 pdev->file_ctrl = -1;
440 return (0); /* success */
444 ugen20_exit_backend(struct libusb20_backend *pbe)
446 return; /* nothing to do */
450 ugen20_get_config_desc_full(struct libusb20_device *pdev,
451 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
453 struct usb_gen_descriptor gen_desc;
454 struct usb_config_descriptor cdesc;
459 /* make sure memory is initialised */
460 memset(&cdesc, 0, sizeof(cdesc));
461 memset(&gen_desc, 0, sizeof(gen_desc));
463 gen_desc.ugd_data = libusb20_pass_ptr(&cdesc);
464 gen_desc.ugd_maxlen = sizeof(cdesc);
465 gen_desc.ugd_config_index = cfg_index;
467 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
469 return (LIBUSB20_ERROR_OTHER);
471 len = UGETW(cdesc.wTotalLength);
472 if (len < sizeof(cdesc)) {
473 /* corrupt descriptor */
474 return (LIBUSB20_ERROR_OTHER);
478 return (LIBUSB20_ERROR_NO_MEM);
481 /* make sure memory is initialised */
484 gen_desc.ugd_data = libusb20_pass_ptr(ptr);
485 gen_desc.ugd_maxlen = len;
487 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
490 return (LIBUSB20_ERROR_OTHER);
492 /* make sure that the device doesn't fool us */
493 memcpy(ptr, &cdesc, sizeof(cdesc));
498 return (0); /* success */
502 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
506 if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) {
507 return (LIBUSB20_ERROR_OTHER);
515 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
517 int temp = cfg_index;
519 /* release all active USB transfers */
520 ugen20_tr_release(pdev);
522 if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) {
523 return (LIBUSB20_ERROR_OTHER);
525 return (ugen20_tr_renew(pdev));
529 ugen20_set_alt_index(struct libusb20_device *pdev,
530 uint8_t iface_index, uint8_t alt_index)
532 struct usb_alt_interface alt_iface;
534 memset(&alt_iface, 0, sizeof(alt_iface));
536 alt_iface.uai_interface_index = iface_index;
537 alt_iface.uai_alt_index = alt_index;
539 /* release all active USB transfers */
540 ugen20_tr_release(pdev);
542 if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) {
543 return (LIBUSB20_ERROR_OTHER);
545 return (ugen20_tr_renew(pdev));
549 ugen20_reset_device(struct libusb20_device *pdev)
553 /* release all active USB transfers */
554 ugen20_tr_release(pdev);
556 if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) {
557 return (LIBUSB20_ERROR_OTHER);
559 return (ugen20_tr_renew(pdev));
563 ugen20_check_connected(struct libusb20_device *pdev)
568 if (ioctl(pdev->file_ctrl, USB_GET_PLUGTIME, &plugtime)) {
569 error = LIBUSB20_ERROR_NO_DEVICE;
573 if (pdev->session_data.plugtime != plugtime) {
574 error = LIBUSB20_ERROR_NO_DEVICE;
582 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
586 switch (power_mode) {
587 case LIBUSB20_POWER_OFF:
588 temp = USB_POWER_MODE_OFF;
590 case LIBUSB20_POWER_ON:
591 temp = USB_POWER_MODE_ON;
593 case LIBUSB20_POWER_SAVE:
594 temp = USB_POWER_MODE_SAVE;
596 case LIBUSB20_POWER_SUSPEND:
597 temp = USB_POWER_MODE_SUSPEND;
599 case LIBUSB20_POWER_RESUME:
600 temp = USB_POWER_MODE_RESUME;
603 return (LIBUSB20_ERROR_INVALID_PARAM);
605 if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) {
606 return (LIBUSB20_ERROR_OTHER);
612 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
616 if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) {
617 return (LIBUSB20_ERROR_OTHER);
620 case USB_POWER_MODE_OFF:
621 temp = LIBUSB20_POWER_OFF;
623 case USB_POWER_MODE_ON:
624 temp = LIBUSB20_POWER_ON;
626 case USB_POWER_MODE_SAVE:
627 temp = LIBUSB20_POWER_SAVE;
629 case USB_POWER_MODE_SUSPEND:
630 temp = LIBUSB20_POWER_SUSPEND;
632 case USB_POWER_MODE_RESUME:
633 temp = LIBUSB20_POWER_RESUME;
636 temp = LIBUSB20_POWER_ON;
640 return (0); /* success */
644 ugen20_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize)
646 struct usb_device_port_path udpp;
648 if (ioctl(pdev->file_ctrl, USB_GET_DEV_PORT_PATH, &udpp))
649 return (LIBUSB20_ERROR_OTHER);
651 if (udpp.udp_port_level > bufsize)
652 return (LIBUSB20_ERROR_OVERFLOW);
654 memcpy(buf, udpp.udp_port_no, udpp.udp_port_level);
656 return (udpp.udp_port_level); /* success */
660 ugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage)
664 if (ioctl(pdev->file_ctrl, USB_GET_POWER_USAGE, &temp)) {
665 return (LIBUSB20_ERROR_OTHER);
668 return (0); /* success */
672 ugen20_kernel_driver_active(struct libusb20_device *pdev,
675 int temp = iface_index;
677 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) {
678 return (LIBUSB20_ERROR_OTHER);
680 return (0); /* kernel driver is active */
684 ugen20_detach_kernel_driver(struct libusb20_device *pdev,
687 int temp = iface_index;
689 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) {
690 return (LIBUSB20_ERROR_OTHER);
692 return (0); /* kernel driver is active */
696 ugen20_do_request_sync(struct libusb20_device *pdev,
697 struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
698 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
700 struct usb_ctl_request req;
702 memset(&req, 0, sizeof(req));
704 req.ucr_data = libusb20_pass_ptr(data);
705 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
706 req.ucr_flags |= USB_SHORT_XFER_OK;
708 if (libusb20_me_encode(&req.ucr_request,
709 sizeof(req.ucr_request), setup)) {
712 if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) {
713 return (LIBUSB20_ERROR_OTHER);
716 /* get actual length */
717 *pactlen = req.ucr_actlen;
719 return (0); /* kernel driver is active */
723 ugen20_process(struct libusb20_device *pdev)
725 struct usb_fs_complete temp;
726 struct usb_fs_endpoint *fsep;
727 struct libusb20_transfer *xfer;
731 if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) {
732 if (errno == EBUSY) {
735 /* device detached */
736 return (LIBUSB20_ERROR_OTHER);
739 fsep = pdev->privBeData;
740 xfer = pdev->pTransfer;
741 fsep += temp.ep_index;
742 xfer += temp.ep_index;
744 /* update transfer status */
746 if (fsep->status == 0) {
747 xfer->aFrames = fsep->aFrames;
748 xfer->timeComplete = fsep->isoc_time_complete;
749 xfer->status = LIBUSB20_TRANSFER_COMPLETED;
750 } else if (fsep->status == USB_ERR_CANCELLED) {
752 xfer->timeComplete = 0;
753 xfer->status = LIBUSB20_TRANSFER_CANCELLED;
754 } else if (fsep->status == USB_ERR_STALLED) {
756 xfer->timeComplete = 0;
757 xfer->status = LIBUSB20_TRANSFER_STALL;
758 } else if (fsep->status == USB_ERR_TIMEOUT) {
760 xfer->timeComplete = 0;
761 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
764 xfer->timeComplete = 0;
765 xfer->status = LIBUSB20_TRANSFER_ERROR;
767 libusb20_tr_callback_wrapper(xfer);
769 return (0); /* done */
773 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
774 uint32_t MaxFrameCount, uint8_t ep_no, uint8_t pre_scale)
776 struct usb_fs_open temp;
777 struct usb_fs_endpoint *fsep;
780 MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE;
782 memset(&temp, 0, sizeof(temp));
784 fsep = xfer->pdev->privBeData;
785 fsep += xfer->trIndex;
787 temp.max_bufsize = MaxBufSize;
788 temp.max_frames = MaxFrameCount;
789 temp.ep_index = xfer->trIndex;
792 if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) {
793 return (LIBUSB20_ERROR_INVALID_PARAM);
795 /* maximums might have changed - update */
796 xfer->maxFrames = temp.max_frames;
798 /* "max_bufsize" should be multiple of "max_packet_length" */
799 xfer->maxTotalLength = temp.max_bufsize;
800 xfer->maxPacketLen = temp.max_packet_length;
802 /* setup buffer and length lists using zero copy */
803 fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer);
804 fsep->pLength = libusb20_pass_ptr(xfer->pLength);
806 return (0); /* success */
810 ugen20_tr_close(struct libusb20_transfer *xfer)
812 struct usb_fs_close temp;
814 memset(&temp, 0, sizeof(temp));
816 temp.ep_index = xfer->trIndex;
818 if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) {
819 return (LIBUSB20_ERROR_INVALID_PARAM);
821 return (0); /* success */
825 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
827 struct usb_fs_clear_stall_sync temp;
829 memset(&temp, 0, sizeof(temp));
831 /* if the transfer is active, an error will be returned */
833 temp.ep_index = xfer->trIndex;
835 if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) {
836 return (LIBUSB20_ERROR_INVALID_PARAM);
838 return (0); /* success */
842 ugen20_tr_submit(struct libusb20_transfer *xfer)
844 struct usb_fs_start temp;
845 struct usb_fs_endpoint *fsep;
847 memset(&temp, 0, sizeof(temp));
849 fsep = xfer->pdev->privBeData;
850 fsep += xfer->trIndex;
852 fsep->nFrames = xfer->nFrames;
854 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
855 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
857 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
858 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
860 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
861 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
863 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
864 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
866 /* NOTE: The "fsep->timeout" variable is 16-bit. */
867 if (xfer->timeout > 65535)
868 fsep->timeout = 65535;
870 fsep->timeout = xfer->timeout;
872 temp.ep_index = xfer->trIndex;
874 if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) {
875 /* ignore any errors - should never happen */
877 return; /* success */
881 ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
883 struct usb_fs_stop temp;
885 memset(&temp, 0, sizeof(temp));
887 temp.ep_index = xfer->trIndex;
889 if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) {
890 /* ignore any errors - should never happen */
896 ugen20_be_ioctl(uint32_t cmd, void *data)
901 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
903 return (LIBUSB20_ERROR_OTHER);
904 error = ioctl(f, cmd, data);
906 if (errno == EPERM) {
907 error = LIBUSB20_ERROR_ACCESS;
909 error = LIBUSB20_ERROR_OTHER;
917 ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
918 uint8_t iface_index, char *buf, uint8_t len)
920 struct usb_gen_descriptor ugd;
922 memset(&ugd, 0, sizeof(ugd));
924 ugd.ugd_data = libusb20_pass_ptr(buf);
925 ugd.ugd_maxlen = len;
926 ugd.ugd_iface_index = iface_index;
928 if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) {
929 return (LIBUSB20_ERROR_INVALID_PARAM);
935 ugen20_dev_get_info(struct libusb20_device *pdev,
936 struct usb_device_info *pinfo)
938 if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) {
939 return (LIBUSB20_ERROR_INVALID_PARAM);
945 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
946 uint16_t quirk_index, struct libusb20_quirk *pq)
948 struct usb_gen_quirk q;
951 memset(&q, 0, sizeof(q));
953 q.index = quirk_index;
955 error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q);
958 if (errno == EINVAL) {
959 return (LIBUSB20_ERROR_NOT_FOUND);
964 pq->bcdDeviceLow = q.bcdDeviceLow;
965 pq->bcdDeviceHigh = q.bcdDeviceHigh;
966 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
972 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
973 struct libusb20_quirk *pq)
975 struct usb_gen_quirk q;
978 memset(&q, 0, sizeof(q));
980 q.index = quirk_index;
982 error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q);
985 if (errno == EINVAL) {
986 return (LIBUSB20_ERROR_NOT_FOUND);
989 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
995 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
996 struct libusb20_quirk *pq)
998 struct usb_gen_quirk q;
1001 memset(&q, 0, sizeof(q));
1005 q.bcdDeviceLow = pq->bcdDeviceLow;
1006 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1007 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1009 error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q);
1011 if (errno == ENOMEM) {
1012 return (LIBUSB20_ERROR_NO_MEM);
1019 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
1020 struct libusb20_quirk *pq)
1022 struct usb_gen_quirk q;
1025 memset(&q, 0, sizeof(q));
1029 q.bcdDeviceLow = pq->bcdDeviceLow;
1030 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1031 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1033 error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q);
1035 if (errno == EINVAL) {
1036 return (LIBUSB20_ERROR_NOT_FOUND);
1043 ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
1045 return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp));
1049 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
1051 return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp));