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_power_usage_t ugen20_get_power_usage;
81 static libusb20_kernel_driver_active_t ugen20_kernel_driver_active;
82 static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver;
83 static libusb20_do_request_sync_t ugen20_do_request_sync;
84 static libusb20_process_t ugen20_process;
86 /* USB transfer specific */
87 static libusb20_tr_open_t ugen20_tr_open;
88 static libusb20_tr_close_t ugen20_tr_close;
89 static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync;
90 static libusb20_tr_submit_t ugen20_tr_submit;
91 static libusb20_tr_cancel_async_t ugen20_tr_cancel_async;
93 static const struct libusb20_device_methods libusb20_ugen20_device_methods = {
94 LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20)
98 ugen20_get_backend_name(void)
100 return ("FreeBSD UGEN 2.0");
104 ugen20_path_convert_one(const char **pp)
111 while ((*ptr >= '0') && (*ptr <= '9')) {
113 temp += (*ptr - '0');
114 if (temp >= 1000000) {
115 /* catch overflow early */
131 ugen20_enumerate(struct libusb20_device *pdev, const char *id)
133 const char *tmp = id;
134 struct usb_device_descriptor ddesc;
135 struct usb_device_info devinfo;
136 struct usb_device_port_path udpp;
142 pdev->bus_number = ugen20_path_convert_one(&tmp);
143 pdev->device_address = ugen20_path_convert_one(&tmp);
145 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
146 pdev->bus_number, pdev->device_address);
148 f = open(buf, O_RDWR);
150 return (LIBUSB20_ERROR_OTHER);
152 if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
153 error = LIBUSB20_ERROR_OTHER;
156 /* store when the device was plugged */
157 pdev->session_data.plugtime = plugtime;
159 if (ioctl(f, IOUSB(USB_GET_DEVICE_DESC), &ddesc)) {
160 error = LIBUSB20_ERROR_OTHER;
163 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
165 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
167 if (pdev->ddesc.bNumConfigurations == 0) {
168 error = LIBUSB20_ERROR_OTHER;
170 } else if (pdev->ddesc.bNumConfigurations >= 8) {
171 error = LIBUSB20_ERROR_OTHER;
174 if (ioctl(f, IOUSB(USB_GET_DEVICEINFO), &devinfo)) {
175 error = LIBUSB20_ERROR_OTHER;
178 switch (devinfo.udi_mode) {
179 case USB_MODE_DEVICE:
180 pdev->usb_mode = LIBUSB20_MODE_DEVICE;
183 pdev->usb_mode = LIBUSB20_MODE_HOST;
187 switch (devinfo.udi_speed) {
189 pdev->usb_speed = LIBUSB20_SPEED_LOW;
192 pdev->usb_speed = LIBUSB20_SPEED_FULL;
195 pdev->usb_speed = LIBUSB20_SPEED_HIGH;
197 case USB_SPEED_VARIABLE:
198 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
200 case USB_SPEED_SUPER:
201 pdev->usb_speed = LIBUSB20_SPEED_SUPER;
204 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
208 /* get parent HUB index and port */
210 pdev->parent_address = devinfo.udi_hubindex;
211 pdev->parent_port = devinfo.udi_hubport;
213 /* generate a nice description for printout */
215 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
216 USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
217 pdev->device_address, devinfo.udi_vendor,
218 devinfo.udi_product, pdev->bus_number);
220 /* get device port path, if any */
221 if (ioctl(f, IOUSB(USB_GET_DEV_PORT_PATH), &udpp) == 0 &&
222 udpp.udp_port_level < LIBUSB20_DEVICE_PORT_PATH_MAX) {
223 memcpy(pdev->port_path, udpp.udp_port_no, udpp.udp_port_level);
224 pdev->port_level = udpp.udp_port_level;
233 struct ugen20_urd_state {
234 struct usb_read_dir urd;
241 uint8_t dummy_zero[1];
245 ugen20_readdir(struct ugen20_urd_state *st)
249 if (st->ptr == NULL) {
250 st->urd.urd_startentry += st->nparsed;
251 st->urd.urd_data = libusb20_pass_ptr(st->buf);
252 st->urd.urd_maxlen = sizeof(st->buf);
255 if (ioctl(st->f, IOUSB(USB_READ_DIR), &st->urd)) {
260 if (st->ptr[0] == 0) {
268 st->src = (void *)(st->ptr + 1);
269 st->dst = st->src + strlen(st->src) + 1;
270 st->ptr = st->ptr + st->ptr[0];
273 if ((st->ptr < st->buf) ||
274 (st->ptr > st->dummy_zero)) {
282 ugen20_init_backend(struct libusb20_backend *pbe)
284 struct ugen20_urd_state state;
285 struct libusb20_device *pdev;
287 memset(&state, 0, sizeof(state));
289 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
291 return (LIBUSB20_ERROR_OTHER);
293 while (ugen20_readdir(&state) == 0) {
295 if ((state.src[0] != 'u') ||
296 (state.src[1] != 'g') ||
297 (state.src[2] != 'e') ||
298 (state.src[3] != 'n')) {
301 pdev = libusb20_dev_alloc();
305 if (ugen20_enumerate(pdev, state.src + 4)) {
306 libusb20_dev_free(pdev);
309 /* put the device on the backend list */
310 libusb20_be_enqueue_device(pbe, pdev);
313 return (0); /* success */
317 ugen20_tr_release(struct libusb20_device *pdev)
319 struct usb_fs_uninit fs_uninit;
321 if (pdev->nTransfer == 0) {
324 /* release all pending USB transfers */
325 if (pdev->privBeData != NULL) {
326 memset(&fs_uninit, 0, sizeof(fs_uninit));
327 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) {
328 /* ignore any errors of this kind */
335 ugen20_tr_renew(struct libusb20_device *pdev)
337 struct usb_fs_init fs_init;
338 struct usb_fs_endpoint *pfse;
341 uint16_t nMaxTransfer;
343 nMaxTransfer = pdev->nTransfer;
346 if (nMaxTransfer == 0) {
349 size = nMaxTransfer * sizeof(*pfse);
351 if (pdev->privBeData == NULL) {
354 error = LIBUSB20_ERROR_NO_MEM;
357 pdev->privBeData = pfse;
359 /* reset endpoint data */
360 memset(pdev->privBeData, 0, size);
362 memset(&fs_init, 0, sizeof(fs_init));
364 fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData);
365 fs_init.ep_index_max = nMaxTransfer;
367 if (ioctl(pdev->file, IOUSB(USB_FS_INIT), &fs_init)) {
368 error = LIBUSB20_ERROR_OTHER;
376 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
384 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
385 pdev->bus_number, pdev->device_address);
388 * We need two file handles, one for the control endpoint and one
389 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
392 g = open(buf, O_RDWR);
394 return (LIBUSB20_ERROR_NO_DEVICE);
396 f = open(buf, O_RDWR);
399 return (LIBUSB20_ERROR_NO_DEVICE);
401 if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
402 error = LIBUSB20_ERROR_OTHER;
405 /* check that the correct device is still plugged */
406 if (pdev->session_data.plugtime != plugtime) {
407 error = LIBUSB20_ERROR_NO_DEVICE;
410 /* need to set this before "tr_renew()" */
414 /* renew all USB transfers */
415 error = ugen20_tr_renew(pdev);
420 pdev->methods = &libusb20_ugen20_device_methods;
424 if (pdev->privBeData) {
425 /* cleanup after "tr_renew()" */
426 free(pdev->privBeData);
427 pdev->privBeData = NULL;
430 pdev->file_ctrl = -1;
438 ugen20_close_device(struct libusb20_device *pdev)
440 struct usb_fs_uninit fs_uninit;
442 if (pdev->privBeData) {
443 memset(&fs_uninit, 0, sizeof(fs_uninit));
444 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) {
445 /* ignore this error */
447 free(pdev->privBeData);
450 pdev->privBeData = NULL;
452 close(pdev->file_ctrl);
454 pdev->file_ctrl = -1;
455 return (0); /* success */
459 ugen20_exit_backend(struct libusb20_backend *pbe)
461 return; /* nothing to do */
465 ugen20_get_config_desc_full(struct libusb20_device *pdev,
466 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
468 struct usb_gen_descriptor gen_desc;
469 struct usb_config_descriptor cdesc;
474 /* make sure memory is initialised */
475 memset(&cdesc, 0, sizeof(cdesc));
476 memset(&gen_desc, 0, sizeof(gen_desc));
478 gen_desc.ugd_data = libusb20_pass_ptr(&cdesc);
479 gen_desc.ugd_maxlen = sizeof(cdesc);
480 gen_desc.ugd_config_index = cfg_index;
482 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc);
484 return (LIBUSB20_ERROR_OTHER);
486 len = UGETW(cdesc.wTotalLength);
487 if (len < sizeof(cdesc)) {
488 /* corrupt descriptor */
489 return (LIBUSB20_ERROR_OTHER);
493 return (LIBUSB20_ERROR_NO_MEM);
496 /* make sure memory is initialised */
499 gen_desc.ugd_data = libusb20_pass_ptr(ptr);
500 gen_desc.ugd_maxlen = len;
502 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc);
505 return (LIBUSB20_ERROR_OTHER);
507 /* make sure that the device doesn't fool us */
508 memcpy(ptr, &cdesc, sizeof(cdesc));
513 return (0); /* success */
517 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
521 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_CONFIG), &temp)) {
522 return (LIBUSB20_ERROR_OTHER);
530 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
532 int temp = cfg_index;
534 /* release all active USB transfers */
535 ugen20_tr_release(pdev);
537 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_CONFIG), &temp)) {
538 return (LIBUSB20_ERROR_OTHER);
540 return (ugen20_tr_renew(pdev));
544 ugen20_set_alt_index(struct libusb20_device *pdev,
545 uint8_t iface_index, uint8_t alt_index)
547 struct usb_alt_interface alt_iface;
549 memset(&alt_iface, 0, sizeof(alt_iface));
551 alt_iface.uai_interface_index = iface_index;
552 alt_iface.uai_alt_index = alt_index;
554 /* release all active USB transfers */
555 ugen20_tr_release(pdev);
557 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_ALTINTERFACE), &alt_iface)) {
558 return (LIBUSB20_ERROR_OTHER);
560 return (ugen20_tr_renew(pdev));
564 ugen20_reset_device(struct libusb20_device *pdev)
568 /* release all active USB transfers */
569 ugen20_tr_release(pdev);
571 if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICEENUMERATE), &temp)) {
572 return (LIBUSB20_ERROR_OTHER);
574 return (ugen20_tr_renew(pdev));
578 ugen20_check_connected(struct libusb20_device *pdev)
583 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_PLUGTIME), &plugtime)) {
584 error = LIBUSB20_ERROR_NO_DEVICE;
588 if (pdev->session_data.plugtime != plugtime) {
589 error = LIBUSB20_ERROR_NO_DEVICE;
597 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
601 switch (power_mode) {
602 case LIBUSB20_POWER_OFF:
603 temp = USB_POWER_MODE_OFF;
605 case LIBUSB20_POWER_ON:
606 temp = USB_POWER_MODE_ON;
608 case LIBUSB20_POWER_SAVE:
609 temp = USB_POWER_MODE_SAVE;
611 case LIBUSB20_POWER_SUSPEND:
612 temp = USB_POWER_MODE_SUSPEND;
614 case LIBUSB20_POWER_RESUME:
615 temp = USB_POWER_MODE_RESUME;
618 return (LIBUSB20_ERROR_INVALID_PARAM);
620 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_POWER_MODE), &temp)) {
621 return (LIBUSB20_ERROR_OTHER);
627 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
631 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_MODE), &temp)) {
632 return (LIBUSB20_ERROR_OTHER);
635 case USB_POWER_MODE_OFF:
636 temp = LIBUSB20_POWER_OFF;
638 case USB_POWER_MODE_ON:
639 temp = LIBUSB20_POWER_ON;
641 case USB_POWER_MODE_SAVE:
642 temp = LIBUSB20_POWER_SAVE;
644 case USB_POWER_MODE_SUSPEND:
645 temp = LIBUSB20_POWER_SUSPEND;
647 case USB_POWER_MODE_RESUME:
648 temp = LIBUSB20_POWER_RESUME;
651 temp = LIBUSB20_POWER_ON;
655 return (0); /* success */
659 ugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage)
663 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_USAGE), &temp)) {
664 return (LIBUSB20_ERROR_OTHER);
667 return (0); /* success */
671 ugen20_kernel_driver_active(struct libusb20_device *pdev,
674 int temp = iface_index;
676 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ACTIVE), &temp)) {
677 return (LIBUSB20_ERROR_OTHER);
679 return (0); /* kernel driver is active */
683 ugen20_detach_kernel_driver(struct libusb20_device *pdev,
686 int temp = iface_index;
688 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_DETACH), &temp)) {
689 return (LIBUSB20_ERROR_OTHER);
691 return (0); /* kernel driver is detached */
695 ugen20_do_request_sync(struct libusb20_device *pdev,
696 struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
697 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
699 struct usb_ctl_request req;
701 memset(&req, 0, sizeof(req));
703 req.ucr_data = libusb20_pass_ptr(data);
704 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
705 req.ucr_flags |= USB_SHORT_XFER_OK;
707 if (libusb20_me_encode(&req.ucr_request,
708 sizeof(req.ucr_request), setup)) {
711 if (ioctl(pdev->file_ctrl, IOUSB(USB_DO_REQUEST), &req)) {
712 return (LIBUSB20_ERROR_OTHER);
715 /* get actual length */
716 *pactlen = req.ucr_actlen;
718 return (0); /* request was successful */
722 ugen20_process(struct libusb20_device *pdev)
724 struct usb_fs_complete temp;
725 struct usb_fs_endpoint *fsep;
726 struct libusb20_transfer *xfer;
730 if (ioctl(pdev->file, IOUSB(USB_FS_COMPLETE), &temp)) {
731 if (errno == EBUSY) {
734 /* device detached */
735 return (LIBUSB20_ERROR_OTHER);
738 fsep = pdev->privBeData;
739 xfer = pdev->pTransfer;
740 fsep += temp.ep_index;
741 xfer += temp.ep_index;
743 /* update transfer status */
745 if (fsep->status == 0) {
746 xfer->aFrames = fsep->aFrames;
747 xfer->timeComplete = fsep->isoc_time_complete;
748 xfer->status = LIBUSB20_TRANSFER_COMPLETED;
749 } else if (fsep->status == USB_ERR_CANCELLED) {
751 xfer->timeComplete = 0;
752 xfer->status = LIBUSB20_TRANSFER_CANCELLED;
753 } else if (fsep->status == USB_ERR_STALLED) {
755 xfer->timeComplete = 0;
756 xfer->status = LIBUSB20_TRANSFER_STALL;
757 } else if (fsep->status == USB_ERR_TIMEOUT) {
759 xfer->timeComplete = 0;
760 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
763 xfer->timeComplete = 0;
764 xfer->status = LIBUSB20_TRANSFER_ERROR;
766 libusb20_tr_callback_wrapper(xfer);
768 return (0); /* done */
772 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
773 uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id,
777 struct usb_fs_open fs_open;
778 struct usb_fs_open_stream fs_open_stream;
780 struct usb_fs_endpoint *fsep;
783 MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE;
785 memset(&temp, 0, sizeof(temp));
787 fsep = xfer->pdev->privBeData;
788 fsep += xfer->trIndex;
790 temp.fs_open.max_bufsize = MaxBufSize;
791 temp.fs_open.max_frames = MaxFrameCount;
792 temp.fs_open.ep_index = xfer->trIndex;
793 temp.fs_open.ep_no = ep_no;
795 if (stream_id != 0) {
796 temp.fs_open_stream.stream_id = stream_id;
798 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN_STREAM), &temp.fs_open_stream))
799 return (LIBUSB20_ERROR_INVALID_PARAM);
801 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN), &temp.fs_open))
802 return (LIBUSB20_ERROR_INVALID_PARAM);
804 /* maximums might have changed - update */
805 xfer->maxFrames = temp.fs_open.max_frames;
807 /* "max_bufsize" should be multiple of "max_packet_length" */
808 xfer->maxTotalLength = temp.fs_open.max_bufsize;
809 xfer->maxPacketLen = temp.fs_open.max_packet_length;
811 /* setup buffer and length lists using zero copy */
812 fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer);
813 fsep->pLength = libusb20_pass_ptr(xfer->pLength);
815 return (0); /* success */
819 ugen20_tr_close(struct libusb20_transfer *xfer)
821 struct usb_fs_close temp;
823 memset(&temp, 0, sizeof(temp));
825 temp.ep_index = xfer->trIndex;
827 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLOSE), &temp)) {
828 return (LIBUSB20_ERROR_INVALID_PARAM);
830 return (0); /* success */
834 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
836 struct usb_fs_clear_stall_sync temp;
838 memset(&temp, 0, sizeof(temp));
840 /* if the transfer is active, an error will be returned */
842 temp.ep_index = xfer->trIndex;
844 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLEAR_STALL_SYNC), &temp)) {
845 return (LIBUSB20_ERROR_INVALID_PARAM);
847 return (0); /* success */
851 ugen20_tr_submit(struct libusb20_transfer *xfer)
853 struct usb_fs_start temp;
854 struct usb_fs_endpoint *fsep;
856 memset(&temp, 0, sizeof(temp));
858 fsep = xfer->pdev->privBeData;
859 fsep += xfer->trIndex;
861 fsep->nFrames = xfer->nFrames;
863 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
864 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
866 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
867 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
869 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
870 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
872 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
873 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
875 /* NOTE: The "fsep->timeout" variable is 16-bit. */
876 if (xfer->timeout > 65535)
877 fsep->timeout = 65535;
879 fsep->timeout = xfer->timeout;
881 temp.ep_index = xfer->trIndex;
883 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_START), &temp)) {
884 /* ignore any errors - should never happen */
886 return; /* success */
890 ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
892 struct usb_fs_stop temp;
894 memset(&temp, 0, sizeof(temp));
896 temp.ep_index = xfer->trIndex;
898 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_STOP), &temp)) {
899 /* ignore any errors - should never happen */
905 ugen20_be_ioctl(uint32_t cmd, void *data)
910 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
912 return (LIBUSB20_ERROR_OTHER);
913 error = ioctl(f, cmd, data);
915 if (errno == EPERM) {
916 error = LIBUSB20_ERROR_ACCESS;
918 error = LIBUSB20_ERROR_OTHER;
926 ugen20_dev_get_iface_desc(struct libusb20_device *pdev,
927 uint8_t iface_index, char *buf, uint8_t len)
929 struct usb_gen_descriptor ugd;
931 memset(&ugd, 0, sizeof(ugd));
933 ugd.ugd_data = libusb20_pass_ptr(buf);
934 ugd.ugd_maxlen = len;
935 ugd.ugd_iface_index = iface_index;
937 if (ioctl(pdev->file, IOUSB(USB_GET_IFACE_DRIVER), &ugd)) {
938 return (LIBUSB20_ERROR_INVALID_PARAM);
944 ugen20_dev_get_info(struct libusb20_device *pdev,
945 struct usb_device_info *pinfo)
947 if (ioctl(pdev->file, IOUSB(USB_GET_DEVICEINFO), pinfo)) {
948 return (LIBUSB20_ERROR_INVALID_PARAM);
954 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
955 uint16_t quirk_index, struct libusb20_quirk *pq)
957 struct usb_gen_quirk q;
960 memset(&q, 0, sizeof(q));
962 q.index = quirk_index;
964 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_GET), &q);
967 if (errno == EINVAL) {
968 return (LIBUSB20_ERROR_NOT_FOUND);
973 pq->bcdDeviceLow = q.bcdDeviceLow;
974 pq->bcdDeviceHigh = q.bcdDeviceHigh;
975 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
981 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
982 struct libusb20_quirk *pq)
984 struct usb_gen_quirk q;
987 memset(&q, 0, sizeof(q));
989 q.index = quirk_index;
991 error = ugen20_be_ioctl(IOUSB(USB_QUIRK_NAME_GET), &q);
994 if (errno == EINVAL) {
995 return (LIBUSB20_ERROR_NOT_FOUND);
998 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
1004 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
1005 struct libusb20_quirk *pq)
1007 struct usb_gen_quirk q;
1010 memset(&q, 0, sizeof(q));
1014 q.bcdDeviceLow = pq->bcdDeviceLow;
1015 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1016 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1018 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_ADD), &q);
1020 if (errno == ENOMEM) {
1021 return (LIBUSB20_ERROR_NO_MEM);
1028 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
1029 struct libusb20_quirk *pq)
1031 struct usb_gen_quirk q;
1034 memset(&q, 0, sizeof(q));
1038 q.bcdDeviceLow = pq->bcdDeviceLow;
1039 q.bcdDeviceHigh = pq->bcdDeviceHigh;
1040 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
1042 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_REMOVE), &q);
1044 if (errno == EINVAL) {
1045 return (LIBUSB20_ERROR_NOT_FOUND);
1052 ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
1054 return (ugen20_be_ioctl(IOUSB(USB_SET_TEMPLATE), &temp));
1058 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
1060 return (ugen20_be_ioctl(IOUSB(USB_GET_TEMPLATE), ptemp));