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>
39 #include "libusb20_desc.h"
40 #include "libusb20_int.h"
42 #include <dev/usb/usb.h>
43 #include <dev/usb/usbdi.h>
44 #include <dev/usb/usb_ioctl.h>
46 static libusb20_init_backend_t ugen20_init_backend;
47 static libusb20_open_device_t ugen20_open_device;
48 static libusb20_close_device_t ugen20_close_device;
49 static libusb20_get_backend_name_t ugen20_get_backend_name;
50 static libusb20_exit_backend_t ugen20_exit_backend;
51 static libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc;
52 static libusb20_dev_get_info_t ugen20_dev_get_info;
53 static libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk;
54 static libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name;
55 static libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk;
56 static libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk;
57 static libusb20_root_set_template_t ugen20_root_set_template;
58 static libusb20_root_get_template_t ugen20_root_get_template;
60 const struct libusb20_backend_methods libusb20_ugen20_backend = {
61 LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
64 /* USB device specific */
65 static libusb20_get_config_desc_full_t ugen20_get_config_desc_full;
66 static libusb20_get_config_index_t ugen20_get_config_index;
67 static libusb20_set_config_index_t ugen20_set_config_index;
68 static libusb20_set_alt_index_t ugen20_set_alt_index;
69 static libusb20_reset_device_t ugen20_reset_device;
70 static libusb20_check_connected_t ugen20_check_connected;
71 static libusb20_set_power_mode_t ugen20_set_power_mode;
72 static libusb20_get_power_mode_t ugen20_get_power_mode;
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 /* generate a nice description for printout */
201 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
202 USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
203 pdev->device_address, devinfo.udi_product,
204 devinfo.udi_vendor, pdev->bus_number);
212 struct ugen20_urd_state {
213 struct usb_read_dir urd;
220 uint8_t dummy_zero[1];
224 ugen20_readdir(struct ugen20_urd_state *st)
228 if (st->ptr == NULL) {
229 st->urd.urd_startentry += st->nparsed;
230 st->urd.urd_data = st->buf;
231 st->urd.urd_maxlen = sizeof(st->buf);
234 if (ioctl(st->f, USB_READ_DIR, &st->urd)) {
239 if (st->ptr[0] == 0) {
247 st->src = (void *)(st->ptr + 1);
248 st->dst = st->src + strlen(st->src) + 1;
249 st->ptr = st->ptr + st->ptr[0];
252 if ((st->ptr < st->buf) ||
253 (st->ptr > st->dummy_zero)) {
261 ugen20_init_backend(struct libusb20_backend *pbe)
263 struct ugen20_urd_state state;
264 struct libusb20_device *pdev;
266 memset(&state, 0, sizeof(state));
268 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
270 return (LIBUSB20_ERROR_OTHER);
272 while (ugen20_readdir(&state) == 0) {
274 if ((state.src[0] != 'u') ||
275 (state.src[1] != 'g') ||
276 (state.src[2] != 'e') ||
277 (state.src[3] != 'n')) {
280 pdev = libusb20_dev_alloc();
284 if (ugen20_enumerate(pdev, state.src + 4)) {
285 libusb20_dev_free(pdev);
288 /* put the device on the backend list */
289 libusb20_be_enqueue_device(pbe, pdev);
292 return (0); /* success */
296 ugen20_tr_release(struct libusb20_device *pdev)
298 struct usb_fs_uninit fs_uninit;
300 if (pdev->nTransfer == 0) {
303 /* release all pending USB transfers */
304 if (pdev->privBeData != NULL) {
305 memset(&fs_uninit, 0, sizeof(fs_uninit));
306 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
307 /* ignore any errors of this kind */
314 ugen20_tr_renew(struct libusb20_device *pdev)
316 struct usb_fs_init fs_init;
317 struct usb_fs_endpoint *pfse;
320 uint16_t nMaxTransfer;
322 nMaxTransfer = pdev->nTransfer;
325 if (nMaxTransfer == 0) {
328 size = nMaxTransfer * sizeof(*pfse);
330 if (pdev->privBeData == NULL) {
333 error = LIBUSB20_ERROR_NO_MEM;
336 pdev->privBeData = pfse;
338 /* reset endpoint data */
339 memset(pdev->privBeData, 0, size);
341 memset(&fs_init, 0, sizeof(fs_init));
343 fs_init.pEndpoints = pdev->privBeData;
344 fs_init.ep_index_max = nMaxTransfer;
346 if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) {
347 error = LIBUSB20_ERROR_OTHER;
355 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
363 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
364 pdev->bus_number, pdev->device_address);
367 * We need two file handles, one for the control endpoint and one
368 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
371 g = open(buf, O_RDWR);
373 return (LIBUSB20_ERROR_NO_DEVICE);
375 f = open(buf, O_RDWR);
378 return (LIBUSB20_ERROR_NO_DEVICE);
380 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
381 error = LIBUSB20_ERROR_OTHER;
384 /* check that the correct device is still plugged */
385 if (pdev->session_data.plugtime != plugtime) {
386 error = LIBUSB20_ERROR_NO_DEVICE;
389 /* need to set this before "tr_renew()" */
393 /* renew all USB transfers */
394 error = ugen20_tr_renew(pdev);
399 pdev->methods = &libusb20_ugen20_device_methods;
403 if (pdev->privBeData) {
404 /* cleanup after "tr_renew()" */
405 free(pdev->privBeData);
406 pdev->privBeData = NULL;
409 pdev->file_ctrl = -1;
417 ugen20_close_device(struct libusb20_device *pdev)
419 struct usb_fs_uninit fs_uninit;
421 if (pdev->privBeData) {
422 memset(&fs_uninit, 0, sizeof(fs_uninit));
423 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
424 /* ignore this error */
426 free(pdev->privBeData);
429 pdev->privBeData = NULL;
431 close(pdev->file_ctrl);
433 pdev->file_ctrl = -1;
434 return (0); /* success */
438 ugen20_exit_backend(struct libusb20_backend *pbe)
440 return; /* nothing to do */
444 ugen20_get_config_desc_full(struct libusb20_device *pdev,
445 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
447 struct usb_gen_descriptor gen_desc;
448 struct usb_config_descriptor cdesc;
453 /* make sure memory is initialised */
454 memset(&cdesc, 0, sizeof(cdesc));
455 memset(&gen_desc, 0, sizeof(gen_desc));
457 gen_desc.ugd_data = &cdesc;
458 gen_desc.ugd_maxlen = sizeof(cdesc);
459 gen_desc.ugd_config_index = cfg_index;
461 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
463 return (LIBUSB20_ERROR_OTHER);
465 len = UGETW(cdesc.wTotalLength);
466 if (len < sizeof(cdesc)) {
467 /* corrupt descriptor */
468 return (LIBUSB20_ERROR_OTHER);
472 return (LIBUSB20_ERROR_NO_MEM);
475 /* make sure memory is initialised */
478 gen_desc.ugd_data = ptr;
479 gen_desc.ugd_maxlen = len;
481 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
484 return (LIBUSB20_ERROR_OTHER);
486 /* make sure that the device doesn't fool us */
487 memcpy(ptr, &cdesc, sizeof(cdesc));
492 return (0); /* success */
496 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
500 if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) {
501 return (LIBUSB20_ERROR_OTHER);
509 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
511 int temp = cfg_index;
513 /* release all active USB transfers */
514 ugen20_tr_release(pdev);
516 if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) {
517 return (LIBUSB20_ERROR_OTHER);
519 return (ugen20_tr_renew(pdev));
523 ugen20_set_alt_index(struct libusb20_device *pdev,
524 uint8_t iface_index, uint8_t alt_index)
526 struct usb_alt_interface alt_iface;
528 memset(&alt_iface, 0, sizeof(alt_iface));
530 alt_iface.uai_interface_index = iface_index;
531 alt_iface.uai_alt_index = alt_index;
533 /* release all active USB transfers */
534 ugen20_tr_release(pdev);
536 if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) {
537 return (LIBUSB20_ERROR_OTHER);
539 return (ugen20_tr_renew(pdev));
543 ugen20_reset_device(struct libusb20_device *pdev)
547 /* release all active USB transfers */
548 ugen20_tr_release(pdev);
550 if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) {
551 return (LIBUSB20_ERROR_OTHER);
553 return (ugen20_tr_renew(pdev));
557 ugen20_check_connected(struct libusb20_device *pdev)
562 if (ioctl(pdev->file_ctrl, USB_GET_PLUGTIME, &plugtime)) {
563 error = LIBUSB20_ERROR_NO_DEVICE;
567 if (pdev->session_data.plugtime != plugtime) {
568 error = LIBUSB20_ERROR_NO_DEVICE;
576 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
580 switch (power_mode) {
581 case LIBUSB20_POWER_OFF:
582 temp = USB_POWER_MODE_OFF;
584 case LIBUSB20_POWER_ON:
585 temp = USB_POWER_MODE_ON;
587 case LIBUSB20_POWER_SAVE:
588 temp = USB_POWER_MODE_SAVE;
590 case LIBUSB20_POWER_SUSPEND:
591 temp = USB_POWER_MODE_SUSPEND;
593 case LIBUSB20_POWER_RESUME:
594 temp = USB_POWER_MODE_RESUME;
597 return (LIBUSB20_ERROR_INVALID_PARAM);
599 if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) {
600 return (LIBUSB20_ERROR_OTHER);
606 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
610 if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) {
611 return (LIBUSB20_ERROR_OTHER);
614 case USB_POWER_MODE_OFF:
615 temp = LIBUSB20_POWER_OFF;
617 case USB_POWER_MODE_ON:
618 temp = LIBUSB20_POWER_ON;
620 case USB_POWER_MODE_SAVE:
621 temp = LIBUSB20_POWER_SAVE;
623 case USB_POWER_MODE_SUSPEND:
624 temp = LIBUSB20_POWER_SUSPEND;
626 case USB_POWER_MODE_RESUME:
627 temp = LIBUSB20_POWER_RESUME;
630 temp = LIBUSB20_POWER_ON;
634 return (0); /* success */
638 ugen20_kernel_driver_active(struct libusb20_device *pdev,
641 int temp = iface_index;
643 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) {
644 return (LIBUSB20_ERROR_OTHER);
646 return (0); /* kernel driver is active */
650 ugen20_detach_kernel_driver(struct libusb20_device *pdev,
653 int temp = iface_index;
655 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) {
656 return (LIBUSB20_ERROR_OTHER);
658 return (0); /* kernel driver is active */
662 ugen20_do_request_sync(struct libusb20_device *pdev,
663 struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
664 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
666 struct usb_ctl_request req;
668 memset(&req, 0, sizeof(req));
671 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
672 req.ucr_flags |= USB_SHORT_XFER_OK;
674 if (libusb20_me_encode(&req.ucr_request,
675 sizeof(req.ucr_request), setup)) {
678 if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) {
679 return (LIBUSB20_ERROR_OTHER);
682 /* get actual length */
683 *pactlen = req.ucr_actlen;
685 return (0); /* kernel driver is active */
689 ugen20_process(struct libusb20_device *pdev)
691 struct usb_fs_complete temp;
692 struct usb_fs_endpoint *fsep;
693 struct libusb20_transfer *xfer;
697 if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) {
698 if (errno == EBUSY) {
701 /* device detached */
702 return (LIBUSB20_ERROR_OTHER);
705 fsep = pdev->privBeData;
706 xfer = pdev->pTransfer;
707 fsep += temp.ep_index;
708 xfer += temp.ep_index;
710 /* update transfer status */
712 if (fsep->status == 0) {
713 xfer->aFrames = fsep->aFrames;
714 xfer->timeComplete = fsep->isoc_time_complete;
715 xfer->status = LIBUSB20_TRANSFER_COMPLETED;
716 } else if (fsep->status == USB_ERR_CANCELLED) {
718 xfer->timeComplete = 0;
719 xfer->status = LIBUSB20_TRANSFER_CANCELLED;
720 } else if (fsep->status == USB_ERR_STALLED) {
722 xfer->timeComplete = 0;
723 xfer->status = LIBUSB20_TRANSFER_STALL;
724 } else if (fsep->status == USB_ERR_TIMEOUT) {
726 xfer->timeComplete = 0;
727 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
730 xfer->timeComplete = 0;
731 xfer->status = LIBUSB20_TRANSFER_ERROR;
733 libusb20_tr_callback_wrapper(xfer);
735 return (0); /* done */
739 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
740 uint32_t MaxFrameCount, uint8_t ep_no)
742 struct usb_fs_open temp;
743 struct usb_fs_endpoint *fsep;
745 memset(&temp, 0, sizeof(temp));
747 fsep = xfer->pdev->privBeData;
748 fsep += xfer->trIndex;
750 temp.max_bufsize = MaxBufSize;
751 temp.max_frames = MaxFrameCount;
752 temp.ep_index = xfer->trIndex;
755 if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) {
756 return (LIBUSB20_ERROR_INVALID_PARAM);
758 /* maximums might have changed - update */
759 xfer->maxFrames = temp.max_frames;
761 /* "max_bufsize" should be multiple of "max_packet_length" */
762 xfer->maxTotalLength = temp.max_bufsize;
763 xfer->maxPacketLen = temp.max_packet_length;
765 /* setup buffer and length lists */
766 fsep->ppBuffer = xfer->ppBuffer;/* zero copy */
767 fsep->pLength = xfer->pLength; /* zero copy */
769 return (0); /* success */
773 ugen20_tr_close(struct libusb20_transfer *xfer)
775 struct usb_fs_close temp;
777 memset(&temp, 0, sizeof(temp));
779 temp.ep_index = xfer->trIndex;
781 if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) {
782 return (LIBUSB20_ERROR_INVALID_PARAM);
784 return (0); /* success */
788 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
790 struct usb_fs_clear_stall_sync temp;
792 memset(&temp, 0, sizeof(temp));
794 /* if the transfer is active, an error will be returned */
796 temp.ep_index = xfer->trIndex;
798 if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) {
799 return (LIBUSB20_ERROR_INVALID_PARAM);
801 return (0); /* success */
805 ugen20_tr_submit(struct libusb20_transfer *xfer)
807 struct usb_fs_start temp;
808 struct usb_fs_endpoint *fsep;
810 memset(&temp, 0, sizeof(temp));
812 fsep = xfer->pdev->privBeData;
813 fsep += xfer->trIndex;
815 fsep->nFrames = xfer->nFrames;
817 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
818 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
820 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
821 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
823 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
824 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
826 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
827 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
829 /* NOTE: The "fsep->timeout" variable is 16-bit. */
830 if (xfer->timeout > 65535)
831 fsep->timeout = 65535;
833 fsep->timeout = xfer->timeout;
835 temp.ep_index = xfer->trIndex;
837 if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) {
838 /* ignore any errors - should never happen */
840 return; /* success */
844 ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
846 struct usb_fs_stop temp;
848 memset(&temp, 0, sizeof(temp));
850 temp.ep_index = xfer->trIndex;
852 if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) {
853 /* ignore any errors - should never happen */
859 ugen20_be_ioctl(uint32_t cmd, void *data)
864 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
866 return (LIBUSB20_ERROR_OTHER);
867 error = ioctl(f, cmd, data);
869 if (errno == EPERM) {
870 error = LIBUSB20_ERROR_ACCESS;
872 error = LIBUSB20_ERROR_OTHER;
880 ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
881 uint8_t iface_index, char *buf, uint8_t len)
883 struct usb_gen_descriptor ugd;
885 memset(&ugd, 0, sizeof(ugd));
888 ugd.ugd_maxlen = len;
889 ugd.ugd_iface_index = iface_index;
891 if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) {
892 return (LIBUSB20_ERROR_INVALID_PARAM);
898 ugen20_dev_get_info(struct libusb20_device *pdev,
899 struct usb_device_info *pinfo)
901 if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) {
902 return (LIBUSB20_ERROR_INVALID_PARAM);
908 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
909 uint16_t quirk_index, struct libusb20_quirk *pq)
911 struct usb_gen_quirk q;
914 memset(&q, 0, sizeof(q));
916 q.index = quirk_index;
918 error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q);
921 if (errno == EINVAL) {
922 return (LIBUSB20_ERROR_NOT_FOUND);
927 pq->bcdDeviceLow = q.bcdDeviceLow;
928 pq->bcdDeviceHigh = q.bcdDeviceHigh;
929 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
935 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
936 struct libusb20_quirk *pq)
938 struct usb_gen_quirk q;
941 memset(&q, 0, sizeof(q));
943 q.index = quirk_index;
945 error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q);
948 if (errno == EINVAL) {
949 return (LIBUSB20_ERROR_NOT_FOUND);
952 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
958 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
959 struct libusb20_quirk *pq)
961 struct usb_gen_quirk q;
964 memset(&q, 0, sizeof(q));
968 q.bcdDeviceLow = pq->bcdDeviceLow;
969 q.bcdDeviceHigh = pq->bcdDeviceHigh;
970 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
972 error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q);
974 if (errno == ENOMEM) {
975 return (LIBUSB20_ERROR_NO_MEM);
982 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
983 struct libusb20_quirk *pq)
985 struct usb_gen_quirk q;
988 memset(&q, 0, sizeof(q));
992 q.bcdDeviceLow = pq->bcdDeviceLow;
993 q.bcdDeviceHigh = pq->bcdDeviceHigh;
994 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
996 error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q);
998 if (errno == EINVAL) {
999 return (LIBUSB20_ERROR_NOT_FOUND);
1006 ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
1008 return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp));
1012 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
1014 return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp));