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"
53 static libusb20_init_backend_t ugen20_init_backend;
54 static libusb20_open_device_t ugen20_open_device;
55 static libusb20_close_device_t ugen20_close_device;
56 static libusb20_get_backend_name_t ugen20_get_backend_name;
57 static libusb20_exit_backend_t ugen20_exit_backend;
58 static libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc;
59 static libusb20_dev_get_info_t ugen20_dev_get_info;
60 static libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk;
61 static libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name;
62 static libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk;
63 static libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk;
64 static libusb20_root_set_template_t ugen20_root_set_template;
65 static libusb20_root_get_template_t ugen20_root_get_template;
67 const struct libusb20_backend_methods libusb20_ugen20_backend = {
68 LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
71 /* USB device specific */
72 static libusb20_get_config_desc_full_t ugen20_get_config_desc_full;
73 static libusb20_get_config_index_t ugen20_get_config_index;
74 static libusb20_set_config_index_t ugen20_set_config_index;
75 static libusb20_set_alt_index_t ugen20_set_alt_index;
76 static libusb20_reset_device_t ugen20_reset_device;
77 static libusb20_check_connected_t ugen20_check_connected;
78 static libusb20_set_power_mode_t ugen20_set_power_mode;
79 static libusb20_get_power_mode_t ugen20_get_power_mode;
80 static libusb20_get_port_path_t ugen20_get_port_path;
81 static libusb20_get_power_usage_t ugen20_get_power_usage;
82 static libusb20_get_stats_t ugen20_get_stats;
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;
143 pdev->bus_number = ugen20_path_convert_one(&tmp);
144 pdev->device_address = ugen20_path_convert_one(&tmp);
146 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
147 pdev->bus_number, pdev->device_address);
149 f = open(buf, O_RDWR);
151 return (LIBUSB20_ERROR_OTHER);
153 if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
154 error = LIBUSB20_ERROR_OTHER;
157 /* store when the device was plugged */
158 pdev->session_data.plugtime = plugtime;
160 if (ioctl(f, IOUSB(USB_GET_DEVICE_DESC), &ddesc)) {
161 error = LIBUSB20_ERROR_OTHER;
164 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
166 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
168 if (pdev->ddesc.bNumConfigurations == 0) {
169 error = LIBUSB20_ERROR_OTHER;
171 } else if (pdev->ddesc.bNumConfigurations >= 8) {
172 error = LIBUSB20_ERROR_OTHER;
175 if (ioctl(f, IOUSB(USB_GET_DEVICEINFO), &devinfo)) {
176 error = LIBUSB20_ERROR_OTHER;
179 switch (devinfo.udi_mode) {
180 case USB_MODE_DEVICE:
181 pdev->usb_mode = LIBUSB20_MODE_DEVICE;
184 pdev->usb_mode = LIBUSB20_MODE_HOST;
188 switch (devinfo.udi_speed) {
190 pdev->usb_speed = LIBUSB20_SPEED_LOW;
193 pdev->usb_speed = LIBUSB20_SPEED_FULL;
196 pdev->usb_speed = LIBUSB20_SPEED_HIGH;
198 case USB_SPEED_VARIABLE:
199 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
201 case USB_SPEED_SUPER:
202 pdev->usb_speed = LIBUSB20_SPEED_SUPER;
205 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
209 /* get parent HUB index and port */
211 pdev->parent_address = devinfo.udi_hubindex;
212 pdev->parent_port = devinfo.udi_hubport;
214 /* generate a nice description for printout */
216 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
217 USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
218 pdev->device_address, devinfo.udi_vendor,
219 devinfo.udi_product, pdev->bus_number);
227 struct ugen20_urd_state {
228 struct usb_read_dir urd;
235 uint8_t dummy_zero[1];
239 ugen20_readdir(struct ugen20_urd_state *st)
243 if (st->ptr == NULL) {
244 st->urd.urd_startentry += st->nparsed;
245 st->urd.urd_data = libusb20_pass_ptr(st->buf);
246 st->urd.urd_maxlen = sizeof(st->buf);
249 if (ioctl(st->f, IOUSB(USB_READ_DIR), &st->urd)) {
254 if (st->ptr[0] == 0) {
262 st->src = (void *)(st->ptr + 1);
263 st->dst = st->src + strlen(st->src) + 1;
264 st->ptr = st->ptr + st->ptr[0];
267 if ((st->ptr < st->buf) ||
268 (st->ptr > st->dummy_zero)) {
276 ugen20_init_backend(struct libusb20_backend *pbe)
278 struct ugen20_urd_state state;
279 struct libusb20_device *pdev;
281 memset(&state, 0, sizeof(state));
283 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
285 return (LIBUSB20_ERROR_OTHER);
287 while (ugen20_readdir(&state) == 0) {
289 if ((state.src[0] != 'u') ||
290 (state.src[1] != 'g') ||
291 (state.src[2] != 'e') ||
292 (state.src[3] != 'n')) {
295 pdev = libusb20_dev_alloc();
299 if (ugen20_enumerate(pdev, state.src + 4)) {
300 libusb20_dev_free(pdev);
303 /* put the device on the backend list */
304 libusb20_be_enqueue_device(pbe, pdev);
307 return (0); /* success */
311 ugen20_tr_release(struct libusb20_device *pdev)
313 struct usb_fs_uninit fs_uninit;
315 if (pdev->nTransfer == 0) {
318 /* release all pending USB transfers */
319 if (pdev->privBeData != NULL) {
320 memset(&fs_uninit, 0, sizeof(fs_uninit));
321 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) {
322 /* ignore any errors of this kind */
329 ugen20_tr_renew(struct libusb20_device *pdev)
331 struct usb_fs_init fs_init;
332 struct usb_fs_endpoint *pfse;
335 uint16_t nMaxTransfer;
337 nMaxTransfer = pdev->nTransfer;
340 if (nMaxTransfer == 0) {
343 size = nMaxTransfer * sizeof(*pfse);
345 if (pdev->privBeData == NULL) {
348 error = LIBUSB20_ERROR_NO_MEM;
351 pdev->privBeData = pfse;
353 /* reset endpoint data */
354 memset(pdev->privBeData, 0, size);
356 memset(&fs_init, 0, sizeof(fs_init));
358 fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData);
359 fs_init.ep_index_max = nMaxTransfer;
361 if (ioctl(pdev->file, IOUSB(USB_FS_INIT), &fs_init)) {
362 error = LIBUSB20_ERROR_OTHER;
370 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
378 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
379 pdev->bus_number, pdev->device_address);
382 * We need two file handles, one for the control endpoint and one
383 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
386 g = open(buf, O_RDWR);
388 return (LIBUSB20_ERROR_NO_DEVICE);
390 f = open(buf, O_RDWR);
393 return (LIBUSB20_ERROR_NO_DEVICE);
395 if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
396 error = LIBUSB20_ERROR_OTHER;
399 /* check that the correct device is still plugged */
400 if (pdev->session_data.plugtime != plugtime) {
401 error = LIBUSB20_ERROR_NO_DEVICE;
404 /* need to set this before "tr_renew()" */
408 /* renew all USB transfers */
409 error = ugen20_tr_renew(pdev);
414 pdev->methods = &libusb20_ugen20_device_methods;
418 if (pdev->privBeData) {
419 /* cleanup after "tr_renew()" */
420 free(pdev->privBeData);
421 pdev->privBeData = NULL;
424 pdev->file_ctrl = -1;
432 ugen20_close_device(struct libusb20_device *pdev)
434 struct usb_fs_uninit fs_uninit;
436 if (pdev->privBeData) {
437 memset(&fs_uninit, 0, sizeof(fs_uninit));
438 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) {
439 /* ignore this error */
441 free(pdev->privBeData);
444 pdev->privBeData = NULL;
446 close(pdev->file_ctrl);
448 pdev->file_ctrl = -1;
449 return (0); /* success */
453 ugen20_exit_backend(struct libusb20_backend *pbe)
455 return; /* nothing to do */
459 ugen20_get_config_desc_full(struct libusb20_device *pdev,
460 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
462 struct usb_gen_descriptor gen_desc;
463 struct usb_config_descriptor cdesc;
468 /* make sure memory is initialised */
469 memset(&cdesc, 0, sizeof(cdesc));
470 memset(&gen_desc, 0, sizeof(gen_desc));
472 gen_desc.ugd_data = libusb20_pass_ptr(&cdesc);
473 gen_desc.ugd_maxlen = sizeof(cdesc);
474 gen_desc.ugd_config_index = cfg_index;
476 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc);
478 return (LIBUSB20_ERROR_OTHER);
480 len = UGETW(cdesc.wTotalLength);
481 if (len < sizeof(cdesc)) {
482 /* corrupt descriptor */
483 return (LIBUSB20_ERROR_OTHER);
487 return (LIBUSB20_ERROR_NO_MEM);
490 /* make sure memory is initialised */
493 gen_desc.ugd_data = libusb20_pass_ptr(ptr);
494 gen_desc.ugd_maxlen = len;
496 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc);
499 return (LIBUSB20_ERROR_OTHER);
501 /* make sure that the device doesn't fool us */
502 memcpy(ptr, &cdesc, sizeof(cdesc));
507 return (0); /* success */
511 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
515 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_CONFIG), &temp)) {
516 return (LIBUSB20_ERROR_OTHER);
524 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
526 int temp = cfg_index;
528 /* release all active USB transfers */
529 ugen20_tr_release(pdev);
531 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_CONFIG), &temp)) {
532 return (LIBUSB20_ERROR_OTHER);
534 return (ugen20_tr_renew(pdev));
538 ugen20_set_alt_index(struct libusb20_device *pdev,
539 uint8_t iface_index, uint8_t alt_index)
541 struct usb_alt_interface alt_iface;
543 memset(&alt_iface, 0, sizeof(alt_iface));
545 alt_iface.uai_interface_index = iface_index;
546 alt_iface.uai_alt_index = alt_index;
548 /* release all active USB transfers */
549 ugen20_tr_release(pdev);
551 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_ALTINTERFACE), &alt_iface)) {
552 return (LIBUSB20_ERROR_OTHER);
554 return (ugen20_tr_renew(pdev));
558 ugen20_reset_device(struct libusb20_device *pdev)
562 /* release all active USB transfers */
563 ugen20_tr_release(pdev);
565 if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICEENUMERATE), &temp)) {
566 return (LIBUSB20_ERROR_OTHER);
568 return (ugen20_tr_renew(pdev));
572 ugen20_check_connected(struct libusb20_device *pdev)
577 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
578 error = LIBUSB20_ERROR_NO_DEVICE;
582 if (pdev->session_data.plugtime != plugtime) {
583 error = LIBUSB20_ERROR_NO_DEVICE;
591 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
595 switch (power_mode) {
596 case LIBUSB20_POWER_OFF:
597 temp = USB_POWER_MODE_OFF;
599 case LIBUSB20_POWER_ON:
600 temp = USB_POWER_MODE_ON;
602 case LIBUSB20_POWER_SAVE:
603 temp = USB_POWER_MODE_SAVE;
605 case LIBUSB20_POWER_SUSPEND:
606 temp = USB_POWER_MODE_SUSPEND;
608 case LIBUSB20_POWER_RESUME:
609 temp = USB_POWER_MODE_RESUME;
612 return (LIBUSB20_ERROR_INVALID_PARAM);
614 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_POWER_MODE), &temp)) {
615 return (LIBUSB20_ERROR_OTHER);
621 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
625 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_MODE), &temp)) {
626 return (LIBUSB20_ERROR_OTHER);
629 case USB_POWER_MODE_OFF:
630 temp = LIBUSB20_POWER_OFF;
632 case USB_POWER_MODE_ON:
633 temp = LIBUSB20_POWER_ON;
635 case USB_POWER_MODE_SAVE:
636 temp = LIBUSB20_POWER_SAVE;
638 case USB_POWER_MODE_SUSPEND:
639 temp = LIBUSB20_POWER_SUSPEND;
641 case USB_POWER_MODE_RESUME:
642 temp = LIBUSB20_POWER_RESUME;
645 temp = LIBUSB20_POWER_ON;
649 return (0); /* success */
653 ugen20_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize)
655 struct usb_device_port_path udpp;
657 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_DEV_PORT_PATH), &udpp))
658 return (LIBUSB20_ERROR_OTHER);
660 if (udpp.udp_port_level > bufsize)
661 return (LIBUSB20_ERROR_OVERFLOW);
663 memcpy(buf, udpp.udp_port_no, udpp.udp_port_level);
665 return (udpp.udp_port_level); /* success */
669 ugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage)
673 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_USAGE), &temp)) {
674 return (LIBUSB20_ERROR_OTHER);
677 return (0); /* success */
681 ugen20_get_stats(struct libusb20_device *pdev, struct libusb20_device_stats *pstats)
683 struct usb_device_stats st;
685 if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICESTATS), &st))
686 return (LIBUSB20_ERROR_OTHER);
688 memset(pstats, 0, sizeof(*pstats));
690 pstats->xfer_ok[0] = st.uds_requests_ok[0];
691 pstats->xfer_ok[1] = st.uds_requests_ok[1];
692 pstats->xfer_ok[2] = st.uds_requests_ok[2];
693 pstats->xfer_ok[3] = st.uds_requests_ok[3];
695 pstats->xfer_fail[0] = st.uds_requests_fail[0];
696 pstats->xfer_fail[1] = st.uds_requests_fail[1];
697 pstats->xfer_fail[2] = st.uds_requests_fail[2];
698 pstats->xfer_fail[3] = st.uds_requests_fail[3];
700 return (0); /* success */
704 ugen20_kernel_driver_active(struct libusb20_device *pdev,
707 int temp = iface_index;
709 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ACTIVE), &temp)) {
710 return (LIBUSB20_ERROR_OTHER);
712 return (0); /* kernel driver is active */
716 ugen20_detach_kernel_driver(struct libusb20_device *pdev,
719 int temp = iface_index;
721 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_DETACH), &temp)) {
722 return (LIBUSB20_ERROR_OTHER);
724 return (0); /* kernel driver is detached */
728 ugen20_do_request_sync(struct libusb20_device *pdev,
729 struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
730 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
732 struct usb_ctl_request req;
734 memset(&req, 0, sizeof(req));
736 req.ucr_data = libusb20_pass_ptr(data);
737 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
738 req.ucr_flags |= USB_SHORT_XFER_OK;
740 if (libusb20_me_encode(&req.ucr_request,
741 sizeof(req.ucr_request), setup)) {
744 if (ioctl(pdev->file_ctrl, IOUSB(USB_DO_REQUEST), &req)) {
745 return (LIBUSB20_ERROR_OTHER);
748 /* get actual length */
749 *pactlen = req.ucr_actlen;
751 return (0); /* request was successful */
755 ugen20_process(struct libusb20_device *pdev)
757 struct usb_fs_complete temp;
758 struct usb_fs_endpoint *fsep;
759 struct libusb20_transfer *xfer;
763 if (ioctl(pdev->file, IOUSB(USB_FS_COMPLETE), &temp)) {
764 if (errno == EBUSY) {
767 /* device detached */
768 return (LIBUSB20_ERROR_OTHER);
771 fsep = pdev->privBeData;
772 xfer = pdev->pTransfer;
773 fsep += temp.ep_index;
774 xfer += temp.ep_index;
776 /* update transfer status */
778 if (fsep->status == 0) {
779 xfer->aFrames = fsep->aFrames;
780 xfer->timeComplete = fsep->isoc_time_complete;
781 xfer->status = LIBUSB20_TRANSFER_COMPLETED;
782 } else if (fsep->status == USB_ERR_CANCELLED) {
784 xfer->timeComplete = 0;
785 xfer->status = LIBUSB20_TRANSFER_CANCELLED;
786 } else if (fsep->status == USB_ERR_STALLED) {
788 xfer->timeComplete = 0;
789 xfer->status = LIBUSB20_TRANSFER_STALL;
790 } else if (fsep->status == USB_ERR_TIMEOUT) {
792 xfer->timeComplete = 0;
793 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
796 xfer->timeComplete = 0;
797 xfer->status = LIBUSB20_TRANSFER_ERROR;
799 libusb20_tr_callback_wrapper(xfer);
801 return (0); /* done */
805 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
806 uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id,
810 struct usb_fs_open fs_open;
811 struct usb_fs_open_stream fs_open_stream;
813 struct usb_fs_endpoint *fsep;
816 MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE;
818 memset(&temp, 0, sizeof(temp));
820 fsep = xfer->pdev->privBeData;
821 fsep += xfer->trIndex;
823 temp.fs_open.max_bufsize = MaxBufSize;
824 temp.fs_open.max_frames = MaxFrameCount;
825 temp.fs_open.ep_index = xfer->trIndex;
826 temp.fs_open.ep_no = ep_no;
828 if (stream_id != 0) {
829 temp.fs_open_stream.stream_id = stream_id;
831 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN_STREAM), &temp.fs_open_stream))
832 return (LIBUSB20_ERROR_INVALID_PARAM);
834 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN), &temp.fs_open))
835 return (LIBUSB20_ERROR_INVALID_PARAM);
837 /* maximums might have changed - update */
838 xfer->maxFrames = temp.fs_open.max_frames;
840 /* "max_bufsize" should be multiple of "max_packet_length" */
841 xfer->maxTotalLength = temp.fs_open.max_bufsize;
842 xfer->maxPacketLen = temp.fs_open.max_packet_length;
844 /* setup buffer and length lists using zero copy */
845 fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer);
846 fsep->pLength = libusb20_pass_ptr(xfer->pLength);
848 return (0); /* success */
852 ugen20_tr_close(struct libusb20_transfer *xfer)
854 struct usb_fs_close temp;
856 memset(&temp, 0, sizeof(temp));
858 temp.ep_index = xfer->trIndex;
860 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLOSE), &temp)) {
861 return (LIBUSB20_ERROR_INVALID_PARAM);
863 return (0); /* success */
867 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
869 struct usb_fs_clear_stall_sync temp;
871 memset(&temp, 0, sizeof(temp));
873 /* if the transfer is active, an error will be returned */
875 temp.ep_index = xfer->trIndex;
877 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLEAR_STALL_SYNC), &temp)) {
878 return (LIBUSB20_ERROR_INVALID_PARAM);
880 return (0); /* success */
884 ugen20_tr_submit(struct libusb20_transfer *xfer)
886 struct usb_fs_start temp;
887 struct usb_fs_endpoint *fsep;
889 memset(&temp, 0, sizeof(temp));
891 fsep = xfer->pdev->privBeData;
892 fsep += xfer->trIndex;
894 fsep->nFrames = xfer->nFrames;
896 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
897 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
899 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
900 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
902 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
903 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
905 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
906 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
908 /* NOTE: The "fsep->timeout" variable is 16-bit. */
909 if (xfer->timeout > 65535)
910 fsep->timeout = 65535;
912 fsep->timeout = xfer->timeout;
914 temp.ep_index = xfer->trIndex;
916 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_START), &temp)) {
917 /* ignore any errors - should never happen */
919 return; /* success */
923 ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
925 struct usb_fs_stop temp;
927 memset(&temp, 0, sizeof(temp));
929 temp.ep_index = xfer->trIndex;
931 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_STOP), &temp)) {
932 /* ignore any errors - should never happen */
938 ugen20_be_ioctl(uint32_t cmd, void *data)
943 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
945 return (LIBUSB20_ERROR_OTHER);
946 error = ioctl(f, cmd, data);
948 if (errno == EPERM) {
949 error = LIBUSB20_ERROR_ACCESS;
951 error = LIBUSB20_ERROR_OTHER;
959 ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
960 uint8_t iface_index, char *buf, uint8_t len)
962 struct usb_gen_descriptor ugd;
964 memset(&ugd, 0, sizeof(ugd));
966 ugd.ugd_data = libusb20_pass_ptr(buf);
967 ugd.ugd_maxlen = len;
968 ugd.ugd_iface_index = iface_index;
970 if (ioctl(pdev->file, IOUSB(USB_GET_IFACE_DRIVER), &ugd)) {
971 return (LIBUSB20_ERROR_INVALID_PARAM);
977 ugen20_dev_get_info(struct libusb20_device *pdev,
978 struct usb_device_info *pinfo)
980 if (ioctl(pdev->file, IOUSB(USB_GET_DEVICEINFO), pinfo)) {
981 return (LIBUSB20_ERROR_INVALID_PARAM);
987 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
988 uint16_t quirk_index, struct libusb20_quirk *pq)
990 struct usb_gen_quirk q;
993 memset(&q, 0, sizeof(q));
995 q.index = quirk_index;
997 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_GET), &q);
1000 if (errno == EINVAL) {
1001 return (LIBUSB20_ERROR_NOT_FOUND);
1006 pq->bcdDeviceLow = q.bcdDeviceLow;
1007 pq->bcdDeviceHigh = q.bcdDeviceHigh;
1008 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
1014 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
1015 struct libusb20_quirk *pq)
1017 struct usb_gen_quirk q;
1020 memset(&q, 0, sizeof(q));
1022 q.index = quirk_index;
1024 error = ugen20_be_ioctl(IOUSB(USB_QUIRK_NAME_GET), &q);
1027 if (errno == EINVAL) {
1028 return (LIBUSB20_ERROR_NOT_FOUND);
1031 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
1037 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
1038 struct libusb20_quirk *pq)
1040 struct usb_gen_quirk q;
1043 memset(&q, 0, sizeof(q));
1047 q.bcdDeviceLow = pq->bcdDeviceLow;
1048 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1049 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1051 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_ADD), &q);
1053 if (errno == ENOMEM) {
1054 return (LIBUSB20_ERROR_NO_MEM);
1061 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
1062 struct libusb20_quirk *pq)
1064 struct usb_gen_quirk q;
1067 memset(&q, 0, sizeof(q));
1071 q.bcdDeviceLow = pq->bcdDeviceLow;
1072 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1073 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1075 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_REMOVE), &q);
1077 if (errno == EINVAL) {
1078 return (LIBUSB20_ERROR_NOT_FOUND);
1085 ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
1087 return (ugen20_be_ioctl(IOUSB(USB_SET_TEMPLATE), &temp));
1091 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
1093 return (ugen20_be_ioctl(IOUSB(USB_GET_TEMPLATE), ptemp));