Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usbdev/src/devpoll.c

    r5a6cc679 r33b8d024  
    11/*
    22 * Copyright (c) 2011 Vojtech Horky
    3  * Copyright (c) 2017 Petr Manek
    43 * All rights reserved.
    54 *
     
    4847#include <errno.h>
    4948#include <fibril.h>
    50 #include <fibril_synch.h>
    5149#include <stdbool.h>
    5250#include <stdlib.h>
     
    5553#include <stdint.h>
    5654
    57 
    58 /** Initialize the polling data structure, its internals and configuration
    59  *  with default values.
    60  *
    61  * @param polling Valid polling data structure.
    62  * @return Error code.
    63  * @retval EOK Polling data structure is ready to be used.
    64  */
    65 int usb_polling_init(usb_polling_t *polling)
    66 {
    67         if (!polling)
    68                 return EBADMEM;
    69 
    70         /* Zero out everything */
    71         memset(polling, 0, sizeof(usb_polling_t));
    72 
    73         /* Internal initializers. */
    74         fibril_mutex_initialize(&polling->guard);
    75         fibril_condvar_initialize(&polling->cv);
    76 
    77         /* Default configuration. */
    78         polling->auto_clear_halt = true;
    79         polling->delay = -1;
    80         polling->max_failures = 3;
    81 
    82         return EOK;
    83 }
    84 
    85 
    86 /** Destroy the polling data structure.
    87  *  This function does nothing but a safety check whether the polling
    88  *  was joined successfully.
    89  *
    90  * @param polling Polling data structure.
    91  */
    92 void usb_polling_fini(usb_polling_t *polling)
    93 {
    94         /* Nothing done at the moment. */
    95         assert(polling);
    96         assert(!polling->running);
    97 }
     55/** Maximum number of failed consecutive requests before announcing failure. */
     56#define MAX_FAILED_ATTEMPTS 3
     57
     58/** Data needed for polling. */
     59typedef struct {
     60        /** Parameters for automated polling. */
     61        usb_device_auto_polling_t auto_polling;
     62
     63        /** USB device to poll. */
     64        usb_device_t *dev;
     65        /** Device enpoint mapping to use for polling. */
     66        usb_endpoint_mapping_t *polling_mapping;
     67        /** Size of the recieved data. */
     68        size_t request_size;
     69        /** Data buffer. */
     70        uint8_t *buffer;
     71} polling_data_t;
    9872
    9973
    10074/** Polling fibril.
    10175 *
    102  * @param arg Pointer to usb_polling_t.
     76 * @param arg Pointer to polling_data_t.
    10377 * @return Always EOK.
    10478 */
     
    10680{
    10781        assert(arg);
    108         usb_polling_t *polling = arg;
    109 
    110         fibril_mutex_lock(&polling->guard);
    111         polling->running = true;
    112         fibril_mutex_unlock(&polling->guard);
    113 
    114         usb_pipe_t *pipe = &polling->ep_mapping->pipe;
    115 
    116         if (polling->debug > 0) {
     82        polling_data_t *data = arg;
     83        /* Helper to reduce typing. */
     84        const usb_device_auto_polling_t *params = &data->auto_polling;
     85
     86        usb_pipe_t *pipe = &data->polling_mapping->pipe;
     87
     88        if (params->debug > 0) {
    11789                const usb_endpoint_mapping_t *mapping =
    118                     polling->ep_mapping;
     90                    data->polling_mapping;
    11991                usb_log_debug("Poll (%p): started polling of `%s' - " \
    12092                    "interface %d (%s,%d,%d), %zuB/%zu.\n",
    121                     polling, usb_device_get_name(polling->device),
     93                    data, usb_device_get_name(data->dev),
    12294                    (int) mapping->interface->interface_number,
    12395                    usb_str_class(mapping->interface->interface_class),
    12496                    (int) mapping->interface->interface_subclass,
    12597                    (int) mapping->interface->interface_protocol,
    126                     polling->request_size, pipe->desc.max_transfer_size);
     98                    data->request_size, pipe->max_packet_size);
    12799        }
    128100
    129101        size_t failed_attempts = 0;
    130         while (failed_attempts <= polling->max_failures) {
     102        while (failed_attempts <= params->max_failures) {
    131103                size_t actual_size;
    132                 const errno_t rc = usb_pipe_read(pipe, polling->buffer,
    133                     polling->request_size, &actual_size);
     104                const errno_t rc = usb_pipe_read(pipe, data->buffer,
     105                    data->request_size, &actual_size);
    134106
    135107                if (rc == EOK) {
    136                         if (polling->debug > 1) {
     108                        if (params->debug > 1) {
    137109                                usb_log_debug(
    138110                                    "Poll%p: received: '%s' (%zuB).\n",
    139                                     polling,
    140                                     usb_debug_str_buffer(polling->buffer,
     111                                    data,
     112                                    usb_debug_str_buffer(data->buffer,
    141113                                        actual_size, 16),
    142114                                    actual_size);
     
    145117                                usb_log_debug(
    146118                                    "Poll%p: polling failed: %s.\n",
    147                                     polling, str_error(rc));
     119                                    data, str_error(rc));
    148120                }
    149121
    150122                /* If the pipe stalled, we can try to reset the stall. */
    151                 if (rc == ESTALL && polling->auto_clear_halt) {
     123                if ((rc == ESTALL) && (params->auto_clear_halt)) {
    152124                        /*
    153125                         * We ignore error here as this is usually a futile
    154126                         * attempt anyway.
    155127                         */
    156                         usb_pipe_clear_halt(
    157                             usb_device_get_default_pipe(polling->device), pipe);
     128                        usb_request_clear_endpoint_halt(
     129                            usb_device_get_default_pipe(data->dev),
     130                            pipe->endpoint_no);
    158131                }
    159132
    160133                if (rc != EOK) {
    161134                        ++failed_attempts;
    162                         const bool carry_on = !polling->on_error ? true :
    163                             polling->on_error(polling->device, rc, polling->arg);
    164 
    165                         if (!carry_on || polling->joining) {
    166                                 /* This is user requested abort, erases failures. */
    167                                 failed_attempts = 0;
    168                                 break;
     135                        const bool cont = (params->on_error == NULL) ? true :
     136                            params->on_error(data->dev, rc, params->arg);
     137                        if (!cont) {
     138                                failed_attempts = params->max_failures;
    169139                        }
    170140                        continue;
     
    172142
    173143                /* We have the data, execute the callback now. */
    174                 assert(polling->on_data);
    175                 const bool carry_on = polling->on_data(polling->device,
    176                     polling->buffer, actual_size, polling->arg);
     144                assert(params->on_data);
     145                const bool carry_on = params->on_data(
     146                    data->dev, data->buffer, actual_size, params->arg);
    177147
    178148                if (!carry_on) {
     
    186156
    187157                /* Take a rest before next request. */
    188 
     158               
    189159                // FIXME TODO: This is broken, the time is in ms not us.
    190160                // but first we need to fix drivers to actually stop using this,
    191161                // since polling delay should be implemented in HC schedule
    192                 async_usleep(polling->delay);
     162                async_usleep(params->delay);
    193163        }
    194164
    195165        const bool failed = failed_attempts > 0;
    196166
    197         if (polling->on_polling_end)
    198                 polling->on_polling_end(polling->device, failed, polling->arg);
    199 
    200         if (polling->debug > 0) {
     167        if (params->on_polling_end != NULL) {
     168                params->on_polling_end(data->dev, failed, params->arg);
     169        }
     170
     171        if (params->debug > 0) {
    201172                if (failed) {
    202173                        usb_log_error("Polling of device `%s' terminated: "
    203174                            "recurring failures.\n",
    204                             usb_device_get_name(polling->device));
     175                            usb_device_get_name(data->dev));
    205176                } else {
    206177                        usb_log_debug("Polling of device `%s' terminated: "
    207178                            "driver request.\n",
    208                             usb_device_get_name(polling->device));
    209                 }
    210         }
    211 
    212         fibril_mutex_lock(&polling->guard);
    213         polling->running = false;
    214         fibril_mutex_unlock(&polling->guard);
    215 
    216         /* Notify joiners, if any. */
    217         fibril_condvar_broadcast(&polling->cv);
     179                            usb_device_get_name(data->dev));
     180                }
     181        }
     182
     183        /* Free the allocated memory. */
     184        free(data->buffer);
     185        free(data);
     186
    218187        return EOK;
    219188}
     
    229198 * first request would be executed prior to return from this function).
    230199 *
    231  * @param polling Polling data structure.
     200 * @param dev Device to be periodically polled.
     201 * @param epm Endpoint mapping to use.
     202 * @param polling Polling settings.
     203 * @param request_size How many bytes to ask for in each request.
     204 * @param arg Custom argument (passed as is to the callbacks).
    232205 * @return Error code.
    233206 * @retval EOK New fibril polling the device was already started.
    234207 */
    235 errno_t usb_polling_start(usb_polling_t *polling)
    236 {
    237         if (!polling || !polling->device || !polling->ep_mapping || !polling->on_data)
     208static errno_t usb_device_auto_polling_internal(usb_device_t *dev,
     209    usb_endpoint_mapping_t *epm, const usb_device_auto_polling_t *polling,
     210    size_t request_size)
     211{
     212        if ((dev == NULL) || (polling == NULL) || (polling->on_data == NULL)) {
    238213                return EBADMEM;
    239 
    240         if (!polling->request_size)
     214        }
     215
     216        if (request_size == 0)
    241217                return EINVAL;
    242 
    243         if (!polling->ep_mapping || (polling->ep_mapping->pipe.desc.transfer_type != USB_TRANSFER_INTERRUPT)
    244             || (polling->ep_mapping->pipe.desc.direction != USB_DIRECTION_IN))
     218       
     219        if (!epm || (epm->pipe.transfer_type != USB_TRANSFER_INTERRUPT) ||
     220            (epm->pipe.direction != USB_DIRECTION_IN))
    245221                return EINVAL;
     222       
     223
     224        polling_data_t *polling_data = malloc(sizeof(polling_data_t));
     225        if (polling_data == NULL) {
     226                return ENOMEM;
     227        }
     228
     229        /* Fill-in the data. */
     230        polling_data->buffer = malloc(sizeof(request_size));
     231        if (polling_data->buffer == NULL) {
     232                free(polling_data);
     233                return ENOMEM;
     234        }
     235        polling_data->request_size = request_size;
     236        polling_data->dev = dev;
     237        polling_data->polling_mapping = epm;
     238
     239        /* Copy provided settings. */
     240        polling_data->auto_polling = *polling;
    246241
    247242        /* Negative value means use descriptor provided value. */
    248         if (polling->delay < 0)
    249                 polling->delay = polling->ep_mapping->descriptor->poll_interval;
    250 
    251         polling->fibril = fibril_create(polling_fibril, polling);
    252         if (!polling->fibril)
     243        if (polling->delay < 0) {
     244                polling_data->auto_polling.delay =
     245                    epm->descriptor->poll_interval;
     246        }
     247
     248        fid_t fibril = fibril_create(polling_fibril, polling_data);
     249        if (fibril == 0) {
     250                free(polling_data->buffer);
     251                free(polling_data);
    253252                return ENOMEM;
    254 
    255         fibril_add_ready(polling->fibril);
     253        }
     254        fibril_add_ready(fibril);
    256255
    257256        /* Fibril launched. That fibril will free the allocated data. */
     257
    258258        return EOK;
    259259}
    260 
    261 /** Close the polling pipe permanently and synchronously wait
    262  *  until the automatic polling fibril terminates.
    263  *
    264  *  It is safe to deallocate the polling data structure (and its
    265  *  data buffer) only after a successful call to this function.
    266  *
    267  *  @warning Call to this function will trigger execution of the
    268  *  on_error() callback with EINTR error code.
    269  *
    270  *  @parram polling Polling data structure.
    271  *  @return Error code.
    272  *  @retval EOK Polling fibril has been successfully terminated.
    273  */
    274 errno_t usb_polling_join(usb_polling_t *polling)
    275 {
    276         errno_t rc;
    277         if (!polling)
    278                 return EBADMEM;
    279 
    280         /* Check if the fibril already terminated. */
    281         if (!polling->running)
    282                 return EOK;
    283 
    284         /* Set the flag */
    285         polling->joining = true;
    286 
    287         /* Unregister the pipe. */
    288         rc = usb_device_unmap_ep(polling->ep_mapping);
    289         if (rc != EOK && rc != ENOENT && rc != EHANGUP)
    290                 return rc;
    291 
    292         /* Wait for the fibril to terminate. */
    293         fibril_mutex_lock(&polling->guard);
    294         while (polling->running)
    295                 fibril_condvar_wait(&polling->cv, &polling->guard);
    296         fibril_mutex_unlock(&polling->guard);
    297 
    298         return EOK;
     260/** Start automatic device polling over interrupt in pipe.
     261 *
     262 * The polling settings is copied thus it is okay to destroy the structure
     263 * after this function returns.
     264 *
     265 * @warning There is no guarantee when the request to the device
     266 * will be sent for the first time (it is possible that this
     267 * first request would be executed prior to return from this function).
     268 *
     269 * @param dev Device to be periodically polled.
     270 * @param pipe_index Index of the endpoint pipe used for polling.
     271 * @param polling Polling settings.
     272 * @param req_size How many bytes to ask for in each request.
     273 * @param arg Custom argument (passed as is to the callbacks).
     274 * @return Error code.
     275 * @retval EOK New fibril polling the device was already started.
     276 */
     277errno_t usb_device_auto_polling(usb_device_t *usb_dev, usb_endpoint_t ep,
     278    const usb_device_auto_polling_t *polling, size_t req_size)
     279{
     280        usb_endpoint_mapping_t *epm = usb_device_get_mapped_ep(usb_dev, ep);
     281        return usb_device_auto_polling_internal(usb_dev, epm, polling, req_size);
     282}
     283
     284/** Start automatic device polling over interrupt in pipe.
     285 *
     286 * @warning It is up to the callback to produce delays between individual
     287 * requests.
     288 *
     289 * @warning There is no guarantee when the request to the device
     290 * will be sent for the first time (it is possible that this
     291 * first request would be executed prior to return from this function).
     292 *
     293 * @param dev Device to be periodically polled.
     294 * @param ep Endpoint  used for polling.
     295 * @param callback Callback when data are available.
     296 * @param request_size How many bytes to ask for in each request.
     297 * @param delay NUmber of ms to wait between queries, -1 to use descriptor val.
     298 * @param terminated_callback Callback when polling is terminated.
     299 * @param arg Custom argument (passed as is to the callbacks).
     300 * @return Error code.
     301 * @retval EOK New fibril polling the device was already started.
     302 */
     303errno_t usb_device_auto_poll(usb_device_t *dev, usb_endpoint_t ep,
     304    usb_polling_callback_t callback, size_t request_size, int delay,
     305    usb_polling_terminted_callback_t terminated_callback, void *arg)
     306{
     307        const usb_device_auto_polling_t auto_polling = {
     308                .debug = 1,
     309                .auto_clear_halt = true,
     310                .delay = delay,
     311                .max_failures = MAX_FAILED_ATTEMPTS,
     312                .on_data = callback,
     313                .on_polling_end = terminated_callback,
     314                .on_error = NULL,
     315                .arg = arg,
     316        };
     317
     318        usb_endpoint_mapping_t *epm = usb_device_get_mapped_ep(dev, ep);
     319        return usb_device_auto_polling_internal(
     320            dev, epm, &auto_polling, request_size);
     321}
     322
     323errno_t usb_device_auto_polling_desc(usb_device_t *usb_dev,
     324    const usb_endpoint_description_t *desc,
     325    const usb_device_auto_polling_t *polling, size_t req_size)
     326{
     327        usb_endpoint_mapping_t *epm =
     328            usb_device_get_mapped_ep_desc(usb_dev, desc);
     329        return usb_device_auto_polling_internal(usb_dev, epm, polling, req_size);
     330}
     331
     332errno_t usb_device_auto_poll_desc(usb_device_t * usb_dev,
     333    const usb_endpoint_description_t *desc, usb_polling_callback_t callback,
     334    size_t req_size, int delay,
     335    usb_polling_terminted_callback_t terminated_callback, void *arg)
     336{
     337        const usb_device_auto_polling_t auto_polling = {
     338                .debug = 1,
     339                .auto_clear_halt = true,
     340                .delay = delay,
     341                .max_failures = MAX_FAILED_ATTEMPTS,
     342                .on_data = callback,
     343                .on_polling_end = terminated_callback,
     344                .on_error = NULL,
     345                .arg = arg,
     346        };
     347
     348        usb_endpoint_mapping_t *epm =
     349            usb_device_get_mapped_ep_desc(usb_dev, desc);
     350        return usb_device_auto_polling_internal(
     351            usb_dev, epm, &auto_polling, req_size);
    299352}
    300353
Note: See TracChangeset for help on using the changeset viewer.