source: mainline/uspace/lib/usb/src/host/device_keeper.c@ 4ca18ae

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

Switch to new endpoint toggle control.

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