source: mainline/uspace/lib/usb/src/port.c@ 3692678

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3692678 was e0a5d4c, checked in by Ondřej Hlavatý <aearsis@…>, 8 years ago

usb: update copyrights

The data was generated by a script, guided manually. If you feel your
name is missing somewhere, please add it!

The semi-automated process was roughly:

1) Changes per file and author (limited to our team) were counted
2) Trivial numbers were thrown away
3) Authors were sorted by lines added to file
4) All previous copyrights were replaced by the newly generated one
5) Hunks changing only year were discarded

It seems that a lot of my copyrights were added. It is due to me being
both sticking my nose everywhere and lazy to update the copyright right
away :)

  • Property mode set to 100644
File size: 6.6 KB
Line 
1/*
2 * Copyright (c) 2018 Ondrej Hlavaty
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 * An USB hub port state machine.
34 *
35 * This helper structure solves a repeated problem in USB world: management of
36 * USB ports. A port is an object which receives events (connect, disconnect,
37 * reset) which are to be handled in an asynchronous way. The tricky part is
38 * that response to events has to wait for different events - the most notable
39 * being USB 2 port requiring port reset to be enabled. This problem is solved
40 * by launching separate fibril for taking the port up.
41 *
42 * This subsystem abstracts the rather complicated state machine, and offers
43 * a simple interface to announce events and leave the fibril management on the
44 * library.
45 */
46
47#include <stdlib.h>
48#include <fibril.h>
49#include <assert.h>
50#include <usb/debug.h>
51
52#include <usb/port.h>
53
54void usb_port_init(usb_port_t *port)
55{
56 fibril_mutex_initialize(&port->guard);
57 fibril_condvar_initialize(&port->finished_cv);
58 fibril_condvar_initialize(&port->enabled_cv);
59}
60
61struct enumerate_worker_args {
62 usb_port_t *port;
63 usb_port_enumerate_t handler;
64};
65
66static int enumerate_worker(void *arg)
67{
68 struct enumerate_worker_args * const args = arg;
69 usb_port_t *port = args->port;
70 usb_port_enumerate_t handler = args->handler;
71 free(args);
72
73 fibril_mutex_lock(&port->guard);
74
75 if (port->state == PORT_ERROR) {
76 /*
77 * The device was removed faster than this fibril acquired the
78 * mutex.
79 */
80 port->state = PORT_DISABLED;
81 goto out;
82 }
83
84 assert(port->state == PORT_CONNECTING);
85
86 port->state = handler(port)
87 ? PORT_DISABLED
88 : PORT_ENUMERATED;
89
90out:
91 fibril_condvar_broadcast(&port->finished_cv);
92 fibril_mutex_unlock(&port->guard);
93 return EOK; // This is a fibril worker. No one will read the value.
94}
95
96int usb_port_connected(usb_port_t *port, usb_port_enumerate_t handler)
97{
98 assert(port);
99 int ret = ENOMEM;
100
101 fibril_mutex_lock(&port->guard);
102
103 if (port->state != PORT_DISABLED) {
104 usb_log_warning("a connected event come for port that is not disabled.");
105 ret = EINVAL;
106 goto out;
107 }
108
109 struct enumerate_worker_args *args = malloc(sizeof(*args));
110 if (!args)
111 goto out;
112
113 fid_t fibril = fibril_create(&enumerate_worker, args);
114 if (!fibril) {
115 free(args);
116 goto out;
117 }
118
119 args->port = port;
120 args->handler = handler;
121
122 port->state = PORT_CONNECTING;
123 fibril_add_ready(fibril);
124out:
125 fibril_mutex_unlock(&port->guard);
126 return ret;
127}
128
129void usb_port_enabled(usb_port_t *port)
130{
131 assert(port);
132
133 fibril_mutex_lock(&port->guard);
134 fibril_condvar_broadcast(&port->enabled_cv);
135 fibril_mutex_unlock(&port->guard);
136}
137
138struct remove_worker_args {
139 usb_port_t *port;
140 usb_port_remove_t handler;
141};
142
143static int remove_worker(void *arg)
144{
145 struct remove_worker_args * const args = arg;
146 usb_port_t *port = args->port;
147 usb_port_remove_t handler = args->handler;
148 free(args);
149
150 fibril_mutex_lock(&port->guard);
151 assert(port->state == PORT_DISCONNECTING);
152
153 handler(port);
154
155 port->state = PORT_DISABLED;
156 fibril_condvar_broadcast(&port->finished_cv);
157 fibril_mutex_unlock(&port->guard);
158 return EOK;
159}
160
161static void fork_remove_worker(usb_port_t *port, usb_port_remove_t handler)
162{
163 struct remove_worker_args *args = malloc(sizeof(*args));
164 if (!args)
165 return;
166
167 fid_t fibril = fibril_create(&remove_worker, args);
168 if (!fibril) {
169 free(args);
170 return;
171 }
172
173 args->port = port;
174 args->handler = handler;
175
176 port->state = PORT_DISCONNECTING;
177 fibril_add_ready(fibril);
178}
179
180void usb_port_disabled(usb_port_t *port, usb_port_remove_t handler)
181{
182 assert(port);
183 fibril_mutex_lock(&port->guard);
184
185 switch (port->state) {
186 case PORT_ENUMERATED:
187 fork_remove_worker(port, handler);
188 break;
189
190 case PORT_CONNECTING:
191 port->state = PORT_ERROR;
192 fibril_condvar_broadcast(&port->enabled_cv);
193 /* fallthrough */
194 case PORT_ERROR:
195 fibril_condvar_wait(&port->finished_cv, &port->guard);
196 /* fallthrough */
197 case PORT_DISCONNECTING:
198 case PORT_DISABLED:
199 break;
200 }
201
202 fibril_mutex_unlock(&port->guard);
203}
204
205void usb_port_fini(usb_port_t *port)
206{
207 assert(port);
208
209 fibril_mutex_lock(&port->guard);
210 switch (port->state) {
211 case PORT_ENUMERATED:
212 /*
213 * We shall inform the HC that the device is gone.
214 * However, we can't wait for it, because if the device is hub,
215 * it would have to use the same IPC handling fibril as we do.
216 * But we cannot even defer it to another fibril, because then
217 * the HC would assume our driver didn't cleanup properly, and
218 * will remove those devices by himself.
219 *
220 * So the solutions seems to be to behave like a bad driver and
221 * leave the work for HC.
222 */
223 port->state = PORT_DISABLED;
224 /* fallthrough */
225 case PORT_DISABLED:
226 break;
227
228 /* We first have to stop the fibril in progress. */
229 case PORT_CONNECTING:
230 port->state = PORT_ERROR;
231 fibril_condvar_broadcast(&port->enabled_cv);
232 /* fallthrough */
233 case PORT_ERROR:
234 case PORT_DISCONNECTING:
235 fibril_condvar_wait(&port->finished_cv, &port->guard);
236 break;
237 }
238 fibril_mutex_unlock(&port->guard);
239}
240
241int usb_port_condvar_wait_timeout(usb_port_t *port, fibril_condvar_t *cv, suseconds_t timeout)
242{
243 assert(port);
244 assert(port->state == PORT_CONNECTING);
245 assert(fibril_mutex_is_locked(&port->guard));
246
247 if (fibril_condvar_wait_timeout(cv, &port->guard, timeout))
248 return ETIMEOUT;
249
250 return port->state == PORT_CONNECTING ? EOK : EINTR;
251}
252
253/**
254 * @}
255 */
Note: See TracBrowser for help on using the repository browser.