devpoll.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Vojtech Horky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00035 #include <usb/dev/poll.h>
00036 #include <usb/dev/request.h>
00037 #include <usb/debug.h>
00038 #include <usb/classes/classes.h>
00039 #include <errno.h>
00040 #include <str_error.h>
00041 #include <assert.h>
00042 
00044 #define MAX_FAILED_ATTEMPTS 3
00045 
00047 typedef struct {
00048         int debug;
00049         size_t max_failures;
00050         useconds_t delay;
00051         bool auto_clear_halt;
00052         bool (*on_data)(usb_device_t *, uint8_t *, size_t, void *);
00053         void (*on_polling_end)(usb_device_t *, bool, void *);
00054         bool (*on_error)(usb_device_t *, int, void *);
00055 
00056         usb_device_t *dev;
00057         size_t pipe_index;
00058         size_t request_size;
00059         uint8_t *buffer;
00060         void *custom_arg;
00061 } polling_data_t;
00062 
00063 
00069 static int polling_fibril(void *arg)
00070 {
00071         polling_data_t *polling_data = (polling_data_t *) arg;
00072         assert(polling_data);
00073 
00074         usb_pipe_t *pipe
00075             = polling_data->dev->pipes[polling_data->pipe_index].pipe;
00076         
00077         if (polling_data->debug > 0) {
00078                 usb_endpoint_mapping_t *mapping
00079                     = &polling_data->dev->pipes[polling_data->pipe_index];
00080                 usb_log_debug("Poll%p: started polling of `%s' - " \
00081                     "interface %d (%s,%d,%d), %zuB/%zu.\n",
00082                     polling_data,
00083                     polling_data->dev->ddf_dev->name,
00084                     (int) mapping->interface->interface_number,
00085                     usb_str_class(mapping->interface->interface_class),
00086                     (int) mapping->interface->interface_subclass,
00087                     (int) mapping->interface->interface_protocol,
00088                     polling_data->request_size, pipe->max_packet_size);
00089         }
00090 
00091         size_t failed_attempts = 0;
00092         while (failed_attempts <= polling_data->max_failures) {
00093                 int rc;
00094 
00095                 size_t actual_size;
00096                 rc = usb_pipe_read(pipe, polling_data->buffer,
00097                     polling_data->request_size, &actual_size);
00098 
00099                 if (polling_data->debug > 1) {
00100                         if (rc == EOK) {
00101                                 usb_log_debug(
00102                                     "Poll%p: received: '%s' (%zuB).\n",
00103                                     polling_data,
00104                                     usb_debug_str_buffer(polling_data->buffer,
00105                                         actual_size, 16),
00106                                     actual_size);
00107                         } else {
00108                                 usb_log_debug(
00109                                     "Poll%p: polling failed: %s.\n",
00110                                     polling_data, str_error(rc));
00111                         }
00112                 }
00113 
00114                 /* If the pipe stalled, we can try to reset the stall. */
00115                 if ((rc == ESTALL) && (polling_data->auto_clear_halt)) {
00116                         /*
00117                          * We ignore error here as this is usually a futile
00118                          * attempt anyway.
00119                          */
00120                         usb_request_clear_endpoint_halt(
00121                             &polling_data->dev->ctrl_pipe,
00122                             pipe->endpoint_no);
00123                 }
00124 
00125                 if (rc != EOK) {
00126                         if (polling_data->on_error != NULL) {
00127                                 bool cont = polling_data->on_error(
00128                                     polling_data->dev, rc,
00129                                     polling_data->custom_arg);
00130                                 if (!cont) {
00131                                         failed_attempts
00132                                             = polling_data->max_failures;
00133                                 }
00134                         }
00135                         failed_attempts++;
00136                         continue;
00137                 }
00138 
00139                 /* We have the data, execute the callback now. */
00140                 bool carry_on = polling_data->on_data(polling_data->dev,
00141                     polling_data->buffer, actual_size,
00142                     polling_data->custom_arg);
00143 
00144                 if (!carry_on) {
00145                         failed_attempts = 0;
00146                         break;
00147                 }
00148 
00149                 /* Reset as something might be only a temporary problem. */
00150                 failed_attempts = 0;
00151 
00152                 /* Take a rest before next request. */
00153                 async_usleep(polling_data->delay);
00154         }
00155 
00156         if (polling_data->on_polling_end != NULL) {
00157                 polling_data->on_polling_end(polling_data->dev,
00158                     failed_attempts > 0, polling_data->custom_arg);
00159         }
00160 
00161         if (polling_data->debug > 0) {
00162                 if (failed_attempts > 0) {
00163                         usb_log_error(
00164                             "Polling of device `%s' terminated: %s.\n",
00165                             polling_data->dev->ddf_dev->name,
00166                             "recurring failures");
00167                 } else {
00168                         usb_log_debug(
00169                             "Polling of device `%s' terminated by user.\n",
00170                             polling_data->dev->ddf_dev->name
00171                         );
00172                 }
00173         }
00174 
00175         /* Free the allocated memory. */
00176         free(polling_data->buffer);
00177         free(polling_data);
00178 
00179         return EOK;
00180 }
00181 
00200 int usb_device_auto_poll(usb_device_t *dev, size_t pipe_index,
00201     usb_polling_callback_t callback, size_t request_size,
00202     usb_polling_terminted_callback_t terminated_callback, void *arg)
00203 {
00204         if ((dev == NULL) || (callback == NULL)) {
00205                 return EBADMEM;
00206         }
00207         if (request_size == 0) {
00208                 return EINVAL;
00209         }
00210         if ((dev->pipes[pipe_index].pipe->transfer_type != USB_TRANSFER_INTERRUPT)
00211             || (dev->pipes[pipe_index].pipe->direction != USB_DIRECTION_IN)) {
00212                 return EINVAL;
00213         }
00214 
00215         usb_device_auto_polling_t *auto_polling
00216             = malloc(sizeof(usb_device_auto_polling_t));
00217         if (auto_polling == NULL) {
00218                 return ENOMEM;
00219         }
00220 
00221         auto_polling->debug = 1;
00222         auto_polling->auto_clear_halt = true;
00223         auto_polling->delay = 0;
00224         auto_polling->max_failures = MAX_FAILED_ATTEMPTS;
00225         auto_polling->on_data = callback;
00226         auto_polling->on_polling_end = terminated_callback;
00227         auto_polling->on_error = NULL;
00228 
00229         int rc = usb_device_auto_polling(dev, pipe_index, auto_polling,
00230            request_size, arg);
00231 
00232         free(auto_polling);
00233 
00234         return rc;
00235 }
00236 
00254 int usb_device_auto_polling(usb_device_t *dev, size_t pipe_index,
00255     usb_device_auto_polling_t *polling,
00256     size_t request_size, void *arg)
00257 {
00258         if (dev == NULL) {
00259                 return EBADMEM;
00260         }
00261         if (pipe_index >= dev->pipes_count) {
00262                 return EINVAL;
00263         }
00264         if ((dev->pipes[pipe_index].pipe->transfer_type != USB_TRANSFER_INTERRUPT)
00265             || (dev->pipes[pipe_index].pipe->direction != USB_DIRECTION_IN)) {
00266                 return EINVAL;
00267         }
00268         if ((polling == NULL) || (polling->on_data == NULL)) {
00269                 return EBADMEM;
00270         }
00271 
00272         polling_data_t *polling_data = malloc(sizeof(polling_data_t));
00273         if (polling_data == NULL) {
00274                 return ENOMEM;
00275         }
00276 
00277         /* Fill-in the data. */
00278         polling_data->buffer = malloc(sizeof(request_size));
00279         if (polling_data->buffer == NULL) {
00280                 free(polling_data);
00281                 return ENOMEM;
00282         }
00283         polling_data->request_size = request_size;
00284         polling_data->dev = dev;
00285         polling_data->pipe_index = pipe_index;
00286         polling_data->custom_arg = arg;
00287 
00288         polling_data->debug = polling->debug;
00289         polling_data->max_failures = polling->max_failures;
00290         if (polling->delay >= 0) {
00291                 polling_data->delay = (useconds_t) polling->delay;
00292         } else {
00293                 polling_data->delay = (useconds_t) dev->pipes[pipe_index]
00294                     .descriptor->poll_interval;
00295         }
00296         polling_data->auto_clear_halt = polling->auto_clear_halt;
00297 
00298         polling_data->on_data = polling->on_data;
00299         polling_data->on_polling_end = polling->on_polling_end;
00300         polling_data->on_error = polling->on_error;
00301 
00302         fid_t fibril = fibril_create(polling_fibril, polling_data);
00303         if (fibril == 0) {
00304                 free(polling_data->buffer);
00305                 free(polling_data);
00306                 return ENOMEM;
00307         }
00308         fibril_add_ready(fibril);
00309 
00310         /* Fibril launched. That fibril will free the allocated data. */
00311 
00312         return EOK;
00313 }
00314 

Generated on Thu Jun 2 07:45:48 2011 for HelenOS/USB by  doxygen 1.4.7