source: mainline/uspace/lib/usb/src/host/device_keeper.c@ 64dbc83

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 64dbc83 was d93b3e3, checked in by Jan Vesely <jano.vesely@…>, 15 years ago

Add lock for control transfers (hc can't guarantee their atomicity)

Use one wait condition for multiple waits (rename)

  • Property mode set to 100644
File size: 11.3 KB
RevLine 
[5f183dc]1/*
2 * Copyright (c) 2011 Jan Vesely
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
[1fb1339]29/** @addtogroup libusb
[5f183dc]30 * @{
31 */
32/** @file
[e34e77a]33 * Device keeper structure and functions (implementation).
[5f183dc]34 */
35#include <assert.h>
36#include <errno.h>
[c0964800]37#include <usb/debug.h>
[1fb1339]38#include <usb/host/device_keeper.h>
[5f183dc]39
40/*----------------------------------------------------------------------------*/
[17ceb72]41/** Initialize device keeper structure.
[a7e2f0d]42 *
43 * @param[in] instance Memory place to initialize.
[17ceb72]44 *
45 * Set all values to false/0.
[a7e2f0d]46 */
[68b5ed6e]47void usb_device_keeper_init(usb_device_keeper_t *instance)
[5f183dc]48{
49 assert(instance);
50 fibril_mutex_initialize(&instance->guard);
[d93b3e3]51 fibril_condvar_initialize(&instance->change);
[5f183dc]52 instance->last_address = 0;
53 unsigned i = 0;
54 for (; i < USB_ADDRESS_COUNT; ++i) {
55 instance->devices[i].occupied = false;
[d93b3e3]56 instance->devices[i].control_used = false;
[5f183dc]57 instance->devices[i].handle = 0;
[c15070c]58 instance->devices[i].toggle_status[0] = 0;
59 instance->devices[i].toggle_status[1] = 0;
[5f183dc]60 }
61}
62/*----------------------------------------------------------------------------*/
[17ceb72]63/** Attempt to obtain address 0, blocks.
[a7e2f0d]64 *
65 * @param[in] instance Device keeper structure to use.
66 * @param[in] speed Speed of the device requesting default address.
67 */
[e34e77a]68void usb_device_keeper_reserve_default_address(usb_device_keeper_t *instance,
69 usb_speed_t speed)
[5f183dc]70{
71 assert(instance);
72 fibril_mutex_lock(&instance->guard);
73 while (instance->devices[USB_ADDRESS_DEFAULT].occupied) {
[d93b3e3]74 fibril_condvar_wait(&instance->change, &instance->guard);
[5f183dc]75 }
76 instance->devices[USB_ADDRESS_DEFAULT].occupied = true;
77 instance->devices[USB_ADDRESS_DEFAULT].speed = speed;
78 fibril_mutex_unlock(&instance->guard);
79}
80/*----------------------------------------------------------------------------*/
[17ceb72]81/** Attempt to obtain address 0, blocks.
[a7e2f0d]82 *
83 * @param[in] instance Device keeper structure to use.
84 * @param[in] speed Speed of the device requesting default address.
85 */
[68b5ed6e]86void usb_device_keeper_release_default_address(usb_device_keeper_t *instance)
[5f183dc]87{
88 assert(instance);
89 fibril_mutex_lock(&instance->guard);
90 instance->devices[USB_ADDRESS_DEFAULT].occupied = false;
91 fibril_mutex_unlock(&instance->guard);
[d93b3e3]92 fibril_condvar_signal(&instance->change);
[5f183dc]93}
94/*----------------------------------------------------------------------------*/
[17ceb72]95/** Check setup packet data for signs of toggle reset.
[a7e2f0d]96 *
97 * @param[in] instance Device keeper structure to use.
98 * @param[in] target Device to receive setup packet.
99 * @param[in] data Setup packet data.
[17ceb72]100 *
101 * Really ugly one.
[a7e2f0d]102 */
[e34e77a]103void usb_device_keeper_reset_if_need(usb_device_keeper_t *instance,
104 usb_target_t target, const uint8_t *data)
[98807e16]105{
106 assert(instance);
107 fibril_mutex_lock(&instance->guard);
108 if (target.endpoint > 15 || target.endpoint < 0
109 || target.address >= USB_ADDRESS_COUNT || target.address < 0
110 || !instance->devices[target.address].occupied) {
[a7e2f0d]111 fibril_mutex_unlock(&instance->guard);
[17ceb72]112 usb_log_error("Invalid data when checking for toggle reset.\n");
[a7e2f0d]113 return;
[98807e16]114 }
115
116 switch (data[1])
117 {
118 case 0x01: /*clear feature*/
[a7e2f0d]119 /* recipient is endpoint, value is zero (ENDPOINT_STALL) */
[98807e16]120 if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
[a7e2f0d]121 /* endpoint number is < 16, thus first byte is enough */
[c15070c]122 instance->devices[target.address].toggle_status[0] &=
123 ~(1 << data[4]);
124 instance->devices[target.address].toggle_status[1] &=
[a7e2f0d]125 ~(1 << data[4]);
[98807e16]126 }
127 break;
128
129 case 0x9: /* set configuration */
130 case 0x11: /* set interface */
[c0964800]131 /* target must be device */
132 if ((data[0] & 0xf) == 0) {
[c15070c]133 instance->devices[target.address].toggle_status[0] = 0;
134 instance->devices[target.address].toggle_status[1] = 0;
[c0964800]135 }
[98807e16]136 break;
137 }
138 fibril_mutex_unlock(&instance->guard);
139}
140/*----------------------------------------------------------------------------*/
[17ceb72]141/** Get current value of endpoint toggle.
[a7e2f0d]142 *
143 * @param[in] instance Device keeper structure to use.
144 * @param[in] target Device and endpoint used.
145 * @return Error code
146 */
[e34e77a]147int usb_device_keeper_get_toggle(usb_device_keeper_t *instance,
148 usb_target_t target, usb_direction_t direction)
[edb5f837]149{
150 assert(instance);
[c15070c]151 /* only control pipes are bi-directional and those do not need toggle */
152 if (direction == USB_DIRECTION_BOTH)
153 return ENOENT;
[edb5f837]154 int ret;
155 fibril_mutex_lock(&instance->guard);
156 if (target.endpoint > 15 || target.endpoint < 0
157 || target.address >= USB_ADDRESS_COUNT || target.address < 0
158 || !instance->devices[target.address].occupied) {
[17ceb72]159 usb_log_error("Invalid data when asking for toggle value.\n");
[edb5f837]160 ret = EINVAL;
161 } else {
[c15070c]162 ret = (instance->devices[target.address].toggle_status[direction]
[a7e2f0d]163 >> target.endpoint) & 1;
[edb5f837]164 }
165 fibril_mutex_unlock(&instance->guard);
166 return ret;
167}
168/*----------------------------------------------------------------------------*/
[17ceb72]169/** Set current value of endpoint toggle.
[a7e2f0d]170 *
171 * @param[in] instance Device keeper structure to use.
172 * @param[in] target Device and endpoint used.
[17ceb72]173 * @param[in] toggle Toggle value.
[a7e2f0d]174 * @return Error code.
175 */
[68b5ed6e]176int usb_device_keeper_set_toggle(usb_device_keeper_t *instance,
[c15070c]177 usb_target_t target, usb_direction_t direction, bool toggle)
[edb5f837]178{
179 assert(instance);
[c15070c]180 /* only control pipes are bi-directional and those do not need toggle */
181 if (direction == USB_DIRECTION_BOTH)
182 return ENOENT;
[edb5f837]183 int ret;
184 fibril_mutex_lock(&instance->guard);
185 if (target.endpoint > 15 || target.endpoint < 0
186 || target.address >= USB_ADDRESS_COUNT || target.address < 0
187 || !instance->devices[target.address].occupied) {
[17ceb72]188 usb_log_error("Invalid data when setting toggle value.\n");
[edb5f837]189 ret = EINVAL;
190 } else {
191 if (toggle) {
[c15070c]192 instance->devices[target.address].toggle_status[direction]
193 |= (1 << target.endpoint);
[edb5f837]194 } else {
[c15070c]195 instance->devices[target.address].toggle_status[direction]
196 &= ~(1 << target.endpoint);
[edb5f837]197 }
198 ret = EOK;
199 }
200 fibril_mutex_unlock(&instance->guard);
201 return ret;
202}
203/*----------------------------------------------------------------------------*/
[17ceb72]204/** Get a free USB address
[a7e2f0d]205 *
206 * @param[in] instance Device keeper structure to use.
207 * @param[in] speed Speed of the device requiring address.
208 * @return Free address, or error code.
209 */
[e34e77a]210usb_address_t device_keeper_get_free_address(usb_device_keeper_t *instance,
211 usb_speed_t speed)
[5f183dc]212{
213 assert(instance);
214 fibril_mutex_lock(&instance->guard);
215
[171cd88]216 usb_address_t new_address = instance->last_address;
217 do {
218 ++new_address;
219 if (new_address > USB11_ADDRESS_MAX)
220 new_address = 1;
[5f183dc]221 if (new_address == instance->last_address) {
222 fibril_mutex_unlock(&instance->guard);
223 return ENOSPC;
224 }
[171cd88]225 } while (instance->devices[new_address].occupied);
[5f183dc]226
227 assert(new_address != USB_ADDRESS_DEFAULT);
228 assert(instance->devices[new_address].occupied == false);
229 instance->devices[new_address].occupied = true;
230 instance->devices[new_address].speed = speed;
[c15070c]231 instance->devices[new_address].toggle_status[0] = 0;
232 instance->devices[new_address].toggle_status[1] = 0;
[5f183dc]233 instance->last_address = new_address;
234 fibril_mutex_unlock(&instance->guard);
235 return new_address;
236}
237/*----------------------------------------------------------------------------*/
[17ceb72]238/** Bind USB address to devman handle.
[a7e2f0d]239 *
240 * @param[in] instance Device keeper structure to use.
241 * @param[in] address Device address
242 * @param[in] handle Devman handle of the device.
243 */
[e34e77a]244void usb_device_keeper_bind(usb_device_keeper_t *instance,
245 usb_address_t address, devman_handle_t handle)
[5f183dc]246{
247 assert(instance);
248 fibril_mutex_lock(&instance->guard);
249 assert(address > 0);
250 assert(address <= USB11_ADDRESS_MAX);
251 assert(instance->devices[address].occupied);
252 instance->devices[address].handle = handle;
253 fibril_mutex_unlock(&instance->guard);
254}
255/*----------------------------------------------------------------------------*/
[17ceb72]256/** Release used USB address.
[a7e2f0d]257 *
258 * @param[in] instance Device keeper structure to use.
259 * @param[in] address Device address
260 */
[e34e77a]261void usb_device_keeper_release(usb_device_keeper_t *instance,
262 usb_address_t address)
[5f183dc]263{
264 assert(instance);
265 assert(address > 0);
266 assert(address <= USB11_ADDRESS_MAX);
267
268 fibril_mutex_lock(&instance->guard);
269 assert(instance->devices[address].occupied);
270 instance->devices[address].occupied = false;
271 fibril_mutex_unlock(&instance->guard);
272}
273/*----------------------------------------------------------------------------*/
[17ceb72]274/** Find USB address associated with the device
[a7e2f0d]275 *
276 * @param[in] instance Device keeper structure to use.
277 * @param[in] handle Devman handle of the device seeking its address.
278 * @return USB Address, or error code.
279 */
[e34e77a]280usb_address_t usb_device_keeper_find(usb_device_keeper_t *instance,
281 devman_handle_t handle)
[5f183dc]282{
283 assert(instance);
284 fibril_mutex_lock(&instance->guard);
285 usb_address_t address = 1;
286 while (address <= USB11_ADDRESS_MAX) {
287 if (instance->devices[address].handle == handle) {
288 fibril_mutex_unlock(&instance->guard);
289 return address;
290 }
[86c2ccd]291 ++address;
[5f183dc]292 }
293 fibril_mutex_unlock(&instance->guard);
294 return ENOENT;
295}
296/*----------------------------------------------------------------------------*/
[17ceb72]297/** Get speed associated with the address
[a7e2f0d]298 *
299 * @param[in] instance Device keeper structure to use.
300 * @param[in] address Address of the device.
301 * @return USB speed.
302 */
[e34e77a]303usb_speed_t usb_device_keeper_get_speed(usb_device_keeper_t *instance,
304 usb_address_t address)
[5f183dc]305{
306 assert(instance);
307 assert(address >= 0);
308 assert(address <= USB11_ADDRESS_MAX);
309 return instance->devices[address].speed;
310}
[d93b3e3]311/*----------------------------------------------------------------------------*/
312void usb_device_keeper_use_control(usb_device_keeper_t *instance,
313 usb_address_t address)
314{
315 assert(instance);
316 fibril_mutex_lock(&instance->guard);
317 while (instance->devices[address].control_used) {
318 fibril_condvar_wait(&instance->change, &instance->guard);
319 }
320 instance->devices[address].control_used = true;
321 fibril_mutex_unlock(&instance->guard);
322}
323/*----------------------------------------------------------------------------*/
324void usb_device_keeper_release_control(usb_device_keeper_t *instance,
325 usb_address_t address)
326{
327 assert(instance);
328 fibril_mutex_lock(&instance->guard);
329 instance->devices[address].control_used = false;
330 fibril_mutex_unlock(&instance->guard);
331 fibril_condvar_signal(&instance->change);
332}
[5f183dc]333/**
334 * @}
335 */
Note: See TracBrowser for help on using the repository browser.