2 * Copyright © 2011 Martin Pieuchot <mpi@openbsd.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <sys/types.h>
29 #include <dev/usb/usb.h>
38 unsigned char *cdesc
; /* active config descriptor */
39 usb_device_descriptor_t ddesc
; /* usb device descriptor */
43 int pipe
[2]; /* for event notification */
44 int endpoints
[USB_MAX_ENDPOINTS
];
50 static int obsd_get_device_list(struct libusb_context
*,
51 struct discovered_devs
**);
52 static int obsd_open(struct libusb_device_handle
*);
53 static void obsd_close(struct libusb_device_handle
*);
55 static int obsd_get_device_descriptor(struct libusb_device
*, unsigned char *,
57 static int obsd_get_active_config_descriptor(struct libusb_device
*,
58 unsigned char *, size_t, int *);
59 static int obsd_get_config_descriptor(struct libusb_device
*, uint8_t,
60 unsigned char *, size_t, int *);
62 static int obsd_get_configuration(struct libusb_device_handle
*, int *);
63 static int obsd_set_configuration(struct libusb_device_handle
*, int);
65 static int obsd_claim_interface(struct libusb_device_handle
*, int);
66 static int obsd_release_interface(struct libusb_device_handle
*, int);
68 static int obsd_set_interface_altsetting(struct libusb_device_handle
*, int,
70 static int obsd_clear_halt(struct libusb_device_handle
*, unsigned char);
71 static int obsd_reset_device(struct libusb_device_handle
*);
72 static void obsd_destroy_device(struct libusb_device
*);
74 static int obsd_submit_transfer(struct usbi_transfer
*);
75 static int obsd_cancel_transfer(struct usbi_transfer
*);
76 static void obsd_clear_transfer_priv(struct usbi_transfer
*);
77 static int obsd_handle_events(struct libusb_context
*ctx
, struct pollfd
*,
79 static int obsd_clock_gettime(int, struct timespec
*);
84 static int _errno_to_libusb(int);
85 static int _cache_active_config_descriptor(struct libusb_device
*, int);
86 static int _sync_control_transfer(struct usbi_transfer
*);
87 static int _sync_gen_transfer(struct usbi_transfer
*);
88 static int _access_endpoint(struct libusb_transfer
*);
90 const struct usbi_os_backend openbsd_backend
= {
91 "Synchronous OpenBSD backend",
99 obsd_get_device_descriptor
,
100 obsd_get_active_config_descriptor
,
101 obsd_get_config_descriptor
,
103 obsd_get_configuration
,
104 obsd_set_configuration
,
106 obsd_claim_interface
,
107 obsd_release_interface
,
109 obsd_set_interface_altsetting
,
113 NULL
, /* kernel_driver_active() */
114 NULL
, /* detach_kernel_driver() */
115 NULL
, /* attach_kernel_driver() */
119 obsd_submit_transfer
,
120 obsd_cancel_transfer
,
121 obsd_clear_transfer_priv
,
126 sizeof(struct device_priv
),
127 sizeof(struct handle_priv
),
128 0, /* transfer_priv_size */
129 0, /* add_iso_packet_size */
133 obsd_get_device_list(struct libusb_context
* ctx
,
134 struct discovered_devs
**discdevs
)
136 struct libusb_device
*dev
;
137 struct device_priv
*dpriv
;
138 struct usb_device_info di
;
139 unsigned long session_id
;
145 /* Only ugen(4) is supported */
146 for (i
= 0; i
< USB_MAX_DEVICES
; i
++) {
147 /* Control endpoint is always .00 */
148 snprintf(devnode
, sizeof(devnode
), "/dev/ugen%d.00", i
);
150 if ((fd
= open(devnode
, O_RDONLY
)) < 0) {
151 if (errno
!= ENOENT
&& errno
!= ENXIO
)
152 usbi_err(ctx
, "could not open %s", devnode
);
156 if (ioctl(fd
, USB_GET_DEVICEINFO
, &di
) < 0)
159 session_id
= (di
.udi_bus
<< 8 | di
.udi_addr
);
160 dev
= usbi_get_device_by_session_id(ctx
, session_id
);
163 dev
= usbi_alloc_device(ctx
, session_id
);
165 return (LIBUSB_ERROR_NO_MEM
);
167 dev
->bus_number
= di
.udi_bus
;
168 dev
->device_address
= di
.udi_addr
;
169 dev
->speed
= di
.udi_speed
;
171 dpriv
= (struct device_priv
*)dev
->os_priv
;
172 strlcpy(dpriv
->devnode
, devnode
, sizeof(devnode
));
175 if (ioctl(fd
, USB_GET_DEVICE_DESC
, &dpriv
->ddesc
) < 0) {
181 if (_cache_active_config_descriptor(dev
, fd
)) {
186 if ((err
= usbi_sanitize_device(dev
)))
191 if (discovered_devs_append(*discdevs
, dev
) == NULL
)
192 return (LIBUSB_ERROR_NO_MEM
);
195 return (LIBUSB_SUCCESS
);
199 libusb_unref_device(dev
);
200 return _errno_to_libusb(err
);
204 obsd_open(struct libusb_device_handle
*handle
)
206 struct handle_priv
*hpriv
= (struct handle_priv
*)handle
->os_priv
;
207 struct device_priv
*dpriv
= (struct device_priv
*)handle
->dev
->os_priv
;
209 dpriv
->fd
= open(dpriv
->devnode
, O_RDWR
);
211 dpriv
->fd
= open(dpriv
->devnode
, O_RDONLY
);
213 return _errno_to_libusb(errno
);
216 usbi_dbg("open %s: fd %d", dpriv
->devnode
, dpriv
->fd
);
218 if (pipe(hpriv
->pipe
) < 0)
219 return _errno_to_libusb(errno
);
221 return usbi_add_pollfd(HANDLE_CTX(handle
), hpriv
->pipe
[0], POLLIN
);
225 obsd_close(struct libusb_device_handle
*handle
)
227 struct handle_priv
*hpriv
= (struct handle_priv
*)handle
->os_priv
;
228 struct device_priv
*dpriv
= (struct device_priv
*)handle
->dev
->os_priv
;
230 usbi_dbg("close: fd %d", dpriv
->fd
);
235 usbi_remove_pollfd(HANDLE_CTX(handle
), hpriv
->pipe
[0]);
237 close(hpriv
->pipe
[0]);
238 close(hpriv
->pipe
[1]);
242 obsd_get_device_descriptor(struct libusb_device
*dev
, unsigned char *buf
,
245 struct device_priv
*dpriv
= (struct device_priv
*)dev
->os_priv
;
249 memcpy(buf
, &dpriv
->ddesc
, DEVICE_DESC_LENGTH
);
253 return (LIBUSB_SUCCESS
);
257 obsd_get_active_config_descriptor(struct libusb_device
*dev
,
258 unsigned char *buf
, size_t len
, int *host_endian
)
260 struct device_priv
*dpriv
= (struct device_priv
*)dev
->os_priv
;
261 usb_config_descriptor_t
*ucd
;
263 ucd
= (usb_config_descriptor_t
*) dpriv
->cdesc
;
264 len
= MIN(len
, UGETW(ucd
->wTotalLength
));
266 usbi_dbg("len %d", len
);
268 memcpy(buf
, dpriv
->cdesc
, len
);
272 return (LIBUSB_SUCCESS
);
276 obsd_get_config_descriptor(struct libusb_device
*dev
, uint8_t idx
,
277 unsigned char *buf
, size_t len
, int *host_endian
)
279 struct device_priv
*dpriv
= (struct device_priv
*)dev
->os_priv
;
280 struct usb_full_desc ufd
;
283 usbi_dbg("index %d, len %d", idx
, len
);
285 /* A config descriptor may be requested before opening the device */
286 if (dpriv
->fd
>= 0) {
289 fd
= open(dpriv
->devnode
, O_RDONLY
);
291 return _errno_to_libusb(errno
);
294 ufd
.ufd_config_index
= idx
;
298 if ((ioctl(fd
, USB_GET_FULL_DESC
, &ufd
)) < 0) {
302 return _errno_to_libusb(err
);
310 return (LIBUSB_SUCCESS
);
314 obsd_get_configuration(struct libusb_device_handle
*handle
, int *config
)
316 struct device_priv
*dpriv
= (struct device_priv
*)handle
->dev
->os_priv
;
320 if (ioctl(dpriv
->fd
, USB_GET_CONFIG
, config
) < 0)
321 return _errno_to_libusb(errno
);
323 usbi_dbg("configuration %d", *config
);
325 return (LIBUSB_SUCCESS
);
329 obsd_set_configuration(struct libusb_device_handle
*handle
, int config
)
331 struct device_priv
*dpriv
= (struct device_priv
*)handle
->dev
->os_priv
;
333 usbi_dbg("configuration %d", config
);
335 if (ioctl(dpriv
->fd
, USB_SET_CONFIG
, &config
) < 0)
336 return _errno_to_libusb(errno
);
338 return _cache_active_config_descriptor(handle
->dev
, dpriv
->fd
);
342 obsd_claim_interface(struct libusb_device_handle
*handle
, int iface
)
344 struct handle_priv
*hpriv
= (struct handle_priv
*)handle
->os_priv
;
347 for (i
= 0; i
< USB_MAX_ENDPOINTS
; i
++)
348 hpriv
->endpoints
[i
] = -1;
350 return (LIBUSB_SUCCESS
);
354 obsd_release_interface(struct libusb_device_handle
*handle
, int iface
)
356 struct handle_priv
*hpriv
= (struct handle_priv
*)handle
->os_priv
;
359 for (i
= 0; i
< USB_MAX_ENDPOINTS
; i
++)
360 if (hpriv
->endpoints
[i
] >= 0)
361 close(hpriv
->endpoints
[i
]);
363 return (LIBUSB_SUCCESS
);
367 obsd_set_interface_altsetting(struct libusb_device_handle
*handle
, int iface
,
370 struct device_priv
*dpriv
= (struct device_priv
*)handle
->dev
->os_priv
;
371 struct usb_alt_interface intf
;
373 usbi_dbg("iface %d, setting %d", iface
, altsetting
);
375 memset(&intf
, 0, sizeof(intf
));
377 intf
.uai_interface_index
= iface
;
378 intf
.uai_alt_no
= altsetting
;
380 if (ioctl(dpriv
->fd
, USB_SET_ALTINTERFACE
, &intf
) < 0)
381 return _errno_to_libusb(errno
);
383 return (LIBUSB_SUCCESS
);
387 obsd_clear_halt(struct libusb_device_handle
*handle
, unsigned char endpoint
)
389 struct device_priv
*dpriv
= (struct device_priv
*)handle
->dev
->os_priv
;
390 struct usb_ctl_request req
;
394 req
.ucr_request
.bmRequestType
= UT_WRITE_ENDPOINT
;
395 req
.ucr_request
.bRequest
= UR_CLEAR_FEATURE
;
396 USETW(req
.ucr_request
.wValue
, UF_ENDPOINT_HALT
);
397 USETW(req
.ucr_request
.wIndex
, endpoint
);
398 USETW(req
.ucr_request
.wLength
, 0);
400 if (ioctl(dpriv
->fd
, USB_DO_REQUEST
, &req
) < 0)
401 return _errno_to_libusb(errno
);
403 return (LIBUSB_SUCCESS
);
407 obsd_reset_device(struct libusb_device_handle
*handle
)
411 return (LIBUSB_ERROR_NOT_SUPPORTED
);
415 obsd_destroy_device(struct libusb_device
*dev
)
417 struct device_priv
*dpriv
= (struct device_priv
*)dev
->os_priv
;
425 obsd_submit_transfer(struct usbi_transfer
*itransfer
)
427 struct libusb_transfer
*transfer
;
428 struct handle_priv
*hpriv
;
433 transfer
= USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer
);
434 hpriv
= (struct handle_priv
*)transfer
->dev_handle
->os_priv
;
436 switch (transfer
->type
) {
437 case LIBUSB_TRANSFER_TYPE_CONTROL
:
438 err
= _sync_control_transfer(itransfer
);
440 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
:
441 if (IS_XFEROUT(transfer
)) {
442 /* Isochronous write is not supported */
443 err
= LIBUSB_ERROR_NOT_SUPPORTED
;
446 err
= _sync_gen_transfer(itransfer
);
448 case LIBUSB_TRANSFER_TYPE_BULK
:
449 case LIBUSB_TRANSFER_TYPE_INTERRUPT
:
450 if (IS_XFEROUT(transfer
) &&
451 transfer
->flags
& LIBUSB_TRANSFER_ADD_ZERO_PACKET
) {
452 err
= LIBUSB_ERROR_NOT_SUPPORTED
;
455 err
= _sync_gen_transfer(itransfer
);
462 if (write(hpriv
->pipe
[1], &itransfer
, sizeof(itransfer
)) < 0)
463 return _errno_to_libusb(errno
);
465 return (LIBUSB_SUCCESS
);
469 obsd_cancel_transfer(struct usbi_transfer
*itransfer
)
473 return (LIBUSB_ERROR_NOT_SUPPORTED
);
477 obsd_clear_transfer_priv(struct usbi_transfer
*itransfer
)
485 obsd_handle_events(struct libusb_context
*ctx
, struct pollfd
*fds
, nfds_t nfds
,
488 struct libusb_device_handle
*handle
;
489 struct handle_priv
*hpriv
= NULL
;
490 struct usbi_transfer
*itransfer
;
491 struct pollfd
*pollfd
;
496 pthread_mutex_lock(&ctx
->open_devs_lock
);
497 for (i
= 0; i
< nfds
&& num_ready
> 0; i
++) {
500 if (!pollfd
->revents
)
505 list_for_each_entry(handle
, &ctx
->open_devs
, list
,
506 struct libusb_device_handle
) {
507 hpriv
= (struct handle_priv
*)handle
->os_priv
;
509 if (hpriv
->pipe
[0] == pollfd
->fd
)
516 usbi_dbg("fd %d is not an event pipe!", pollfd
->fd
);
521 if (pollfd
->revents
& POLLERR
) {
522 usbi_remove_pollfd(HANDLE_CTX(handle
), hpriv
->pipe
[0]);
523 usbi_handle_disconnect(handle
);
527 if (read(hpriv
->pipe
[0], &itransfer
, sizeof(itransfer
)) < 0) {
532 if ((err
= usbi_handle_transfer_completion(itransfer
,
533 LIBUSB_TRANSFER_COMPLETED
)))
536 pthread_mutex_unlock(&ctx
->open_devs_lock
);
539 return _errno_to_libusb(err
);
541 return (LIBUSB_SUCCESS
);
545 obsd_clock_gettime(int clkid
, struct timespec
*tp
)
547 usbi_dbg("clock %d", clkid
);
549 if (clkid
== USBI_CLOCK_REALTIME
)
550 return clock_gettime(CLOCK_REALTIME
, tp
);
552 if (clkid
== USBI_CLOCK_MONOTONIC
)
553 return clock_gettime(CLOCK_MONOTONIC
, tp
);
555 return (LIBUSB_ERROR_INVALID_PARAM
);
559 _errno_to_libusb(int err
)
563 return (LIBUSB_ERROR_IO
);
565 return (LIBUSB_ERROR_ACCESS
);
567 return (LIBUSB_ERROR_NO_DEVICE
);
569 return (LIBUSB_ERROR_NO_MEM
);
572 usbi_dbg("error: %s", strerror(err
));
574 return (LIBUSB_ERROR_OTHER
);
578 _cache_active_config_descriptor(struct libusb_device
*dev
, int fd
)
580 struct device_priv
*dpriv
= (struct device_priv
*)dev
->os_priv
;
581 struct usb_config_desc ucd
;
582 struct usb_full_desc ufd
;
586 usbi_dbg("fd %d", fd
);
588 ucd
.ucd_config_index
= USB_CURRENT_CONFIG_INDEX
;
590 if ((ioctl(fd
, USB_GET_CONFIG_DESC
, &ucd
)) < 0)
591 return _errno_to_libusb(errno
);
593 usbi_dbg("active bLength %d", ucd
.ucd_desc
.bLength
);
595 len
= UGETW(ucd
.ucd_desc
.wTotalLength
);
598 return (LIBUSB_ERROR_NO_MEM
);
600 ufd
.ufd_config_index
= ucd
.ucd_config_index
;
604 usbi_dbg("index %d, len %d", ufd
.ufd_config_index
, len
);
606 if ((ioctl(fd
, USB_GET_FULL_DESC
, &ufd
)) < 0) {
608 return _errno_to_libusb(errno
);
619 _sync_control_transfer(struct usbi_transfer
*itransfer
)
621 struct libusb_transfer
*transfer
;
622 struct libusb_control_setup
*setup
;
623 struct device_priv
*dpriv
;
624 struct usb_ctl_request req
;
626 transfer
= USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer
);
627 dpriv
= (struct device_priv
*)transfer
->dev_handle
->dev
->os_priv
;
628 setup
= (struct libusb_control_setup
*)transfer
->buffer
;
630 usbi_dbg("type %d request %d value %d index %d length %d timeout %d",
631 setup
->bmRequestType
, setup
->bRequest
,
632 libusb_le16_to_cpu(setup
->wValue
),
633 libusb_le16_to_cpu(setup
->wIndex
),
634 libusb_le16_to_cpu(setup
->wLength
), transfer
->timeout
);
636 req
.ucr_request
.bmRequestType
= setup
->bmRequestType
;
637 req
.ucr_request
.bRequest
= setup
->bRequest
;
638 /* Don't use USETW, libusbx already deals with the endianness */
639 (*(uint16_t *)req
.ucr_request
.wValue
) = setup
->wValue
;
640 (*(uint16_t *)req
.ucr_request
.wIndex
) = setup
->wIndex
;
641 (*(uint16_t *)req
.ucr_request
.wLength
) = setup
->wLength
;
642 req
.ucr_data
= transfer
->buffer
+ LIBUSB_CONTROL_SETUP_SIZE
;
644 if ((transfer
->flags
& LIBUSB_TRANSFER_SHORT_NOT_OK
) == 0)
645 req
.ucr_flags
= USBD_SHORT_XFER_OK
;
647 if ((ioctl(dpriv
->fd
, USB_SET_TIMEOUT
, &transfer
->timeout
)) < 0)
648 return _errno_to_libusb(errno
);
650 if ((ioctl(dpriv
->fd
, USB_DO_REQUEST
, &req
)) < 0)
651 return _errno_to_libusb(errno
);
653 itransfer
->transferred
= req
.ucr_actlen
;
655 usbi_dbg("transferred %d", itransfer
->transferred
);
661 _access_endpoint(struct libusb_transfer
*transfer
)
663 struct handle_priv
*hpriv
;
664 struct device_priv
*dpriv
;
665 char *s
, devnode
[16];
669 hpriv
= (struct handle_priv
*)transfer
->dev_handle
->os_priv
;
670 dpriv
= (struct device_priv
*)transfer
->dev_handle
->dev
->os_priv
;
672 endpt
= UE_GET_ADDR(transfer
->endpoint
);
673 mode
= IS_XFERIN(transfer
) ? O_RDONLY
: O_WRONLY
;
675 usbi_dbg("endpoint %d mode %d", endpt
, mode
);
677 if (hpriv
->endpoints
[endpt
] < 0) {
678 /* Pick the right node given the control one */
679 strlcpy(devnode
, dpriv
->devnode
, sizeof(devnode
));
680 s
= strchr(devnode
, '.');
681 snprintf(s
, 4, ".%02d", endpt
);
683 /* We may need to read/write to the same endpoint later. */
684 if (((fd
= open(devnode
, O_RDWR
)) < 0) && (errno
== ENXIO
))
685 if ((fd
= open(devnode
, mode
)) < 0)
688 hpriv
->endpoints
[endpt
] = fd
;
691 return (hpriv
->endpoints
[endpt
]);
695 _sync_gen_transfer(struct usbi_transfer
*itransfer
)
697 struct libusb_transfer
*transfer
;
700 transfer
= USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer
);
703 * Bulk, Interrupt or Isochronous transfer depends on the
704 * endpoint and thus the node to open.
706 if ((fd
= _access_endpoint(transfer
)) < 0)
707 return _errno_to_libusb(errno
);
709 if ((ioctl(fd
, USB_SET_TIMEOUT
, &transfer
->timeout
)) < 0)
710 return _errno_to_libusb(errno
);
712 if (IS_XFERIN(transfer
)) {
713 if ((transfer
->flags
& LIBUSB_TRANSFER_SHORT_NOT_OK
) == 0)
714 if ((ioctl(fd
, USB_SET_SHORT_XFER
, &nr
)) < 0)
715 return _errno_to_libusb(errno
);
717 nr
= read(fd
, transfer
->buffer
, transfer
->length
);
719 nr
= write(fd
, transfer
->buffer
, transfer
->length
);
723 return _errno_to_libusb(errno
);
725 itransfer
->transferred
= nr
;