source: mainline/uspace/lib/usb/src/addrkeep.c@ 1efe89b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1efe89b was 8555112, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

Address keeping in addrkeep.h only

Removed symbolic link, the hcd.h file makes no sense.

  • Property mode set to 100644
File size: 9.4 KB
Line 
1/*
2 * Copyright (c) 2010 Vojtech Horky
3 * 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 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libusb
30 * @{
31 */
32/** @file
33 * @brief Address keeping.
34 */
35#include <usb/addrkeep.h>
36#include <errno.h>
37#include <assert.h>
38
39/** For loop over all used addresses in address keeping.
40 *
41 * @param link Iterator.
42 * @param addresses Addresses keeping structure to iterate.
43 */
44#define for_all_used_addresses(link, addresses) \
45 for (link = (addresses)->used_addresses.next; \
46 link != &(addresses)->used_addresses; \
47 link = link->next)
48
49/** Get instance of usb_address_keeping_used_t. */
50#define used_address_get_instance(lnk) \
51 list_get_instance(lnk, usb_address_keeping_used_t, link)
52
53/** Invalid value of devman handle. */
54#define INVALID_DEVMAN_HANDLE \
55 ((devman_handle_t)-1)
56
57/** Creates structure for used USB address.
58 *
59 * @param address USB address.
60 * @return Initialized structure.
61 * @retval NULL Out of memory.
62 */
63static usb_address_keeping_used_t *usb_address_keeping_used_create(
64 usb_address_t address)
65{
66 usb_address_keeping_used_t *info
67 = malloc(sizeof(usb_address_keeping_used_t));
68 if (info == NULL) {
69 return NULL;
70 }
71
72 info->address = address;
73 info->devman_handle = INVALID_DEVMAN_HANDLE;
74 list_initialize(&info->link);
75 return info;
76}
77
78/** Destroys structure for used USB address.
79 *
80 * @param info Structure to be destroyed.
81 */
82static void usb_address_keeping_used_destroy(usb_address_keeping_used_t *info)
83{
84 free(info);
85}
86
87/** Find used USB address structure by USB address.
88 *
89 * It is expected that guard mutex is already locked.
90 *
91 * @param addresses Address keeping info.
92 * @param address Address to be found.
93 * @return Structure describing looked for address.
94 * @retval NULL Address not found.
95 */
96static usb_address_keeping_used_t *usb_address_keeping_used_find_no_lock(
97 usb_address_keeping_t *addresses, usb_address_t address)
98{
99 link_t *link;
100 for_all_used_addresses(link, addresses) {
101 usb_address_keeping_used_t *info
102 = used_address_get_instance(link);
103
104 if (info->address == address) {
105 return info;
106 }
107 }
108
109 return NULL;
110}
111
112/** Initialize address keeping structure.
113 *
114 * @param addresses Address keeping info.
115 * @param max_address Maximum USB address (exclusive bound).
116 */
117void usb_address_keeping_init(usb_address_keeping_t *addresses,
118 usb_address_t max_address)
119{
120 /*
121 * Items related with used addresses.
122 */
123 addresses->max_address = max_address;
124 list_initialize(&addresses->used_addresses);
125 fibril_mutex_initialize(&addresses->used_addresses_guard);
126 fibril_condvar_initialize(&addresses->used_addresses_condvar);
127
128 /*
129 * Items related with default address.
130 */
131 addresses->default_available = true;
132 fibril_condvar_initialize(&addresses->default_condvar);
133 fibril_mutex_initialize(&addresses->default_condvar_guard);
134}
135
136/** Reserved default USB address.
137 *
138 * This function blocks until reserved address is available.
139 *
140 * @see usb_address_keeping_release_default
141 *
142 * @param addresses Address keeping info.
143 */
144void usb_address_keeping_reserve_default(usb_address_keeping_t *addresses)
145{
146 fibril_mutex_lock(&addresses->default_condvar_guard);
147 while (!addresses->default_available) {
148 fibril_condvar_wait(&addresses->default_condvar,
149 &addresses->default_condvar_guard);
150 }
151 addresses->default_available = false;
152 fibril_mutex_unlock(&addresses->default_condvar_guard);
153}
154
155/** Releases default USB address.
156 *
157 * @see usb_address_keeping_reserve_default
158 *
159 * @param addresses Address keeping info.
160 */
161void usb_address_keeping_release_default(usb_address_keeping_t *addresses)
162{
163 fibril_mutex_lock(&addresses->default_condvar_guard);
164 addresses->default_available = true;
165 fibril_condvar_signal(&addresses->default_condvar);
166 fibril_mutex_unlock(&addresses->default_condvar_guard);
167}
168
169/** Request free address assignment.
170 *
171 * This function does not block when there are not free addresses to be
172 * assigned.
173 *
174 * @param addresses Address keeping info.
175 * @return USB address that could be used or negative error code.
176 * @retval ELIMIT No more addresses to assign.
177 * @retval ENOMEM Out of memory.
178 */
179usb_address_t usb_address_keeping_request(usb_address_keeping_t *addresses)
180{
181 usb_address_t previous_address = 0;
182 usb_address_t free_address = 0;
183
184 fibril_mutex_lock(&addresses->used_addresses_guard);
185 link_t *new_address_position;
186 if (list_empty(&addresses->used_addresses)) {
187 free_address = 1;
188 new_address_position = addresses->used_addresses.next;
189 } else {
190 usb_address_keeping_used_t *first
191 = used_address_get_instance(addresses->used_addresses.next);
192 previous_address = first->address;
193
194 for_all_used_addresses(new_address_position, addresses) {
195 usb_address_keeping_used_t *info
196 = used_address_get_instance(new_address_position);
197 if (info->address > previous_address + 1) {
198 free_address = previous_address + 1;
199 break;
200 }
201 previous_address = info->address;
202 }
203
204 if (free_address == 0) {
205 usb_address_keeping_used_t *last
206 = used_address_get_instance(addresses->used_addresses.next);
207 free_address = last->address + 1;
208 }
209 }
210
211 if (free_address >= addresses->max_address) {
212 free_address = ELIMIT;
213 goto leave;
214 }
215
216 usb_address_keeping_used_t *used
217 = usb_address_keeping_used_create(free_address);
218 if (used == NULL) {
219 free_address = ENOMEM;
220 goto leave;
221 }
222
223 list_prepend(&used->link, new_address_position);
224
225leave:
226 fibril_mutex_unlock(&addresses->used_addresses_guard);
227
228 return free_address;
229}
230
231/** Release USB address.
232 *
233 * @param addresses Address keeping info.
234 * @param address Address to be released.
235 * @return Error code.
236 * @retval ENOENT Address is not in use.
237 */
238int usb_address_keeping_release(usb_address_keeping_t *addresses,
239 usb_address_t address)
240{
241 int rc = ENOENT;
242
243 fibril_mutex_lock(&addresses->used_addresses_guard);
244
245 usb_address_keeping_used_t *info
246 = usb_address_keeping_used_find_no_lock(addresses, address);
247
248 if (info != NULL) {
249 rc = EOK;
250 list_remove(&info->link);
251 usb_address_keeping_used_destroy(info);
252 }
253
254 fibril_mutex_unlock(&addresses->used_addresses_guard);
255
256 return rc;
257}
258
259/** Bind devman handle with USB address.
260 *
261 * When the @p address is invalid (e.g. no such entry), the request
262 * is silently ignored.
263 *
264 * @param addresses Address keeping info.
265 * @param address USB address.
266 * @param handle Devman handle.
267 */
268void usb_address_keeping_devman_bind(usb_address_keeping_t *addresses,
269 usb_address_t address, devman_handle_t handle)
270{
271 fibril_mutex_lock(&addresses->used_addresses_guard);
272
273 usb_address_keeping_used_t *info
274 = usb_address_keeping_used_find_no_lock(addresses, address);
275 if (info == NULL) {
276 goto leave;
277 }
278
279 assert(info->address == address);
280 info->devman_handle = handle;
281
282 /*
283 * Inform that new handle was added.
284 */
285 fibril_condvar_broadcast(&addresses->used_addresses_condvar);
286
287leave:
288 fibril_mutex_unlock(&addresses->used_addresses_guard);
289}
290
291/** Find address by its devman handle.
292 *
293 * @param addresses Address keeping info.
294 * @param handle Devman handle.
295 * @return USB address or negative error code.
296 * @retval ENOENT No such address.
297 */
298static usb_address_t usb_address_keeping_find_no_lock(
299 usb_address_keeping_t *addresses, devman_handle_t handle)
300{
301 usb_address_t address = ENOENT;
302
303 link_t *link;
304 for_all_used_addresses(link, addresses) {
305 usb_address_keeping_used_t *info
306 = used_address_get_instance(link);
307
308 if (info->devman_handle == handle) {
309 address = info->address;
310 break;
311 }
312 }
313
314 return address;
315}
316
317/** Find USB address by its devman handle.
318 *
319 * This function blocks until corresponding address is found.
320 *
321 * @param addresses Address keeping info.
322 * @param handle Devman handle.
323 * @return USB address or negative error code.
324 */
325usb_address_t usb_address_keeping_find(usb_address_keeping_t *addresses,
326 devman_handle_t handle)
327{
328 usb_address_t address = ENOENT;
329
330 fibril_mutex_lock(&addresses->used_addresses_guard);
331 while (true) {
332 address = usb_address_keeping_find_no_lock(addresses, handle);
333 if (address != ENOENT) {
334 break;
335 }
336 fibril_condvar_wait(&addresses->used_addresses_condvar,
337 &addresses->used_addresses_guard);
338 }
339
340 fibril_mutex_unlock(&addresses->used_addresses_guard);
341
342 return address;
343}
344
345/**
346 * @}
347 */
Note: See TracBrowser for help on using the repository browser.