source: mainline/uspace/lib/usbdev/src/devpoll.c@ 8b71f3e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8b71f3e was 8b71f3e, checked in by Petr Manek <petr.manek@…>, 7 years ago

usbdev: refactor polling more

For clarity, the opaque usb_device_polling_t and its complementary
configuration data structure usb_device_polling_config_t have been
merged into usb_polling_t. All related methods have dropped the
"device" from their prefix as well.

The usage semantics have transitioned to malloc-free model, where the
user is entirely responsible for (de)allocation of the polling structure
and its data buffer, and (de)initialization happens in designated
functions during its lifetime in the system.

In addition, the distinction between mandatory / optional / internal
parameters has been documented. Optional parameters now have default
values, which are set to sensible constants in order to allow dropping
some lines in USB driver implementations.

The drivers usbhid and usbhub were refactored to match the API
changes.

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/*
2 * Copyright (c) 2011 Vojtech Horky
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 libusbdev
30 * @{
31 */
32/** @file
33 * USB device driver framework - automatic interrupt polling.
34 */
35
36#include <usb/dev/device.h>
37#include <usb/dev/pipes.h>
38#include <usb/dev/poll.h>
39#include <usb/dev/request.h>
40#include <usb/classes/classes.h>
41#include <usb/debug.h>
42#include <usb/descriptor.h>
43#include <usb/usb.h>
44
45#include <assert.h>
46#include <async.h>
47#include <errno.h>
48#include <fibril.h>
49#include <fibril_synch.h>
50#include <stdbool.h>
51#include <stdlib.h>
52#include <str_error.h>
53#include <stddef.h>
54#include <stdint.h>
55
56
57/** Initialize the polling data structure, its internals and configuration
58 * with default values.
59 *
60 * @param polling Valid polling data structure.
61 * @return Error code.
62 * @retval EOK Polling data structure is ready to be used.
63 */
64int usb_polling_init(usb_polling_t *polling)
65{
66 if (!polling)
67 return EBADMEM;
68
69 /* Zero out everything */
70 memset(polling, 0, sizeof(usb_polling_t));
71
72 /* Internal initializers. */
73 fibril_mutex_initialize(&polling->guard);
74 fibril_condvar_initialize(&polling->cv);
75
76 /* Default configuration. */
77 polling->auto_clear_halt = true;
78 polling->delay = -1;
79 polling->max_failures = 3;
80
81 return EOK;
82}
83
84
85/** Destroy the polling data structure.
86 * This function does nothing but a safety check whether the polling
87 * was joined successfully.
88 *
89 * @param polling Polling data structure.
90 */
91void usb_polling_fini(usb_polling_t *polling)
92{
93 /* Nothing done at the moment. */
94 assert(polling);
95 assert(!polling->running);
96}
97
98
99/** Polling fibril.
100 *
101 * @param arg Pointer to usb_polling_t.
102 * @return Always EOK.
103 */
104static int polling_fibril(void *arg)
105{
106 assert(arg);
107 usb_polling_t *polling = arg;
108 polling->running = true;
109
110 usb_pipe_t *pipe = &polling->ep_mapping->pipe;
111
112 if (polling->debug > 0) {
113 const usb_endpoint_mapping_t *mapping =
114 polling->ep_mapping;
115 usb_log_debug("Poll (%p): started polling of `%s' - " \
116 "interface %d (%s,%d,%d), %zuB/%zu.\n",
117 polling, usb_device_get_name(polling->device),
118 (int) mapping->interface->interface_number,
119 usb_str_class(mapping->interface->interface_class),
120 (int) mapping->interface->interface_subclass,
121 (int) mapping->interface->interface_protocol,
122 polling->request_size, pipe->desc.max_transfer_size);
123 }
124
125 size_t failed_attempts = 0;
126 while (failed_attempts <= polling->max_failures) {
127 size_t actual_size;
128 const int rc = usb_pipe_read(pipe, polling->buffer,
129 polling->request_size, &actual_size);
130
131 if (rc == EOK) {
132 if (polling->debug > 1) {
133 usb_log_debug(
134 "Poll%p: received: '%s' (%zuB).\n",
135 polling,
136 usb_debug_str_buffer(polling->buffer,
137 actual_size, 16),
138 actual_size);
139 }
140 } else {
141 usb_log_debug(
142 "Poll%p: polling failed: %s.\n",
143 polling, str_error(rc));
144 }
145
146 /* If the pipe stalled, we can try to reset the stall. */
147 if (rc == ESTALL && polling->auto_clear_halt) {
148 /*
149 * We ignore error here as this is usually a futile
150 * attempt anyway.
151 */
152 usb_request_clear_endpoint_halt(
153 usb_device_get_default_pipe(polling->device),
154 pipe->desc.endpoint_no);
155 }
156
157 if (rc != EOK) {
158 ++failed_attempts;
159 const bool carry_on = !polling->on_error ? true :
160 polling->on_error(polling->device, rc, polling->arg);
161
162 if (!carry_on || polling->joining) {
163 /* This is user requested abort, erases failures. */
164 failed_attempts = 0;
165 break;
166 }
167 continue;
168 }
169
170 /* We have the data, execute the callback now. */
171 assert(polling->on_data);
172 const bool carry_on = polling->on_data(polling->device,
173 polling->buffer, actual_size, polling->arg);
174
175 if (!carry_on) {
176 /* This is user requested abort, erases failures. */
177 failed_attempts = 0;
178 break;
179 }
180
181 /* Reset as something might be only a temporary problem. */
182 failed_attempts = 0;
183
184 /* Take a rest before next request. */
185
186 // FIXME TODO: This is broken, the time is in ms not us.
187 // but first we need to fix drivers to actually stop using this,
188 // since polling delay should be implemented in HC schedule
189 async_usleep(polling->delay);
190 }
191
192 const bool failed = failed_attempts > 0;
193
194 if (polling->on_polling_end)
195 polling->on_polling_end(polling->device, failed, polling->arg);
196
197 if (polling->debug > 0) {
198 if (failed) {
199 usb_log_error("Polling of device `%s' terminated: "
200 "recurring failures.\n",
201 usb_device_get_name(polling->device));
202 } else {
203 usb_log_debug("Polling of device `%s' terminated: "
204 "driver request.\n",
205 usb_device_get_name(polling->device));
206 }
207 }
208
209 polling->running = false;
210
211 /* Notify joiners, if any. */
212 fibril_condvar_broadcast(&polling->cv);
213 return EOK;
214}
215
216
217/** Start automatic device polling over interrupt in pipe.
218 *
219 * The polling settings is copied thus it is okay to destroy the structure
220 * after this function returns.
221 *
222 * @warning There is no guarantee when the request to the device
223 * will be sent for the first time (it is possible that this
224 * first request would be executed prior to return from this function).
225 *
226 * @param polling Polling data structure.
227 * @return Error code.
228 * @retval EOK New fibril polling the device was already started.
229 */
230int usb_polling_start(usb_polling_t *polling)
231{
232 if (!polling || !polling->device || !polling->ep_mapping || !polling->on_data)
233 return EBADMEM;
234
235 if (!polling->request_size)
236 return EINVAL;
237
238 if (!polling->ep_mapping || (polling->ep_mapping->pipe.desc.transfer_type != USB_TRANSFER_INTERRUPT)
239 || (polling->ep_mapping->pipe.desc.direction != USB_DIRECTION_IN))
240 return EINVAL;
241
242 /* Negative value means use descriptor provided value. */
243 if (polling->delay < 0)
244 polling->delay = polling->ep_mapping->descriptor->poll_interval;
245
246 polling->fibril = fibril_create(polling_fibril, polling);
247 if (!polling->fibril)
248 return ENOMEM;
249
250 fibril_add_ready(polling->fibril);
251
252 /* Fibril launched. That fibril will free the allocated data. */
253 return EOK;
254}
255
256/** Close the polling pipe permanently and synchronously wait
257 * until the automatic polling fibril terminates.
258 *
259 * It is safe to deallocate the polling data structure (and its
260 * data buffer) only after a successful call to this function.
261 *
262 * @warning Call to this function will trigger execution of the
263 * on_error() callback with EINTR error code.
264 *
265 * @parram polling Polling data structure.
266 * @return Error code.
267 * @retval EOK Polling fibril has been successfully terminated.
268 */
269int usb_polling_join(usb_polling_t *polling)
270{
271 int rc;
272 if (!polling)
273 return EBADMEM;
274
275 /* Check if the fibril already terminated. */
276 if (!polling->running)
277 return EOK;
278
279 /* Set the flag */
280 polling->joining = true;
281
282 /* Unregister the pipe. */
283 if ((rc = usb_device_unmap_ep(polling->ep_mapping)))
284 return rc;
285
286 /* Wait for the fibril to terminate. */
287 fibril_mutex_lock(&polling->guard);
288 while (polling->running)
289 fibril_condvar_wait(&polling->cv, &polling->guard);
290 fibril_mutex_unlock(&polling->guard);
291
292 return EOK;
293}
294
295/**
296 * @}
297 */
Note: See TracBrowser for help on using the repository browser.