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_power_usage_t ugen20_get_power_usage;
73 static libusb20_kernel_driver_active_t ugen20_kernel_driver_active;
74 static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver;
75 static libusb20_do_request_sync_t ugen20_do_request_sync;
76 static libusb20_process_t ugen20_process;
78 /* USB transfer specific */
79 static libusb20_tr_open_t ugen20_tr_open;
80 static libusb20_tr_close_t ugen20_tr_close;
81 static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync;
82 static libusb20_tr_submit_t ugen20_tr_submit;
83 static libusb20_tr_cancel_async_t ugen20_tr_cancel_async;
85 static const struct libusb20_device_methods libusb20_ugen20_device_methods = {
86 LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20)
90 ugen20_get_backend_name(void)
92 return ("FreeBSD UGEN 2.0");
96 ugen20_path_convert_one(const char **pp)
103 while ((*ptr >= '0') && (*ptr <= '9')) {
105 temp += (*ptr - '0');
106 if (temp >= 1000000) {
107 /* catch overflow early */
123 ugen20_enumerate(struct libusb20_device *pdev, const char *id)
125 const char *tmp = id;
126 struct usb_device_descriptor ddesc;
127 struct usb_device_info devinfo;
133 pdev->bus_number = ugen20_path_convert_one(&tmp);
134 pdev->device_address = ugen20_path_convert_one(&tmp);
136 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
137 pdev->bus_number, pdev->device_address);
139 f = open(buf, O_RDWR);
141 return (LIBUSB20_ERROR_OTHER);
143 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
144 error = LIBUSB20_ERROR_OTHER;
147 /* store when the device was plugged */
148 pdev->session_data.plugtime = plugtime;
150 if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) {
151 error = LIBUSB20_ERROR_OTHER;
154 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
156 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
158 if (pdev->ddesc.bNumConfigurations == 0) {
159 error = LIBUSB20_ERROR_OTHER;
161 } else if (pdev->ddesc.bNumConfigurations >= 8) {
162 error = LIBUSB20_ERROR_OTHER;
165 if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) {
166 error = LIBUSB20_ERROR_OTHER;
169 switch (devinfo.udi_mode) {
170 case USB_MODE_DEVICE:
171 pdev->usb_mode = LIBUSB20_MODE_DEVICE;
174 pdev->usb_mode = LIBUSB20_MODE_HOST;
178 switch (devinfo.udi_speed) {
180 pdev->usb_speed = LIBUSB20_SPEED_LOW;
183 pdev->usb_speed = LIBUSB20_SPEED_FULL;
186 pdev->usb_speed = LIBUSB20_SPEED_HIGH;
188 case USB_SPEED_VARIABLE:
189 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
191 case USB_SPEED_SUPER:
192 pdev->usb_speed = LIBUSB20_SPEED_SUPER;
195 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
199 /* get parent HUB index and port */
201 pdev->parent_address = devinfo.udi_hubindex;
202 pdev->parent_port = devinfo.udi_hubport;
204 /* generate a nice description for printout */
206 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
207 USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
208 pdev->device_address, devinfo.udi_product,
209 devinfo.udi_vendor, pdev->bus_number);
217 struct ugen20_urd_state {
218 struct usb_read_dir urd;
225 uint8_t dummy_zero[1];
229 ugen20_readdir(struct ugen20_urd_state *st)
233 if (st->ptr == NULL) {
234 st->urd.urd_startentry += st->nparsed;
235 st->urd.urd_data = libusb20_pass_ptr(st->buf);
236 st->urd.urd_maxlen = sizeof(st->buf);
239 if (ioctl(st->f, USB_READ_DIR, &st->urd)) {
244 if (st->ptr[0] == 0) {
252 st->src = (void *)(st->ptr + 1);
253 st->dst = st->src + strlen(st->src) + 1;
254 st->ptr = st->ptr + st->ptr[0];
257 if ((st->ptr < st->buf) ||
258 (st->ptr > st->dummy_zero)) {
266 ugen20_init_backend(struct libusb20_backend *pbe)
268 struct ugen20_urd_state state;
269 struct libusb20_device *pdev;
271 memset(&state, 0, sizeof(state));
273 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
275 return (LIBUSB20_ERROR_OTHER);
277 while (ugen20_readdir(&state) == 0) {
279 if ((state.src[0] != 'u') ||
280 (state.src[1] != 'g') ||
281 (state.src[2] != 'e') ||
282 (state.src[3] != 'n')) {
285 pdev = libusb20_dev_alloc();
289 if (ugen20_enumerate(pdev, state.src + 4)) {
290 libusb20_dev_free(pdev);
293 /* put the device on the backend list */
294 libusb20_be_enqueue_device(pbe, pdev);
297 return (0); /* success */
301 ugen20_tr_release(struct libusb20_device *pdev)
303 struct usb_fs_uninit fs_uninit;
305 if (pdev->nTransfer == 0) {
308 /* release all pending USB transfers */
309 if (pdev->privBeData != NULL) {
310 memset(&fs_uninit, 0, sizeof(fs_uninit));
311 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
312 /* ignore any errors of this kind */
319 ugen20_tr_renew(struct libusb20_device *pdev)
321 struct usb_fs_init fs_init;
322 struct usb_fs_endpoint *pfse;
325 uint16_t nMaxTransfer;
327 nMaxTransfer = pdev->nTransfer;
330 if (nMaxTransfer == 0) {
333 size = nMaxTransfer * sizeof(*pfse);
335 if (pdev->privBeData == NULL) {
338 error = LIBUSB20_ERROR_NO_MEM;
341 pdev->privBeData = pfse;
343 /* reset endpoint data */
344 memset(pdev->privBeData, 0, size);
346 memset(&fs_init, 0, sizeof(fs_init));
348 fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData);
349 fs_init.ep_index_max = nMaxTransfer;
351 if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) {
352 error = LIBUSB20_ERROR_OTHER;
360 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
368 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
369 pdev->bus_number, pdev->device_address);
372 * We need two file handles, one for the control endpoint and one
373 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
376 g = open(buf, O_RDWR);
378 return (LIBUSB20_ERROR_NO_DEVICE);
380 f = open(buf, O_RDWR);
383 return (LIBUSB20_ERROR_NO_DEVICE);
385 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
386 error = LIBUSB20_ERROR_OTHER;
389 /* check that the correct device is still plugged */
390 if (pdev->session_data.plugtime != plugtime) {
391 error = LIBUSB20_ERROR_NO_DEVICE;
394 /* need to set this before "tr_renew()" */
398 /* renew all USB transfers */
399 error = ugen20_tr_renew(pdev);
404 pdev->methods = &libusb20_ugen20_device_methods;
408 if (pdev->privBeData) {
409 /* cleanup after "tr_renew()" */
410 free(pdev->privBeData);
411 pdev->privBeData = NULL;
414 pdev->file_ctrl = -1;
422 ugen20_close_device(struct libusb20_device *pdev)
424 struct usb_fs_uninit fs_uninit;
426 if (pdev->privBeData) {
427 memset(&fs_uninit, 0, sizeof(fs_uninit));
428 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
429 /* ignore this error */
431 free(pdev->privBeData);
434 pdev->privBeData = NULL;
436 close(pdev->file_ctrl);
438 pdev->file_ctrl = -1;
439 return (0); /* success */
443 ugen20_exit_backend(struct libusb20_backend *pbe)
445 return; /* nothing to do */
449 ugen20_get_config_desc_full(struct libusb20_device *pdev,
450 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
452 struct usb_gen_descriptor gen_desc;
453 struct usb_config_descriptor cdesc;
458 /* make sure memory is initialised */
459 memset(&cdesc, 0, sizeof(cdesc));
460 memset(&gen_desc, 0, sizeof(gen_desc));
462 gen_desc.ugd_data = libusb20_pass_ptr(&cdesc);
463 gen_desc.ugd_maxlen = sizeof(cdesc);
464 gen_desc.ugd_config_index = cfg_index;
466 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
468 return (LIBUSB20_ERROR_OTHER);
470 len = UGETW(cdesc.wTotalLength);
471 if (len < sizeof(cdesc)) {
472 /* corrupt descriptor */
473 return (LIBUSB20_ERROR_OTHER);
477 return (LIBUSB20_ERROR_NO_MEM);
480 /* make sure memory is initialised */
483 gen_desc.ugd_data = libusb20_pass_ptr(ptr);
484 gen_desc.ugd_maxlen = len;
486 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
489 return (LIBUSB20_ERROR_OTHER);
491 /* make sure that the device doesn't fool us */
492 memcpy(ptr, &cdesc, sizeof(cdesc));
497 return (0); /* success */
501 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
505 if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) {
506 return (LIBUSB20_ERROR_OTHER);
514 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
516 int temp = cfg_index;
518 /* release all active USB transfers */
519 ugen20_tr_release(pdev);
521 if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) {
522 return (LIBUSB20_ERROR_OTHER);
524 return (ugen20_tr_renew(pdev));
528 ugen20_set_alt_index(struct libusb20_device *pdev,
529 uint8_t iface_index, uint8_t alt_index)
531 struct usb_alt_interface alt_iface;
533 memset(&alt_iface, 0, sizeof(alt_iface));
535 alt_iface.uai_interface_index = iface_index;
536 alt_iface.uai_alt_index = alt_index;
538 /* release all active USB transfers */
539 ugen20_tr_release(pdev);
541 if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) {
542 return (LIBUSB20_ERROR_OTHER);
544 return (ugen20_tr_renew(pdev));
548 ugen20_reset_device(struct libusb20_device *pdev)
552 /* release all active USB transfers */
553 ugen20_tr_release(pdev);
555 if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) {
556 return (LIBUSB20_ERROR_OTHER);
558 return (ugen20_tr_renew(pdev));
562 ugen20_check_connected(struct libusb20_device *pdev)
567 if (ioctl(pdev->file_ctrl, USB_GET_PLUGTIME, &plugtime)) {
568 error = LIBUSB20_ERROR_NO_DEVICE;
572 if (pdev->session_data.plugtime != plugtime) {
573 error = LIBUSB20_ERROR_NO_DEVICE;
581 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
585 switch (power_mode) {
586 case LIBUSB20_POWER_OFF:
587 temp = USB_POWER_MODE_OFF;
589 case LIBUSB20_POWER_ON:
590 temp = USB_POWER_MODE_ON;
592 case LIBUSB20_POWER_SAVE:
593 temp = USB_POWER_MODE_SAVE;
595 case LIBUSB20_POWER_SUSPEND:
596 temp = USB_POWER_MODE_SUSPEND;
598 case LIBUSB20_POWER_RESUME:
599 temp = USB_POWER_MODE_RESUME;
602 return (LIBUSB20_ERROR_INVALID_PARAM);
604 if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) {
605 return (LIBUSB20_ERROR_OTHER);
611 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
615 if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) {
616 return (LIBUSB20_ERROR_OTHER);
619 case USB_POWER_MODE_OFF:
620 temp = LIBUSB20_POWER_OFF;
622 case USB_POWER_MODE_ON:
623 temp = LIBUSB20_POWER_ON;
625 case USB_POWER_MODE_SAVE:
626 temp = LIBUSB20_POWER_SAVE;
628 case USB_POWER_MODE_SUSPEND:
629 temp = LIBUSB20_POWER_SUSPEND;
631 case USB_POWER_MODE_RESUME:
632 temp = LIBUSB20_POWER_RESUME;
635 temp = LIBUSB20_POWER_ON;
639 return (0); /* success */
643 ugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage)
647 if (ioctl(pdev->file_ctrl, USB_GET_POWER_USAGE, &temp)) {
648 return (LIBUSB20_ERROR_OTHER);
651 return (0); /* success */
655 ugen20_kernel_driver_active(struct libusb20_device *pdev,
658 int temp = iface_index;
660 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) {
661 return (LIBUSB20_ERROR_OTHER);
663 return (0); /* kernel driver is active */
667 ugen20_detach_kernel_driver(struct libusb20_device *pdev,
670 int temp = iface_index;
672 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) {
673 return (LIBUSB20_ERROR_OTHER);
675 return (0); /* kernel driver is active */
679 ugen20_do_request_sync(struct libusb20_device *pdev,
680 struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
681 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
683 struct usb_ctl_request req;
685 memset(&req, 0, sizeof(req));
687 req.ucr_data = libusb20_pass_ptr(data);
688 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
689 req.ucr_flags |= USB_SHORT_XFER_OK;
691 if (libusb20_me_encode(&req.ucr_request,
692 sizeof(req.ucr_request), setup)) {
695 if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) {
696 return (LIBUSB20_ERROR_OTHER);
699 /* get actual length */
700 *pactlen = req.ucr_actlen;
702 return (0); /* kernel driver is active */
706 ugen20_process(struct libusb20_device *pdev)
708 struct usb_fs_complete temp;
709 struct usb_fs_endpoint *fsep;
710 struct libusb20_transfer *xfer;
714 if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) {
715 if (errno == EBUSY) {
718 /* device detached */
719 return (LIBUSB20_ERROR_OTHER);
722 fsep = pdev->privBeData;
723 xfer = pdev->pTransfer;
724 fsep += temp.ep_index;
725 xfer += temp.ep_index;
727 /* update transfer status */
729 if (fsep->status == 0) {
730 xfer->aFrames = fsep->aFrames;
731 xfer->timeComplete = fsep->isoc_time_complete;
732 xfer->status = LIBUSB20_TRANSFER_COMPLETED;
733 } else if (fsep->status == USB_ERR_CANCELLED) {
735 xfer->timeComplete = 0;
736 xfer->status = LIBUSB20_TRANSFER_CANCELLED;
737 } else if (fsep->status == USB_ERR_STALLED) {
739 xfer->timeComplete = 0;
740 xfer->status = LIBUSB20_TRANSFER_STALL;
741 } else if (fsep->status == USB_ERR_TIMEOUT) {
743 xfer->timeComplete = 0;
744 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
747 xfer->timeComplete = 0;
748 xfer->status = LIBUSB20_TRANSFER_ERROR;
750 libusb20_tr_callback_wrapper(xfer);
752 return (0); /* done */
756 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
757 uint32_t MaxFrameCount, uint8_t ep_no, uint8_t pre_scale)
759 struct usb_fs_open temp;
760 struct usb_fs_endpoint *fsep;
763 MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE;
765 memset(&temp, 0, sizeof(temp));
767 fsep = xfer->pdev->privBeData;
768 fsep += xfer->trIndex;
770 temp.max_bufsize = MaxBufSize;
771 temp.max_frames = MaxFrameCount;
772 temp.ep_index = xfer->trIndex;
775 if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) {
776 return (LIBUSB20_ERROR_INVALID_PARAM);
778 /* maximums might have changed - update */
779 xfer->maxFrames = temp.max_frames;
781 /* "max_bufsize" should be multiple of "max_packet_length" */
782 xfer->maxTotalLength = temp.max_bufsize;
783 xfer->maxPacketLen = temp.max_packet_length;
785 /* setup buffer and length lists using zero copy */
786 fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer);
787 fsep->pLength = libusb20_pass_ptr(xfer->pLength);
789 return (0); /* success */
793 ugen20_tr_close(struct libusb20_transfer *xfer)
795 struct usb_fs_close temp;
797 memset(&temp, 0, sizeof(temp));
799 temp.ep_index = xfer->trIndex;
801 if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) {
802 return (LIBUSB20_ERROR_INVALID_PARAM);
804 return (0); /* success */
808 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
810 struct usb_fs_clear_stall_sync temp;
812 memset(&temp, 0, sizeof(temp));
814 /* if the transfer is active, an error will be returned */
816 temp.ep_index = xfer->trIndex;
818 if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) {
819 return (LIBUSB20_ERROR_INVALID_PARAM);
821 return (0); /* success */
825 ugen20_tr_submit(struct libusb20_transfer *xfer)
827 struct usb_fs_start temp;
828 struct usb_fs_endpoint *fsep;
830 memset(&temp, 0, sizeof(temp));
832 fsep = xfer->pdev->privBeData;
833 fsep += xfer->trIndex;
835 fsep->nFrames = xfer->nFrames;
837 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
838 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
840 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
841 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
843 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
844 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
846 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
847 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
849 /* NOTE: The "fsep->timeout" variable is 16-bit. */
850 if (xfer->timeout > 65535)
851 fsep->timeout = 65535;
853 fsep->timeout = xfer->timeout;
855 temp.ep_index = xfer->trIndex;
857 if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) {
858 /* ignore any errors - should never happen */
860 return; /* success */
864 ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
866 struct usb_fs_stop temp;
868 memset(&temp, 0, sizeof(temp));
870 temp.ep_index = xfer->trIndex;
872 if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) {
873 /* ignore any errors - should never happen */
879 ugen20_be_ioctl(uint32_t cmd, void *data)
884 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
886 return (LIBUSB20_ERROR_OTHER);
887 error = ioctl(f, cmd, data);
889 if (errno == EPERM) {
890 error = LIBUSB20_ERROR_ACCESS;
892 error = LIBUSB20_ERROR_OTHER;
900 ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
901 uint8_t iface_index, char *buf, uint8_t len)
903 struct usb_gen_descriptor ugd;
905 memset(&ugd, 0, sizeof(ugd));
907 ugd.ugd_data = libusb20_pass_ptr(buf);
908 ugd.ugd_maxlen = len;
909 ugd.ugd_iface_index = iface_index;
911 if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) {
912 return (LIBUSB20_ERROR_INVALID_PARAM);
918 ugen20_dev_get_info(struct libusb20_device *pdev,
919 struct usb_device_info *pinfo)
921 if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) {
922 return (LIBUSB20_ERROR_INVALID_PARAM);
928 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
929 uint16_t quirk_index, struct libusb20_quirk *pq)
931 struct usb_gen_quirk q;
934 memset(&q, 0, sizeof(q));
936 q.index = quirk_index;
938 error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q);
941 if (errno == EINVAL) {
942 return (LIBUSB20_ERROR_NOT_FOUND);
947 pq->bcdDeviceLow = q.bcdDeviceLow;
948 pq->bcdDeviceHigh = q.bcdDeviceHigh;
949 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
955 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
956 struct libusb20_quirk *pq)
958 struct usb_gen_quirk q;
961 memset(&q, 0, sizeof(q));
963 q.index = quirk_index;
965 error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q);
968 if (errno == EINVAL) {
969 return (LIBUSB20_ERROR_NOT_FOUND);
972 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
978 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
979 struct libusb20_quirk *pq)
981 struct usb_gen_quirk q;
984 memset(&q, 0, sizeof(q));
988 q.bcdDeviceLow = pq->bcdDeviceLow;
989 q.bcdDeviceHigh = pq->bcdDeviceHigh;
990 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
992 error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q);
994 if (errno == ENOMEM) {
995 return (LIBUSB20_ERROR_NO_MEM);
1002 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
1003 struct libusb20_quirk *pq)
1005 struct usb_gen_quirk q;
1008 memset(&q, 0, sizeof(q));
1012 q.bcdDeviceLow = pq->bcdDeviceLow;
1013 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1014 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1016 error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q);
1018 if (errno == EINVAL) {
1019 return (LIBUSB20_ERROR_NOT_FOUND);
1026 ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
1028 return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp));
1032 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
1034 return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp));