Changeset 8b71f3e in mainline for uspace/lib/usbdev/src/devpoll.c


Ignore:
Timestamp:
2018-01-14T21:16:03Z (6 years ago)
Author:
Petr Manek <petr.manek@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
17c1d9db
Parents:
edc51615
git-author:
Petr Manek <petr.manek@…> (2018-01-14 21:16:00)
git-committer:
Petr Manek <petr.manek@…> (2018-01-14 21:16:03)
Message:

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.

File:
1 edited

Legend:

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

    redc51615 r8b71f3e  
    5454#include <stdint.h>
    5555
    56 /** Private automated polling instance data. */
    57 struct usb_device_polling {
    58         /** Parameters for automated polling. */
    59         usb_device_polling_config_t config;
    60 
    61         /** USB device to poll. */
    62         usb_device_t *dev;
    63 
    64         /** Device enpoint mapping to use for polling. */
    65         usb_endpoint_mapping_t *ep_mapping;
    66 
    67         /** Size of the recieved data. */
    68         size_t request_size;
    69 
    70         /** Data buffer. */
    71         uint8_t *buffer;
    72 
    73         /** True if polling is currently in operation. */
    74         volatile bool running;
    75 
    76         /** True if polling should terminate as soon as possible. */
    77         volatile bool joining;
    78 
    79         /** Synchronization primitives for joining polling end. */
    80         fibril_mutex_t guard;
    81         fibril_condvar_t cv;
    82 };
    83 
    84 
    85 static void polling_fini(usb_device_polling_t *polling)
    86 {
    87         /* Free the allocated memory. */
    88         free(polling->buffer);
    89         free(polling);
     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);
    9096}
    9197
     
    9399/** Polling fibril.
    94100 *
    95  * @param arg Pointer to usb_device_polling_t.
     101 * @param arg Pointer to usb_polling_t.
    96102 * @return Always EOK.
    97103 */
     
    99105{
    100106        assert(arg);
    101         usb_device_polling_t *data = arg;
    102         data->running = true;
    103 
    104         /* Helper to reduce typing. */
    105         const usb_device_polling_config_t *params = &data->config;
    106 
    107         usb_pipe_t *pipe = &data->ep_mapping->pipe;
    108 
    109         if (params->debug > 0) {
     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) {
    110113                const usb_endpoint_mapping_t *mapping =
    111                     data->ep_mapping;
     114                    polling->ep_mapping;
    112115                usb_log_debug("Poll (%p): started polling of `%s' - " \
    113116                    "interface %d (%s,%d,%d), %zuB/%zu.\n",
    114                     data, usb_device_get_name(data->dev),
     117                    polling, usb_device_get_name(polling->device),
    115118                    (int) mapping->interface->interface_number,
    116119                    usb_str_class(mapping->interface->interface_class),
    117120                    (int) mapping->interface->interface_subclass,
    118121                    (int) mapping->interface->interface_protocol,
    119                     data->request_size, pipe->desc.max_transfer_size);
     122                    polling->request_size, pipe->desc.max_transfer_size);
    120123        }
    121124
    122125        size_t failed_attempts = 0;
    123         while (failed_attempts <= params->max_failures) {
     126        while (failed_attempts <= polling->max_failures) {
    124127                size_t actual_size;
    125                 const int rc = usb_pipe_read(pipe, data->buffer,
    126                     data->request_size, &actual_size);
     128                const int rc = usb_pipe_read(pipe, polling->buffer,
     129                    polling->request_size, &actual_size);
    127130
    128131                if (rc == EOK) {
    129                         if (params->debug > 1) {
     132                        if (polling->debug > 1) {
    130133                                usb_log_debug(
    131134                                    "Poll%p: received: '%s' (%zuB).\n",
    132                                     data,
    133                                     usb_debug_str_buffer(data->buffer,
     135                                    polling,
     136                                    usb_debug_str_buffer(polling->buffer,
    134137                                        actual_size, 16),
    135138                                    actual_size);
     
    138141                                usb_log_debug(
    139142                                    "Poll%p: polling failed: %s.\n",
    140                                     data, str_error(rc));
     143                                    polling, str_error(rc));
    141144                }
    142145
    143146                /* If the pipe stalled, we can try to reset the stall. */
    144                 if ((rc == ESTALL) && (params->auto_clear_halt)) {
     147                if (rc == ESTALL && polling->auto_clear_halt) {
    145148                        /*
    146149                         * We ignore error here as this is usually a futile
     
    148151                         */
    149152                        usb_request_clear_endpoint_halt(
    150                             usb_device_get_default_pipe(data->dev),
     153                            usb_device_get_default_pipe(polling->device),
    151154                            pipe->desc.endpoint_no);
    152155                }
     
    154157                if (rc != EOK) {
    155158                        ++failed_attempts;
    156                         const bool cont = (params->on_error == NULL) ? true :
    157                             params->on_error(data->dev, rc, params->arg);
    158                         if (!cont || data->joining) {
     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) {
    159163                                /* This is user requested abort, erases failures. */
    160164                                failed_attempts = 0;
     
    165169
    166170                /* We have the data, execute the callback now. */
    167                 assert(params->on_data);
    168                 const bool carry_on = params->on_data(
    169                     data->dev, data->buffer, actual_size, params->arg);
     171                assert(polling->on_data);
     172                const bool carry_on = polling->on_data(polling->device,
     173                    polling->buffer, actual_size, polling->arg);
    170174
    171175                if (!carry_on) {
     
    183187                // but first we need to fix drivers to actually stop using this,
    184188                // since polling delay should be implemented in HC schedule
    185                 async_usleep(params->delay);
     189                async_usleep(polling->delay);
    186190        }
    187191
    188192        const bool failed = failed_attempts > 0;
    189193
    190         if (params->on_polling_end != NULL) {
    191                 params->on_polling_end(data->dev, failed, params->arg);
    192         }
    193 
    194         if (params->debug > 0) {
     194        if (polling->on_polling_end)
     195                polling->on_polling_end(polling->device, failed, polling->arg);
     196
     197        if (polling->debug > 0) {
    195198                if (failed) {
    196199                        usb_log_error("Polling of device `%s' terminated: "
    197200                            "recurring failures.\n",
    198                             usb_device_get_name(data->dev));
     201                            usb_device_get_name(polling->device));
    199202                } else {
    200203                        usb_log_debug("Polling of device `%s' terminated: "
    201204                            "driver request.\n",
    202                             usb_device_get_name(data->dev));
     205                            usb_device_get_name(polling->device));
    203206                }
    204207        }
    205208
    206         data->running = false;
     209        polling->running = false;
    207210
    208211        /* Notify joiners, if any. */
    209         fibril_condvar_broadcast(&data->cv);
    210 
    211         /* Free allocated memory. */
    212         if (!data->joining) {
    213                 polling_fini(data);
    214         }
    215 
     212        fibril_condvar_broadcast(&polling->cv);
    216213        return EOK;
    217214}
     
    227224 * first request would be executed prior to return from this function).
    228225 *
    229  * @param dev Device to be periodically polled.
    230  * @param epm Endpoint mapping to use.
    231  * @param config Polling settings.
    232  * @param req_size How many bytes to ask for in each request.
     226 * @param polling Polling data structure.
    233227 * @return Error code.
    234228 * @retval EOK New fibril polling the device was already started.
    235229 */
    236 int usb_device_poll(usb_device_t *dev, usb_endpoint_mapping_t *epm,
    237     const usb_device_polling_config_t *config, size_t req_size,
    238     usb_device_polling_t **handle)
    239 {
    240         int rc;
    241         if (!dev || !config || !config->on_data)
     230int usb_polling_start(usb_polling_t *polling)
     231{
     232        if (!polling || !polling->device || !polling->ep_mapping || !polling->on_data)
    242233                return EBADMEM;
    243234
    244         if (!req_size)
     235        if (!polling->request_size)
    245236                return EINVAL;
    246237
    247         if (!epm || (epm->pipe.desc.transfer_type != USB_TRANSFER_INTERRUPT) ||
    248             (epm->pipe.desc.direction != USB_DIRECTION_IN))
     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))
    249240                return EINVAL;
    250241
    251         usb_device_polling_t *instance = malloc(sizeof(usb_device_polling_t));
    252         if (!instance)
     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)
    253248                return ENOMEM;
    254249
    255         /* Fill-in the data. */
    256         instance->buffer = malloc(req_size);
    257         if (!instance->buffer) {
    258                 rc = ENOMEM;
    259                 goto err_instance;
    260         }
    261         instance->request_size = req_size;
    262         instance->dev = dev;
    263         instance->ep_mapping = epm;
    264         instance->joining = false;
    265         fibril_mutex_initialize(&instance->guard);
    266         fibril_condvar_initialize(&instance->cv);
    267 
    268         /* Copy provided settings. */
    269         instance->config = *config;
    270 
    271         /* Negative value means use descriptor provided value. */
    272         if (config->delay < 0) {
    273                 instance->config.delay = epm->descriptor->poll_interval;
    274         }
    275 
    276         fid_t fibril = fibril_create(polling_fibril, instance);
    277         if (!fibril) {
    278                 rc = ENOMEM;
    279                 goto err_buffer;
    280         }
    281         fibril_add_ready(fibril);
    282 
    283         if (handle)
    284                 *handle = instance;
     250        fibril_add_ready(polling->fibril);
    285251
    286252        /* Fibril launched. That fibril will free the allocated data. */
    287253        return EOK;
    288 
    289 err_buffer:
    290         free(instance->buffer);
    291 err_instance:
    292         free(instance);
    293         return rc;
    294 }
    295 
    296 int usb_device_poll_join(usb_device_polling_t *polling)
     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)
    297270{
    298271        int rc;
     
    300273                return EBADMEM;
    301274
     275        /* Check if the fibril already terminated. */
     276        if (!polling->running)
     277                return EOK;
     278
    302279        /* Set the flag */
    303280        polling->joining = true;
    304281
    305282        /* Unregister the pipe. */
    306         if ((rc = usb_device_unmap_ep(polling->ep_mapping))) {
     283        if ((rc = usb_device_unmap_ep(polling->ep_mapping)))
    307284                return rc;
    308         }
    309285
    310286        /* Wait for the fibril to terminate. */
     
    314290        fibril_mutex_unlock(&polling->guard);
    315291
    316         /* Free the instance. */
    317         polling_fini(polling);
    318 
    319292        return EOK;
    320293}
Note: See TracChangeset for help on using the changeset viewer.