source: mainline/uspace/drv/uhci-hcd/utils/device_keeper.c@ f8c190e

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

Another toggle protocol fix.

SET CONFIGURATION resets toggle only if the target is device.

  • Property mode set to 100644
File size: 9.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 drvusbuhci
30 * @{
31 */
32/** @file
33 * @brief UHCI driver
34 */
35#include <assert.h>
36#include <errno.h>
37#include <usb/debug.h>
38
39#include "device_keeper.h"
40
41/*----------------------------------------------------------------------------*/
42/** Initializes device keeper structure.
43 *
44 * @param[in] instance Memory place to initialize.
45 */
46void device_keeper_init(device_keeper_t *instance)
47{
48 assert(instance);
49 fibril_mutex_initialize(&instance->guard);
50 fibril_condvar_initialize(&instance->default_address_occupied);
51 instance->last_address = 0;
52 unsigned i = 0;
53 for (; i < USB_ADDRESS_COUNT; ++i) {
54 instance->devices[i].occupied = false;
55 instance->devices[i].handle = 0;
56 instance->devices[i].toggle_status = 0;
57 }
58}
59/*----------------------------------------------------------------------------*/
60/** Attempts to obtain address 0, blocks.
61 *
62 * @param[in] instance Device keeper structure to use.
63 * @param[in] speed Speed of the device requesting default address.
64 */
65void device_keeper_reserve_default(device_keeper_t *instance, usb_speed_t speed)
66{
67 assert(instance);
68 fibril_mutex_lock(&instance->guard);
69 while (instance->devices[USB_ADDRESS_DEFAULT].occupied) {
70 fibril_condvar_wait(&instance->default_address_occupied,
71 &instance->guard);
72 }
73 instance->devices[USB_ADDRESS_DEFAULT].occupied = true;
74 instance->devices[USB_ADDRESS_DEFAULT].speed = speed;
75 fibril_mutex_unlock(&instance->guard);
76}
77/*----------------------------------------------------------------------------*/
78/** Attempts to obtain address 0, blocks.
79 *
80 * @param[in] instance Device keeper structure to use.
81 * @param[in] speed Speed of the device requesting default address.
82 */
83void device_keeper_release_default(device_keeper_t *instance)
84{
85 assert(instance);
86 fibril_mutex_lock(&instance->guard);
87 instance->devices[USB_ADDRESS_DEFAULT].occupied = false;
88 fibril_mutex_unlock(&instance->guard);
89 fibril_condvar_signal(&instance->default_address_occupied);
90}
91/*----------------------------------------------------------------------------*/
92/** Checks setup data for signs of toggle reset.
93 *
94 * @param[in] instance Device keeper structure to use.
95 * @param[in] target Device to receive setup packet.
96 * @param[in] data Setup packet data.
97 */
98void device_keeper_reset_if_need(
99 device_keeper_t *instance, usb_target_t target, const unsigned char *data)
100{
101 assert(instance);
102 fibril_mutex_lock(&instance->guard);
103 if (target.endpoint > 15 || target.endpoint < 0
104 || target.address >= USB_ADDRESS_COUNT || target.address < 0
105 || !instance->devices[target.address].occupied) {
106 fibril_mutex_unlock(&instance->guard);
107 return;
108 }
109
110 switch (data[1])
111 {
112 case 0x01: /*clear feature*/
113 /* recipient is endpoint, value is zero (ENDPOINT_STALL) */
114 if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
115 /* endpoint number is < 16, thus first byte is enough */
116 instance->devices[target.address].toggle_status &=
117 ~(1 << data[4]);
118 }
119 break;
120
121 case 0x9: /* set configuration */
122 case 0x11: /* set interface */
123 /* target must be device */
124 if ((data[0] & 0xf) == 0) {
125 instance->devices[target.address].toggle_status = 0;
126 }
127 break;
128 }
129 fibril_mutex_unlock(&instance->guard);
130}
131/*----------------------------------------------------------------------------*/
132/** Gets current value of endpoint toggle.
133 *
134 * @param[in] instance Device keeper structure to use.
135 * @param[in] target Device and endpoint used.
136 * @return Error code
137 */
138int device_keeper_get_toggle(device_keeper_t *instance, usb_target_t target)
139{
140 assert(instance);
141 int ret;
142 fibril_mutex_lock(&instance->guard);
143 if (target.endpoint > 15 || target.endpoint < 0
144 || target.address >= USB_ADDRESS_COUNT || target.address < 0
145 || !instance->devices[target.address].occupied) {
146 ret = EINVAL;
147 } else {
148 ret =
149 (instance->devices[target.address].toggle_status
150 >> target.endpoint) & 1;
151 }
152 fibril_mutex_unlock(&instance->guard);
153 return ret;
154}
155/*----------------------------------------------------------------------------*/
156/** Sets current value of endpoint toggle.
157 *
158 * @param[in] instance Device keeper structure to use.
159 * @param[in] target Device and endpoint used.
160 * @param[in] toggle Current toggle value.
161 * @return Error code.
162 */
163int device_keeper_set_toggle(
164 device_keeper_t *instance, usb_target_t target, bool toggle)
165{
166 assert(instance);
167 int ret;
168 fibril_mutex_lock(&instance->guard);
169 if (target.endpoint > 15 || target.endpoint < 0
170 || target.address >= USB_ADDRESS_COUNT || target.address < 0
171 || !instance->devices[target.address].occupied) {
172 ret = EINVAL;
173 } else {
174 if (toggle) {
175 instance->devices[target.address].toggle_status |= (1 << target.endpoint);
176 } else {
177 instance->devices[target.address].toggle_status &= ~(1 << target.endpoint);
178 }
179 ret = EOK;
180 }
181 fibril_mutex_unlock(&instance->guard);
182 return ret;
183}
184/*----------------------------------------------------------------------------*/
185/** Gets a free USB address
186 *
187 * @param[in] instance Device keeper structure to use.
188 * @param[in] speed Speed of the device requiring address.
189 * @return Free address, or error code.
190 */
191usb_address_t device_keeper_request(
192 device_keeper_t *instance, usb_speed_t speed)
193{
194 assert(instance);
195 fibril_mutex_lock(&instance->guard);
196
197 usb_address_t new_address = instance->last_address + 1;
198 while (instance->devices[new_address].occupied) {
199 if (new_address == instance->last_address) {
200 fibril_mutex_unlock(&instance->guard);
201 return ENOSPC;
202 }
203 if (new_address == USB11_ADDRESS_MAX)
204 new_address = 1;
205 ++new_address;
206 }
207
208 assert(new_address != USB_ADDRESS_DEFAULT);
209 assert(instance->devices[new_address].occupied == false);
210 instance->devices[new_address].occupied = true;
211 instance->devices[new_address].speed = speed;
212 instance->devices[new_address].toggle_status = 0;
213 instance->last_address = new_address;
214 fibril_mutex_unlock(&instance->guard);
215 return new_address;
216}
217/*----------------------------------------------------------------------------*/
218/** Binds USB address to devman handle.
219 *
220 * @param[in] instance Device keeper structure to use.
221 * @param[in] address Device address
222 * @param[in] handle Devman handle of the device.
223 */
224void device_keeper_bind(
225 device_keeper_t *instance, usb_address_t address, devman_handle_t handle)
226{
227 assert(instance);
228 fibril_mutex_lock(&instance->guard);
229 assert(address > 0);
230 assert(address <= USB11_ADDRESS_MAX);
231 assert(instance->devices[address].occupied);
232 instance->devices[address].handle = handle;
233 fibril_mutex_unlock(&instance->guard);
234}
235/*----------------------------------------------------------------------------*/
236/** Releases used USB address.
237 *
238 * @param[in] instance Device keeper structure to use.
239 * @param[in] address Device address
240 */
241void device_keeper_release(device_keeper_t *instance, usb_address_t address)
242{
243 assert(instance);
244 assert(address > 0);
245 assert(address <= USB11_ADDRESS_MAX);
246
247 fibril_mutex_lock(&instance->guard);
248 assert(instance->devices[address].occupied);
249 instance->devices[address].occupied = false;
250 fibril_mutex_unlock(&instance->guard);
251}
252/*----------------------------------------------------------------------------*/
253/** Finds USB address associated with the device
254 *
255 * @param[in] instance Device keeper structure to use.
256 * @param[in] handle Devman handle of the device seeking its address.
257 * @return USB Address, or error code.
258 */
259usb_address_t device_keeper_find(
260 device_keeper_t *instance, devman_handle_t handle)
261{
262 assert(instance);
263 fibril_mutex_lock(&instance->guard);
264 usb_address_t address = 1;
265 while (address <= USB11_ADDRESS_MAX) {
266 if (instance->devices[address].handle == handle) {
267 fibril_mutex_unlock(&instance->guard);
268 return address;
269 }
270 ++address;
271 }
272 fibril_mutex_unlock(&instance->guard);
273 return ENOENT;
274}
275/*----------------------------------------------------------------------------*/
276/** Gets speed associated with the address
277 *
278 * @param[in] instance Device keeper structure to use.
279 * @param[in] address Address of the device.
280 * @return USB speed.
281 */
282usb_speed_t device_keeper_speed(
283 device_keeper_t *instance, usb_address_t address)
284{
285 assert(instance);
286 assert(address >= 0);
287 assert(address <= USB11_ADDRESS_MAX);
288 return instance->devices[address].speed;
289}
290/**
291 * @}
292 */
Note: See TracBrowser for help on using the repository browser.