xref: /freebsd/lib/libusb/libusb10.h (revision 7850fa71f55a16f414bb21163d80a03a5ab34522)
1 /* $FreeBSD$ */
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 
73 static int get_next_timeout(libusb_context *ctx, struct timeval *tv, struct timeval *out);
74 static int handle_timeouts(struct libusb_context *ctx);
75 static int handle_events(struct libusb_context *ctx, struct timeval *tv);
76 extern struct libusb_context *usbi_default_context;
77 extern 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 
87 static inline void
88 dprintf(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 
109 struct usb_pollfd {
110 	struct libusb_pollfd pollfd;
111 	struct list_head list;
112 };
113 
114 struct 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 
122 static inline int
123 usb_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 
146 static inline void
147 usb_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 
175 static inline void
176 usb_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 
214 static inline void
215 usb_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