Various changes for OpenBSD's backend with inputs from upstream.
Transfer completion notifications are now send asynchronously this should prevent potential lock of applications using a different thread for polling events. Fix interrupt tranfers, reported by and helped to debug, sebastia@ Other minor improvements and style fixes. Tested by sebastia@ and ajacoutot@ ok ajacoutot@
This commit is contained in:
parent
5a74b62623
commit
94e772dbcc
@ -1,11 +1,11 @@
|
||||
# $OpenBSD: Makefile,v 1.3 2011/11/04 12:17:50 jasper Exp $
|
||||
# $OpenBSD: Makefile,v 1.4 2011/11/18 15:18:50 mpi Exp $
|
||||
|
||||
COMMENT = library for USB device access from userspace
|
||||
|
||||
VERSION = 1.0.8
|
||||
DISTNAME = libusb-${VERSION}
|
||||
PKGNAME = libusb1-${VERSION}
|
||||
REVISION = 0
|
||||
REVISION = 1
|
||||
SHARED_LIBS += usb-1.0 0.0 # 0.0
|
||||
|
||||
CATEGORIES = devel
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: openbsd_ugen.c,v 1.2 2011/11/04 09:18:11 mpi Exp $ */
|
||||
/* $OpenBSD: openbsd_ugen.c,v 1.3 2011/11/18 15:18:50 mpi Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
|
||||
*
|
||||
@ -27,17 +27,22 @@
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
|
||||
#include "libusb.h"
|
||||
#include "libusbi.h"
|
||||
|
||||
struct device_priv {
|
||||
char devnode[16];
|
||||
int fd;
|
||||
int open;
|
||||
|
||||
unsigned char *cdesc; /* active config descriptor */
|
||||
usb_device_descriptor_t ddesc; /* usb device descriptor */
|
||||
};
|
||||
|
||||
struct handle_priv {
|
||||
int pipe[2]; /* for event notification */
|
||||
int endpoints[USB_MAX_ENDPOINTS];
|
||||
};
|
||||
|
||||
/*
|
||||
* Backend functions
|
||||
*/
|
||||
@ -75,6 +80,7 @@ int ugen_clock_gettime(int, struct timespec *);
|
||||
int _errno_to_libusb(int);
|
||||
int _cache_active_config_descriptor(struct libusb_device *, int);
|
||||
int _sync_control_transfer(struct usbi_transfer *);
|
||||
int _access_endpoint(struct libusb_transfer *);
|
||||
int _sync_gen_transfer(struct usbi_transfer *);
|
||||
|
||||
const struct usbi_os_backend openbsd_backend = {
|
||||
@ -113,7 +119,7 @@ const struct usbi_os_backend openbsd_backend = {
|
||||
|
||||
ugen_clock_gettime,
|
||||
sizeof(struct device_priv),
|
||||
0, /* device_handle_priv_size */
|
||||
sizeof(struct handle_priv),
|
||||
0, /* transfer_priv_size */
|
||||
0, /* add_iso_packet_size */
|
||||
};
|
||||
@ -158,6 +164,7 @@ ugen_get_device_list(struct libusb_context * ctx,
|
||||
|
||||
dpriv = (struct device_priv *)dev->os_priv;
|
||||
strlcpy(dpriv->devnode, devnode, sizeof(devnode));
|
||||
dpriv->fd = -1;
|
||||
|
||||
if (ioctl(fd, USB_GET_DEVICE_DESC, &dpriv->ddesc) < 0) {
|
||||
err = errno;
|
||||
@ -179,17 +186,18 @@ ugen_get_device_list(struct libusb_context * ctx,
|
||||
return (LIBUSB_ERROR_NO_MEM);
|
||||
}
|
||||
|
||||
return (0);
|
||||
return (LIBUSB_SUCCESS);
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
libusb_unref_device(dev);
|
||||
return (err);
|
||||
return _errno_to_libusb(err);
|
||||
}
|
||||
|
||||
int
|
||||
ugen_open(struct libusb_device_handle *handle)
|
||||
{
|
||||
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
|
||||
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
|
||||
|
||||
dpriv->fd = open(dpriv->devnode, O_RDWR);
|
||||
@ -201,23 +209,27 @@ ugen_open(struct libusb_device_handle *handle)
|
||||
|
||||
usbi_dbg("open %s: fd %d", dpriv->devnode, dpriv->fd);
|
||||
|
||||
dpriv->open = 1;
|
||||
if (pipe(hpriv->pipe) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
return (usbi_add_pollfd(HANDLE_CTX(handle), dpriv->fd, POLLOUT));
|
||||
return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->pipe[0], POLLIN);
|
||||
}
|
||||
|
||||
void
|
||||
ugen_close(struct libusb_device_handle *handle)
|
||||
{
|
||||
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
|
||||
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
|
||||
|
||||
usbi_dbg("close: fd %d", dpriv->fd);
|
||||
|
||||
usbi_remove_pollfd(HANDLE_CTX(handle), dpriv->fd);
|
||||
|
||||
close(dpriv->fd);
|
||||
dpriv->fd = -1;
|
||||
|
||||
dpriv->open = 0;
|
||||
usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]);
|
||||
|
||||
close(hpriv->pipe[0]);
|
||||
close(hpriv->pipe[1]);
|
||||
}
|
||||
|
||||
int
|
||||
@ -232,7 +244,7 @@ ugen_get_device_descriptor(struct libusb_device *dev, unsigned char *buf,
|
||||
|
||||
*host_endian = 0;
|
||||
|
||||
return (0);
|
||||
return (LIBUSB_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
@ -251,7 +263,7 @@ ugen_get_active_config_descriptor(struct libusb_device *dev,
|
||||
|
||||
*host_endian = 0;
|
||||
|
||||
return (0);
|
||||
return (LIBUSB_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
@ -264,8 +276,8 @@ ugen_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
|
||||
|
||||
usbi_dbg("index %d, len %d", idx, len);
|
||||
|
||||
/* Endpoint cannot be opened twice */
|
||||
if (dpriv->open) {
|
||||
/* A config descriptor may be requested before opening the device */
|
||||
if (dpriv->fd >= 0) {
|
||||
fd = dpriv->fd;
|
||||
} else {
|
||||
fd = open(dpriv->devnode, O_RDONLY);
|
||||
@ -279,17 +291,17 @@ ugen_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
|
||||
|
||||
if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
|
||||
err = errno;
|
||||
if (!dpriv->open)
|
||||
if (dpriv->fd < 0)
|
||||
close(fd);
|
||||
return _errno_to_libusb(err);
|
||||
}
|
||||
|
||||
if (!dpriv->open)
|
||||
if (dpriv->fd < 0)
|
||||
close(fd);
|
||||
|
||||
*host_endian = 0;
|
||||
|
||||
return (0);
|
||||
return (LIBUSB_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
@ -304,7 +316,7 @@ ugen_get_configuration(struct libusb_device_handle *handle, int *config)
|
||||
|
||||
usbi_dbg("configuration %d", *config);
|
||||
|
||||
return (0);
|
||||
return (LIBUSB_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
@ -323,21 +335,26 @@ ugen_set_configuration(struct libusb_device_handle *handle, int config)
|
||||
int
|
||||
ugen_claim_interface(struct libusb_device_handle *handle, int iface)
|
||||
{
|
||||
/*
|
||||
* The USB specification does not speak about interface
|
||||
* claiming and OpenBSD does not provide such mechanism.
|
||||
*
|
||||
* But because people shouldn't be able to attach or
|
||||
* detach a specific driver for a device it is safe to
|
||||
* return 0 instead of LIBUSB_ERROR_NOT_SUPPORTED.
|
||||
*/
|
||||
return (0);
|
||||
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
|
||||
hpriv->endpoints[i] = -1;
|
||||
|
||||
return (LIBUSB_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
ugen_release_interface(struct libusb_device_handle *handle, int iface)
|
||||
{
|
||||
return (0);
|
||||
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
|
||||
if (hpriv->endpoints[i] >= 0)
|
||||
close(hpriv->endpoints[i]);
|
||||
|
||||
return (LIBUSB_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
@ -357,7 +374,7 @@ ugen_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
|
||||
if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
return (0);
|
||||
return (LIBUSB_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
@ -377,7 +394,7 @@ ugen_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
|
||||
if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
return (0);
|
||||
return (LIBUSB_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
@ -399,18 +416,20 @@ ugen_destroy_device(struct libusb_device *dev)
|
||||
}
|
||||
|
||||
int
|
||||
ugen_submit_transfer(struct usbi_transfer *itr)
|
||||
ugen_submit_transfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
struct handle_priv *hpriv;
|
||||
int err = 0;
|
||||
|
||||
usbi_dbg("");
|
||||
|
||||
transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itr);
|
||||
transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
|
||||
|
||||
switch (transfer->type) {
|
||||
case LIBUSB_TRANSFER_TYPE_CONTROL:
|
||||
err = _sync_control_transfer(itr);
|
||||
err = _sync_control_transfer(itransfer);
|
||||
break;
|
||||
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
|
||||
if (transfer->endpoint & LIBUSB_ENDPOINT_OUT) {
|
||||
@ -421,18 +440,17 @@ ugen_submit_transfer(struct usbi_transfer *itr)
|
||||
/* PASSTHROUGH */
|
||||
case LIBUSB_TRANSFER_TYPE_BULK:
|
||||
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
|
||||
err = _sync_gen_transfer(itr);
|
||||
err = _sync_gen_transfer(itransfer);
|
||||
break;
|
||||
}
|
||||
|
||||
if (err)
|
||||
return (err);
|
||||
|
||||
/*
|
||||
* Because this backend is synchronous we have
|
||||
* notify now that the transfer is complete.
|
||||
*/
|
||||
return usbi_handle_transfer_completion(itr, LIBUSB_TRANSFER_COMPLETED);
|
||||
if (write(hpriv->pipe[1], &itransfer, sizeof(itransfer)) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
return (LIBUSB_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
@ -446,6 +464,8 @@ ugen_cancel_transfer(struct usbi_transfer *itransfer)
|
||||
void
|
||||
ugen_clear_transfer_priv(struct usbi_transfer *itransfer)
|
||||
{
|
||||
usbi_dbg("");
|
||||
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
@ -453,13 +473,50 @@ int
|
||||
ugen_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds_t nfds,
|
||||
int num_ready)
|
||||
{
|
||||
struct libusb_device_handle *handle;
|
||||
struct handle_priv *hpriv;
|
||||
struct usbi_transfer *itransfer;
|
||||
struct pollfd *pollfd;
|
||||
int i, err = 0;
|
||||
|
||||
usbi_dbg("");
|
||||
|
||||
/*
|
||||
* This backend is synchronous so there's no event to handle.
|
||||
*/
|
||||
pthread_mutex_lock(&ctx->open_devs_lock);
|
||||
for (i = 0; i < nfds && num_ready > 0; i++) {
|
||||
pollfd = &fds[i];
|
||||
|
||||
return (0);
|
||||
if (!pollfd->revents)
|
||||
continue;
|
||||
|
||||
num_ready--;
|
||||
list_for_each_entry(handle, &ctx->open_devs, list) {
|
||||
hpriv = (struct handle_priv *)handle->os_priv;
|
||||
|
||||
if (hpriv->pipe[0] == pollfd->fd)
|
||||
break;
|
||||
}
|
||||
|
||||
if (pollfd->revents & POLLERR) {
|
||||
usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]);
|
||||
usbi_handle_disconnect(handle);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (read(hpriv->pipe[0], &itransfer, sizeof(itransfer)) < 0) {
|
||||
err = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((err = usbi_handle_transfer_completion(itransfer,
|
||||
LIBUSB_TRANSFER_COMPLETED)))
|
||||
break;
|
||||
}
|
||||
pthread_mutex_unlock(&ctx->open_devs_lock);
|
||||
|
||||
if (err)
|
||||
return _errno_to_libusb(err);
|
||||
|
||||
return (LIBUSB_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
@ -552,8 +609,6 @@ _sync_control_transfer(struct usbi_transfer *itransfer)
|
||||
libusb_le16_to_cpu(setup->wIndex),
|
||||
libusb_le16_to_cpu(setup->wLength), transfer->timeout);
|
||||
|
||||
usbi_dbg("byte %p", transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE);
|
||||
|
||||
req.ucr_request.bmRequestType = setup->bmRequestType;
|
||||
req.ucr_request.bRequest = setup->bRequest;
|
||||
/* Don't use USETW, libusb already deals with the endianness */
|
||||
@ -579,15 +634,15 @@ _sync_control_transfer(struct usbi_transfer *itransfer)
|
||||
}
|
||||
|
||||
int
|
||||
_sync_gen_transfer(struct usbi_transfer *itransfer)
|
||||
_access_endpoint(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
struct handle_priv *hpriv;
|
||||
struct device_priv *dpriv;
|
||||
int fd, err, endpt, nr = 1;
|
||||
char *s, devnode[16];
|
||||
int fd, endpt;
|
||||
mode_t mode;
|
||||
|
||||
transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
|
||||
dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
|
||||
|
||||
endpt = UE_GET_ADDR(transfer->endpoint);
|
||||
@ -595,16 +650,34 @@ _sync_gen_transfer(struct usbi_transfer *itransfer)
|
||||
|
||||
usbi_dbg("endpoint %d mode %d", endpt, mode);
|
||||
|
||||
/* Pick the right node given the control one */
|
||||
strlcpy(devnode, dpriv->devnode, sizeof(devnode));
|
||||
s = strchr(devnode, '.');
|
||||
snprintf(s, 4, ".%02d", endpt);
|
||||
if (hpriv->endpoints[endpt] < 0) {
|
||||
/* Pick the right node given the control one */
|
||||
strlcpy(devnode, dpriv->devnode, sizeof(devnode));
|
||||
s = strchr(devnode, '.');
|
||||
snprintf(s, 4, ".%02d", endpt);
|
||||
|
||||
if ((fd = open(devnode, mode)) < 0)
|
||||
return (-1);
|
||||
|
||||
hpriv->endpoints[endpt] = fd;
|
||||
}
|
||||
|
||||
return (hpriv->endpoints[endpt]);
|
||||
}
|
||||
|
||||
int
|
||||
_sync_gen_transfer(struct usbi_transfer *itransfer)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
int fd, err, nr = 1;
|
||||
|
||||
transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||
|
||||
/*
|
||||
* Bulk, Interrupt or Isochronous transfer depends on the
|
||||
* endpoint and thus the node to open.
|
||||
*/
|
||||
if ((fd = open(devnode, mode)) < 0)
|
||||
if ((fd = _access_endpoint(transfer)) < 0)
|
||||
return _errno_to_libusb(errno);
|
||||
|
||||
if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
|
||||
@ -626,7 +699,6 @@ _sync_gen_transfer(struct usbi_transfer *itransfer)
|
||||
return _errno_to_libusb(err);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
itransfer->transferred = nr;
|
||||
|
||||
return (0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user