libusb10.h revision 194676
1/* $FreeBSD: head/lib/libusb/libusb10.h 194676 2009-06-23 01:04:58Z thompsa $ */ 2/*- 3 * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 13 * 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 24 * SUCH DAMAGE. 25 */ 26 27#ifndef __LIBUSB10_H__ 28#define __LIBUSB10_H__ 29 30/* 31 * The two following macros were taken from the original LibUSB v1.0 32 * for sake of compatibility: 33 */ 34#define USB_LIST_INIT(entry) \ 35 (entry)->prev = (entry)->next = entry; 36#define USB_LIST_EMPTY(entry) \ 37 ((entry)->next = (entry)) 38 39#define LIST_ADD(entry, head) \ 40 (entry)->next = (head)->next; \ 41 (entry)->prev = (head); \ 42 (head)->next->prev = (entry); \ 43 (head)->next = (entry); 44#define LIST_ADD_TAIL(entry, head) \ 45 (entry)->next = (head); \ 46 (entry)->prev = (head)->prev; \ 47 (head)->prev->next = (entry); \ 48 (head)->prev = (entry); 49#define LIST_DEL(entry) \ 50 (entry)->next->prev = (entry)->prev; \ 51 (entry)->prev->next = (entry)->next; 52 53#define LIST_ENT(ptr, type, member) \ 54 ((type *)((char *)(ptr) - (unsigned long) (&((type*)0L)->member))) 55#define LIST_FOREACH_ENTRY(pos, head, member) \ 56 for (pos = LIST_ENT((head)->next, typeof(*pos), member) ; \ 57 &pos->member != head ; \ 58 pos = LIST_ENT(pos->member.next, typeof(*pos), member)) 59#define LIST_FOREACH_ENTRY_SAFE(pos, n, head, member) \ 60 for (pos = LIST_ENT((head)->next, typeof(*pos), member), \ 61 n = LIST_ENT(pos->member.next, typeof(*pos), member); \ 62 &pos->member != (head); \ 63 pos = n, n = LIST_ENT(n->member.next, typeof(*n), member)) 64 65/* fetch libusb20_transfer from libusb20_device */ 66#define GET_XFER(xfer, endpoint, pdev)\ 67 xfer = libusb20_tr_get_pointer(pdev, \ 68 (2 *endpoint)|(endpoint/0x80)); \ 69 if (xfer == NULL) \ 70 return (LIBUSB_ERROR_OTHER); 71 72 73static int get_next_timeout(libusb_context *ctx, struct timeval *tv, struct timeval *out); 74static int handle_timeouts(struct libusb_context *ctx); 75static int handle_events(struct libusb_context *ctx, struct timeval *tv); 76extern struct libusb_context *usbi_default_context; 77extern pthread_mutex_t libusb20_lock; 78 79/* if ctx is NULL use default context*/ 80 81#define GET_CONTEXT(ctx) \ 82 if (ctx == NULL) ctx = usbi_default_context; 83 84#define MAX(a,b) (((a)>(b))?(a):(b)) 85#define USB_TIMED_OUT (1<<0) 86 87static inline void 88dprintf(libusb_context *ctx, int debug, char *str) 89{ 90 if (ctx->debug != debug) 91 return ; 92 93 switch (ctx->debug) { 94 case LIBUSB_DEBUG_NO: 95 break ; 96 case LIBUSB_DEBUG_FUNCTION: 97 printf("LIBUSB FUNCTION : %s\n", str); 98 break ; 99 case LIBUSB_DEBUG_TRANSFER: 100 printf("LIBUSB TRANSFER : %s\n", str); 101 break ; 102 default: 103 printf("LIBUSB UNKNOW DEBUG\n"); 104 break ; 105 } 106 return ; 107} 108 109struct usb_pollfd { 110 struct libusb_pollfd pollfd; 111 struct list_head list; 112}; 113 114struct usb_transfer { 115 int num_iso_packets; 116 struct list_head list; 117 struct timeval timeout; 118 int transferred; 119 uint8_t flags; 120}; 121 122static inline int 123usb_add_pollfd(libusb_context *ctx, int fd, short events) 124{ 125 struct usb_pollfd *pollfd; 126 127 if (ctx == NULL) 128 return (LIBUSB_ERROR_INVALID_PARAM); 129 130 pollfd = malloc(sizeof(*pollfd)); 131 if (pollfd == NULL) 132 return (LIBUSB_ERROR_NO_MEM); 133 134 pollfd->pollfd.fd = fd; 135 pollfd->pollfd.events = events; 136 137 pthread_mutex_lock(&ctx->pollfds_lock); 138 LIST_ADD_TAIL(&pollfd->list, &ctx->pollfds); 139 pthread_mutex_unlock(&ctx->pollfds_lock); 140 141 if (ctx->fd_added_cb) 142 ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data); 143 return (0); 144} 145 146static inline void 147usb_remove_pollfd(libusb_context *ctx, int fd) 148{ 149 struct usb_pollfd *pollfd; 150 int found; 151 152 found = 0; 153 pthread_mutex_lock(&ctx->pollfds_lock); 154 155 LIST_FOREACH_ENTRY(pollfd, &ctx->pollfds, list) { 156 if (pollfd->pollfd.fd == fd) { 157 found = 1; 158 break ; 159 } 160 } 161 162 if (found == 0) { 163 pthread_mutex_unlock(&ctx->pollfds_lock); 164 return ; 165 } 166 167 LIST_DEL(&pollfd->list); 168 pthread_mutex_unlock(&ctx->pollfds_lock); 169 free(pollfd); 170 171 if (ctx->fd_removed_cb) 172 ctx->fd_removed_cb(fd, ctx->fd_cb_user_data); 173} 174 175static inline void 176usb_handle_transfer_completion(struct usb_transfer *uxfer, 177 enum libusb_transfer_status status) 178{ 179 libusb_transfer *xfer; 180 libusb_context *ctx; 181 int len; 182 183 xfer = (struct libusb_transfer *) ((uint8_t *)uxfer + 184 sizeof(struct usb_transfer)); 185 ctx = xfer->dev_handle->dev->ctx; 186 187 pthread_mutex_lock(&ctx->flying_transfers_lock); 188 LIST_DEL(&uxfer->list); 189 pthread_mutex_unlock(&ctx->flying_transfers_lock); 190 191 if (status == LIBUSB_TRANSFER_COMPLETED && xfer->flags & 192 LIBUSB_TRANSFER_SHORT_NOT_OK) { 193 len = xfer->length; 194 if (xfer->type == LIBUSB_TRANSFER_TYPE_CONTROL) 195 len -= sizeof(libusb_control_setup); 196 if (len != uxfer->transferred) { 197 status = LIBUSB_TRANSFER_ERROR; 198 } 199 } 200 201 xfer->status = status; 202 xfer->actual_length = uxfer->transferred; 203 204 if (xfer->callback) 205 xfer->callback(xfer); 206 if (xfer->flags & LIBUSB_TRANSFER_FREE_TRANSFER) 207 libusb_free_transfer(xfer); 208 209 pthread_mutex_lock(&ctx->event_waiters_lock); 210 pthread_cond_broadcast(&ctx->event_waiters_cond); 211 pthread_mutex_unlock(&ctx->event_waiters_lock); 212} 213 214static inline void 215usb_handle_disconnect(struct libusb_device_handle *devh) 216{ 217 struct libusb_context *ctx; 218 struct libusb_transfer *xfer; 219 struct usb_transfer *cur; 220 struct usb_transfer *to_cancel; 221 222 ctx = devh->dev->ctx; 223 224 while (1) { 225 pthread_mutex_lock(&ctx->flying_transfers_lock); 226 to_cancel = NULL; 227 LIST_FOREACH_ENTRY(cur, &ctx->flying_transfers, list) { 228 xfer = (struct libusb_transfer *) ((uint8_t *)cur + 229 sizeof(struct usb_transfer)); 230 if (xfer->dev_handle == devh) { 231 to_cancel = cur; 232 break ; 233 } 234 } 235 pthread_mutex_unlock(&ctx->flying_transfers_lock); 236 237 if (to_cancel == NULL) 238 break ; 239 240 usb_handle_transfer_completion(to_cancel, LIBUSB_TRANSFER_NO_DEVICE); 241 } 242 return ; 243} 244 245#endif /*__LIBUSB10_H__*/ 246