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