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_get_stats_t ugen20_get_stats;
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;
139 struct usb_device_port_path udpp;
145 pdev->bus_number = ugen20_path_convert_one(&tmp);
146 pdev->device_address = ugen20_path_convert_one(&tmp);
148 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
149 pdev->bus_number, pdev->device_address);
151 f = open(buf, O_RDWR);
153 return (LIBUSB20_ERROR_OTHER);
155 if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
156 error = LIBUSB20_ERROR_OTHER;
159 /* store when the device was plugged */
160 pdev->session_data.plugtime = plugtime;
162 if (ioctl(f, IOUSB(USB_GET_DEVICE_DESC), &ddesc)) {
163 error = LIBUSB20_ERROR_OTHER;
166 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
168 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
170 if (pdev->ddesc.bNumConfigurations == 0) {
171 error = LIBUSB20_ERROR_OTHER;
173 } else if (pdev->ddesc.bNumConfigurations >= 8) {
174 error = LIBUSB20_ERROR_OTHER;
177 if (ioctl(f, IOUSB(USB_GET_DEVICEINFO), &devinfo)) {
178 error = LIBUSB20_ERROR_OTHER;
181 switch (devinfo.udi_mode) {
182 case USB_MODE_DEVICE:
183 pdev->usb_mode = LIBUSB20_MODE_DEVICE;
186 pdev->usb_mode = LIBUSB20_MODE_HOST;
190 switch (devinfo.udi_speed) {
192 pdev->usb_speed = LIBUSB20_SPEED_LOW;
195 pdev->usb_speed = LIBUSB20_SPEED_FULL;
198 pdev->usb_speed = LIBUSB20_SPEED_HIGH;
200 case USB_SPEED_VARIABLE:
201 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
203 case USB_SPEED_SUPER:
204 pdev->usb_speed = LIBUSB20_SPEED_SUPER;
207 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
211 /* get parent HUB index and port */
213 pdev->parent_address = devinfo.udi_hubindex;
214 pdev->parent_port = devinfo.udi_hubport;
216 /* generate a nice description for printout */
218 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
219 USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
220 pdev->device_address, devinfo.udi_vendor,
221 devinfo.udi_product, pdev->bus_number);
223 /* get device port path, if any */
224 if (ioctl(f, IOUSB(USB_GET_DEV_PORT_PATH), &udpp) == 0 &&
225 udpp.udp_port_level < LIBUSB20_DEVICE_PORT_PATH_MAX) {
226 memcpy(pdev->port_path, udpp.udp_port_no, udpp.udp_port_level);
227 pdev->port_level = udpp.udp_port_level;
236 struct ugen20_urd_state {
237 struct usb_read_dir urd;
244 uint8_t dummy_zero[1];
248 ugen20_readdir(struct ugen20_urd_state *st)
252 if (st->ptr == NULL) {
253 st->urd.urd_startentry += st->nparsed;
254 st->urd.urd_data = libusb20_pass_ptr(st->buf);
255 st->urd.urd_maxlen = sizeof(st->buf);
258 if (ioctl(st->f, IOUSB(USB_READ_DIR), &st->urd)) {
263 if (st->ptr[0] == 0) {
271 st->src = (void *)(st->ptr + 1);
272 st->dst = st->src + strlen(st->src) + 1;
273 st->ptr = st->ptr + st->ptr[0];
276 if ((st->ptr < st->buf) ||
277 (st->ptr > st->dummy_zero)) {
285 ugen20_init_backend(struct libusb20_backend *pbe)
287 struct ugen20_urd_state state;
288 struct libusb20_device *pdev;
290 memset(&state, 0, sizeof(state));
292 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
294 return (LIBUSB20_ERROR_OTHER);
296 while (ugen20_readdir(&state) == 0) {
298 if ((state.src[0] != 'u') ||
299 (state.src[1] != 'g') ||
300 (state.src[2] != 'e') ||
301 (state.src[3] != 'n')) {
304 pdev = libusb20_dev_alloc();
308 if (ugen20_enumerate(pdev, state.src + 4)) {
309 libusb20_dev_free(pdev);
312 /* put the device on the backend list */
313 libusb20_be_enqueue_device(pbe, pdev);
316 return (0); /* success */
320 ugen20_tr_release(struct libusb20_device *pdev)
322 struct usb_fs_uninit fs_uninit;
324 if (pdev->nTransfer == 0) {
327 /* release all pending USB transfers */
328 if (pdev->privBeData != NULL) {
329 memset(&fs_uninit, 0, sizeof(fs_uninit));
330 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) {
331 /* ignore any errors of this kind */
338 ugen20_tr_renew(struct libusb20_device *pdev)
340 struct usb_fs_init fs_init;
341 struct usb_fs_endpoint *pfse;
344 uint16_t nMaxTransfer;
346 nMaxTransfer = pdev->nTransfer;
349 if (nMaxTransfer == 0) {
352 size = nMaxTransfer * sizeof(*pfse);
354 if (pdev->privBeData == NULL) {
357 error = LIBUSB20_ERROR_NO_MEM;
360 pdev->privBeData = pfse;
362 /* reset endpoint data */
363 memset(pdev->privBeData, 0, size);
365 memset(&fs_init, 0, sizeof(fs_init));
367 fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData);
368 fs_init.ep_index_max = nMaxTransfer;
370 if (ioctl(pdev->file, IOUSB(USB_FS_INIT), &fs_init)) {
371 error = LIBUSB20_ERROR_OTHER;
379 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
387 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
388 pdev->bus_number, pdev->device_address);
391 * We need two file handles, one for the control endpoint and one
392 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
395 g = open(buf, O_RDWR);
397 return (LIBUSB20_ERROR_NO_DEVICE);
399 f = open(buf, O_RDWR);
402 return (LIBUSB20_ERROR_NO_DEVICE);
404 if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
405 error = LIBUSB20_ERROR_OTHER;
408 /* check that the correct device is still plugged */
409 if (pdev->session_data.plugtime != plugtime) {
410 error = LIBUSB20_ERROR_NO_DEVICE;
413 /* need to set this before "tr_renew()" */
417 /* renew all USB transfers */
418 error = ugen20_tr_renew(pdev);
423 pdev->methods = &libusb20_ugen20_device_methods;
427 if (pdev->privBeData) {
428 /* cleanup after "tr_renew()" */
429 free(pdev->privBeData);
430 pdev->privBeData = NULL;
433 pdev->file_ctrl = -1;
441 ugen20_close_device(struct libusb20_device *pdev)
443 struct usb_fs_uninit fs_uninit;
445 if (pdev->privBeData) {
446 memset(&fs_uninit, 0, sizeof(fs_uninit));
447 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) {
448 /* ignore this error */
450 free(pdev->privBeData);
453 pdev->privBeData = NULL;
455 close(pdev->file_ctrl);
457 pdev->file_ctrl = -1;
458 return (0); /* success */
462 ugen20_exit_backend(struct libusb20_backend *pbe)
464 return; /* nothing to do */
468 ugen20_get_config_desc_full(struct libusb20_device *pdev,
469 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
471 struct usb_gen_descriptor gen_desc;
472 struct usb_config_descriptor cdesc;
477 /* make sure memory is initialised */
478 memset(&cdesc, 0, sizeof(cdesc));
479 memset(&gen_desc, 0, sizeof(gen_desc));
481 gen_desc.ugd_data = libusb20_pass_ptr(&cdesc);
482 gen_desc.ugd_maxlen = sizeof(cdesc);
483 gen_desc.ugd_config_index = cfg_index;
485 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc);
487 return (LIBUSB20_ERROR_OTHER);
489 len = UGETW(cdesc.wTotalLength);
490 if (len < sizeof(cdesc)) {
491 /* corrupt descriptor */
492 return (LIBUSB20_ERROR_OTHER);
496 return (LIBUSB20_ERROR_NO_MEM);
499 /* make sure memory is initialised */
502 gen_desc.ugd_data = libusb20_pass_ptr(ptr);
503 gen_desc.ugd_maxlen = len;
505 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc);
508 return (LIBUSB20_ERROR_OTHER);
510 /* make sure that the device doesn't fool us */
511 memcpy(ptr, &cdesc, sizeof(cdesc));
516 return (0); /* success */
520 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
524 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_CONFIG), &temp)) {
525 return (LIBUSB20_ERROR_OTHER);
533 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
535 int temp = cfg_index;
537 /* release all active USB transfers */
538 ugen20_tr_release(pdev);
540 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_CONFIG), &temp)) {
541 return (LIBUSB20_ERROR_OTHER);
543 return (ugen20_tr_renew(pdev));
547 ugen20_set_alt_index(struct libusb20_device *pdev,
548 uint8_t iface_index, uint8_t alt_index)
550 struct usb_alt_interface alt_iface;
552 memset(&alt_iface, 0, sizeof(alt_iface));
554 alt_iface.uai_interface_index = iface_index;
555 alt_iface.uai_alt_index = alt_index;
557 /* release all active USB transfers */
558 ugen20_tr_release(pdev);
560 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_ALTINTERFACE), &alt_iface)) {
561 return (LIBUSB20_ERROR_OTHER);
563 return (ugen20_tr_renew(pdev));
567 ugen20_reset_device(struct libusb20_device *pdev)
571 /* release all active USB transfers */
572 ugen20_tr_release(pdev);
574 if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICEENUMERATE), &temp)) {
575 return (LIBUSB20_ERROR_OTHER);
577 return (ugen20_tr_renew(pdev));
581 ugen20_check_connected(struct libusb20_device *pdev)
586 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
587 error = LIBUSB20_ERROR_NO_DEVICE;
591 if (pdev->session_data.plugtime != plugtime) {
592 error = LIBUSB20_ERROR_NO_DEVICE;
600 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
604 switch (power_mode) {
605 case LIBUSB20_POWER_OFF:
606 temp = USB_POWER_MODE_OFF;
608 case LIBUSB20_POWER_ON:
609 temp = USB_POWER_MODE_ON;
611 case LIBUSB20_POWER_SAVE:
612 temp = USB_POWER_MODE_SAVE;
614 case LIBUSB20_POWER_SUSPEND:
615 temp = USB_POWER_MODE_SUSPEND;
617 case LIBUSB20_POWER_RESUME:
618 temp = USB_POWER_MODE_RESUME;
621 return (LIBUSB20_ERROR_INVALID_PARAM);
623 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_POWER_MODE), &temp)) {
624 return (LIBUSB20_ERROR_OTHER);
630 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
634 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_MODE), &temp)) {
635 return (LIBUSB20_ERROR_OTHER);
638 case USB_POWER_MODE_OFF:
639 temp = LIBUSB20_POWER_OFF;
641 case USB_POWER_MODE_ON:
642 temp = LIBUSB20_POWER_ON;
644 case USB_POWER_MODE_SAVE:
645 temp = LIBUSB20_POWER_SAVE;
647 case USB_POWER_MODE_SUSPEND:
648 temp = LIBUSB20_POWER_SUSPEND;
650 case USB_POWER_MODE_RESUME:
651 temp = LIBUSB20_POWER_RESUME;
654 temp = LIBUSB20_POWER_ON;
658 return (0); /* success */
662 ugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage)
666 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_USAGE), &temp)) {
667 return (LIBUSB20_ERROR_OTHER);
670 return (0); /* success */
674 ugen20_get_stats(struct libusb20_device *pdev, struct libusb20_device_stats *pstats)
676 struct usb_device_stats st;
678 if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICESTATS), &st))
679 return (LIBUSB20_ERROR_OTHER);
681 memset(pstats, 0, sizeof(*pstats));
683 pstats->xfer_ok[0] = st.uds_requests_ok[0];
684 pstats->xfer_ok[1] = st.uds_requests_ok[1];
685 pstats->xfer_ok[2] = st.uds_requests_ok[2];
686 pstats->xfer_ok[3] = st.uds_requests_ok[3];
688 pstats->xfer_fail[0] = st.uds_requests_fail[0];
689 pstats->xfer_fail[1] = st.uds_requests_fail[1];
690 pstats->xfer_fail[2] = st.uds_requests_fail[2];
691 pstats->xfer_fail[3] = st.uds_requests_fail[3];
693 return (0); /* success */
697 ugen20_kernel_driver_active(struct libusb20_device *pdev,
700 int temp = iface_index;
702 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ACTIVE), &temp)) {
703 return (LIBUSB20_ERROR_OTHER);
705 return (0); /* kernel driver is active */
709 ugen20_detach_kernel_driver(struct libusb20_device *pdev,
712 int temp = iface_index;
714 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_DETACH), &temp)) {
715 return (LIBUSB20_ERROR_OTHER);
717 return (0); /* kernel driver is detached */
721 ugen20_do_request_sync(struct libusb20_device *pdev,
722 struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
723 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
725 struct usb_ctl_request req;
727 memset(&req, 0, sizeof(req));
729 req.ucr_data = libusb20_pass_ptr(data);
730 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
731 req.ucr_flags |= USB_SHORT_XFER_OK;
733 if (libusb20_me_encode(&req.ucr_request,
734 sizeof(req.ucr_request), setup)) {
737 if (ioctl(pdev->file_ctrl, IOUSB(USB_DO_REQUEST), &req)) {
738 return (LIBUSB20_ERROR_OTHER);
741 /* get actual length */
742 *pactlen = req.ucr_actlen;
744 return (0); /* request was successful */
748 ugen20_process(struct libusb20_device *pdev)
750 struct usb_fs_complete temp;
751 struct usb_fs_endpoint *fsep;
752 struct libusb20_transfer *xfer;
756 if (ioctl(pdev->file, IOUSB(USB_FS_COMPLETE), &temp)) {
757 if (errno == EBUSY) {
760 /* device detached */
761 return (LIBUSB20_ERROR_OTHER);
764 fsep = pdev->privBeData;
765 xfer = pdev->pTransfer;
766 fsep += temp.ep_index;
767 xfer += temp.ep_index;
769 /* update transfer status */
771 if (fsep->status == 0) {
772 xfer->aFrames = fsep->aFrames;
773 xfer->timeComplete = fsep->isoc_time_complete;
774 xfer->status = LIBUSB20_TRANSFER_COMPLETED;
775 } else if (fsep->status == USB_ERR_CANCELLED) {
777 xfer->timeComplete = 0;
778 xfer->status = LIBUSB20_TRANSFER_CANCELLED;
779 } else if (fsep->status == USB_ERR_STALLED) {
781 xfer->timeComplete = 0;
782 xfer->status = LIBUSB20_TRANSFER_STALL;
783 } else if (fsep->status == USB_ERR_TIMEOUT) {
785 xfer->timeComplete = 0;
786 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
789 xfer->timeComplete = 0;
790 xfer->status = LIBUSB20_TRANSFER_ERROR;
792 libusb20_tr_callback_wrapper(xfer);
794 return (0); /* done */
798 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
799 uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id,
803 struct usb_fs_open fs_open;
804 struct usb_fs_open_stream fs_open_stream;
806 struct usb_fs_endpoint *fsep;
809 MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE;
811 memset(&temp, 0, sizeof(temp));
813 fsep = xfer->pdev->privBeData;
814 fsep += xfer->trIndex;
816 temp.fs_open.max_bufsize = MaxBufSize;
817 temp.fs_open.max_frames = MaxFrameCount;
818 temp.fs_open.ep_index = xfer->trIndex;
819 temp.fs_open.ep_no = ep_no;
821 if (stream_id != 0) {
822 temp.fs_open_stream.stream_id = stream_id;
824 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN_STREAM), &temp.fs_open_stream))
825 return (LIBUSB20_ERROR_INVALID_PARAM);
827 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN), &temp.fs_open))
828 return (LIBUSB20_ERROR_INVALID_PARAM);
830 /* maximums might have changed - update */
831 xfer->maxFrames = temp.fs_open.max_frames;
833 /* "max_bufsize" should be multiple of "max_packet_length" */
834 xfer->maxTotalLength = temp.fs_open.max_bufsize;
835 xfer->maxPacketLen = temp.fs_open.max_packet_length;
837 /* setup buffer and length lists using zero copy */
838 fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer);
839 fsep->pLength = libusb20_pass_ptr(xfer->pLength);
841 return (0); /* success */
845 ugen20_tr_close(struct libusb20_transfer *xfer)
847 struct usb_fs_close temp;
849 memset(&temp, 0, sizeof(temp));
851 temp.ep_index = xfer->trIndex;
853 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLOSE), &temp)) {
854 return (LIBUSB20_ERROR_INVALID_PARAM);
856 return (0); /* success */
860 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
862 struct usb_fs_clear_stall_sync temp;
864 memset(&temp, 0, sizeof(temp));
866 /* if the transfer is active, an error will be returned */
868 temp.ep_index = xfer->trIndex;
870 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLEAR_STALL_SYNC), &temp)) {
871 return (LIBUSB20_ERROR_INVALID_PARAM);
873 return (0); /* success */
877 ugen20_tr_submit(struct libusb20_transfer *xfer)
879 struct usb_fs_start temp;
880 struct usb_fs_endpoint *fsep;
882 memset(&temp, 0, sizeof(temp));
884 fsep = xfer->pdev->privBeData;
885 fsep += xfer->trIndex;
887 fsep->nFrames = xfer->nFrames;
889 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
890 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
892 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
893 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
895 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
896 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
898 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
899 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
901 /* NOTE: The "fsep->timeout" variable is 16-bit. */
902 if (xfer->timeout > 65535)
903 fsep->timeout = 65535;
905 fsep->timeout = xfer->timeout;
907 temp.ep_index = xfer->trIndex;
909 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_START), &temp)) {
910 /* ignore any errors - should never happen */
912 return; /* success */
916 ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
918 struct usb_fs_stop temp;
920 memset(&temp, 0, sizeof(temp));
922 temp.ep_index = xfer->trIndex;
924 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_STOP), &temp)) {
925 /* ignore any errors - should never happen */
931 ugen20_be_ioctl(uint32_t cmd, void *data)
936 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
938 return (LIBUSB20_ERROR_OTHER);
939 error = ioctl(f, cmd, data);
941 if (errno == EPERM) {
942 error = LIBUSB20_ERROR_ACCESS;
944 error = LIBUSB20_ERROR_OTHER;
952 ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
953 uint8_t iface_index, char *buf, uint8_t len)
955 struct usb_gen_descriptor ugd;
957 memset(&ugd, 0, sizeof(ugd));
959 ugd.ugd_data = libusb20_pass_ptr(buf);
960 ugd.ugd_maxlen = len;
961 ugd.ugd_iface_index = iface_index;
963 if (ioctl(pdev->file, IOUSB(USB_GET_IFACE_DRIVER), &ugd)) {
964 return (LIBUSB20_ERROR_INVALID_PARAM);
970 ugen20_dev_get_info(struct libusb20_device *pdev,
971 struct usb_device_info *pinfo)
973 if (ioctl(pdev->file, IOUSB(USB_GET_DEVICEINFO), pinfo)) {
974 return (LIBUSB20_ERROR_INVALID_PARAM);
980 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
981 uint16_t quirk_index, struct libusb20_quirk *pq)
983 struct usb_gen_quirk q;
986 memset(&q, 0, sizeof(q));
988 q.index = quirk_index;
990 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_GET), &q);
993 if (errno == EINVAL) {
994 return (LIBUSB20_ERROR_NOT_FOUND);
999 pq->bcdDeviceLow = q.bcdDeviceLow;
1000 pq->bcdDeviceHigh = q.bcdDeviceHigh;
1001 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
1007 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
1008 struct libusb20_quirk *pq)
1010 struct usb_gen_quirk q;
1013 memset(&q, 0, sizeof(q));
1015 q.index = quirk_index;
1017 error = ugen20_be_ioctl(IOUSB(USB_QUIRK_NAME_GET), &q);
1020 if (errno == EINVAL) {
1021 return (LIBUSB20_ERROR_NOT_FOUND);
1024 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
1030 ugen20_root_add_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_ADD), &q);
1046 if (errno == ENOMEM) {
1047 return (LIBUSB20_ERROR_NO_MEM);
1054 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
1055 struct libusb20_quirk *pq)
1057 struct usb_gen_quirk q;
1060 memset(&q, 0, sizeof(q));
1064 q.bcdDeviceLow = pq->bcdDeviceLow;
1065 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1066 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1068 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_REMOVE), &q);
1070 if (errno == EINVAL) {
1071 return (LIBUSB20_ERROR_NOT_FOUND);
1078 ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
1080 return (ugen20_be_ioctl(IOUSB(USB_SET_TEMPLATE), &temp));
1084 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
1086 return (ugen20_be_ioctl(IOUSB(USB_GET_TEMPLATE), ptemp));