246 lines
6.7 KiB
C
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__*/
|