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_power_usage_t ugen20_get_power_usage;
83 static libusb20_kernel_driver_active_t ugen20_kernel_driver_active;
84 static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver;
85 static libusb20_do_request_sync_t ugen20_do_request_sync;
86 static libusb20_process_t ugen20_process;
88 /* USB transfer specific */
89 static libusb20_tr_open_t ugen20_tr_open;
90 static libusb20_tr_close_t ugen20_tr_close;
91 static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync;
92 static libusb20_tr_submit_t ugen20_tr_submit;
93 static libusb20_tr_cancel_async_t ugen20_tr_cancel_async;
95 static const struct libusb20_device_methods libusb20_ugen20_device_methods = {
96 LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20)
100 ugen20_get_backend_name(void)
102 return ("FreeBSD UGEN 2.0");
106 ugen20_path_convert_one(const char **pp)
113 while ((*ptr >= '0') && (*ptr <= '9')) {
115 temp += (*ptr - '0');
116 if (temp >= 1000000) {
117 /* catch overflow early */
133 ugen20_enumerate(struct libusb20_device *pdev, const char *id)
135 const char *tmp = id;
136 struct usb_device_descriptor ddesc;
137 struct usb_device_info devinfo;
138 struct usb_device_port_path udpp;
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);
222 /* get device port path, if any */
223 if (ioctl(f, IOUSB(USB_GET_DEV_PORT_PATH), &udpp) == 0 &&
224 udpp.udp_port_level < LIBUSB20_DEVICE_PORT_PATH_MAX) {
225 memcpy(pdev->port_path, udpp.udp_port_no, udpp.udp_port_level);
226 pdev->port_level = udpp.udp_port_level;
235 struct ugen20_urd_state {
236 struct usb_read_dir urd;
243 uint8_t dummy_zero[1];
247 ugen20_readdir(struct ugen20_urd_state *st)
251 if (st->ptr == NULL) {
252 st->urd.urd_startentry += st->nparsed;
253 st->urd.urd_data = libusb20_pass_ptr(st->buf);
254 st->urd.urd_maxlen = sizeof(st->buf);
257 if (ioctl(st->f, IOUSB(USB_READ_DIR), &st->urd)) {
262 if (st->ptr[0] == 0) {
270 st->src = (void *)(st->ptr + 1);
271 st->dst = st->src + strlen(st->src) + 1;
272 st->ptr = st->ptr + st->ptr[0];
275 if ((st->ptr < st->buf) ||
276 (st->ptr > st->dummy_zero)) {
284 ugen20_init_backend(struct libusb20_backend *pbe)
286 struct ugen20_urd_state state;
287 struct libusb20_device *pdev;
289 memset(&state, 0, sizeof(state));
291 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
293 return (LIBUSB20_ERROR_OTHER);
295 while (ugen20_readdir(&state) == 0) {
297 if ((state.src[0] != 'u') ||
298 (state.src[1] != 'g') ||
299 (state.src[2] != 'e') ||
300 (state.src[3] != 'n')) {
303 pdev = libusb20_dev_alloc();
307 if (ugen20_enumerate(pdev, state.src + 4)) {
308 libusb20_dev_free(pdev);
311 /* put the device on the backend list */
312 libusb20_be_enqueue_device(pbe, pdev);
315 return (0); /* success */
319 ugen20_tr_release(struct libusb20_device *pdev)
321 struct usb_fs_uninit fs_uninit;
323 if (pdev->nTransfer == 0) {
326 /* release all pending USB transfers */
327 if (pdev->privBeData != NULL) {
328 memset(&fs_uninit, 0, sizeof(fs_uninit));
329 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) {
330 /* ignore any errors of this kind */
337 ugen20_tr_renew(struct libusb20_device *pdev)
339 struct usb_fs_init fs_init;
340 struct usb_fs_endpoint *pfse;
343 uint16_t nMaxTransfer;
345 nMaxTransfer = pdev->nTransfer;
348 if (nMaxTransfer == 0) {
351 size = nMaxTransfer * sizeof(*pfse);
353 if (pdev->privBeData == NULL) {
356 error = LIBUSB20_ERROR_NO_MEM;
359 pdev->privBeData = pfse;
361 /* reset endpoint data */
362 memset(pdev->privBeData, 0, size);
364 memset(&fs_init, 0, sizeof(fs_init));
366 fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData);
367 fs_init.ep_index_max = nMaxTransfer;
369 if (ioctl(pdev->file, IOUSB(USB_FS_INIT), &fs_init)) {
370 error = LIBUSB20_ERROR_OTHER;
378 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
386 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
387 pdev->bus_number, pdev->device_address);
390 * We need two file handles, one for the control endpoint and one
391 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
394 g = open(buf, O_RDWR);
396 return (LIBUSB20_ERROR_NO_DEVICE);
398 f = open(buf, O_RDWR);
401 return (LIBUSB20_ERROR_NO_DEVICE);
403 if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
404 error = LIBUSB20_ERROR_OTHER;
407 /* check that the correct device is still plugged */
408 if (pdev->session_data.plugtime != plugtime) {
409 error = LIBUSB20_ERROR_NO_DEVICE;
412 /* need to set this before "tr_renew()" */
416 /* renew all USB transfers */
417 error = ugen20_tr_renew(pdev);
422 pdev->methods = &libusb20_ugen20_device_methods;
426 if (pdev->privBeData) {
427 /* cleanup after "tr_renew()" */
428 free(pdev->privBeData);
429 pdev->privBeData = NULL;
432 pdev->file_ctrl = -1;
440 ugen20_close_device(struct libusb20_device *pdev)
442 struct usb_fs_uninit fs_uninit;
444 if (pdev->privBeData) {
445 memset(&fs_uninit, 0, sizeof(fs_uninit));
446 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) {
447 /* ignore this error */
449 free(pdev->privBeData);
452 pdev->privBeData = NULL;
454 close(pdev->file_ctrl);
456 pdev->file_ctrl = -1;
457 return (0); /* success */
461 ugen20_exit_backend(struct libusb20_backend *pbe)
463 return; /* nothing to do */
467 ugen20_get_config_desc_full(struct libusb20_device *pdev,
468 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
470 struct usb_gen_descriptor gen_desc;
471 struct usb_config_descriptor cdesc;
476 /* make sure memory is initialised */
477 memset(&cdesc, 0, sizeof(cdesc));
478 memset(&gen_desc, 0, sizeof(gen_desc));
480 gen_desc.ugd_data = libusb20_pass_ptr(&cdesc);
481 gen_desc.ugd_maxlen = sizeof(cdesc);
482 gen_desc.ugd_config_index = cfg_index;
484 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc);
486 return (LIBUSB20_ERROR_OTHER);
488 len = UGETW(cdesc.wTotalLength);
489 if (len < sizeof(cdesc)) {
490 /* corrupt descriptor */
491 return (LIBUSB20_ERROR_OTHER);
495 return (LIBUSB20_ERROR_NO_MEM);
498 /* make sure memory is initialised */
501 gen_desc.ugd_data = libusb20_pass_ptr(ptr);
502 gen_desc.ugd_maxlen = len;
504 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc);
507 return (LIBUSB20_ERROR_OTHER);
509 /* make sure that the device doesn't fool us */
510 memcpy(ptr, &cdesc, sizeof(cdesc));
515 return (0); /* success */
519 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
523 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_CONFIG), &temp)) {
524 return (LIBUSB20_ERROR_OTHER);
532 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
534 int temp = cfg_index;
536 /* release all active USB transfers */
537 ugen20_tr_release(pdev);
539 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_CONFIG), &temp)) {
540 return (LIBUSB20_ERROR_OTHER);
542 return (ugen20_tr_renew(pdev));
546 ugen20_set_alt_index(struct libusb20_device *pdev,
547 uint8_t iface_index, uint8_t alt_index)
549 struct usb_alt_interface alt_iface;
551 memset(&alt_iface, 0, sizeof(alt_iface));
553 alt_iface.uai_interface_index = iface_index;
554 alt_iface.uai_alt_index = alt_index;
556 /* release all active USB transfers */
557 ugen20_tr_release(pdev);
559 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_ALTINTERFACE), &alt_iface)) {
560 return (LIBUSB20_ERROR_OTHER);
562 return (ugen20_tr_renew(pdev));
566 ugen20_reset_device(struct libusb20_device *pdev)
570 /* release all active USB transfers */
571 ugen20_tr_release(pdev);
573 if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICEENUMERATE), &temp)) {
574 return (LIBUSB20_ERROR_OTHER);
576 return (ugen20_tr_renew(pdev));
580 ugen20_check_connected(struct libusb20_device *pdev)
585 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
586 error = LIBUSB20_ERROR_NO_DEVICE;
590 if (pdev->session_data.plugtime != plugtime) {
591 error = LIBUSB20_ERROR_NO_DEVICE;
599 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
603 switch (power_mode) {
604 case LIBUSB20_POWER_OFF:
605 temp = USB_POWER_MODE_OFF;
607 case LIBUSB20_POWER_ON:
608 temp = USB_POWER_MODE_ON;
610 case LIBUSB20_POWER_SAVE:
611 temp = USB_POWER_MODE_SAVE;
613 case LIBUSB20_POWER_SUSPEND:
614 temp = USB_POWER_MODE_SUSPEND;
616 case LIBUSB20_POWER_RESUME:
617 temp = USB_POWER_MODE_RESUME;
620 return (LIBUSB20_ERROR_INVALID_PARAM);
622 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_POWER_MODE), &temp)) {
623 return (LIBUSB20_ERROR_OTHER);
629 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
633 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_MODE), &temp)) {
634 return (LIBUSB20_ERROR_OTHER);
637 case USB_POWER_MODE_OFF:
638 temp = LIBUSB20_POWER_OFF;
640 case USB_POWER_MODE_ON:
641 temp = LIBUSB20_POWER_ON;
643 case USB_POWER_MODE_SAVE:
644 temp = LIBUSB20_POWER_SAVE;
646 case USB_POWER_MODE_SUSPEND:
647 temp = LIBUSB20_POWER_SUSPEND;
649 case USB_POWER_MODE_RESUME:
650 temp = LIBUSB20_POWER_RESUME;
653 temp = LIBUSB20_POWER_ON;
657 return (0); /* success */
661 ugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage)
665 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_USAGE), &temp)) {
666 return (LIBUSB20_ERROR_OTHER);
669 return (0); /* success */
673 ugen20_kernel_driver_active(struct libusb20_device *pdev,
676 int temp = iface_index;
678 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ACTIVE), &temp)) {
679 return (LIBUSB20_ERROR_OTHER);
681 return (0); /* kernel driver is active */
685 ugen20_detach_kernel_driver(struct libusb20_device *pdev,
688 int temp = iface_index;
690 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_DETACH), &temp)) {
691 return (LIBUSB20_ERROR_OTHER);
693 return (0); /* kernel driver is detached */
697 ugen20_do_request_sync(struct libusb20_device *pdev,
698 struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
699 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
701 struct usb_ctl_request req;
703 memset(&req, 0, sizeof(req));
705 req.ucr_data = libusb20_pass_ptr(data);
706 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
707 req.ucr_flags |= USB_SHORT_XFER_OK;
709 if (libusb20_me_encode(&req.ucr_request,
710 sizeof(req.ucr_request), setup)) {
713 if (ioctl(pdev->file_ctrl, IOUSB(USB_DO_REQUEST), &req)) {
714 return (LIBUSB20_ERROR_OTHER);
717 /* get actual length */
718 *pactlen = req.ucr_actlen;
720 return (0); /* request was successful */
724 ugen20_process(struct libusb20_device *pdev)
726 struct usb_fs_complete temp;
727 struct usb_fs_endpoint *fsep;
728 struct libusb20_transfer *xfer;
732 if (ioctl(pdev->file, IOUSB(USB_FS_COMPLETE), &temp)) {
733 if (errno == EBUSY) {
736 /* device detached */
737 return (LIBUSB20_ERROR_OTHER);
740 fsep = pdev->privBeData;
741 xfer = pdev->pTransfer;
742 fsep += temp.ep_index;
743 xfer += temp.ep_index;
745 /* update transfer status */
747 if (fsep->status == 0) {
748 xfer->aFrames = fsep->aFrames;
749 xfer->timeComplete = fsep->isoc_time_complete;
750 xfer->status = LIBUSB20_TRANSFER_COMPLETED;
751 } else if (fsep->status == USB_ERR_CANCELLED) {
753 xfer->timeComplete = 0;
754 xfer->status = LIBUSB20_TRANSFER_CANCELLED;
755 } else if (fsep->status == USB_ERR_STALLED) {
757 xfer->timeComplete = 0;
758 xfer->status = LIBUSB20_TRANSFER_STALL;
759 } else if (fsep->status == USB_ERR_TIMEOUT) {
761 xfer->timeComplete = 0;
762 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
765 xfer->timeComplete = 0;
766 xfer->status = LIBUSB20_TRANSFER_ERROR;
768 libusb20_tr_callback_wrapper(xfer);
770 return (0); /* done */
774 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
775 uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id,
779 struct usb_fs_open fs_open;
780 struct usb_fs_open_stream fs_open_stream;
782 struct usb_fs_endpoint *fsep;
785 MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE;
787 memset(&temp, 0, sizeof(temp));
789 fsep = xfer->pdev->privBeData;
790 fsep += xfer->trIndex;
792 temp.fs_open.max_bufsize = MaxBufSize;
793 temp.fs_open.max_frames = MaxFrameCount;
794 temp.fs_open.ep_index = xfer->trIndex;
795 temp.fs_open.ep_no = ep_no;
797 if (stream_id != 0) {
798 temp.fs_open_stream.stream_id = stream_id;
800 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN_STREAM), &temp.fs_open_stream))
801 return (LIBUSB20_ERROR_INVALID_PARAM);
803 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN), &temp.fs_open))
804 return (LIBUSB20_ERROR_INVALID_PARAM);
806 /* maximums might have changed - update */
807 xfer->maxFrames = temp.fs_open.max_frames;
809 /* "max_bufsize" should be multiple of "max_packet_length" */
810 xfer->maxTotalLength = temp.fs_open.max_bufsize;
811 xfer->maxPacketLen = temp.fs_open.max_packet_length;
813 /* setup buffer and length lists using zero copy */
814 fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer);
815 fsep->pLength = libusb20_pass_ptr(xfer->pLength);
817 return (0); /* success */
821 ugen20_tr_close(struct libusb20_transfer *xfer)
823 struct usb_fs_close temp;
825 memset(&temp, 0, sizeof(temp));
827 temp.ep_index = xfer->trIndex;
829 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLOSE), &temp)) {
830 return (LIBUSB20_ERROR_INVALID_PARAM);
832 return (0); /* success */
836 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
838 struct usb_fs_clear_stall_sync temp;
840 memset(&temp, 0, sizeof(temp));
842 /* if the transfer is active, an error will be returned */
844 temp.ep_index = xfer->trIndex;
846 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLEAR_STALL_SYNC), &temp)) {
847 return (LIBUSB20_ERROR_INVALID_PARAM);
849 return (0); /* success */
853 ugen20_tr_submit(struct libusb20_transfer *xfer)
855 struct usb_fs_start temp;
856 struct usb_fs_endpoint *fsep;
858 memset(&temp, 0, sizeof(temp));
860 fsep = xfer->pdev->privBeData;
861 fsep += xfer->trIndex;
863 fsep->nFrames = xfer->nFrames;
865 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
866 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
868 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
869 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
871 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
872 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
874 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
875 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
877 /* NOTE: The "fsep->timeout" variable is 16-bit. */
878 if (xfer->timeout > 65535)
879 fsep->timeout = 65535;
881 fsep->timeout = xfer->timeout;
883 temp.ep_index = xfer->trIndex;
885 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_START), &temp)) {
886 /* ignore any errors - should never happen */
888 return; /* success */
892 ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
894 struct usb_fs_stop temp;
896 memset(&temp, 0, sizeof(temp));
898 temp.ep_index = xfer->trIndex;
900 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_STOP), &temp)) {
901 /* ignore any errors - should never happen */
907 ugen20_be_ioctl(uint32_t cmd, void *data)
912 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
914 return (LIBUSB20_ERROR_OTHER);
915 error = ioctl(f, cmd, data);
917 if (errno == EPERM) {
918 error = LIBUSB20_ERROR_ACCESS;
920 error = LIBUSB20_ERROR_OTHER;
928 ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
929 uint8_t iface_index, char *buf, uint8_t len)
931 struct usb_gen_descriptor ugd;
933 memset(&ugd, 0, sizeof(ugd));
935 ugd.ugd_data = libusb20_pass_ptr(buf);
936 ugd.ugd_maxlen = len;
937 ugd.ugd_iface_index = iface_index;
939 if (ioctl(pdev->file, IOUSB(USB_GET_IFACE_DRIVER), &ugd)) {
940 return (LIBUSB20_ERROR_INVALID_PARAM);
946 ugen20_dev_get_info(struct libusb20_device *pdev,
947 struct usb_device_info *pinfo)
949 if (ioctl(pdev->file, IOUSB(USB_GET_DEVICEINFO), pinfo)) {
950 return (LIBUSB20_ERROR_INVALID_PARAM);
956 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
957 uint16_t quirk_index, struct libusb20_quirk *pq)
959 struct usb_gen_quirk q;
962 memset(&q, 0, sizeof(q));
964 q.index = quirk_index;
966 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_GET), &q);
969 if (errno == EINVAL) {
970 return (LIBUSB20_ERROR_NOT_FOUND);
975 pq->bcdDeviceLow = q.bcdDeviceLow;
976 pq->bcdDeviceHigh = q.bcdDeviceHigh;
977 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
983 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
984 struct libusb20_quirk *pq)
986 struct usb_gen_quirk q;
989 memset(&q, 0, sizeof(q));
991 q.index = quirk_index;
993 error = ugen20_be_ioctl(IOUSB(USB_QUIRK_NAME_GET), &q);
996 if (errno == EINVAL) {
997 return (LIBUSB20_ERROR_NOT_FOUND);
1000 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
1006 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
1007 struct libusb20_quirk *pq)
1009 struct usb_gen_quirk q;
1012 memset(&q, 0, sizeof(q));
1016 q.bcdDeviceLow = pq->bcdDeviceLow;
1017 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1018 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1020 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_ADD), &q);
1022 if (errno == ENOMEM) {
1023 return (LIBUSB20_ERROR_NO_MEM);
1030 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
1031 struct libusb20_quirk *pq)
1033 struct usb_gen_quirk q;
1036 memset(&q, 0, sizeof(q));
1040 q.bcdDeviceLow = pq->bcdDeviceLow;
1041 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1042 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1044 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_REMOVE), &q);
1046 if (errno == EINVAL) {
1047 return (LIBUSB20_ERROR_NOT_FOUND);
1054 ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
1056 return (ugen20_be_ioctl(IOUSB(USB_SET_TEMPLATE), &temp));
1060 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
1062 return (ugen20_be_ioctl(IOUSB(USB_GET_TEMPLATE), ptemp));