source: mainline/uspace/lib/usbdev/src/devpoll.c@ 69b9740

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

lilbusbdev: Consider polling to be one long transfer.

This prevents hc reconnect for every interrupt transfer.
This also prevents others from temperring with the pipe while there is polling going on (client side only), not that there were such attempts.

  • Property mode set to 100644
File size: 8.7 KB
RevLine 
[4bf94df]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
[160b75e]29/** @addtogroup libusbdev
[4bf94df]30 * @{
31 */
32/** @file
33 * USB device driver framework - automatic interrupt polling.
34 */
[7d521e24]35#include <usb/dev/poll.h>
36#include <usb/dev/request.h>
[4bf94df]37#include <usb/debug.h>
[5e168be1]38#include <usb/classes/classes.h>
[4bf94df]39#include <errno.h>
40#include <str_error.h>
41#include <assert.h>
42
43/** Maximum number of failed consecutive requests before announcing failure. */
44#define MAX_FAILED_ATTEMPTS 3
45
46/** Data needed for polling. */
47typedef struct {
[2703331b]48 usb_device_auto_polling_t auto_polling;
[8989f48f]49
[4bf94df]50 usb_device_t *dev;
51 size_t pipe_index;
52 size_t request_size;
53 uint8_t *buffer;
54 void *custom_arg;
55} polling_data_t;
56
[8989f48f]57
[4bf94df]58/** Polling fibril.
59 *
60 * @param arg Pointer to polling_data_t.
61 * @return Always EOK.
62 */
63static int polling_fibril(void *arg)
64{
65 polling_data_t *polling_data = (polling_data_t *) arg;
66 assert(polling_data);
67
[a372663]68 usb_pipe_t *pipe
[b77931d]69 = &polling_data->dev->pipes[polling_data->pipe_index].pipe;
[7f2e33a]70
[2703331b]71 if (polling_data->auto_polling.debug > 0) {
[b81410f]72 const usb_endpoint_mapping_t *mapping
[5e168be1]73 = &polling_data->dev->pipes[polling_data->pipe_index];
[4125b7d]74 usb_log_debug("Poll%p: started polling of `%s' - " \
[5e168be1]75 "interface %d (%s,%d,%d), %zuB/%zu.\n",
76 polling_data,
77 polling_data->dev->ddf_dev->name,
78 (int) mapping->interface->interface_number,
79 usb_str_class(mapping->interface->interface_class),
80 (int) mapping->interface->interface_subclass,
81 (int) mapping->interface->interface_protocol,
82 polling_data->request_size, pipe->max_packet_size);
83 }
[4bf94df]84
[d085fbbe]85 usb_pipe_start_long_transfer(pipe);
[4bf94df]86 size_t failed_attempts = 0;
[2703331b]87 while (failed_attempts <= polling_data->auto_polling.max_failures) {
[4bf94df]88 size_t actual_size;
[b81410f]89 const int rc = usb_pipe_read(pipe, polling_data->buffer,
[4bf94df]90 polling_data->request_size, &actual_size);
91
[2703331b]92 if (polling_data->auto_polling.debug > 1) {
[5e168be1]93 if (rc == EOK) {
94 usb_log_debug(
[4125b7d]95 "Poll%p: received: '%s' (%zuB).\n",
[5e168be1]96 polling_data,
97 usb_debug_str_buffer(polling_data->buffer,
98 actual_size, 16),
99 actual_size);
100 } else {
101 usb_log_debug(
[4125b7d]102 "Poll%p: polling failed: %s.\n",
[5e168be1]103 polling_data, str_error(rc));
104 }
105 }
106
[8989f48f]107 /* If the pipe stalled, we can try to reset the stall. */
[2703331b]108 if ((rc == ESTALL) && (polling_data->auto_polling.auto_clear_halt)) {
[8989f48f]109 /*
110 * We ignore error here as this is usually a futile
111 * attempt anyway.
112 */
113 usb_request_clear_endpoint_halt(
[b81410f]114 &polling_data->dev->ctrl_pipe, pipe->endpoint_no);
[8989f48f]115 }
[4bf94df]116
117 if (rc != EOK) {
[2703331b]118 if (polling_data->auto_polling.on_error != NULL) {
119 bool cont = polling_data->auto_polling.on_error(
[8989f48f]120 polling_data->dev, rc,
121 polling_data->custom_arg);
122 if (!cont) {
123 failed_attempts
[2703331b]124 = polling_data->auto_polling.max_failures;
[8989f48f]125 }
126 }
[4bf94df]127 failed_attempts++;
128 continue;
129 }
130
131 /* We have the data, execute the callback now. */
[2703331b]132 const bool carry_on = polling_data->auto_polling.on_data(
133 polling_data->dev, polling_data->buffer, actual_size,
[4bf94df]134 polling_data->custom_arg);
135
136 if (!carry_on) {
137 failed_attempts = 0;
138 break;
139 }
140
141 /* Reset as something might be only a temporary problem. */
142 failed_attempts = 0;
[8989f48f]143
144 /* Take a rest before next request. */
[2703331b]145 async_usleep(polling_data->auto_polling.delay);
[4bf94df]146 }
147
[d085fbbe]148 usb_pipe_end_long_transfer(pipe);
[2703331b]149 if (polling_data->auto_polling.on_polling_end != NULL) {
150 polling_data->auto_polling.on_polling_end(polling_data->dev,
[4bf94df]151 failed_attempts > 0, polling_data->custom_arg);
152 }
153
[2703331b]154 if (polling_data->auto_polling.debug > 0) {
[5e168be1]155 if (failed_attempts > 0) {
156 usb_log_error(
157 "Polling of device `%s' terminated: %s.\n",
158 polling_data->dev->ddf_dev->name,
159 "recurring failures");
160 } else {
161 usb_log_debug(
162 "Polling of device `%s' terminated by user.\n",
163 polling_data->dev->ddf_dev->name
164 );
165 }
166 }
167
[4bf94df]168 /* Free the allocated memory. */
169 free(polling_data->buffer);
170 free(polling_data);
171
172 return EOK;
173}
174
175/** Start automatic device polling over interrupt in pipe.
176 *
177 * @warning It is up to the callback to produce delays between individual
178 * requests.
179 *
180 * @warning There is no guarantee when the request to the device
181 * will be sent for the first time (it is possible that this
182 * first request would be executed prior to return from this function).
183 *
184 * @param dev Device to be periodically polled.
185 * @param pipe_index Index of the endpoint pipe used for polling.
186 * @param callback Callback when data are available.
187 * @param request_size How many bytes to ask for in each request.
188 * @param terminated_callback Callback when polling is terminated.
189 * @param arg Custom argument (passed as is to the callbacks).
190 * @return Error code.
191 * @retval EOK New fibril polling the device was already started.
192 */
193int usb_device_auto_poll(usb_device_t *dev, size_t pipe_index,
194 usb_polling_callback_t callback, size_t request_size,
195 usb_polling_terminted_callback_t terminated_callback, void *arg)
196{
[99a1a56]197 const usb_device_auto_polling_t auto_polling = {
198 .debug = 1,
199 .auto_clear_halt = true,
200 .delay = 0,
201 .max_failures = MAX_FAILED_ATTEMPTS,
202 .on_data = callback,
203 .on_polling_end = terminated_callback,
204 .on_error = NULL,
205 };
[8989f48f]206
[99a1a56]207 return usb_device_auto_polling(dev, pipe_index, &auto_polling,
[8989f48f]208 request_size, arg);
209}
210
211/** Start automatic device polling over interrupt in pipe.
212 *
213 * The polling settings is copied thus it is okay to destroy the structure
214 * after this function returns.
215 *
216 * @warning There is no guarantee when the request to the device
217 * will be sent for the first time (it is possible that this
218 * first request would be executed prior to return from this function).
219 *
220 * @param dev Device to be periodically polled.
221 * @param pipe_index Index of the endpoint pipe used for polling.
222 * @param polling Polling settings.
223 * @param request_size How many bytes to ask for in each request.
224 * @param arg Custom argument (passed as is to the callbacks).
225 * @return Error code.
226 * @retval EOK New fibril polling the device was already started.
227 */
228int usb_device_auto_polling(usb_device_t *dev, size_t pipe_index,
[99a1a56]229 const usb_device_auto_polling_t *polling,
[8989f48f]230 size_t request_size, void *arg)
231{
[b81410f]232 if ((dev == NULL) || (polling == NULL) || (polling->on_data == NULL)) {
[8989f48f]233 return EBADMEM;
234 }
[b81410f]235
236 if (pipe_index >= dev->pipes_count || request_size == 0) {
[8989f48f]237 return EINVAL;
238 }
[b77931d]239 if ((dev->pipes[pipe_index].pipe.transfer_type != USB_TRANSFER_INTERRUPT)
240 || (dev->pipes[pipe_index].pipe.direction != USB_DIRECTION_IN)) {
[8989f48f]241 return EINVAL;
242 }
243
[4bf94df]244 polling_data_t *polling_data = malloc(sizeof(polling_data_t));
245 if (polling_data == NULL) {
246 return ENOMEM;
247 }
248
[8989f48f]249 /* Fill-in the data. */
250 polling_data->buffer = malloc(sizeof(request_size));
[4bf94df]251 if (polling_data->buffer == NULL) {
252 free(polling_data);
253 return ENOMEM;
254 }
[8989f48f]255 polling_data->request_size = request_size;
[4bf94df]256 polling_data->dev = dev;
257 polling_data->pipe_index = pipe_index;
258 polling_data->custom_arg = arg;
259
[2703331b]260 /* Copy provided settings. */
261 polling_data->auto_polling = *polling;
[8989f48f]262
[2703331b]263 /* Negative value means use descriptor provided value. */
264 if (polling->delay < 0) {
265 polling_data->auto_polling.delay =
266 (int) dev->pipes[pipe_index].descriptor->poll_interval;
267 }
[8989f48f]268
[4bf94df]269 fid_t fibril = fibril_create(polling_fibril, polling_data);
270 if (fibril == 0) {
271 free(polling_data->buffer);
272 free(polling_data);
273 return ENOMEM;
274 }
275 fibril_add_ready(fibril);
276
[8989f48f]277 /* Fibril launched. That fibril will free the allocated data. */
[4bf94df]278
279 return EOK;
280}
281
282/**
283 * @}
284 */
Note: See TracBrowser for help on using the repository browser.