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 #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
28 #include LIBUSB_GLOBAL_INCLUDE_FILE
37 #include <sys/queue.h>
38 #include <sys/types.h>
41 #include <dev/usb/usb.h>
42 #include <dev/usb/usbdi.h>
43 #include <dev/usb/usb_ioctl.h>
46 #include "libusb20_desc.h"
47 #include "libusb20_int.h"
49 static libusb20_init_backend_t ugen20_init_backend;
50 static libusb20_open_device_t ugen20_open_device;
51 static libusb20_close_device_t ugen20_close_device;
52 static libusb20_get_backend_name_t ugen20_get_backend_name;
53 static libusb20_exit_backend_t ugen20_exit_backend;
54 static libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc;
55 static libusb20_dev_get_info_t ugen20_dev_get_info;
56 static libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk;
57 static libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name;
58 static libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk;
59 static libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk;
60 static libusb20_root_set_template_t ugen20_root_set_template;
61 static libusb20_root_get_template_t ugen20_root_get_template;
63 const struct libusb20_backend_methods libusb20_ugen20_backend = {
64 LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
67 /* USB device specific */
68 static libusb20_get_config_desc_full_t ugen20_get_config_desc_full;
69 static libusb20_get_config_index_t ugen20_get_config_index;
70 static libusb20_set_config_index_t ugen20_set_config_index;
71 static libusb20_set_alt_index_t ugen20_set_alt_index;
72 static libusb20_reset_device_t ugen20_reset_device;
73 static libusb20_check_connected_t ugen20_check_connected;
74 static libusb20_set_power_mode_t ugen20_set_power_mode;
75 static libusb20_get_power_mode_t ugen20_get_power_mode;
76 static libusb20_get_port_path_t ugen20_get_port_path;
77 static libusb20_get_power_usage_t ugen20_get_power_usage;
78 static libusb20_kernel_driver_active_t ugen20_kernel_driver_active;
79 static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver;
80 static libusb20_do_request_sync_t ugen20_do_request_sync;
81 static libusb20_process_t ugen20_process;
83 /* USB transfer specific */
84 static libusb20_tr_open_t ugen20_tr_open;
85 static libusb20_tr_close_t ugen20_tr_close;
86 static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync;
87 static libusb20_tr_submit_t ugen20_tr_submit;
88 static libusb20_tr_cancel_async_t ugen20_tr_cancel_async;
90 static const struct libusb20_device_methods libusb20_ugen20_device_methods = {
91 LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20)
95 ugen20_get_backend_name(void)
97 return ("FreeBSD UGEN 2.0");
101 ugen20_path_convert_one(const char **pp)
108 while ((*ptr >= '0') && (*ptr <= '9')) {
110 temp += (*ptr - '0');
111 if (temp >= 1000000) {
112 /* catch overflow early */
128 ugen20_enumerate(struct libusb20_device *pdev, const char *id)
130 const char *tmp = id;
131 struct usb_device_descriptor ddesc;
132 struct usb_device_info devinfo;
138 pdev->bus_number = ugen20_path_convert_one(&tmp);
139 pdev->device_address = ugen20_path_convert_one(&tmp);
141 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
142 pdev->bus_number, pdev->device_address);
144 f = open(buf, O_RDWR);
146 return (LIBUSB20_ERROR_OTHER);
148 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
149 error = LIBUSB20_ERROR_OTHER;
152 /* store when the device was plugged */
153 pdev->session_data.plugtime = plugtime;
155 if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) {
156 error = LIBUSB20_ERROR_OTHER;
159 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
161 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
163 if (pdev->ddesc.bNumConfigurations == 0) {
164 error = LIBUSB20_ERROR_OTHER;
166 } else if (pdev->ddesc.bNumConfigurations >= 8) {
167 error = LIBUSB20_ERROR_OTHER;
170 if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) {
171 error = LIBUSB20_ERROR_OTHER;
174 switch (devinfo.udi_mode) {
175 case USB_MODE_DEVICE:
176 pdev->usb_mode = LIBUSB20_MODE_DEVICE;
179 pdev->usb_mode = LIBUSB20_MODE_HOST;
183 switch (devinfo.udi_speed) {
185 pdev->usb_speed = LIBUSB20_SPEED_LOW;
188 pdev->usb_speed = LIBUSB20_SPEED_FULL;
191 pdev->usb_speed = LIBUSB20_SPEED_HIGH;
193 case USB_SPEED_VARIABLE:
194 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
196 case USB_SPEED_SUPER:
197 pdev->usb_speed = LIBUSB20_SPEED_SUPER;
200 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
204 /* get parent HUB index and port */
206 pdev->parent_address = devinfo.udi_hubindex;
207 pdev->parent_port = devinfo.udi_hubport;
209 /* generate a nice description for printout */
211 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
212 USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
213 pdev->device_address, devinfo.udi_product,
214 devinfo.udi_vendor, pdev->bus_number);
222 struct ugen20_urd_state {
223 struct usb_read_dir urd;
230 uint8_t dummy_zero[1];
234 ugen20_readdir(struct ugen20_urd_state *st)
238 if (st->ptr == NULL) {
239 st->urd.urd_startentry += st->nparsed;
240 st->urd.urd_data = libusb20_pass_ptr(st->buf);
241 st->urd.urd_maxlen = sizeof(st->buf);
244 if (ioctl(st->f, USB_READ_DIR, &st->urd)) {
249 if (st->ptr[0] == 0) {
257 st->src = (void *)(st->ptr + 1);
258 st->dst = st->src + strlen(st->src) + 1;
259 st->ptr = st->ptr + st->ptr[0];
262 if ((st->ptr < st->buf) ||
263 (st->ptr > st->dummy_zero)) {
271 ugen20_init_backend(struct libusb20_backend *pbe)
273 struct ugen20_urd_state state;
274 struct libusb20_device *pdev;
276 memset(&state, 0, sizeof(state));
278 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
280 return (LIBUSB20_ERROR_OTHER);
282 while (ugen20_readdir(&state) == 0) {
284 if ((state.src[0] != 'u') ||
285 (state.src[1] != 'g') ||
286 (state.src[2] != 'e') ||
287 (state.src[3] != 'n')) {
290 pdev = libusb20_dev_alloc();
294 if (ugen20_enumerate(pdev, state.src + 4)) {
295 libusb20_dev_free(pdev);
298 /* put the device on the backend list */
299 libusb20_be_enqueue_device(pbe, pdev);
302 return (0); /* success */
306 ugen20_tr_release(struct libusb20_device *pdev)
308 struct usb_fs_uninit fs_uninit;
310 if (pdev->nTransfer == 0) {
313 /* release all pending USB transfers */
314 if (pdev->privBeData != NULL) {
315 memset(&fs_uninit, 0, sizeof(fs_uninit));
316 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
317 /* ignore any errors of this kind */
324 ugen20_tr_renew(struct libusb20_device *pdev)
326 struct usb_fs_init fs_init;
327 struct usb_fs_endpoint *pfse;
330 uint16_t nMaxTransfer;
332 nMaxTransfer = pdev->nTransfer;
335 if (nMaxTransfer == 0) {
338 size = nMaxTransfer * sizeof(*pfse);
340 if (pdev->privBeData == NULL) {
343 error = LIBUSB20_ERROR_NO_MEM;
346 pdev->privBeData = pfse;
348 /* reset endpoint data */
349 memset(pdev->privBeData, 0, size);
351 memset(&fs_init, 0, sizeof(fs_init));
353 fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData);
354 fs_init.ep_index_max = nMaxTransfer;
356 if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) {
357 error = LIBUSB20_ERROR_OTHER;
365 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
373 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
374 pdev->bus_number, pdev->device_address);
377 * We need two file handles, one for the control endpoint and one
378 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
381 g = open(buf, O_RDWR);
383 return (LIBUSB20_ERROR_NO_DEVICE);
385 f = open(buf, O_RDWR);
388 return (LIBUSB20_ERROR_NO_DEVICE);
390 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
391 error = LIBUSB20_ERROR_OTHER;
394 /* check that the correct device is still plugged */
395 if (pdev->session_data.plugtime != plugtime) {
396 error = LIBUSB20_ERROR_NO_DEVICE;
399 /* need to set this before "tr_renew()" */
403 /* renew all USB transfers */
404 error = ugen20_tr_renew(pdev);
409 pdev->methods = &libusb20_ugen20_device_methods;
413 if (pdev->privBeData) {
414 /* cleanup after "tr_renew()" */
415 free(pdev->privBeData);
416 pdev->privBeData = NULL;
419 pdev->file_ctrl = -1;
427 ugen20_close_device(struct libusb20_device *pdev)
429 struct usb_fs_uninit fs_uninit;
431 if (pdev->privBeData) {
432 memset(&fs_uninit, 0, sizeof(fs_uninit));
433 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
434 /* ignore this error */
436 free(pdev->privBeData);
439 pdev->privBeData = NULL;
441 close(pdev->file_ctrl);
443 pdev->file_ctrl = -1;
444 return (0); /* success */
448 ugen20_exit_backend(struct libusb20_backend *pbe)
450 return; /* nothing to do */
454 ugen20_get_config_desc_full(struct libusb20_device *pdev,
455 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
457 struct usb_gen_descriptor gen_desc;
458 struct usb_config_descriptor cdesc;
463 /* make sure memory is initialised */
464 memset(&cdesc, 0, sizeof(cdesc));
465 memset(&gen_desc, 0, sizeof(gen_desc));
467 gen_desc.ugd_data = libusb20_pass_ptr(&cdesc);
468 gen_desc.ugd_maxlen = sizeof(cdesc);
469 gen_desc.ugd_config_index = cfg_index;
471 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
473 return (LIBUSB20_ERROR_OTHER);
475 len = UGETW(cdesc.wTotalLength);
476 if (len < sizeof(cdesc)) {
477 /* corrupt descriptor */
478 return (LIBUSB20_ERROR_OTHER);
482 return (LIBUSB20_ERROR_NO_MEM);
485 /* make sure memory is initialised */
488 gen_desc.ugd_data = libusb20_pass_ptr(ptr);
489 gen_desc.ugd_maxlen = len;
491 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
494 return (LIBUSB20_ERROR_OTHER);
496 /* make sure that the device doesn't fool us */
497 memcpy(ptr, &cdesc, sizeof(cdesc));
502 return (0); /* success */
506 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
510 if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) {
511 return (LIBUSB20_ERROR_OTHER);
519 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
521 int temp = cfg_index;
523 /* release all active USB transfers */
524 ugen20_tr_release(pdev);
526 if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) {
527 return (LIBUSB20_ERROR_OTHER);
529 return (ugen20_tr_renew(pdev));
533 ugen20_set_alt_index(struct libusb20_device *pdev,
534 uint8_t iface_index, uint8_t alt_index)
536 struct usb_alt_interface alt_iface;
538 memset(&alt_iface, 0, sizeof(alt_iface));
540 alt_iface.uai_interface_index = iface_index;
541 alt_iface.uai_alt_index = alt_index;
543 /* release all active USB transfers */
544 ugen20_tr_release(pdev);
546 if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) {
547 return (LIBUSB20_ERROR_OTHER);
549 return (ugen20_tr_renew(pdev));
553 ugen20_reset_device(struct libusb20_device *pdev)
557 /* release all active USB transfers */
558 ugen20_tr_release(pdev);
560 if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) {
561 return (LIBUSB20_ERROR_OTHER);
563 return (ugen20_tr_renew(pdev));
567 ugen20_check_connected(struct libusb20_device *pdev)
572 if (ioctl(pdev->file_ctrl, USB_GET_PLUGTIME, &plugtime)) {
573 error = LIBUSB20_ERROR_NO_DEVICE;
577 if (pdev->session_data.plugtime != plugtime) {
578 error = LIBUSB20_ERROR_NO_DEVICE;
586 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
590 switch (power_mode) {
591 case LIBUSB20_POWER_OFF:
592 temp = USB_POWER_MODE_OFF;
594 case LIBUSB20_POWER_ON:
595 temp = USB_POWER_MODE_ON;
597 case LIBUSB20_POWER_SAVE:
598 temp = USB_POWER_MODE_SAVE;
600 case LIBUSB20_POWER_SUSPEND:
601 temp = USB_POWER_MODE_SUSPEND;
603 case LIBUSB20_POWER_RESUME:
604 temp = USB_POWER_MODE_RESUME;
607 return (LIBUSB20_ERROR_INVALID_PARAM);
609 if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) {
610 return (LIBUSB20_ERROR_OTHER);
616 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
620 if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) {
621 return (LIBUSB20_ERROR_OTHER);
624 case USB_POWER_MODE_OFF:
625 temp = LIBUSB20_POWER_OFF;
627 case USB_POWER_MODE_ON:
628 temp = LIBUSB20_POWER_ON;
630 case USB_POWER_MODE_SAVE:
631 temp = LIBUSB20_POWER_SAVE;
633 case USB_POWER_MODE_SUSPEND:
634 temp = LIBUSB20_POWER_SUSPEND;
636 case USB_POWER_MODE_RESUME:
637 temp = LIBUSB20_POWER_RESUME;
640 temp = LIBUSB20_POWER_ON;
644 return (0); /* success */
648 ugen20_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize)
650 struct usb_device_port_path udpp;
652 if (ioctl(pdev->file_ctrl, USB_GET_DEV_PORT_PATH, &udpp))
653 return (LIBUSB20_ERROR_OTHER);
655 if (udpp.udp_port_level > bufsize)
656 return (LIBUSB20_ERROR_OVERFLOW);
658 memcpy(buf, udpp.udp_port_no, udpp.udp_port_level);
660 return (udpp.udp_port_level); /* success */
664 ugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage)
668 if (ioctl(pdev->file_ctrl, USB_GET_POWER_USAGE, &temp)) {
669 return (LIBUSB20_ERROR_OTHER);
672 return (0); /* success */
676 ugen20_kernel_driver_active(struct libusb20_device *pdev,
679 int temp = iface_index;
681 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) {
682 return (LIBUSB20_ERROR_OTHER);
684 return (0); /* kernel driver is active */
688 ugen20_detach_kernel_driver(struct libusb20_device *pdev,
691 int temp = iface_index;
693 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) {
694 return (LIBUSB20_ERROR_OTHER);
696 return (0); /* kernel driver is active */
700 ugen20_do_request_sync(struct libusb20_device *pdev,
701 struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
702 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
704 struct usb_ctl_request req;
706 memset(&req, 0, sizeof(req));
708 req.ucr_data = libusb20_pass_ptr(data);
709 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
710 req.ucr_flags |= USB_SHORT_XFER_OK;
712 if (libusb20_me_encode(&req.ucr_request,
713 sizeof(req.ucr_request), setup)) {
716 if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) {
717 return (LIBUSB20_ERROR_OTHER);
720 /* get actual length */
721 *pactlen = req.ucr_actlen;
723 return (0); /* kernel driver is active */
727 ugen20_process(struct libusb20_device *pdev)
729 struct usb_fs_complete temp;
730 struct usb_fs_endpoint *fsep;
731 struct libusb20_transfer *xfer;
735 if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) {
736 if (errno == EBUSY) {
739 /* device detached */
740 return (LIBUSB20_ERROR_OTHER);
743 fsep = pdev->privBeData;
744 xfer = pdev->pTransfer;
745 fsep += temp.ep_index;
746 xfer += temp.ep_index;
748 /* update transfer status */
750 if (fsep->status == 0) {
751 xfer->aFrames = fsep->aFrames;
752 xfer->timeComplete = fsep->isoc_time_complete;
753 xfer->status = LIBUSB20_TRANSFER_COMPLETED;
754 } else if (fsep->status == USB_ERR_CANCELLED) {
756 xfer->timeComplete = 0;
757 xfer->status = LIBUSB20_TRANSFER_CANCELLED;
758 } else if (fsep->status == USB_ERR_STALLED) {
760 xfer->timeComplete = 0;
761 xfer->status = LIBUSB20_TRANSFER_STALL;
762 } else if (fsep->status == USB_ERR_TIMEOUT) {
764 xfer->timeComplete = 0;
765 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
768 xfer->timeComplete = 0;
769 xfer->status = LIBUSB20_TRANSFER_ERROR;
771 libusb20_tr_callback_wrapper(xfer);
773 return (0); /* done */
777 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
778 uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id,
782 struct usb_fs_open fs_open;
783 struct usb_fs_open_stream fs_open_stream;
785 struct usb_fs_endpoint *fsep;
788 MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE;
790 memset(&temp, 0, sizeof(temp));
792 fsep = xfer->pdev->privBeData;
793 fsep += xfer->trIndex;
795 temp.fs_open.max_bufsize = MaxBufSize;
796 temp.fs_open.max_frames = MaxFrameCount;
797 temp.fs_open.ep_index = xfer->trIndex;
798 temp.fs_open.ep_no = ep_no;
800 if (stream_id != 0) {
801 temp.fs_open_stream.stream_id = stream_id;
803 if (ioctl(xfer->pdev->file, USB_FS_OPEN_STREAM, &temp.fs_open_stream))
804 return (LIBUSB20_ERROR_INVALID_PARAM);
806 if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp.fs_open))
807 return (LIBUSB20_ERROR_INVALID_PARAM);
809 /* maximums might have changed - update */
810 xfer->maxFrames = temp.fs_open.max_frames;
812 /* "max_bufsize" should be multiple of "max_packet_length" */
813 xfer->maxTotalLength = temp.fs_open.max_bufsize;
814 xfer->maxPacketLen = temp.fs_open.max_packet_length;
816 /* setup buffer and length lists using zero copy */
817 fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer);
818 fsep->pLength = libusb20_pass_ptr(xfer->pLength);
820 return (0); /* success */
824 ugen20_tr_close(struct libusb20_transfer *xfer)
826 struct usb_fs_close temp;
828 memset(&temp, 0, sizeof(temp));
830 temp.ep_index = xfer->trIndex;
832 if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) {
833 return (LIBUSB20_ERROR_INVALID_PARAM);
835 return (0); /* success */
839 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
841 struct usb_fs_clear_stall_sync temp;
843 memset(&temp, 0, sizeof(temp));
845 /* if the transfer is active, an error will be returned */
847 temp.ep_index = xfer->trIndex;
849 if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) {
850 return (LIBUSB20_ERROR_INVALID_PARAM);
852 return (0); /* success */
856 ugen20_tr_submit(struct libusb20_transfer *xfer)
858 struct usb_fs_start temp;
859 struct usb_fs_endpoint *fsep;
861 memset(&temp, 0, sizeof(temp));
863 fsep = xfer->pdev->privBeData;
864 fsep += xfer->trIndex;
866 fsep->nFrames = xfer->nFrames;
868 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
869 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
871 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
872 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
874 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
875 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
877 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
878 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
880 /* NOTE: The "fsep->timeout" variable is 16-bit. */
881 if (xfer->timeout > 65535)
882 fsep->timeout = 65535;
884 fsep->timeout = xfer->timeout;
886 temp.ep_index = xfer->trIndex;
888 if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) {
889 /* ignore any errors - should never happen */
891 return; /* success */
895 ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
897 struct usb_fs_stop temp;
899 memset(&temp, 0, sizeof(temp));
901 temp.ep_index = xfer->trIndex;
903 if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) {
904 /* ignore any errors - should never happen */
910 ugen20_be_ioctl(uint32_t cmd, void *data)
915 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
917 return (LIBUSB20_ERROR_OTHER);
918 error = ioctl(f, cmd, data);
920 if (errno == EPERM) {
921 error = LIBUSB20_ERROR_ACCESS;
923 error = LIBUSB20_ERROR_OTHER;
931 ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
932 uint8_t iface_index, char *buf, uint8_t len)
934 struct usb_gen_descriptor ugd;
936 memset(&ugd, 0, sizeof(ugd));
938 ugd.ugd_data = libusb20_pass_ptr(buf);
939 ugd.ugd_maxlen = len;
940 ugd.ugd_iface_index = iface_index;
942 if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) {
943 return (LIBUSB20_ERROR_INVALID_PARAM);
949 ugen20_dev_get_info(struct libusb20_device *pdev,
950 struct usb_device_info *pinfo)
952 if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) {
953 return (LIBUSB20_ERROR_INVALID_PARAM);
959 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
960 uint16_t quirk_index, struct libusb20_quirk *pq)
962 struct usb_gen_quirk q;
965 memset(&q, 0, sizeof(q));
967 q.index = quirk_index;
969 error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q);
972 if (errno == EINVAL) {
973 return (LIBUSB20_ERROR_NOT_FOUND);
978 pq->bcdDeviceLow = q.bcdDeviceLow;
979 pq->bcdDeviceHigh = q.bcdDeviceHigh;
980 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
986 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
987 struct libusb20_quirk *pq)
989 struct usb_gen_quirk q;
992 memset(&q, 0, sizeof(q));
994 q.index = quirk_index;
996 error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q);
999 if (errno == EINVAL) {
1000 return (LIBUSB20_ERROR_NOT_FOUND);
1003 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
1009 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
1010 struct libusb20_quirk *pq)
1012 struct usb_gen_quirk q;
1015 memset(&q, 0, sizeof(q));
1019 q.bcdDeviceLow = pq->bcdDeviceLow;
1020 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1021 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1023 error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q);
1025 if (errno == ENOMEM) {
1026 return (LIBUSB20_ERROR_NO_MEM);
1033 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
1034 struct libusb20_quirk *pq)
1036 struct usb_gen_quirk q;
1039 memset(&q, 0, sizeof(q));
1043 q.bcdDeviceLow = pq->bcdDeviceLow;
1044 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1045 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1047 error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q);
1049 if (errno == EINVAL) {
1050 return (LIBUSB20_ERROR_NOT_FOUND);
1057 ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
1059 return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp));
1063 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
1065 return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp));