Changeset 5400606 in mainline


Ignore:
Timestamp:
2011-10-29T13:35:40Z (12 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
4dfc905
Parents:
2fd1f0c6
Message:

libusbhost: Fixes and improvements for usb_endpoint_manager.

Add doxygen comments.
Add asserts and input checks.
Fix bandwidth count (bits vs. bytes).
Refactor usb_endpoint_manager_add_ep to avoid crash/leak in error path.

Location:
uspace/lib/usbhost
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h

    r2fd1f0c6 r5400606  
    4646#include <usb/host/endpoint.h>
    4747
    48 #define BANDWIDTH_TOTAL_USB11 12000000
     48/** Bytes per second in FULL SPEED */
     49#define BANDWIDTH_TOTAL_USB11 (12000000 / 8)
     50/** 90% of total bandwidth is available for periodic transfers */
    4951#define BANDWIDTH_AVAILABLE_USB11 ((BANDWIDTH_TOTAL_USB11 / 10) * 9)
     52/** 16 addresses per list */
    5053#define ENDPOINT_LIST_COUNT 8
    5154
     55/** Endpoint management structure */
    5256typedef struct usb_endpoint_manager {
     57        /** Store endpoint_t instances */
    5358        list_t endpoint_lists[ENDPOINT_LIST_COUNT];
     59        /** Prevents races accessing lists */
    5460        fibril_mutex_t guard;
     61        /** Size of the bandwidth pool */
    5562        size_t free_bw;
     63        /** Use this function to count bw required by EP */
    5664        size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t);
    5765} usb_endpoint_manager_t;
     
    6472    size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t));
    6573
    66 void usb_endpoint_manager_reset_eps_if_need(
    67     usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data);
     74void usb_endpoint_manager_reset_eps_if_need(usb_endpoint_manager_t *instance,
     75    usb_target_t target, const uint8_t data[8]);
    6876
    6977int usb_endpoint_manager_register_ep(
  • uspace/lib/usbhost/src/usb_endpoint_manager.c

    r2fd1f0c6 r5400606  
    3434#include <usb/host/usb_endpoint_manager.h>
    3535
     36/** Endpoint compare helper function.
     37 *
     38 * USB_DIRECTION_BOTH matches both IN and OUT.
     39 * @param ep Endpoint to compare, non-null.
     40 * @param address Tested address.
     41 * @param endpoint Tested endpoint number.
     42 * @param direction Tested direction.
     43 * @return True if ep can be used to communicate with given device,
     44 * false otherwise.
     45 */
    3646static inline bool ep_match(const endpoint_t *ep,
    3747    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
     
    4656}
    4757/*----------------------------------------------------------------------------*/
     58/** Get list that holds endpints for given address.
     59 * @param instance usb_endpoint_manager structure, non-null.
     60 * @param addr USB address, must be >= 0.
     61 * @return Pointer to the appropriate list.
     62 */
    4863static list_t * get_list(usb_endpoint_manager_t *instance, usb_address_t addr)
    4964{
    5065        assert(instance);
     66        assert(addr >= 0);
    5167        return &instance->endpoint_lists[addr % ENDPOINT_LIST_COUNT];
    5268}
    5369/*----------------------------------------------------------------------------*/
     70/** Internal search function, works on locked structure.
     71 * @param instance usb_endpoint_manager structure, non-null.
     72 * @param address USB address, must be valid.
     73 * @param endpoint USB endpoint number.
     74 * @param direction Communication direction.
     75 * @return Pointer to endpoint_t structure representing given communication
     76 * target, NULL if there is no such endpoint registered.
     77 */
    5478static endpoint_t * find_locked(usb_endpoint_manager_t *instance,
    5579    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
     
    5781        assert(instance);
    5882        assert(fibril_mutex_is_locked(&instance->guard));
     83        if (address < 0)
     84                return NULL;
    5985        list_foreach(*get_list(instance, address), iterator) {
    6086                endpoint_t *ep = endpoint_get_instance(iterator);
     
    6591}
    6692/*----------------------------------------------------------------------------*/
     93/** Calculate bandwidth that needs to be reserved for communication with EP.
     94 * Calculation follows USB 1.1 specification.
     95 * @param speed Device's speed.
     96 * @param type Type of the transfer.
     97 * @param size Number of byte to transfer.
     98 * @param max_packet_size Maximum bytes in one packet.
     99 */
    67100size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type,
    68101    size_t size, size_t max_packet_size)
     
    106139}
    107140/*----------------------------------------------------------------------------*/
     141/** Initialize to default state.
     142 * You need to provide valid bw_count function if you plan to use
     143 * add_endpoint/remove_endpoint pair.
     144 *
     145 * @param instance usb_endpoint_manager structure, non-null.
     146 * @param available_bandwidth Size of the bandwidth pool.
     147 * @param bw_count function to use to calculate endpoint bw requirements.
     148 * @return Error code.
     149 */
    108150int usb_endpoint_manager_init(usb_endpoint_manager_t *instance,
    109151    size_t available_bandwidth,
     
    122164/** Check setup packet data for signs of toggle reset.
    123165 *
    124  * @param[in] instance Device keeper structure to use.
     166 * @param[in] instance usb_endpoint_manager structure, non-null.
    125167 * @param[in] target Device to receive setup packet.
    126168 * @param[in] data Setup packet data.
    127169 *
    128  * Really ugly one.
    129  */
    130 void usb_endpoint_manager_reset_eps_if_need(
    131     usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data)
     170 * Really ugly one. Resets toggle bit on all endpoints that need it.
     171 */
     172void usb_endpoint_manager_reset_eps_if_need(usb_endpoint_manager_t *instance,
     173    usb_target_t target, const uint8_t data[8])
    132174{
    133175        assert(instance);
     
    175217}
    176218/*----------------------------------------------------------------------------*/
     219/** Register endpoint structure.
     220 * Checks for duplicates.
     221 * @param instance usb_endpoint_manager, non-null.
     222 * @param ep endpoint_t to register.
     223 * @param data_size Size of data to transfer.
     224 * @return Error code.
     225 */
    177226int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
    178227    endpoint_t *ep, size_t data_size)
    179228{
    180229        assert(instance);
    181         assert(instance->bw_count);
    182         assert(ep);
    183         fibril_mutex_lock(&instance->guard);
    184 
     230        if (ep == NULL || ep->address < 0)
     231                return EINVAL;
     232
     233        fibril_mutex_lock(&instance->guard);
     234        /* Check for available bandwidth */
    185235        if (ep->bandwidth > instance->free_bw) {
    186236                fibril_mutex_unlock(&instance->guard);
     
    195245                return EEXISTS;
    196246        }
    197         list_t *list = get_list(instance, ep->address);
    198         list_append(&ep->link, list);
     247        list_append(&ep->link, get_list(instance, ep->address));
    199248
    200249        instance->free_bw -= ep->bandwidth;
     
    203252}
    204253/*----------------------------------------------------------------------------*/
     254/** Unregister endpoint structure.
     255 * Checks for duplicates.
     256 * @param instance usb_endpoint_manager, non-null.
     257 * @param ep endpoint_t to unregister.
     258 * @return Error code.
     259 */
    205260int usb_endpoint_manager_unregister_ep(
    206261    usb_endpoint_manager_t *instance, endpoint_t *ep)
    207262{
    208263        assert(instance);
    209         if (ep == NULL)
     264        if (ep == NULL || ep->address < 0)
     265                return EINVAL;
     266
     267        fibril_mutex_lock(&instance->guard);
     268        if (!list_member(&ep->link, get_list(instance, ep->address))) {
     269                fibril_mutex_unlock(&instance->guard);
    210270                return ENOENT;
    211         fibril_mutex_lock(&instance->guard);
     271        }
    212272        list_remove(&ep->link);
    213         fibril_mutex_unlock(&instance->guard);
    214         return EOK;
    215 }
    216 /*----------------------------------------------------------------------------*/
     273        instance->free_bw += ep->bandwidth;
     274        fibril_mutex_unlock(&instance->guard);
     275        return EOK;
     276}
     277/*----------------------------------------------------------------------------*/
     278/** Find endpoint_t representing the given communication route.
     279 * @param instance usb_endpoint_manager, non-null.
     280 * @param address
     281 */
    217282endpoint_t * usb_endpoint_manager_find_ep(usb_endpoint_manager_t *instance,
    218283    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
     
    223288        endpoint_t *ep = find_locked(instance, address, endpoint, direction);
    224289        fibril_mutex_unlock(&instance->guard);
    225 
    226290        return ep;
    227291}
    228292/*----------------------------------------------------------------------------*/
     293/** Create and register new endpoint_t structure.
     294 * @param instance usb_endpoint_manager structure, non-null.
     295 * @param address USB address.
     296 * @param endpoint USB endpoint number.
     297 * @param direction Communication direction.
     298 * @param type USB transfer type.
     299 * @param speed USB Communication speed.
     300 * @param max_packet_size Maximum size of data packets.
     301 * @param data_size Expected communication size.
     302 * @param callback function to call just after registering.
     303 * @param arg Argument to pass to the callback function.
     304 * @return Error code.
     305 */
    229306int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance,
    230307    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
     
    233310{
    234311        assert(instance);
     312        if (instance->bw_count == NULL)
     313                return ENOTSUP;
     314        if (address < 0)
     315                return EINVAL;
     316
    235317        const size_t bw =
    236318            instance->bw_count(speed, type, data_size, max_packet_size);
    237319
    238         endpoint_t *ep = endpoint_create(
     320        fibril_mutex_lock(&instance->guard);
     321        /* Check for available bandwidth */
     322        if (bw > instance->free_bw) {
     323                fibril_mutex_unlock(&instance->guard);
     324                return ENOSPC;
     325        }
     326
     327        /* Check for existence */
     328        endpoint_t *ep = find_locked(instance, address, endpoint, direction);
     329        if (ep != NULL) {
     330                fibril_mutex_unlock(&instance->guard);
     331                return EEXISTS;
     332        }
     333
     334        ep = endpoint_create(
    239335            address, endpoint, direction, type, speed, max_packet_size, bw);
    240         if (!ep)
     336        if (!ep) {
     337                fibril_mutex_unlock(&instance->guard);
    241338                return ENOMEM;
     339        }
    242340
    243341        if (callback) {
    244342                const int ret = callback(ep, arg);
    245343                if (ret != EOK) {
     344                        fibril_mutex_unlock(&instance->guard);
    246345                        endpoint_destroy(ep);
    247346                        return ret;
    248347                }
    249348        }
    250 
    251         const int ret =
    252             usb_endpoint_manager_register_ep(instance, ep, data_size);
    253         if (ret != EOK) {
    254                 endpoint_destroy(ep);
    255         }
    256         return ret;
    257 }
    258 /*----------------------------------------------------------------------------*/
     349        list_append(&ep->link, get_list(instance, ep->address));
     350
     351        instance->free_bw -= ep->bandwidth;
     352        fibril_mutex_unlock(&instance->guard);
     353        return EOK;
     354}
     355/*----------------------------------------------------------------------------*/
     356/** Unregister and destroy endpoint_t structure representing given route.
     357 * @param instance usb_endpoint_manager structure, non-null.
     358 * @param address USB address.
     359 * @param endpoint USB endpoint number.
     360 * @param direction Communication direction.
     361 * @param callback Function to call after unregister, before destruction.
     362 * @arg Argument to pass to the callback function.
     363 * @return Error code.
     364 */
    259365int usb_endpoint_manager_remove_ep(usb_endpoint_manager_t *instance,
    260366    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
Note: See TracChangeset for help on using the changeset viewer.