source: mainline/uspace/lib/usb/src/host/device_keeper.c@ 0053fa38

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

Use per endpoint control transfer mutex

  • Property mode set to 100644
File size: 11.5 KB
Line 
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
29/** @addtogroup libusb
30 * @{
31 */
32/** @file
33 * Device keeper structure and functions (implementation).
34 */
35#include <assert.h>
36#include <errno.h>
37#include <usb/debug.h>
38#include <usb/host/device_keeper.h>
39
40/*----------------------------------------------------------------------------*/
41/** Initialize device keeper structure.
42 *
43 * @param[in] instance Memory place to initialize.
44 *
45 * Set all values to false/0.
46 */
47void usb_device_keeper_init(usb_device_keeper_t *instance)
48{
49 assert(instance);
50 fibril_mutex_initialize(&instance->guard);
51 fibril_condvar_initialize(&instance->change);
52 instance->last_address = 0;
53 unsigned i = 0;
54 for (; i < USB_ADDRESS_COUNT; ++i) {
55 instance->devices[i].occupied = false;
56 instance->devices[i].control_used = 0;
57 instance->devices[i].handle = 0;
58 instance->devices[i].toggle_status[0] = 0;
59 instance->devices[i].toggle_status[1] = 0;
60 }
61}
62/*----------------------------------------------------------------------------*/
63/** Attempt to obtain address 0, blocks.
64 *
65 * @param[in] instance Device keeper structure to use.
66 * @param[in] speed Speed of the device requesting default address.
67 */
68void usb_device_keeper_reserve_default_address(usb_device_keeper_t *instance,
69 usb_speed_t speed)
70{
71 assert(instance);
72 fibril_mutex_lock(&instance->guard);
73 while (instance->devices[USB_ADDRESS_DEFAULT].occupied) {
74 fibril_condvar_wait(&instance->change, &instance->guard);
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/*----------------------------------------------------------------------------*/
81/** Attempt to obtain address 0, blocks.
82 *
83 * @param[in] instance Device keeper structure to use.
84 * @param[in] speed Speed of the device requesting default address.
85 */
86void usb_device_keeper_release_default_address(usb_device_keeper_t *instance)
87{
88 assert(instance);
89 fibril_mutex_lock(&instance->guard);
90 instance->devices[USB_ADDRESS_DEFAULT].occupied = false;
91 fibril_mutex_unlock(&instance->guard);
92 fibril_condvar_signal(&instance->change);
93}
94/*----------------------------------------------------------------------------*/
95/** Check setup packet data for signs of toggle reset.
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.
100 *
101 * Really ugly one.
102 */
103void usb_device_keeper_reset_if_need(usb_device_keeper_t *instance,
104 usb_target_t target, const uint8_t *data)
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) {
111 fibril_mutex_unlock(&instance->guard);
112 usb_log_error("Invalid data when checking for toggle reset.\n");
113 return;
114 }
115
116 switch (data[1])
117 {
118 case 0x01: /*clear feature*/
119 /* recipient is endpoint, value is zero (ENDPOINT_STALL) */
120 if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
121 /* endpoint number is < 16, thus first byte is enough */
122 instance->devices[target.address].toggle_status[0] &=
123 ~(1 << data[4]);
124 instance->devices[target.address].toggle_status[1] &=
125 ~(1 << data[4]);
126 }
127 break;
128
129 case 0x9: /* set configuration */
130 case 0x11: /* set interface */
131 /* target must be device */
132 if ((data[0] & 0xf) == 0) {
133 instance->devices[target.address].toggle_status[0] = 0;
134 instance->devices[target.address].toggle_status[1] = 0;
135 }
136 break;
137 }
138 fibril_mutex_unlock(&instance->guard);
139}
140/*----------------------------------------------------------------------------*/
141/** Get current value of endpoint toggle.
142 *
143 * @param[in] instance Device keeper structure to use.
144 * @param[in] target Device and endpoint used.
145 * @return Error code
146 */
147int usb_device_keeper_get_toggle(usb_device_keeper_t *instance,
148 usb_target_t target, usb_direction_t direction)
149{
150 assert(instance);
151 /* only control pipes are bi-directional and those do not need toggle */
152 if (direction == USB_DIRECTION_BOTH)
153 return ENOENT;
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) {
159 usb_log_error("Invalid data when asking for toggle value.\n");
160 ret = EINVAL;
161 } else {
162 ret = (instance->devices[target.address].toggle_status[direction]
163 >> target.endpoint) & 1;
164 }
165 fibril_mutex_unlock(&instance->guard);
166 return ret;
167}
168/*----------------------------------------------------------------------------*/
169/** Set current value of endpoint toggle.
170 *
171 * @param[in] instance Device keeper structure to use.
172 * @param[in] target Device and endpoint used.
173 * @param[in] toggle Toggle value.
174 * @return Error code.
175 */
176int usb_device_keeper_set_toggle(usb_device_keeper_t *instance,
177 usb_target_t target, usb_direction_t direction, bool toggle)
178{
179 assert(instance);
180 /* only control pipes are bi-directional and those do not need toggle */
181 if (direction == USB_DIRECTION_BOTH)
182 return ENOENT;
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) {
188 usb_log_error("Invalid data when setting toggle value.\n");
189 ret = EINVAL;
190 } else {
191 if (toggle) {
192 instance->devices[target.address].toggle_status[direction]
193 |= (1 << target.endpoint);
194 } else {
195 instance->devices[target.address].toggle_status[direction]
196 &= ~(1 << target.endpoint);
197 }
198 ret = EOK;
199 }
200 fibril_mutex_unlock(&instance->guard);
201 return ret;
202}
203/*----------------------------------------------------------------------------*/
204/** Get a free USB address
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 */
210usb_address_t device_keeper_get_free_address(usb_device_keeper_t *instance,
211 usb_speed_t speed)
212{
213 assert(instance);
214 fibril_mutex_lock(&instance->guard);
215
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;
221 if (new_address == instance->last_address) {
222 fibril_mutex_unlock(&instance->guard);
223 return ENOSPC;
224 }
225 } while (instance->devices[new_address].occupied);
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;
231 instance->devices[new_address].toggle_status[0] = 0;
232 instance->devices[new_address].toggle_status[1] = 0;
233 instance->last_address = new_address;
234 fibril_mutex_unlock(&instance->guard);
235 return new_address;
236}
237/*----------------------------------------------------------------------------*/
238/** Bind USB address to devman handle.
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 */
244void usb_device_keeper_bind(usb_device_keeper_t *instance,
245 usb_address_t address, devman_handle_t handle)
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/*----------------------------------------------------------------------------*/
256/** Release used USB address.
257 *
258 * @param[in] instance Device keeper structure to use.
259 * @param[in] address Device address
260 */
261void usb_device_keeper_release(usb_device_keeper_t *instance,
262 usb_address_t address)
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/*----------------------------------------------------------------------------*/
274/** Find USB address associated with the device
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 */
280usb_address_t usb_device_keeper_find(usb_device_keeper_t *instance,
281 devman_handle_t handle)
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 }
291 ++address;
292 }
293 fibril_mutex_unlock(&instance->guard);
294 return ENOENT;
295}
296/*----------------------------------------------------------------------------*/
297/** Get speed associated with the address
298 *
299 * @param[in] instance Device keeper structure to use.
300 * @param[in] address Address of the device.
301 * @return USB speed.
302 */
303usb_speed_t usb_device_keeper_get_speed(usb_device_keeper_t *instance,
304 usb_address_t address)
305{
306 assert(instance);
307 assert(address >= 0);
308 assert(address <= USB11_ADDRESS_MAX);
309 return instance->devices[address].speed;
310}
311/*----------------------------------------------------------------------------*/
312void usb_device_keeper_use_control(usb_device_keeper_t *instance,
313 usb_target_t target)
314{
315 assert(instance);
316 const uint16_t ep = 1 << target.endpoint;
317 fibril_mutex_lock(&instance->guard);
318 while (instance->devices[target.address].control_used & ep) {
319 fibril_condvar_wait(&instance->change, &instance->guard);
320 }
321 instance->devices[target.address].control_used |= ep;
322 fibril_mutex_unlock(&instance->guard);
323}
324/*----------------------------------------------------------------------------*/
325void usb_device_keeper_release_control(usb_device_keeper_t *instance,
326 usb_target_t target)
327{
328 assert(instance);
329 const uint16_t ep = 1 << target.endpoint;
330 fibril_mutex_lock(&instance->guard);
331 assert((instance->devices[target.address].control_used & ep) != 0);
332 instance->devices[target.address].control_used &= ~ep;
333 fibril_mutex_unlock(&instance->guard);
334 fibril_condvar_signal(&instance->change);
335}
336/**
337 * @}
338 */
Note: See TracBrowser for help on using the repository browser.