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
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;
[d773285f]56 instance->devices[i].control_used = 0;
[5f183dc]57 instance->devices[i].handle = 0;
[f567bcf]58// instance->devices[i].toggle_status[0] = 0;
59// instance->devices[i].toggle_status[1] = 0;
[88dd355]60 list_initialize(&instance->devices[i].endpoints);
[5f183dc]61 }
62}
63/*----------------------------------------------------------------------------*/
[88dd355]64void usb_device_keeper_add_ep(
[f567bcf]65 usb_device_keeper_t *instance, usb_address_t address, endpoint_t *ep)
[8dc762e0]66{
67 assert(instance);
68 fibril_mutex_lock(&instance->guard);
69 assert(instance->devices[address].occupied);
[f567bcf]70 list_append(&ep->same_device_eps, &instance->devices[address].endpoints);
[8dc762e0]71 fibril_mutex_unlock(&instance->guard);
72}
[88dd355]73/*----------------------------------------------------------------------------*/
[17ceb72]74/** Attempt to obtain address 0, blocks.
[a7e2f0d]75 *
76 * @param[in] instance Device keeper structure to use.
77 * @param[in] speed Speed of the device requesting default address.
78 */
[88dd355]79void usb_device_keeper_reserve_default_address(
80 usb_device_keeper_t *instance, usb_speed_t speed)
[5f183dc]81{
82 assert(instance);
83 fibril_mutex_lock(&instance->guard);
84 while (instance->devices[USB_ADDRESS_DEFAULT].occupied) {
[d93b3e3]85 fibril_condvar_wait(&instance->change, &instance->guard);
[5f183dc]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/*----------------------------------------------------------------------------*/
[17ceb72]92/** Attempt to obtain address 0, blocks.
[a7e2f0d]93 *
94 * @param[in] instance Device keeper structure to use.
95 * @param[in] speed Speed of the device requesting default address.
96 */
[68b5ed6e]97void usb_device_keeper_release_default_address(usb_device_keeper_t *instance)
[5f183dc]98{
99 assert(instance);
100 fibril_mutex_lock(&instance->guard);
101 instance->devices[USB_ADDRESS_DEFAULT].occupied = false;
102 fibril_mutex_unlock(&instance->guard);
[d93b3e3]103 fibril_condvar_signal(&instance->change);
[5f183dc]104}
105/*----------------------------------------------------------------------------*/
[17ceb72]106/** Check setup packet data for signs of toggle reset.
[a7e2f0d]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.
[17ceb72]111 *
112 * Really ugly one.
[a7e2f0d]113 */
[88dd355]114void usb_device_keeper_reset_if_need(
115 usb_device_keeper_t *instance, usb_target_t target, const uint8_t *data)
[98807e16]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) {
[a7e2f0d]122 fibril_mutex_unlock(&instance->guard);
[17ceb72]123 usb_log_error("Invalid data when checking for toggle reset.\n");
[a7e2f0d]124 return;
[98807e16]125 }
126
127 switch (data[1])
128 {
129 case 0x01: /*clear feature*/
[a7e2f0d]130 /* recipient is endpoint, value is zero (ENDPOINT_STALL) */
[98807e16]131 if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
[a7e2f0d]132 /* endpoint number is < 16, thus first byte is enough */
[f567bcf]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]);
[98807e16]138 }
139 break;
140
141 case 0x9: /* set configuration */
142 case 0x11: /* set interface */
[c0964800]143 /* target must be device */
144 if ((data[0] & 0xf) == 0) {
[f567bcf]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;
[c0964800]155 }
[98807e16]156 break;
157 }
158 fibril_mutex_unlock(&instance->guard);
159}
160/*----------------------------------------------------------------------------*/
[f567bcf]161#if 0
[17ceb72]162/** Get current value of endpoint toggle.
[a7e2f0d]163 *
164 * @param[in] instance Device keeper structure to use.
165 * @param[in] target Device and endpoint used.
166 * @return Error code
167 */
[e34e77a]168int usb_device_keeper_get_toggle(usb_device_keeper_t *instance,
169 usb_target_t target, usb_direction_t direction)
[edb5f837]170{
171 assert(instance);
[c15070c]172 /* only control pipes are bi-directional and those do not need toggle */
173 if (direction == USB_DIRECTION_BOTH)
174 return ENOENT;
[edb5f837]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) {
[17ceb72]180 usb_log_error("Invalid data when asking for toggle value.\n");
[edb5f837]181 ret = EINVAL;
182 } else {
[c15070c]183 ret = (instance->devices[target.address].toggle_status[direction]
[a7e2f0d]184 >> target.endpoint) & 1;
[edb5f837]185 }
186 fibril_mutex_unlock(&instance->guard);
187 return ret;
188}
189/*----------------------------------------------------------------------------*/
[17ceb72]190/** Set current value of endpoint toggle.
[a7e2f0d]191 *
192 * @param[in] instance Device keeper structure to use.
193 * @param[in] target Device and endpoint used.
[17ceb72]194 * @param[in] toggle Toggle value.
[a7e2f0d]195 * @return Error code.
196 */
[68b5ed6e]197int usb_device_keeper_set_toggle(usb_device_keeper_t *instance,
[c15070c]198 usb_target_t target, usb_direction_t direction, bool toggle)
[edb5f837]199{
200 assert(instance);
[c15070c]201 /* only control pipes are bi-directional and those do not need toggle */
202 if (direction == USB_DIRECTION_BOTH)
203 return ENOENT;
[edb5f837]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) {
[17ceb72]209 usb_log_error("Invalid data when setting toggle value.\n");
[edb5f837]210 ret = EINVAL;
211 } else {
212 if (toggle) {
[c15070c]213 instance->devices[target.address].toggle_status[direction]
214 |= (1 << target.endpoint);
[edb5f837]215 } else {
[c15070c]216 instance->devices[target.address].toggle_status[direction]
217 &= ~(1 << target.endpoint);
[edb5f837]218 }
219 ret = EOK;
220 }
221 fibril_mutex_unlock(&instance->guard);
222 return ret;
223}
[f567bcf]224#endif
[edb5f837]225/*----------------------------------------------------------------------------*/
[17ceb72]226/** Get a free USB address
[a7e2f0d]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 */
[88dd355]232usb_address_t device_keeper_get_free_address(
233 usb_device_keeper_t *instance, usb_speed_t speed)
[5f183dc]234{
235 assert(instance);
236 fibril_mutex_lock(&instance->guard);
237
[171cd88]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;
[5f183dc]243 if (new_address == instance->last_address) {
244 fibril_mutex_unlock(&instance->guard);
245 return ENOSPC;
246 }
[171cd88]247 } while (instance->devices[new_address].occupied);
[5f183dc]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;
[c15070c]253 instance->devices[new_address].toggle_status[0] = 0;
254 instance->devices[new_address].toggle_status[1] = 0;
[5f183dc]255 instance->last_address = new_address;
256 fibril_mutex_unlock(&instance->guard);
257 return new_address;
258}
259/*----------------------------------------------------------------------------*/
[17ceb72]260/** Bind USB address to devman handle.
[a7e2f0d]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 */
[e34e77a]266void usb_device_keeper_bind(usb_device_keeper_t *instance,
267 usb_address_t address, devman_handle_t handle)
[5f183dc]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/*----------------------------------------------------------------------------*/
[17ceb72]278/** Release used USB address.
[a7e2f0d]279 *
280 * @param[in] instance Device keeper structure to use.
281 * @param[in] address Device address
282 */
[88dd355]283void usb_device_keeper_release(
284 usb_device_keeper_t *instance, usb_address_t address)
[5f183dc]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/*----------------------------------------------------------------------------*/
[17ceb72]296/** Find USB address associated with the device
[a7e2f0d]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 */
[88dd355]302usb_address_t usb_device_keeper_find(
303 usb_device_keeper_t *instance, devman_handle_t handle)
[5f183dc]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 }
[86c2ccd]313 ++address;
[5f183dc]314 }
315 fibril_mutex_unlock(&instance->guard);
316 return ENOENT;
317}
318/*----------------------------------------------------------------------------*/
[17ceb72]319/** Get speed associated with the address
[a7e2f0d]320 *
321 * @param[in] instance Device keeper structure to use.
322 * @param[in] address Address of the device.
323 * @return USB speed.
324 */
[88dd355]325usb_speed_t usb_device_keeper_get_speed(
326 usb_device_keeper_t *instance, usb_address_t address)
[5f183dc]327{
328 assert(instance);
329 assert(address >= 0);
330 assert(address <= USB11_ADDRESS_MAX);
331 return instance->devices[address].speed;
332}
[d93b3e3]333/*----------------------------------------------------------------------------*/
[88dd355]334void usb_device_keeper_use_control(
335 usb_device_keeper_t *instance, usb_target_t target)
[d93b3e3]336{
337 assert(instance);
[d773285f]338 const uint16_t ep = 1 << target.endpoint;
[d93b3e3]339 fibril_mutex_lock(&instance->guard);
[d773285f]340 while (instance->devices[target.address].control_used & ep) {
[d93b3e3]341 fibril_condvar_wait(&instance->change, &instance->guard);
342 }
[d773285f]343 instance->devices[target.address].control_used |= ep;
[d93b3e3]344 fibril_mutex_unlock(&instance->guard);
345}
346/*----------------------------------------------------------------------------*/
[88dd355]347void usb_device_keeper_release_control(
348 usb_device_keeper_t *instance, usb_target_t target)
[d93b3e3]349{
350 assert(instance);
[d773285f]351 const uint16_t ep = 1 << target.endpoint;
[d93b3e3]352 fibril_mutex_lock(&instance->guard);
[d773285f]353 assert((instance->devices[target.address].control_used & ep) != 0);
354 instance->devices[target.address].control_used &= ~ep;
[d93b3e3]355 fibril_mutex_unlock(&instance->guard);
356 fibril_condvar_signal(&instance->change);
357}
[5f183dc]358/**
359 * @}
360 */
Note: See TracBrowser for help on using the repository browser.