Changeset 8b71f3e in mainline


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.

Location:
uspace
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/usbhub/usbhub.c

    redc51615 r8b71f3e  
    161161
    162162        /* Start hub operation. */
    163         const usb_device_polling_config_t config = {
    164                 .debug = 1,
    165                 .auto_clear_halt = true,
    166                 .delay = -1,
    167                 .max_failures = 3,
    168                 .on_data = hub_port_changes_callback,
    169                 .on_polling_end = usb_hub_polling_terminated_callback,
    170                 .on_error = usb_hub_polling_error_callback,
    171                 .arg = hub_dev,
    172         };
    173 
    174         usb_endpoint_mapping_t *epm =
    175             usb_device_get_mapped_ep_desc(hub_dev->usb_device,
     163        usb_polling_t *polling = &hub_dev->polling;
     164        opResult = usb_polling_init(polling);
     165        if (opResult != EOK) {
     166                ddf_fun_unbind(hub_dev->hub_fun);
     167                ddf_fun_destroy(hub_dev->hub_fun);
     168                usb_log_error("Failed to initialize polling fibril: %s.\n",
     169                    str_error(opResult));
     170                return opResult;
     171        }
     172
     173        polling->device = hub_dev->usb_device;
     174        polling->ep_mapping = usb_device_get_mapped_ep_desc(hub_dev->usb_device,
    176175            &hub_status_change_endpoint_description);
    177         opResult = usb_device_poll(hub_dev->usb_device, epm, &config,
    178             ((hub_dev->port_count + 1 + 7) / 8), &hub_dev->polling);
    179        
     176        polling->request_size = ((hub_dev->port_count + 1 + 7) / 8);
     177        polling->buffer = malloc(polling->request_size);
     178        polling->on_data = hub_port_changes_callback;
     179        polling->on_polling_end = usb_hub_polling_terminated_callback;
     180        polling->on_error = usb_hub_polling_error_callback;
     181        polling->arg = hub_dev;
     182
     183        opResult = usb_polling_start(polling);
    180184        if (opResult != EOK) {
    181185                /* Function is already bound */
     186                free(polling->buffer);
    182187                ddf_fun_unbind(hub_dev->hub_fun);
    183188                ddf_fun_destroy(hub_dev->hub_fun);
     
    186191                return opResult;
    187192        }
     193
    188194        hub_dev->running = true;
    189195        usb_log_info("Controlling hub '%s' (%p: %zu ports).\n",
     
    197203{
    198204        assert(!hub->running);
     205
     206        free(hub->polling.buffer);
     207        usb_polling_fini(&hub->polling);
    199208
    200209        for (size_t port = 0; port < hub->port_count; ++port) {
     
    233242        usb_log_info("(%p) USB hub removed, joining polling fibril.", hub);
    234243
    235         /* Join polling fibril. */
    236         usb_device_poll_join(hub->polling);
     244        /* Join polling fibril (ignoring error code). */
     245        usb_polling_join(&hub->polling);
    237246        usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub);
    238247
     
    254263        usb_log_info("(%p) USB hub gone, joining polling fibril.", hub);
    255264
    256         /* Join polling fibril. */
    257         usb_device_poll_join(hub->polling);
     265        /* Join polling fibril (ignoring error code). */
     266        usb_polling_join(&hub->polling);
    258267        usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub);
    259268
  • uspace/drv/bus/usb/usbhub/usbhub.h

    redc51615 r8b71f3e  
    6060        usb_device_t *usb_device;
    6161        /** Data polling handle. */
    62         usb_device_polling_t *polling;
     62        usb_polling_t polling;
    6363        /** Number of pending operations on the mutex to prevent shooting
    6464         * ourselves in the foot.
  • uspace/drv/hid/usbhid/main.c

    redc51615 r8b71f3e  
    8989         * This will create a separate fibril that will query the device
    9090         * for the data continuously. */
    91         const usb_device_polling_config_t config = {
    92                 .debug = 1,
    93                 .auto_clear_halt = true,
    94                 .delay = -1,
    95                 .max_failures = 3,
    96                 .on_data = usb_hid_polling_callback,
    97                 .on_polling_end = usb_hid_polling_ended_callback,
    98                 .on_error = usb_hid_polling_error_callback,
    99                 .arg = hid_dev,
    100         };
    101 
    102         rc = usb_device_poll(dev, hid_dev->poll_pipe_mapping, &config,
    103             hid_dev->poll_pipe_mapping->pipe.desc.max_transfer_size, &hid_dev->polling);
     91        rc = usb_polling_start(&hid_dev->polling);
    10492
    10593        if (rc != EOK) {
     
    122110        assert(hid_dev);
    123111
    124         /* Join polling fibril. */
    125         usb_device_poll_join(hid_dev->polling);
     112        /* Join polling fibril (ignoring error code). */
     113        usb_polling_join(&hid_dev->polling);
    126114
    127115        /* Clean up. */
  • uspace/drv/hid/usbhid/usbhid.c

    redc51615 r8b71f3e  
    445445                            ".\n");
    446446                }
     447
     448                usb_polling_t *polling = &hid_dev->polling;
     449                if ((rc = usb_polling_init(polling))) {
     450                        // FIXME
     451                }
     452
     453                polling->device = hid_dev->usb_dev;
     454                polling->ep_mapping = hid_dev->poll_pipe_mapping;
     455                polling->request_size = hid_dev->poll_pipe_mapping->pipe.desc.max_transfer_size;
     456                polling->buffer = malloc(polling->request_size);
     457                polling->on_data = usb_hid_polling_callback,
     458                polling->on_polling_end = usb_hid_polling_ended_callback,
     459                polling->on_error = usb_hid_polling_error_callback,
     460                polling->arg = hid_dev;
    447461        }
    448462
     
    537551        assert(hid_dev->subdrivers != NULL || hid_dev->subdriver_count == 0);
    538552
     553        free(hid_dev->polling.buffer);
     554        usb_polling_fini(&hid_dev->polling);
     555
    539556        usb_log_debug("Subdrivers: %p, subdriver count: %d\n",
    540557            hid_dev->subdrivers, hid_dev->subdriver_count);
  • uspace/drv/hid/usbhid/usbhid.h

    redc51615 r8b71f3e  
    107107        usb_endpoint_mapping_t *poll_pipe_mapping;
    108108
    109         /** Device polling handle. */
    110         usb_device_polling_t *polling;
     109        /** Device polling structure. */
     110        usb_polling_t polling;
    111111
    112112        /** Subdrivers. */
  • uspace/lib/usbdev/include/usb/dev/poll.h

    redc51615 r8b71f3e  
    4343#include <stddef.h>
    4444#include <stdint.h>
     45#include <fibril_synch.h>
    4546
    46 /** Automated polling instance. */
    47 typedef struct usb_device_polling usb_device_polling_t;
    4847
    49 /** Parameters and callbacks for automated polling. */
    50 typedef struct usb_device_polling_config {
    51         /** Level of debugging messages from auto polling.
    52          * 0 - nothing
    53          * 1 - inform about errors and polling start/end
    54          * 2 - also dump every retrieved buffer
    55          */
    56         int debug;
     48/** USB automated polling. */
     49typedef struct usb_polling {
     50        /** Mandatory parameters - user is expected to configure these. */
    5751
    58         /** Maximum number of consecutive errors before polling termination. */
    59         size_t max_failures;
     52        /** USB device to poll. */
     53        usb_device_t *device;
    6054
    61         /** Delay between poll requests in milliseconds.
    62          * Set to negative value to use value from endpoint descriptor.
    63          */
    64         int delay;
     55        /** Device enpoint mapping to use for polling. */
     56        usb_endpoint_mapping_t *ep_mapping;
    6557
    66         /** Whether to automatically try to clear the HALT feature after
    67          * the endpoint stalls.
    68          */
    69         bool auto_clear_halt;
     58        /** Size of the recieved data. */
     59        size_t request_size;
     60
     61        /** Data buffer of at least `request_size`. User is responsible for its allocation. */
     62        uint8_t *buffer;
    7063
    7164        /** Callback when data arrives.
     
    7972        bool (*on_data)(usb_device_t *dev, uint8_t *data, size_t data_size,
    8073            void *arg);
     74
     75
     76        /** Optional parameters - user can customize them, but they are defaulted to
     77         *  some reasonable values.
     78         */
     79
     80        /** Level of debugging messages from auto polling.
     81         * 0 - nothing (default)
     82         * 1 - inform about errors and polling start/end
     83         * 2 - also dump every retrieved buffer
     84         */
     85        int debug;
     86
     87        /** Maximum number of consecutive errors before polling termination (default 3). */
     88        size_t max_failures;
     89
     90        /** Delay between poll requests in milliseconds.
     91         * By default, value from endpoint descriptor used.
     92         */
     93        int delay;
     94
     95        /** Whether to automatically try to clear the HALT feature after
     96         * the endpoint stalls (true by default).
     97         */
     98        bool auto_clear_halt;
     99
     100        /** Argument to pass to callbacks (default NULL). */
     101        void *arg;
    81102
    82103        /** Callback when polling is terminated.
     
    98119        bool (*on_error)(usb_device_t *dev, int err_code, void *arg);
    99120
    100         /** Argument to pass to callbacks. */
    101         void *arg;
    102 } usb_device_polling_config_t;
    103121
    104 int usb_device_poll(usb_device_t *, usb_endpoint_mapping_t *,
    105     const usb_device_polling_config_t *, size_t, usb_device_polling_t **);
     122        /** Internal parameters - user is not expected to set them. Messing with them
     123         *  can result in unexpected behavior if you do not know what you are doing.
     124         */
    106125
    107 int usb_device_poll_join(usb_device_polling_t *);
     126        /** Fibril used for polling. */
     127        fid_t fibril;
     128
     129        /** True if polling is currently in operation. */
     130        volatile bool running;
     131
     132        /** True if polling should terminate as soon as possible. */
     133        volatile bool joining;
     134
     135        /** Synchronization primitives for joining polling end. */
     136        fibril_mutex_t guard;
     137        fibril_condvar_t cv;
     138} usb_polling_t;
     139
     140int usb_polling_init(usb_polling_t *);
     141void usb_polling_fini(usb_polling_t *);
     142
     143int usb_polling_start(usb_polling_t *);
     144int usb_polling_join(usb_polling_t *);
    108145
    109146#endif
  • 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.