1 /* $FreeBSD: head/lib/libusb/libusb20_ugen20.c 255242 2013-09-05 12:21:11Z hselasky $ */
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 <bus/u4b/usb.h>
42 #include <bus/u4b/usbdi.h>
43 #include <bus/u4b/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_kernel_driver_active_t ugen20_kernel_driver_active
;
83 static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver
;
84 static libusb20_do_request_sync_t ugen20_do_request_sync
;
85 static libusb20_process_t ugen20_process
;
87 /* USB transfer specific */
88 static libusb20_tr_open_t ugen20_tr_open
;
89 static libusb20_tr_close_t ugen20_tr_close
;
90 static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync
;
91 static libusb20_tr_submit_t ugen20_tr_submit
;
92 static libusb20_tr_cancel_async_t ugen20_tr_cancel_async
;
94 static const struct libusb20_device_methods libusb20_ugen20_device_methods
= {
95 LIBUSB20_DEVICE(LIBUSB20_DECLARE
, ugen20
)
99 ugen20_get_backend_name(void)
101 return ("FreeBSD UGEN 2.0");
105 ugen20_path_convert_one(const char **pp
)
112 while ((*ptr
>= '0') && (*ptr
<= '9')) {
114 temp
+= (*ptr
- '0');
115 if (temp
>= 1000000) {
116 /* catch overflow early */
132 ugen20_enumerate(struct libusb20_device
*pdev
, const char *id
)
134 const char *tmp
= id
;
135 struct usb_device_descriptor ddesc
;
136 struct usb_device_info devinfo
;
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_product
,
218 devinfo
.udi_vendor
, pdev
->bus_number
);
226 struct ugen20_urd_state
{
227 struct usb_read_dir urd
;
234 uint8_t dummy_zero
[1];
238 ugen20_readdir(struct ugen20_urd_state
*st
)
242 if (st
->ptr
== NULL
) {
243 st
->urd
.urd_startentry
+= st
->nparsed
;
244 st
->urd
.urd_data
= libusb20_pass_ptr(st
->buf
);
245 st
->urd
.urd_maxlen
= sizeof(st
->buf
);
248 if (ioctl(st
->f
, IOUSB(USB_READ_DIR
), &st
->urd
)) {
253 if (st
->ptr
[0] == 0) {
261 st
->src
= (void *)(st
->ptr
+ 1);
262 st
->dst
= st
->src
+ strlen(st
->src
) + 1;
263 st
->ptr
= st
->ptr
+ st
->ptr
[0];
266 if ((st
->ptr
< st
->buf
) ||
267 (st
->ptr
> st
->dummy_zero
)) {
275 ugen20_init_backend(struct libusb20_backend
*pbe
)
277 struct ugen20_urd_state state
;
278 struct libusb20_device
*pdev
;
280 memset(&state
, 0, sizeof(state
));
282 state
.f
= open("/dev/" USB_DEVICE_NAME
, O_RDONLY
);
284 return (LIBUSB20_ERROR_OTHER
);
286 while (ugen20_readdir(&state
) == 0) {
288 if ((state
.src
[0] != 'u') ||
289 (state
.src
[1] != 'g') ||
290 (state
.src
[2] != 'e') ||
291 (state
.src
[3] != 'n')) {
294 pdev
= libusb20_dev_alloc();
298 if (ugen20_enumerate(pdev
, state
.src
+ 4)) {
299 libusb20_dev_free(pdev
);
302 /* put the device on the backend list */
303 libusb20_be_enqueue_device(pbe
, pdev
);
306 return (0); /* success */
310 ugen20_tr_release(struct libusb20_device
*pdev
)
312 struct usb_fs_uninit fs_uninit
;
314 if (pdev
->nTransfer
== 0) {
317 /* release all pending USB transfers */
318 if (pdev
->privBeData
!= NULL
) {
319 memset(&fs_uninit
, 0, sizeof(fs_uninit
));
320 if (ioctl(pdev
->file
, IOUSB(USB_FS_UNINIT
), &fs_uninit
)) {
321 /* ignore any errors of this kind */
328 ugen20_tr_renew(struct libusb20_device
*pdev
)
330 struct usb_fs_init fs_init
;
331 struct usb_fs_endpoint
*pfse
;
334 uint16_t nMaxTransfer
;
336 nMaxTransfer
= pdev
->nTransfer
;
339 if (nMaxTransfer
== 0) {
342 size
= nMaxTransfer
* sizeof(*pfse
);
344 if (pdev
->privBeData
== NULL
) {
347 error
= LIBUSB20_ERROR_NO_MEM
;
350 pdev
->privBeData
= pfse
;
352 /* reset endpoint data */
353 memset(pdev
->privBeData
, 0, size
);
355 memset(&fs_init
, 0, sizeof(fs_init
));
357 fs_init
.pEndpoints
= libusb20_pass_ptr(pdev
->privBeData
);
358 fs_init
.ep_index_max
= nMaxTransfer
;
360 if (ioctl(pdev
->file
, IOUSB(USB_FS_INIT
), &fs_init
)) {
361 error
= LIBUSB20_ERROR_OTHER
;
369 ugen20_open_device(struct libusb20_device
*pdev
, uint16_t nMaxTransfer
)
377 snprintf(buf
, sizeof(buf
), "/dev/" USB_GENERIC_NAME
"%u.%u",
378 pdev
->bus_number
, pdev
->device_address
);
381 * We need two file handles, one for the control endpoint and one
382 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
385 g
= open(buf
, O_RDWR
);
387 return (LIBUSB20_ERROR_NO_DEVICE
);
389 f
= open(buf
, O_RDWR
);
392 return (LIBUSB20_ERROR_NO_DEVICE
);
394 if (ioctl(f
, IOUSB(USB_GET_PLUGTIME
), &plugtime
)) {
395 error
= LIBUSB20_ERROR_OTHER
;
398 /* check that the correct device is still plugged */
399 if (pdev
->session_data
.plugtime
!= plugtime
) {
400 error
= LIBUSB20_ERROR_NO_DEVICE
;
403 /* need to set this before "tr_renew()" */
407 /* renew all USB transfers */
408 error
= ugen20_tr_renew(pdev
);
413 pdev
->methods
= &libusb20_ugen20_device_methods
;
417 if (pdev
->privBeData
) {
418 /* cleanup after "tr_renew()" */
419 free(pdev
->privBeData
);
420 pdev
->privBeData
= NULL
;
423 pdev
->file_ctrl
= -1;
431 ugen20_close_device(struct libusb20_device
*pdev
)
433 struct usb_fs_uninit fs_uninit
;
435 if (pdev
->privBeData
) {
436 memset(&fs_uninit
, 0, sizeof(fs_uninit
));
437 if (ioctl(pdev
->file
, IOUSB(USB_FS_UNINIT
), &fs_uninit
)) {
438 /* ignore this error */
440 free(pdev
->privBeData
);
443 pdev
->privBeData
= NULL
;
445 close(pdev
->file_ctrl
);
447 pdev
->file_ctrl
= -1;
448 return (0); /* success */
452 ugen20_exit_backend(struct libusb20_backend
*pbe
)
454 return; /* nothing to do */
458 ugen20_get_config_desc_full(struct libusb20_device
*pdev
,
459 uint8_t **ppbuf
, uint16_t *plen
, uint8_t cfg_index
)
461 struct usb_gen_descriptor gen_desc
;
462 struct usb_config_descriptor cdesc
;
467 /* make sure memory is initialised */
468 memset(&cdesc
, 0, sizeof(cdesc
));
469 memset(&gen_desc
, 0, sizeof(gen_desc
));
471 gen_desc
.ugd_data
= libusb20_pass_ptr(&cdesc
);
472 gen_desc
.ugd_maxlen
= sizeof(cdesc
);
473 gen_desc
.ugd_config_index
= cfg_index
;
475 error
= ioctl(pdev
->file_ctrl
, IOUSB(USB_GET_FULL_DESC
), &gen_desc
);
477 return (LIBUSB20_ERROR_OTHER
);
479 len
= UGETW(cdesc
.wTotalLength
);
480 if (len
< sizeof(cdesc
)) {
481 /* corrupt descriptor */
482 return (LIBUSB20_ERROR_OTHER
);
486 return (LIBUSB20_ERROR_NO_MEM
);
489 /* make sure memory is initialised */
492 gen_desc
.ugd_data
= libusb20_pass_ptr(ptr
);
493 gen_desc
.ugd_maxlen
= len
;
495 error
= ioctl(pdev
->file_ctrl
, IOUSB(USB_GET_FULL_DESC
), &gen_desc
);
498 return (LIBUSB20_ERROR_OTHER
);
500 /* make sure that the device doesn't fool us */
501 memcpy(ptr
, &cdesc
, sizeof(cdesc
));
506 return (0); /* success */
510 ugen20_get_config_index(struct libusb20_device
*pdev
, uint8_t *pindex
)
514 if (ioctl(pdev
->file_ctrl
, IOUSB(USB_GET_CONFIG
), &temp
)) {
515 return (LIBUSB20_ERROR_OTHER
);
523 ugen20_set_config_index(struct libusb20_device
*pdev
, uint8_t cfg_index
)
525 int temp
= cfg_index
;
527 /* release all active USB transfers */
528 ugen20_tr_release(pdev
);
530 if (ioctl(pdev
->file_ctrl
, IOUSB(USB_SET_CONFIG
), &temp
)) {
531 return (LIBUSB20_ERROR_OTHER
);
533 return (ugen20_tr_renew(pdev
));
537 ugen20_set_alt_index(struct libusb20_device
*pdev
,
538 uint8_t iface_index
, uint8_t alt_index
)
540 struct usb_alt_interface alt_iface
;
542 memset(&alt_iface
, 0, sizeof(alt_iface
));
544 alt_iface
.uai_interface_index
= iface_index
;
545 alt_iface
.uai_alt_index
= alt_index
;
547 /* release all active USB transfers */
548 ugen20_tr_release(pdev
);
550 if (ioctl(pdev
->file_ctrl
, IOUSB(USB_SET_ALTINTERFACE
), &alt_iface
)) {
551 return (LIBUSB20_ERROR_OTHER
);
553 return (ugen20_tr_renew(pdev
));
557 ugen20_reset_device(struct libusb20_device
*pdev
)
561 /* release all active USB transfers */
562 ugen20_tr_release(pdev
);
564 if (ioctl(pdev
->file_ctrl
, IOUSB(USB_DEVICEENUMERATE
), &temp
)) {
565 return (LIBUSB20_ERROR_OTHER
);
567 return (ugen20_tr_renew(pdev
));
571 ugen20_check_connected(struct libusb20_device
*pdev
)
576 if (ioctl(pdev
->file_ctrl
, IOUSB(USB_GET_PLUGTIME
), &plugtime
)) {
577 error
= LIBUSB20_ERROR_NO_DEVICE
;
581 if (pdev
->session_data
.plugtime
!= plugtime
) {
582 error
= LIBUSB20_ERROR_NO_DEVICE
;
590 ugen20_set_power_mode(struct libusb20_device
*pdev
, uint8_t power_mode
)
594 switch (power_mode
) {
595 case LIBUSB20_POWER_OFF
:
596 temp
= USB_POWER_MODE_OFF
;
598 case LIBUSB20_POWER_ON
:
599 temp
= USB_POWER_MODE_ON
;
601 case LIBUSB20_POWER_SAVE
:
602 temp
= USB_POWER_MODE_SAVE
;
604 case LIBUSB20_POWER_SUSPEND
:
605 temp
= USB_POWER_MODE_SUSPEND
;
607 case LIBUSB20_POWER_RESUME
:
608 temp
= USB_POWER_MODE_RESUME
;
611 return (LIBUSB20_ERROR_INVALID_PARAM
);
613 if (ioctl(pdev
->file_ctrl
, IOUSB(USB_SET_POWER_MODE
), &temp
)) {
614 return (LIBUSB20_ERROR_OTHER
);
620 ugen20_get_power_mode(struct libusb20_device
*pdev
, uint8_t *power_mode
)
624 if (ioctl(pdev
->file_ctrl
, IOUSB(USB_GET_POWER_MODE
), &temp
)) {
625 return (LIBUSB20_ERROR_OTHER
);
628 case USB_POWER_MODE_OFF
:
629 temp
= LIBUSB20_POWER_OFF
;
631 case USB_POWER_MODE_ON
:
632 temp
= LIBUSB20_POWER_ON
;
634 case USB_POWER_MODE_SAVE
:
635 temp
= LIBUSB20_POWER_SAVE
;
637 case USB_POWER_MODE_SUSPEND
:
638 temp
= LIBUSB20_POWER_SUSPEND
;
640 case USB_POWER_MODE_RESUME
:
641 temp
= LIBUSB20_POWER_RESUME
;
644 temp
= LIBUSB20_POWER_ON
;
648 return (0); /* success */
652 ugen20_get_port_path(struct libusb20_device
*pdev
, uint8_t *buf
, uint8_t bufsize
)
654 struct usb_device_port_path udpp
;
656 if (ioctl(pdev
->file_ctrl
, IOUSB(USB_GET_DEV_PORT_PATH
), &udpp
))
657 return (LIBUSB20_ERROR_OTHER
);
659 if (udpp
.udp_port_level
> bufsize
)
660 return (LIBUSB20_ERROR_OVERFLOW
);
662 memcpy(buf
, udpp
.udp_port_no
, udpp
.udp_port_level
);
664 return (udpp
.udp_port_level
); /* success */
668 ugen20_get_power_usage(struct libusb20_device
*pdev
, uint16_t *power_usage
)
672 if (ioctl(pdev
->file_ctrl
, IOUSB(USB_GET_POWER_USAGE
), &temp
)) {
673 return (LIBUSB20_ERROR_OTHER
);
676 return (0); /* success */
680 ugen20_kernel_driver_active(struct libusb20_device
*pdev
,
683 int temp
= iface_index
;
685 if (ioctl(pdev
->file_ctrl
, IOUSB(USB_IFACE_DRIVER_ACTIVE
), &temp
)) {
686 return (LIBUSB20_ERROR_OTHER
);
688 return (0); /* kernel driver is active */
692 ugen20_detach_kernel_driver(struct libusb20_device
*pdev
,
695 int temp
= iface_index
;
697 if (ioctl(pdev
->file_ctrl
, IOUSB(USB_IFACE_DRIVER_DETACH
), &temp
)) {
698 return (LIBUSB20_ERROR_OTHER
);
700 return (0); /* kernel driver is detached */
704 ugen20_do_request_sync(struct libusb20_device
*pdev
,
705 struct LIBUSB20_CONTROL_SETUP_DECODED
*setup
,
706 void *data
, uint16_t *pactlen
, uint32_t timeout
, uint8_t flags
)
708 struct usb_ctl_request req
;
710 memset(&req
, 0, sizeof(req
));
712 req
.ucr_data
= libusb20_pass_ptr(data
);
713 if (!(flags
& LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK
)) {
714 req
.ucr_flags
|= USB_SHORT_XFER_OK
;
716 if (libusb20_me_encode(&req
.ucr_request
,
717 sizeof(req
.ucr_request
), setup
)) {
720 if (ioctl(pdev
->file_ctrl
, IOUSB(USB_DO_REQUEST
), &req
)) {
721 return (LIBUSB20_ERROR_OTHER
);
724 /* get actual length */
725 *pactlen
= req
.ucr_actlen
;
727 return (0); /* request was successful */
731 ugen20_process(struct libusb20_device
*pdev
)
733 struct usb_fs_complete temp
;
734 struct usb_fs_endpoint
*fsep
;
735 struct libusb20_transfer
*xfer
;
739 if (ioctl(pdev
->file
, IOUSB(USB_FS_COMPLETE
), &temp
)) {
740 if (errno
== EBUSY
) {
743 /* device detached */
744 return (LIBUSB20_ERROR_OTHER
);
747 fsep
= pdev
->privBeData
;
748 xfer
= pdev
->pTransfer
;
749 fsep
+= temp
.ep_index
;
750 xfer
+= temp
.ep_index
;
752 /* update transfer status */
754 if (fsep
->status
== 0) {
755 xfer
->aFrames
= fsep
->aFrames
;
756 xfer
->timeComplete
= fsep
->isoc_time_complete
;
757 xfer
->status
= LIBUSB20_TRANSFER_COMPLETED
;
758 } else if (fsep
->status
== USB_ERR_CANCELLED
) {
760 xfer
->timeComplete
= 0;
761 xfer
->status
= LIBUSB20_TRANSFER_CANCELLED
;
762 } else if (fsep
->status
== USB_ERR_STALLED
) {
764 xfer
->timeComplete
= 0;
765 xfer
->status
= LIBUSB20_TRANSFER_STALL
;
766 } else if (fsep
->status
== USB_ERR_TIMEOUT
) {
768 xfer
->timeComplete
= 0;
769 xfer
->status
= LIBUSB20_TRANSFER_TIMED_OUT
;
772 xfer
->timeComplete
= 0;
773 xfer
->status
= LIBUSB20_TRANSFER_ERROR
;
775 libusb20_tr_callback_wrapper(xfer
);
777 return (0); /* done */
781 ugen20_tr_open(struct libusb20_transfer
*xfer
, uint32_t MaxBufSize
,
782 uint32_t MaxFrameCount
, uint8_t ep_no
, uint16_t stream_id
,
786 struct usb_fs_open fs_open
;
787 struct usb_fs_open_stream fs_open_stream
;
789 struct usb_fs_endpoint
*fsep
;
792 MaxFrameCount
|= USB_FS_MAX_FRAMES_PRE_SCALE
;
794 memset(&temp
, 0, sizeof(temp
));
796 fsep
= xfer
->pdev
->privBeData
;
797 fsep
+= xfer
->trIndex
;
799 temp
.fs_open
.max_bufsize
= MaxBufSize
;
800 temp
.fs_open
.max_frames
= MaxFrameCount
;
801 temp
.fs_open
.ep_index
= xfer
->trIndex
;
802 temp
.fs_open
.ep_no
= ep_no
;
804 if (stream_id
!= 0) {
805 temp
.fs_open_stream
.stream_id
= stream_id
;
807 if (ioctl(xfer
->pdev
->file
, IOUSB(USB_FS_OPEN_STREAM
), &temp
.fs_open_stream
))
808 return (LIBUSB20_ERROR_INVALID_PARAM
);
810 if (ioctl(xfer
->pdev
->file
, IOUSB(USB_FS_OPEN
), &temp
.fs_open
))
811 return (LIBUSB20_ERROR_INVALID_PARAM
);
813 /* maximums might have changed - update */
814 xfer
->maxFrames
= temp
.fs_open
.max_frames
;
816 /* "max_bufsize" should be multiple of "max_packet_length" */
817 xfer
->maxTotalLength
= temp
.fs_open
.max_bufsize
;
818 xfer
->maxPacketLen
= temp
.fs_open
.max_packet_length
;
820 /* setup buffer and length lists using zero copy */
821 fsep
->ppBuffer
= libusb20_pass_ptr(xfer
->ppBuffer
);
822 fsep
->pLength
= libusb20_pass_ptr(xfer
->pLength
);
824 return (0); /* success */
828 ugen20_tr_close(struct libusb20_transfer
*xfer
)
830 struct usb_fs_close temp
;
832 memset(&temp
, 0, sizeof(temp
));
834 temp
.ep_index
= xfer
->trIndex
;
836 if (ioctl(xfer
->pdev
->file
, IOUSB(USB_FS_CLOSE
), &temp
)) {
837 return (LIBUSB20_ERROR_INVALID_PARAM
);
839 return (0); /* success */
843 ugen20_tr_clear_stall_sync(struct libusb20_transfer
*xfer
)
845 struct usb_fs_clear_stall_sync temp
;
847 memset(&temp
, 0, sizeof(temp
));
849 /* if the transfer is active, an error will be returned */
851 temp
.ep_index
= xfer
->trIndex
;
853 if (ioctl(xfer
->pdev
->file
, IOUSB(USB_FS_CLEAR_STALL_SYNC
), &temp
)) {
854 return (LIBUSB20_ERROR_INVALID_PARAM
);
856 return (0); /* success */
860 ugen20_tr_submit(struct libusb20_transfer
*xfer
)
862 struct usb_fs_start temp
;
863 struct usb_fs_endpoint
*fsep
;
865 memset(&temp
, 0, sizeof(temp
));
867 fsep
= xfer
->pdev
->privBeData
;
868 fsep
+= xfer
->trIndex
;
870 fsep
->nFrames
= xfer
->nFrames
;
872 if (!(xfer
->flags
& LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK
)) {
873 fsep
->flags
|= USB_FS_FLAG_SINGLE_SHORT_OK
;
875 if (!(xfer
->flags
& LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK
)) {
876 fsep
->flags
|= USB_FS_FLAG_MULTI_SHORT_OK
;
878 if (xfer
->flags
& LIBUSB20_TRANSFER_FORCE_SHORT
) {
879 fsep
->flags
|= USB_FS_FLAG_FORCE_SHORT
;
881 if (xfer
->flags
& LIBUSB20_TRANSFER_DO_CLEAR_STALL
) {
882 fsep
->flags
|= USB_FS_FLAG_CLEAR_STALL
;
884 /* NOTE: The "fsep->timeout" variable is 16-bit. */
885 if (xfer
->timeout
> 65535)
886 fsep
->timeout
= 65535;
888 fsep
->timeout
= xfer
->timeout
;
890 temp
.ep_index
= xfer
->trIndex
;
892 if (ioctl(xfer
->pdev
->file
, IOUSB(USB_FS_START
), &temp
)) {
893 /* ignore any errors - should never happen */
895 return; /* success */
899 ugen20_tr_cancel_async(struct libusb20_transfer
*xfer
)
901 struct usb_fs_stop temp
;
903 memset(&temp
, 0, sizeof(temp
));
905 temp
.ep_index
= xfer
->trIndex
;
907 if (ioctl(xfer
->pdev
->file
, IOUSB(USB_FS_STOP
), &temp
)) {
908 /* ignore any errors - should never happen */
914 ugen20_be_ioctl(uint32_t cmd
, void *data
)
919 f
= open("/dev/" USB_DEVICE_NAME
, O_RDONLY
);
921 return (LIBUSB20_ERROR_OTHER
);
922 error
= ioctl(f
, cmd
, data
);
924 if (errno
== EPERM
) {
925 error
= LIBUSB20_ERROR_ACCESS
;
927 error
= LIBUSB20_ERROR_OTHER
;
935 ugen20_dev_get_iface_desc(struct libusb20_device
*pdev
,
936 uint8_t iface_index
, char *buf
, uint8_t len
)
938 struct usb_gen_descriptor ugd
;
940 memset(&ugd
, 0, sizeof(ugd
));
942 ugd
.ugd_data
= libusb20_pass_ptr(buf
);
943 ugd
.ugd_maxlen
= len
;
944 ugd
.ugd_iface_index
= iface_index
;
946 if (ioctl(pdev
->file
, IOUSB(USB_GET_IFACE_DRIVER
), &ugd
)) {
947 return (LIBUSB20_ERROR_INVALID_PARAM
);
953 ugen20_dev_get_info(struct libusb20_device
*pdev
,
954 struct usb_device_info
*pinfo
)
956 if (ioctl(pdev
->file
, IOUSB(USB_GET_DEVICEINFO
), pinfo
)) {
957 return (LIBUSB20_ERROR_INVALID_PARAM
);
963 ugen20_root_get_dev_quirk(struct libusb20_backend
*pbe
,
964 uint16_t quirk_index
, struct libusb20_quirk
*pq
)
966 struct usb_gen_quirk q
;
969 memset(&q
, 0, sizeof(q
));
971 q
.index
= quirk_index
;
973 error
= ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_GET
), &q
);
976 if (errno
== EINVAL
) {
977 return (LIBUSB20_ERROR_NOT_FOUND
);
982 pq
->bcdDeviceLow
= q
.bcdDeviceLow
;
983 pq
->bcdDeviceHigh
= q
.bcdDeviceHigh
;
984 strlcpy(pq
->quirkname
, q
.quirkname
, sizeof(pq
->quirkname
));
990 ugen20_root_get_quirk_name(struct libusb20_backend
*pbe
, uint16_t quirk_index
,
991 struct libusb20_quirk
*pq
)
993 struct usb_gen_quirk q
;
996 memset(&q
, 0, sizeof(q
));
998 q
.index
= quirk_index
;
1000 error
= ugen20_be_ioctl(IOUSB(USB_QUIRK_NAME_GET
), &q
);
1003 if (errno
== EINVAL
) {
1004 return (LIBUSB20_ERROR_NOT_FOUND
);
1007 strlcpy(pq
->quirkname
, q
.quirkname
, sizeof(pq
->quirkname
));
1013 ugen20_root_add_dev_quirk(struct libusb20_backend
*pbe
,
1014 struct libusb20_quirk
*pq
)
1016 struct usb_gen_quirk q
;
1019 memset(&q
, 0, sizeof(q
));
1023 q
.bcdDeviceLow
= pq
->bcdDeviceLow
;
1024 q
.bcdDeviceHigh
= pq
->bcdDeviceHigh
;
1025 strlcpy(q
.quirkname
, pq
->quirkname
, sizeof(q
.quirkname
));
1027 error
= ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_ADD
), &q
);
1029 if (errno
== ENOMEM
) {
1030 return (LIBUSB20_ERROR_NO_MEM
);
1037 ugen20_root_remove_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_REMOVE
), &q
);
1053 if (errno
== EINVAL
) {
1054 return (LIBUSB20_ERROR_NOT_FOUND
);
1061 ugen20_root_set_template(struct libusb20_backend
*pbe
, int temp
)
1063 return (ugen20_be_ioctl(IOUSB(USB_SET_TEMPLATE
), &temp
));
1067 ugen20_root_get_template(struct libusb20_backend
*pbe
, int *ptemp
)
1069 return (ugen20_be_ioctl(IOUSB(USB_GET_TEMPLATE
), ptemp
));