freebsd-src/lib/libusb/libusb10.h
Andrew Thompson 8c8fff3177 Add files missed in r194674.
Add libusb 1.0 support which is compatible with the latest revision on
Sourceforge. Libusb 1.0 is a portable usb api released December 2008 and
supersedes the original libusb released 10 years ago, it supports isochronous
endpoints and asynchronous I/O.  Many applications have already started using
the interfaces.

This has been developed as part of Google Summer of Code this year by Sylvestre
Gallon and has been cribbed early due to it being desirable in FreeBSD 8.0

Submitted by: Sylvestre Gallon
Sponsored by: Google Summer of Code 2009
Reviewed by:  Hans Petter Selasky
2009-06-23 01:04:58 +00:00

246 lines
6.7 KiB
C

/* $FreeBSD$ */
/*-
* Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __LIBUSB10_H__
#define __LIBUSB10_H__
/*
* The two following macros were taken from the original LibUSB v1.0
* for sake of compatibility:
*/
#define USB_LIST_INIT(entry) \
(entry)->prev = (entry)->next = entry;
#define USB_LIST_EMPTY(entry) \
((entry)->next = (entry))
#define LIST_ADD(entry, head) \
(entry)->next = (head)->next; \
(entry)->prev = (head); \
(head)->next->prev = (entry); \
(head)->next = (entry);
#define LIST_ADD_TAIL(entry, head) \
(entry)->next = (head); \
(entry)->prev = (head)->prev; \
(head)->prev->next = (entry); \
(head)->prev = (entry);
#define LIST_DEL(entry) \
(entry)->next->prev = (entry)->prev; \
(entry)->prev->next = (entry)->next;
#define LIST_ENT(ptr, type, member) \
((type *)((char *)(ptr) - (unsigned long) (&((type*)0L)->member)))
#define LIST_FOREACH_ENTRY(pos, head, member) \
for (pos = LIST_ENT((head)->next, typeof(*pos), member) ; \
&pos->member != head ; \
pos = LIST_ENT(pos->member.next, typeof(*pos), member))
#define LIST_FOREACH_ENTRY_SAFE(pos, n, head, member) \
for (pos = LIST_ENT((head)->next, typeof(*pos), member), \
n = LIST_ENT(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = LIST_ENT(n->member.next, typeof(*n), member))
/* fetch libusb20_transfer from libusb20_device */
#define GET_XFER(xfer, endpoint, pdev)\
xfer = libusb20_tr_get_pointer(pdev, \
(2 *endpoint)|(endpoint/0x80)); \
if (xfer == NULL) \
return (LIBUSB_ERROR_OTHER);
static int get_next_timeout(libusb_context *ctx, struct timeval *tv, struct timeval *out);
static int handle_timeouts(struct libusb_context *ctx);
static int handle_events(struct libusb_context *ctx, struct timeval *tv);
extern struct libusb_context *usbi_default_context;
extern pthread_mutex_t libusb20_lock;
/* if ctx is NULL use default context*/
#define GET_CONTEXT(ctx) \
if (ctx == NULL) ctx = usbi_default_context;
#define MAX(a,b) (((a)>(b))?(a):(b))
#define USB_TIMED_OUT (1<<0)
static inline void
dprintf(libusb_context *ctx, int debug, char *str)
{
if (ctx->debug != debug)
return ;
switch (ctx->debug) {
case LIBUSB_DEBUG_NO:
break ;
case LIBUSB_DEBUG_FUNCTION:
printf("LIBUSB FUNCTION : %s\n", str);
break ;
case LIBUSB_DEBUG_TRANSFER:
printf("LIBUSB TRANSFER : %s\n", str);
break ;
default:
printf("LIBUSB UNKNOW DEBUG\n");
break ;
}
return ;
}
struct usb_pollfd {
struct libusb_pollfd pollfd;
struct list_head list;
};
struct usb_transfer {
int num_iso_packets;
struct list_head list;
struct timeval timeout;
int transferred;
uint8_t flags;
};
static inline int
usb_add_pollfd(libusb_context *ctx, int fd, short events)
{
struct usb_pollfd *pollfd;
if (ctx == NULL)
return (LIBUSB_ERROR_INVALID_PARAM);
pollfd = malloc(sizeof(*pollfd));
if (pollfd == NULL)
return (LIBUSB_ERROR_NO_MEM);
pollfd->pollfd.fd = fd;
pollfd->pollfd.events = events;
pthread_mutex_lock(&ctx->pollfds_lock);
LIST_ADD_TAIL(&pollfd->list, &ctx->pollfds);
pthread_mutex_unlock(&ctx->pollfds_lock);
if (ctx->fd_added_cb)
ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data);
return (0);
}
static inline void
usb_remove_pollfd(libusb_context *ctx, int fd)
{
struct usb_pollfd *pollfd;
int found;
found = 0;
pthread_mutex_lock(&ctx->pollfds_lock);
LIST_FOREACH_ENTRY(pollfd, &ctx->pollfds, list) {
if (pollfd->pollfd.fd == fd) {
found = 1;
break ;
}
}
if (found == 0) {
pthread_mutex_unlock(&ctx->pollfds_lock);
return ;
}
LIST_DEL(&pollfd->list);
pthread_mutex_unlock(&ctx->pollfds_lock);
free(pollfd);
if (ctx->fd_removed_cb)
ctx->fd_removed_cb(fd, ctx->fd_cb_user_data);
}
static inline void
usb_handle_transfer_completion(struct usb_transfer *uxfer,
enum libusb_transfer_status status)
{
libusb_transfer *xfer;
libusb_context *ctx;
int len;
xfer = (struct libusb_transfer *) ((uint8_t *)uxfer +
sizeof(struct usb_transfer));
ctx = xfer->dev_handle->dev->ctx;
pthread_mutex_lock(&ctx->flying_transfers_lock);
LIST_DEL(&uxfer->list);
pthread_mutex_unlock(&ctx->flying_transfers_lock);
if (status == LIBUSB_TRANSFER_COMPLETED && xfer->flags &
LIBUSB_TRANSFER_SHORT_NOT_OK) {
len = xfer->length;
if (xfer->type == LIBUSB_TRANSFER_TYPE_CONTROL)
len -= sizeof(libusb_control_setup);
if (len != uxfer->transferred) {
status = LIBUSB_TRANSFER_ERROR;
}
}
xfer->status = status;
xfer->actual_length = uxfer->transferred;
if (xfer->callback)
xfer->callback(xfer);
if (xfer->flags & LIBUSB_TRANSFER_FREE_TRANSFER)
libusb_free_transfer(xfer);
pthread_mutex_lock(&ctx->event_waiters_lock);
pthread_cond_broadcast(&ctx->event_waiters_cond);
pthread_mutex_unlock(&ctx->event_waiters_lock);
}
static inline void
usb_handle_disconnect(struct libusb_device_handle *devh)
{
struct libusb_context *ctx;
struct libusb_transfer *xfer;
struct usb_transfer *cur;
struct usb_transfer *to_cancel;
ctx = devh->dev->ctx;
while (1) {
pthread_mutex_lock(&ctx->flying_transfers_lock);
to_cancel = NULL;
LIST_FOREACH_ENTRY(cur, &ctx->flying_transfers, list) {
xfer = (struct libusb_transfer *) ((uint8_t *)cur +
sizeof(struct usb_transfer));
if (xfer->dev_handle == devh) {
to_cancel = cur;
break ;
}
}
pthread_mutex_unlock(&ctx->flying_transfers_lock);
if (to_cancel == NULL)
break ;
usb_handle_transfer_completion(to_cancel, LIBUSB_TRANSFER_NO_DEVICE);
}
return ;
}
#endif /*__LIBUSB10_H__*/