3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
30 #include LIBUSB_GLOBAL_INCLUDE_FILE
39 #include <sys/queue.h>
40 #include <sys/types.h>
43 #include <dev/usb/usb.h>
44 #include <dev/usb/usbdi.h>
45 #include <dev/usb/usb_ioctl.h>
48 #include "libusb20_desc.h"
49 #include "libusb20_int.h"
55 static libusb20_init_backend_t ugen20_init_backend;
56 static libusb20_open_device_t ugen20_open_device;
57 static libusb20_close_device_t ugen20_close_device;
58 static libusb20_get_backend_name_t ugen20_get_backend_name;
59 static libusb20_exit_backend_t ugen20_exit_backend;
60 static libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc;
61 static libusb20_dev_get_info_t ugen20_dev_get_info;
62 static libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk;
63 static libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name;
64 static libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk;
65 static libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk;
66 static libusb20_root_set_template_t ugen20_root_set_template;
67 static libusb20_root_get_template_t ugen20_root_get_template;
69 const struct libusb20_backend_methods libusb20_ugen20_backend = {
70 LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
73 /* USB device specific */
74 static libusb20_get_config_desc_full_t ugen20_get_config_desc_full;
75 static libusb20_get_config_index_t ugen20_get_config_index;
76 static libusb20_set_config_index_t ugen20_set_config_index;
77 static libusb20_set_alt_index_t ugen20_set_alt_index;
78 static libusb20_reset_device_t ugen20_reset_device;
79 static libusb20_check_connected_t ugen20_check_connected;
80 static libusb20_set_power_mode_t ugen20_set_power_mode;
81 static libusb20_get_power_mode_t ugen20_get_power_mode;
82 static libusb20_get_port_path_t ugen20_get_port_path;
83 static libusb20_get_power_usage_t ugen20_get_power_usage;
84 static libusb20_kernel_driver_active_t ugen20_kernel_driver_active;
85 static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver;
86 static libusb20_do_request_sync_t ugen20_do_request_sync;
87 static libusb20_process_t ugen20_process;
89 /* USB transfer specific */
90 static libusb20_tr_open_t ugen20_tr_open;
91 static libusb20_tr_close_t ugen20_tr_close;
92 static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync;
93 static libusb20_tr_submit_t ugen20_tr_submit;
94 static libusb20_tr_cancel_async_t ugen20_tr_cancel_async;
96 static const struct libusb20_device_methods libusb20_ugen20_device_methods = {
97 LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20)
101 ugen20_get_backend_name(void)
103 return ("FreeBSD UGEN 2.0");
107 ugen20_path_convert_one(const char **pp)
114 while ((*ptr >= '0') && (*ptr <= '9')) {
116 temp += (*ptr - '0');
117 if (temp >= 1000000) {
118 /* catch overflow early */
134 ugen20_enumerate(struct libusb20_device *pdev, const char *id)
136 const char *tmp = id;
137 struct usb_device_descriptor ddesc;
138 struct usb_device_info devinfo;
144 pdev->bus_number = ugen20_path_convert_one(&tmp);
145 pdev->device_address = ugen20_path_convert_one(&tmp);
147 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
148 pdev->bus_number, pdev->device_address);
150 f = open(buf, O_RDWR);
152 return (LIBUSB20_ERROR_OTHER);
154 if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
155 error = LIBUSB20_ERROR_OTHER;
158 /* store when the device was plugged */
159 pdev->session_data.plugtime = plugtime;
161 if (ioctl(f, IOUSB(USB_GET_DEVICE_DESC), &ddesc)) {
162 error = LIBUSB20_ERROR_OTHER;
165 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
167 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
169 if (pdev->ddesc.bNumConfigurations == 0) {
170 error = LIBUSB20_ERROR_OTHER;
172 } else if (pdev->ddesc.bNumConfigurations >= 8) {
173 error = LIBUSB20_ERROR_OTHER;
176 if (ioctl(f, IOUSB(USB_GET_DEVICEINFO), &devinfo)) {
177 error = LIBUSB20_ERROR_OTHER;
180 switch (devinfo.udi_mode) {
181 case USB_MODE_DEVICE:
182 pdev->usb_mode = LIBUSB20_MODE_DEVICE;
185 pdev->usb_mode = LIBUSB20_MODE_HOST;
189 switch (devinfo.udi_speed) {
191 pdev->usb_speed = LIBUSB20_SPEED_LOW;
194 pdev->usb_speed = LIBUSB20_SPEED_FULL;
197 pdev->usb_speed = LIBUSB20_SPEED_HIGH;
199 case USB_SPEED_VARIABLE:
200 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
202 case USB_SPEED_SUPER:
203 pdev->usb_speed = LIBUSB20_SPEED_SUPER;
206 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
210 /* get parent HUB index and port */
212 pdev->parent_address = devinfo.udi_hubindex;
213 pdev->parent_port = devinfo.udi_hubport;
215 /* generate a nice description for printout */
217 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
218 USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
219 pdev->device_address, devinfo.udi_vendor,
220 devinfo.udi_product, pdev->bus_number);
228 struct ugen20_urd_state {
229 struct usb_read_dir urd;
236 uint8_t dummy_zero[1];
240 ugen20_readdir(struct ugen20_urd_state *st)
244 if (st->ptr == NULL) {
245 st->urd.urd_startentry += st->nparsed;
246 st->urd.urd_data = libusb20_pass_ptr(st->buf);
247 st->urd.urd_maxlen = sizeof(st->buf);
250 if (ioctl(st->f, IOUSB(USB_READ_DIR), &st->urd)) {
255 if (st->ptr[0] == 0) {
263 st->src = (void *)(st->ptr + 1);
264 st->dst = st->src + strlen(st->src) + 1;
265 st->ptr = st->ptr + st->ptr[0];
268 if ((st->ptr < st->buf) ||
269 (st->ptr > st->dummy_zero)) {
277 ugen20_init_backend(struct libusb20_backend *pbe)
279 struct ugen20_urd_state state;
280 struct libusb20_device *pdev;
282 memset(&state, 0, sizeof(state));
284 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
286 return (LIBUSB20_ERROR_OTHER);
288 while (ugen20_readdir(&state) == 0) {
290 if ((state.src[0] != 'u') ||
291 (state.src[1] != 'g') ||
292 (state.src[2] != 'e') ||
293 (state.src[3] != 'n')) {
296 pdev = libusb20_dev_alloc();
300 if (ugen20_enumerate(pdev, state.src + 4)) {
301 libusb20_dev_free(pdev);
304 /* put the device on the backend list */
305 libusb20_be_enqueue_device(pbe, pdev);
308 return (0); /* success */
312 ugen20_tr_release(struct libusb20_device *pdev)
314 struct usb_fs_uninit fs_uninit;
316 if (pdev->nTransfer == 0) {
319 /* release all pending USB transfers */
320 if (pdev->privBeData != NULL) {
321 memset(&fs_uninit, 0, sizeof(fs_uninit));
322 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) {
323 /* ignore any errors of this kind */
330 ugen20_tr_renew(struct libusb20_device *pdev)
332 struct usb_fs_init fs_init;
333 struct usb_fs_endpoint *pfse;
336 uint16_t nMaxTransfer;
338 nMaxTransfer = pdev->nTransfer;
341 if (nMaxTransfer == 0) {
344 size = nMaxTransfer * sizeof(*pfse);
346 if (pdev->privBeData == NULL) {
349 error = LIBUSB20_ERROR_NO_MEM;
352 pdev->privBeData = pfse;
354 /* reset endpoint data */
355 memset(pdev->privBeData, 0, size);
357 memset(&fs_init, 0, sizeof(fs_init));
359 fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData);
360 fs_init.ep_index_max = nMaxTransfer;
362 if (ioctl(pdev->file, IOUSB(USB_FS_INIT), &fs_init)) {
363 error = LIBUSB20_ERROR_OTHER;
371 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
379 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
380 pdev->bus_number, pdev->device_address);
383 * We need two file handles, one for the control endpoint and one
384 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
387 g = open(buf, O_RDWR);
389 return (LIBUSB20_ERROR_NO_DEVICE);
391 f = open(buf, O_RDWR);
394 return (LIBUSB20_ERROR_NO_DEVICE);
396 if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
397 error = LIBUSB20_ERROR_OTHER;
400 /* check that the correct device is still plugged */
401 if (pdev->session_data.plugtime != plugtime) {
402 error = LIBUSB20_ERROR_NO_DEVICE;
405 /* need to set this before "tr_renew()" */
409 /* renew all USB transfers */
410 error = ugen20_tr_renew(pdev);
415 pdev->methods = &libusb20_ugen20_device_methods;
419 if (pdev->privBeData) {
420 /* cleanup after "tr_renew()" */
421 free(pdev->privBeData);
422 pdev->privBeData = NULL;
425 pdev->file_ctrl = -1;
433 ugen20_close_device(struct libusb20_device *pdev)
435 struct usb_fs_uninit fs_uninit;
437 if (pdev->privBeData) {
438 memset(&fs_uninit, 0, sizeof(fs_uninit));
439 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) {
440 /* ignore this error */
442 free(pdev->privBeData);
445 pdev->privBeData = NULL;
447 close(pdev->file_ctrl);
449 pdev->file_ctrl = -1;
450 return (0); /* success */
454 ugen20_exit_backend(struct libusb20_backend *pbe)
456 return; /* nothing to do */
460 ugen20_get_config_desc_full(struct libusb20_device *pdev,
461 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
463 struct usb_gen_descriptor gen_desc;
464 struct usb_config_descriptor cdesc;
469 /* make sure memory is initialised */
470 memset(&cdesc, 0, sizeof(cdesc));
471 memset(&gen_desc, 0, sizeof(gen_desc));
473 gen_desc.ugd_data = libusb20_pass_ptr(&cdesc);
474 gen_desc.ugd_maxlen = sizeof(cdesc);
475 gen_desc.ugd_config_index = cfg_index;
477 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc);
479 return (LIBUSB20_ERROR_OTHER);
481 len = UGETW(cdesc.wTotalLength);
482 if (len < sizeof(cdesc)) {
483 /* corrupt descriptor */
484 return (LIBUSB20_ERROR_OTHER);
488 return (LIBUSB20_ERROR_NO_MEM);
491 /* make sure memory is initialised */
494 gen_desc.ugd_data = libusb20_pass_ptr(ptr);
495 gen_desc.ugd_maxlen = len;
497 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc);
500 return (LIBUSB20_ERROR_OTHER);
502 /* make sure that the device doesn't fool us */
503 memcpy(ptr, &cdesc, sizeof(cdesc));
508 return (0); /* success */
512 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
516 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_CONFIG), &temp)) {
517 return (LIBUSB20_ERROR_OTHER);
525 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
527 int temp = cfg_index;
529 /* release all active USB transfers */
530 ugen20_tr_release(pdev);
532 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_CONFIG), &temp)) {
533 return (LIBUSB20_ERROR_OTHER);
535 return (ugen20_tr_renew(pdev));
539 ugen20_set_alt_index(struct libusb20_device *pdev,
540 uint8_t iface_index, uint8_t alt_index)
542 struct usb_alt_interface alt_iface;
544 memset(&alt_iface, 0, sizeof(alt_iface));
546 alt_iface.uai_interface_index = iface_index;
547 alt_iface.uai_alt_index = alt_index;
549 /* release all active USB transfers */
550 ugen20_tr_release(pdev);
552 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_ALTINTERFACE), &alt_iface)) {
553 return (LIBUSB20_ERROR_OTHER);
555 return (ugen20_tr_renew(pdev));
559 ugen20_reset_device(struct libusb20_device *pdev)
563 /* release all active USB transfers */
564 ugen20_tr_release(pdev);
566 if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICEENUMERATE), &temp)) {
567 return (LIBUSB20_ERROR_OTHER);
569 return (ugen20_tr_renew(pdev));
573 ugen20_check_connected(struct libusb20_device *pdev)
578 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
579 error = LIBUSB20_ERROR_NO_DEVICE;
583 if (pdev->session_data.plugtime != plugtime) {
584 error = LIBUSB20_ERROR_NO_DEVICE;
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, IOUSB(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, IOUSB(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_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize)
656 struct usb_device_port_path udpp;
658 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_DEV_PORT_PATH), &udpp))
659 return (LIBUSB20_ERROR_OTHER);
661 if (udpp.udp_port_level > bufsize)
662 return (LIBUSB20_ERROR_OVERFLOW);
664 memcpy(buf, udpp.udp_port_no, udpp.udp_port_level);
666 return (udpp.udp_port_level); /* success */
670 ugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage)
674 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_USAGE), &temp)) {
675 return (LIBUSB20_ERROR_OTHER);
678 return (0); /* success */
682 ugen20_kernel_driver_active(struct libusb20_device *pdev,
685 int temp = iface_index;
687 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ACTIVE), &temp)) {
688 return (LIBUSB20_ERROR_OTHER);
690 return (0); /* kernel driver is active */
694 ugen20_detach_kernel_driver(struct libusb20_device *pdev,
697 int temp = iface_index;
699 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_DETACH), &temp)) {
700 return (LIBUSB20_ERROR_OTHER);
702 return (0); /* kernel driver is detached */
706 ugen20_do_request_sync(struct libusb20_device *pdev,
707 struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
708 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
710 struct usb_ctl_request req;
712 memset(&req, 0, sizeof(req));
714 req.ucr_data = libusb20_pass_ptr(data);
715 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
716 req.ucr_flags |= USB_SHORT_XFER_OK;
718 if (libusb20_me_encode(&req.ucr_request,
719 sizeof(req.ucr_request), setup)) {
722 if (ioctl(pdev->file_ctrl, IOUSB(USB_DO_REQUEST), &req)) {
723 return (LIBUSB20_ERROR_OTHER);
726 /* get actual length */
727 *pactlen = req.ucr_actlen;
729 return (0); /* request was successful */
733 ugen20_process(struct libusb20_device *pdev)
735 struct usb_fs_complete temp;
736 struct usb_fs_endpoint *fsep;
737 struct libusb20_transfer *xfer;
741 if (ioctl(pdev->file, IOUSB(USB_FS_COMPLETE), &temp)) {
742 if (errno == EBUSY) {
745 /* device detached */
746 return (LIBUSB20_ERROR_OTHER);
749 fsep = pdev->privBeData;
750 xfer = pdev->pTransfer;
751 fsep += temp.ep_index;
752 xfer += temp.ep_index;
754 /* update transfer status */
756 if (fsep->status == 0) {
757 xfer->aFrames = fsep->aFrames;
758 xfer->timeComplete = fsep->isoc_time_complete;
759 xfer->status = LIBUSB20_TRANSFER_COMPLETED;
760 } else if (fsep->status == USB_ERR_CANCELLED) {
762 xfer->timeComplete = 0;
763 xfer->status = LIBUSB20_TRANSFER_CANCELLED;
764 } else if (fsep->status == USB_ERR_STALLED) {
766 xfer->timeComplete = 0;
767 xfer->status = LIBUSB20_TRANSFER_STALL;
768 } else if (fsep->status == USB_ERR_TIMEOUT) {
770 xfer->timeComplete = 0;
771 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
774 xfer->timeComplete = 0;
775 xfer->status = LIBUSB20_TRANSFER_ERROR;
777 libusb20_tr_callback_wrapper(xfer);
779 return (0); /* done */
783 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
784 uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id,
788 struct usb_fs_open fs_open;
789 struct usb_fs_open_stream fs_open_stream;
791 struct usb_fs_endpoint *fsep;
794 MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE;
796 memset(&temp, 0, sizeof(temp));
798 fsep = xfer->pdev->privBeData;
799 fsep += xfer->trIndex;
801 temp.fs_open.max_bufsize = MaxBufSize;
802 temp.fs_open.max_frames = MaxFrameCount;
803 temp.fs_open.ep_index = xfer->trIndex;
804 temp.fs_open.ep_no = ep_no;
806 if (stream_id != 0) {
807 temp.fs_open_stream.stream_id = stream_id;
809 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN_STREAM), &temp.fs_open_stream))
810 return (LIBUSB20_ERROR_INVALID_PARAM);
812 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN), &temp.fs_open))
813 return (LIBUSB20_ERROR_INVALID_PARAM);
815 /* maximums might have changed - update */
816 xfer->maxFrames = temp.fs_open.max_frames;
818 /* "max_bufsize" should be multiple of "max_packet_length" */
819 xfer->maxTotalLength = temp.fs_open.max_bufsize;
820 xfer->maxPacketLen = temp.fs_open.max_packet_length;
822 /* setup buffer and length lists using zero copy */
823 fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer);
824 fsep->pLength = libusb20_pass_ptr(xfer->pLength);
826 return (0); /* success */
830 ugen20_tr_close(struct libusb20_transfer *xfer)
832 struct usb_fs_close temp;
834 memset(&temp, 0, sizeof(temp));
836 temp.ep_index = xfer->trIndex;
838 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLOSE), &temp)) {
839 return (LIBUSB20_ERROR_INVALID_PARAM);
841 return (0); /* success */
845 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
847 struct usb_fs_clear_stall_sync temp;
849 memset(&temp, 0, sizeof(temp));
851 /* if the transfer is active, an error will be returned */
853 temp.ep_index = xfer->trIndex;
855 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLEAR_STALL_SYNC), &temp)) {
856 return (LIBUSB20_ERROR_INVALID_PARAM);
858 return (0); /* success */
862 ugen20_tr_submit(struct libusb20_transfer *xfer)
864 struct usb_fs_start temp;
865 struct usb_fs_endpoint *fsep;
867 memset(&temp, 0, sizeof(temp));
869 fsep = xfer->pdev->privBeData;
870 fsep += xfer->trIndex;
872 fsep->nFrames = xfer->nFrames;
874 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
875 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
877 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
878 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
880 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
881 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
883 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
884 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
886 /* NOTE: The "fsep->timeout" variable is 16-bit. */
887 if (xfer->timeout > 65535)
888 fsep->timeout = 65535;
890 fsep->timeout = xfer->timeout;
892 temp.ep_index = xfer->trIndex;
894 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_START), &temp)) {
895 /* ignore any errors - should never happen */
897 return; /* success */
901 ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
903 struct usb_fs_stop temp;
905 memset(&temp, 0, sizeof(temp));
907 temp.ep_index = xfer->trIndex;
909 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_STOP), &temp)) {
910 /* ignore any errors - should never happen */
916 ugen20_be_ioctl(uint32_t cmd, void *data)
921 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
923 return (LIBUSB20_ERROR_OTHER);
924 error = ioctl(f, cmd, data);
926 if (errno == EPERM) {
927 error = LIBUSB20_ERROR_ACCESS;
929 error = LIBUSB20_ERROR_OTHER;
937 ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
938 uint8_t iface_index, char *buf, uint8_t len)
940 struct usb_gen_descriptor ugd;
942 memset(&ugd, 0, sizeof(ugd));
944 ugd.ugd_data = libusb20_pass_ptr(buf);
945 ugd.ugd_maxlen = len;
946 ugd.ugd_iface_index = iface_index;
948 if (ioctl(pdev->file, IOUSB(USB_GET_IFACE_DRIVER), &ugd)) {
949 return (LIBUSB20_ERROR_INVALID_PARAM);
955 ugen20_dev_get_info(struct libusb20_device *pdev,
956 struct usb_device_info *pinfo)
958 if (ioctl(pdev->file, IOUSB(USB_GET_DEVICEINFO), pinfo)) {
959 return (LIBUSB20_ERROR_INVALID_PARAM);
965 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
966 uint16_t quirk_index, struct libusb20_quirk *pq)
968 struct usb_gen_quirk q;
971 memset(&q, 0, sizeof(q));
973 q.index = quirk_index;
975 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_GET), &q);
978 if (errno == EINVAL) {
979 return (LIBUSB20_ERROR_NOT_FOUND);
984 pq->bcdDeviceLow = q.bcdDeviceLow;
985 pq->bcdDeviceHigh = q.bcdDeviceHigh;
986 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
992 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
993 struct libusb20_quirk *pq)
995 struct usb_gen_quirk q;
998 memset(&q, 0, sizeof(q));
1000 q.index = quirk_index;
1002 error = ugen20_be_ioctl(IOUSB(USB_QUIRK_NAME_GET), &q);
1005 if (errno == EINVAL) {
1006 return (LIBUSB20_ERROR_NOT_FOUND);
1009 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
1015 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
1016 struct libusb20_quirk *pq)
1018 struct usb_gen_quirk q;
1021 memset(&q, 0, sizeof(q));
1025 q.bcdDeviceLow = pq->bcdDeviceLow;
1026 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1027 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1029 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_ADD), &q);
1031 if (errno == ENOMEM) {
1032 return (LIBUSB20_ERROR_NO_MEM);
1039 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
1040 struct libusb20_quirk *pq)
1042 struct usb_gen_quirk q;
1045 memset(&q, 0, sizeof(q));
1049 q.bcdDeviceLow = pq->bcdDeviceLow;
1050 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1051 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1053 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_REMOVE), &q);
1055 if (errno == EINVAL) {
1056 return (LIBUSB20_ERROR_NOT_FOUND);
1063 ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
1065 return (ugen20_be_ioctl(IOUSB(USB_SET_TEMPLATE), &temp));
1069 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
1071 return (ugen20_be_ioctl(IOUSB(USB_GET_TEMPLATE), ptemp));