Changeset df6ded8 in mainline for uspace/lib/usbhost/src/ddf_helpers.c


Ignore:
Timestamp:
2018-02-28T16:37:50Z (6 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
1b20da0
Parents:
f5e5f73 (diff), b2dca8de (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
Jakub Jermar <jakub@…> (2018-02-28 16:06:42)
git-committer:
Jakub Jermar <jakub@…> (2018-02-28 16:37:50)
Message:

Merge github.com:helenos-xhci-team/helenos

This commit merges support for USB 3 and generally refactors, fixes,
extends and cleans up the existing USB framework.

Notable additions and features:

  • new host controller driver has been implemented to control various xHC models (among others, NEC Renesas uPD720200)
  • isochronous data transfer mode
  • support for explicit USB device removal
  • USB tablet driver
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usbhost/src/ddf_helpers.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2013 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty, Michal Staruch, Petr Manek
    34 * All rights reserved.
    45 *
     
    3132 */
    3233/** @file
    33  *
    34  */
    35 
    36 #include <usb/classes/classes.h>
    37 #include <usb/debug.h>
    38 #include <usb/descriptor.h>
    39 #include <usb/request.h>
    40 #include <usb/usb.h>
     34 * Helpers to work with the DDF interface.
     35 */
    4136
    4237#include <adt/list.h>
     
    4742#include <device/hw_res_parsed.h>
    4843#include <errno.h>
    49 #include <fibril_synch.h>
    50 #include <macros.h>
    51 #include <stdio.h>
    52 #include <stdlib.h>
    5344#include <str_error.h>
     45#include <usb/classes/classes.h>
     46#include <usb/debug.h>
     47#include <usb/descriptor.h>
     48#include <usb/usb.h>
     49#include <usb/dma_buffer.h>
    5450#include <usb_iface.h>
     51#include <usbhc_iface.h>
     52
     53#include "bus.h"
     54#include "endpoint.h"
    5555
    5656#include "ddf_helpers.h"
    5757
    58 #define CTRL_PIPE_MIN_PACKET_SIZE 8
    59 
    60 typedef struct usb_dev {
    61         link_t link;
    62         list_t devices;
    63         fibril_mutex_t guard;
    64         ddf_fun_t *fun;
    65         usb_address_t address;
    66         usb_speed_t speed;
    67         usb_address_t tt_address;
    68         unsigned port;
    69 } usb_dev_t;
    70 
    71 typedef struct hc_dev {
    72         ddf_fun_t *ctl_fun;
    73         hcd_t hcd;
    74         usb_dev_t *root_hub;
    75 } hc_dev_t;
    76 
    77 static hc_dev_t *dev_to_hc_dev(ddf_dev_t *dev)
    78 {
    79         return ddf_dev_data_get(dev);
    80 }
    81 
    82 hcd_t *dev_to_hcd(ddf_dev_t *dev)
    83 {
    84         hc_dev_t *hc_dev = dev_to_hc_dev(dev);
    85         if (!hc_dev) {
    86                 usb_log_error("Invalid HCD device.\n");
    87                 return NULL;
    88         }
    89         return &hc_dev->hcd;
    90 }
    91 
    92 
    93 static errno_t hcd_ddf_new_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port);
    94 static errno_t hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port);
    95 
    96 
    97 /* DDF INTERFACE */
    98 
    99 /** Register endpoint interface function.
    100  * @param fun DDF function.
    101  * @param address USB address of the device.
    102  * @param endpoint USB endpoint number to be registered.
    103  * @param transfer_type Endpoint's transfer type.
    104  * @param direction USB communication direction the endpoint is capable of.
    105  * @param max_packet_size Maximu size of packets the endpoint accepts.
    106  * @param interval Preferred timeout between communication.
     58/**
     59 * DDF usbhc_iface callback. Passes the endpoint descriptors, fills the pipe
     60 * descriptor according to the contents of the endpoint.
     61 *
     62 * @param[in] fun DDF function of the device in question.
     63 * @param[out] pipe_desc The pipe descriptor to be filled.
     64 * @param[in] endpoint_desc Endpoint descriptors from the device.
    10765 * @return Error code.
    10866 */
    109 static errno_t register_endpoint(
    110     ddf_fun_t *fun, usb_endpoint_t endpoint,
    111     usb_transfer_type_t transfer_type, usb_direction_t direction,
    112     size_t max_packet_size, unsigned packets, unsigned interval)
    113 {
    114         assert(fun);
    115         hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    116         usb_dev_t *dev = ddf_fun_data_get(fun);
     67static errno_t register_endpoint(ddf_fun_t *fun, usb_pipe_desc_t *pipe_desc,
     68     const usb_endpoint_descriptors_t *ep_desc)
     69{
     70        assert(fun);
     71        hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
     72        device_t *dev = ddf_fun_data_get(fun);
    11773        assert(hcd);
     74        assert(hcd->bus);
    11875        assert(dev);
    119         const size_t size = max_packet_size;
    120         const usb_target_t target =
    121             {{.address = dev->address, .endpoint = endpoint}};
    122 
    123         usb_log_debug("Register endpoint %d:%d %s-%s %zuB %ums.\n",
    124             dev->address, endpoint, usb_str_transfer_type(transfer_type),
    125             usb_str_direction(direction), max_packet_size, interval);
    126 
    127         return hcd_add_ep(hcd, target, direction, transfer_type,
    128             max_packet_size, packets, size, dev->tt_address, dev->port);
    129 }
    130 
    131 /** Unregister endpoint interface function.
    132  * @param fun DDF function.
    133  * @param address USB address of the endpoint.
    134  * @param endpoint USB endpoint number.
    135  * @param direction Communication direction of the enpdoint to unregister.
     76
     77        endpoint_t *ep;
     78        const int err = bus_endpoint_add(dev, ep_desc, &ep);
     79        if (err)
     80                return err;
     81
     82        if (pipe_desc) {
     83                pipe_desc->endpoint_no = ep->endpoint;
     84                pipe_desc->direction = ep->direction;
     85                pipe_desc->transfer_type = ep->transfer_type;
     86                pipe_desc->max_transfer_size = ep->max_transfer_size;
     87                pipe_desc->transfer_buffer_policy = ep->transfer_buffer_policy;
     88        }
     89        endpoint_del_ref(ep);
     90
     91        return EOK;
     92}
     93
     94 /**
     95  * DDF usbhc_iface callback. Unregister endpoint that makes the other end of
     96  * the pipe described.
     97  *
     98  * @param fun DDF function of the device in question.
     99  * @param pipe_desc Pipe description.
     100  * @return Error code.
     101  */
     102static errno_t unregister_endpoint(ddf_fun_t *fun, const usb_pipe_desc_t *pipe_desc)
     103{
     104        assert(fun);
     105        hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
     106        device_t *dev = ddf_fun_data_get(fun);
     107        assert(hcd);
     108        assert(hcd->bus);
     109        assert(dev);
     110
     111        endpoint_t *ep = bus_find_endpoint(dev, pipe_desc->endpoint_no, pipe_desc->direction);
     112        if (!ep)
     113                return ENOENT;
     114
     115        const errno_t err = bus_endpoint_remove(ep);
     116
     117        endpoint_del_ref(ep);
     118        return err;
     119}
     120
     121/**
     122 * DDF usbhc_iface callback. Calls the respective bus operation directly.
     123 *
     124 * @param fun DDF function of the device (hub) requesting the address.
     125 */
     126static errno_t default_address_reservation(ddf_fun_t *fun, bool reserve)
     127{
     128        assert(fun);
     129        hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
     130        device_t *dev = ddf_fun_data_get(fun);
     131        assert(hcd);
     132        assert(hcd->bus);
     133        assert(dev);
     134
     135        usb_log_debug("Device %d %s default address", dev->address, reserve ? "requested" : "releasing");
     136        if (reserve) {
     137                return bus_reserve_default_address(hcd->bus, dev);
     138        } else {
     139                bus_release_default_address(hcd->bus, dev);
     140                return EOK;
     141        }
     142}
     143
     144/**
     145 * DDF usbhc_iface callback. Calls the bus operation directly.
     146 *
     147 * @param fun DDF function of the device (hub) requesting the address.
     148 * @param speed USB speed of the new device
     149 */
     150static errno_t device_enumerate(ddf_fun_t *fun, unsigned port, usb_speed_t speed)
     151{
     152        assert(fun);
     153        ddf_dev_t *hc = ddf_fun_get_dev(fun);
     154        assert(hc);
     155        hc_device_t *hcd = dev_to_hcd(hc);
     156        assert(hcd);
     157        device_t *hub = ddf_fun_data_get(fun);
     158        assert(hub);
     159
     160        errno_t err;
     161
     162        if (!usb_speed_is_valid(speed))
     163                return EINVAL;
     164
     165        usb_log_debug("Hub %d reported a new %s speed device on port: %u",
     166            hub->address, usb_str_speed(speed), port);
     167
     168        device_t *dev = hcd_ddf_fun_create(hcd, speed);
     169        if (!dev) {
     170                usb_log_error("Failed to create USB device function.");
     171                return ENOMEM;
     172        }
     173
     174        dev->hub = hub;
     175        dev->tier = hub->tier + 1;
     176        dev->port = port;
     177        dev->speed = speed;
     178
     179        if ((err = bus_device_enumerate(dev))) {
     180                usb_log_error("Failed to initialize USB dev memory structures.");
     181                goto err_usb_dev;
     182        }
     183
     184        /* If the driver didn't name the dev when enumerating,
     185         * do it in some generic way.
     186         */
     187        if (!ddf_fun_get_name(dev->fun)) {
     188                bus_device_set_default_name(dev);
     189        }
     190
     191        if ((err = ddf_fun_bind(dev->fun))) {
     192                usb_log_error("Device(%d): Failed to register: %s.", dev->address, str_error(err));
     193                goto err_usb_dev;
     194        }
     195
     196        return EOK;
     197
     198err_usb_dev:
     199        hcd_ddf_fun_destroy(dev);
     200        return err;
     201}
     202
     203static errno_t device_remove(ddf_fun_t *fun, unsigned port)
     204{
     205        assert(fun);
     206        device_t *hub = ddf_fun_data_get(fun);
     207        assert(hub);
     208        usb_log_debug("Hub `%s' reported removal of device on port %u",
     209            ddf_fun_get_name(fun), port);
     210
     211        device_t *victim = NULL;
     212
     213        fibril_mutex_lock(&hub->guard);
     214        list_foreach(hub->devices, link, device_t, it) {
     215                if (it->port == port) {
     216                        victim = it;
     217                        break;
     218                }
     219        }
     220        fibril_mutex_unlock(&hub->guard);
     221
     222        if (!victim) {
     223                usb_log_warning("Hub '%s' tried to remove non-existent"
     224                    " device.", ddf_fun_get_name(fun));
     225                return ENOENT;
     226        }
     227
     228        assert(victim->fun);
     229        assert(victim->port == port);
     230        assert(victim->hub == hub);
     231
     232        bus_device_gone(victim);
     233        return EOK;
     234}
     235
     236/**
     237 * Gets description of the device that is calling.
     238 *
     239 * @param[in] fun Device function.
     240 * @param[out] desc Device descriptor to be filled.
    136241 * @return Error code.
    137242 */
    138 static errno_t unregister_endpoint(
    139     ddf_fun_t *fun, usb_endpoint_t endpoint, usb_direction_t direction)
    140 {
    141         assert(fun);
    142         hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    143         usb_dev_t *dev = ddf_fun_data_get(fun);
    144         assert(hcd);
     243static errno_t get_device_description(ddf_fun_t *fun, usb_device_desc_t *desc)
     244{
     245        assert(fun);
     246        device_t *dev = ddf_fun_data_get(fun);
    145247        assert(dev);
    146         const usb_target_t target =
    147             {{.address = dev->address, .endpoint = endpoint}};
    148         usb_log_debug("Unregister endpoint %d:%d %s.\n",
    149             dev->address, endpoint, usb_str_direction(direction));
    150         return hcd_remove_ep(hcd, target, direction);
    151 }
    152 
    153 static errno_t reserve_default_address(ddf_fun_t *fun, usb_speed_t speed)
    154 {
    155         assert(fun);
    156         hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    157         usb_dev_t *dev = ddf_fun_data_get(fun);
    158         assert(hcd);
    159         assert(dev);
    160 
    161         usb_log_debug("Device %d requested default address at %s speed\n",
    162             dev->address, usb_str_speed(speed));
    163         return hcd_reserve_default_address(hcd, speed);
    164 }
    165 
    166 static errno_t release_default_address(ddf_fun_t *fun)
    167 {
    168         assert(fun);
    169         hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    170         usb_dev_t *dev = ddf_fun_data_get(fun);
    171         assert(hcd);
    172         assert(dev);
    173 
    174         usb_log_debug("Device %d released default address\n", dev->address);
    175         return hcd_release_default_address(hcd);
    176 }
    177 
    178 static errno_t device_enumerate(ddf_fun_t *fun, unsigned port)
    179 {
    180         assert(fun);
    181         ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun);
    182         usb_dev_t *dev = ddf_fun_data_get(fun);
    183         assert(ddf_dev);
    184         assert(dev);
    185         usb_log_debug("Hub %d reported a new USB device on port: %u\n",
    186             dev->address, port);
    187         return hcd_ddf_new_device(ddf_dev, dev, port);
    188 }
    189 
    190 static errno_t device_remove(ddf_fun_t *fun, unsigned port)
    191 {
    192         assert(fun);
    193         ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun);
    194         usb_dev_t *dev = ddf_fun_data_get(fun);
    195         assert(ddf_dev);
    196         assert(dev);
    197         usb_log_debug("Hub `%s' reported removal of device on port %u\n",
    198             ddf_fun_get_name(fun), port);
    199         return hcd_ddf_remove_device(ddf_dev, dev, port);
    200 }
    201 
    202 /** Gets handle of the respective device.
    203  *
    204  * @param[in] fun Device function.
    205  * @param[out] handle Place to write the handle.
    206  * @return Error code.
    207  */
    208 static errno_t get_my_device_handle(ddf_fun_t *fun, devman_handle_t *handle)
    209 {
    210         assert(fun);
    211         if (handle)
    212                 *handle = ddf_fun_get_handle(fun);
    213         return EOK;
    214 }
    215 
    216 /** Inbound communication interface function.
     248
     249        if (!desc)
     250                return EOK;
     251
     252        *desc = (usb_device_desc_t) {
     253                .address = dev->address,
     254                .depth = dev->tier,
     255                .speed = dev->speed,
     256                .handle = ddf_fun_get_handle(fun),
     257                .iface = -1,
     258        };
     259        return EOK;
     260}
     261
     262/**
     263 * Transfer issuing interface function.
     264 *
    217265 * @param fun DDF function.
    218266 * @param target Communication target.
     267 * @param dir Communication direction.
    219268 * @param setup_data Data to use in setup stage (control transfers).
    220269 * @param data Pointer to data buffer.
     
    224273 * @return Error code.
    225274 */
    226 static errno_t dev_read(ddf_fun_t *fun, usb_endpoint_t endpoint,
    227     uint64_t setup_data, uint8_t *data, size_t size,
    228     usbhc_iface_transfer_in_callback_t callback, void *arg)
    229 {
    230         assert(fun);
    231         usb_dev_t *usb_dev = ddf_fun_data_get(fun);
    232         assert(usb_dev);
     275static errno_t transfer(ddf_fun_t *fun,
     276    const usbhc_iface_transfer_request_t *ifreq,
     277    usbhc_iface_transfer_callback_t callback, void *arg)
     278{
     279        assert(fun);
     280        device_t *dev = ddf_fun_data_get(fun);
     281        assert(dev);
     282
    233283        const usb_target_t target = {{
    234             .address =  usb_dev->address,
    235             .endpoint = endpoint,
     284                .address = dev->address,
     285                .endpoint = ifreq->endpoint,
     286                .stream = ifreq->stream,
    236287        }};
    237         return hcd_send_batch(dev_to_hcd(ddf_fun_get_dev(fun)), target,
    238             USB_DIRECTION_IN, data, size, setup_data, callback, NULL, arg,
    239             "READ");
    240 }
    241 
    242 /** Outbound communication interface function.
    243  * @param fun DDF function.
    244  * @param target Communication target.
    245  * @param setup_data Data to use in setup stage (control transfers).
    246  * @param data Pointer to data buffer.
    247  * @param size Size of the data buffer.
    248  * @param callback Function to call on communication end.
    249  * @param arg Argument passed to the callback function.
    250  * @return Error code.
    251  */
    252 static errno_t dev_write(ddf_fun_t *fun, usb_endpoint_t endpoint,
    253     uint64_t setup_data, const uint8_t *data, size_t size,
    254     usbhc_iface_transfer_out_callback_t callback, void *arg)
    255 {
    256         assert(fun);
    257         usb_dev_t *usb_dev = ddf_fun_data_get(fun);
    258         assert(usb_dev);
    259         const usb_target_t target = {{
    260             .address =  usb_dev->address,
    261             .endpoint = endpoint,
    262         }};
    263         return hcd_send_batch(dev_to_hcd(ddf_fun_get_dev(fun)),
    264             target, USB_DIRECTION_OUT, (uint8_t*)data, size, setup_data, NULL,
    265             callback, arg, "WRITE");
     288
     289        if (!usb_target_is_valid(&target))
     290                return EINVAL;
     291
     292        if (ifreq->offset > 0 && ifreq->size == 0)
     293                return EINVAL;
     294
     295        if (ifreq->size > 0 && !dma_buffer_is_set(&ifreq->buffer))
     296                return EBADMEM;
     297
     298        if (!callback && arg)
     299                return EBADMEM;
     300
     301        const transfer_request_t request = {
     302                .target = target,
     303                .dir = ifreq->dir,
     304                .buffer = ifreq->buffer,
     305                .offset = ifreq->offset,
     306                .size = ifreq->size,
     307                .setup = ifreq->setup,
     308                .on_complete = callback,
     309                .arg = arg,
     310                .name = (ifreq->dir == USB_DIRECTION_IN) ? "READ" : "WRITE",
     311        };
     312
     313        return bus_issue_transfer(dev, &request);
    266314}
    267315
    268316/** USB device interface */
    269317static usb_iface_t usb_iface = {
    270         .get_my_device_handle = get_my_device_handle,
    271 
    272         .reserve_default_address = reserve_default_address,
    273         .release_default_address = release_default_address,
     318        .get_my_description = get_device_description,
     319};
     320
     321/** USB host controller interface */
     322static usbhc_iface_t usbhc_iface = {
     323        .default_address_reservation = default_address_reservation,
    274324
    275325        .device_enumerate = device_enumerate,
     
    279329        .unregister_endpoint = unregister_endpoint,
    280330
    281         .read = dev_read,
    282         .write = dev_write,
     331        .transfer = transfer,
    283332};
    284333
     
    286335static ddf_dev_ops_t usb_ops = {
    287336        .interfaces[USB_DEV_IFACE] = &usb_iface,
     337        .interfaces[USBHC_DEV_IFACE] = &usbhc_iface,
    288338};
    289339
    290340
    291341/* DDF HELPERS */
    292 
    293 #define GET_DEVICE_DESC(size) \
    294 { \
    295         .request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST \
    296             | (USB_REQUEST_TYPE_STANDARD << 5) \
    297             | USB_REQUEST_RECIPIENT_DEVICE, \
    298         .request = USB_DEVREQ_GET_DESCRIPTOR, \
    299         .value = uint16_host2usb(USB_DESCTYPE_DEVICE << 8), \
    300         .index = uint16_host2usb(0), \
    301         .length = uint16_host2usb(size), \
    302 };
    303 
    304 #define SET_ADDRESS(address) \
    305 { \
    306         .request_type = SETUP_REQUEST_TYPE_HOST_TO_DEVICE \
    307             | (USB_REQUEST_TYPE_STANDARD << 5) \
    308             | USB_REQUEST_RECIPIENT_DEVICE, \
    309         .request = USB_DEVREQ_SET_ADDRESS, \
    310         .value = uint16_host2usb(address), \
    311         .index = uint16_host2usb(0), \
    312         .length = uint16_host2usb(0), \
    313 };
    314 
    315 static errno_t hcd_ddf_add_device(ddf_dev_t *parent, usb_dev_t *hub_dev,
    316     unsigned port, usb_address_t address, usb_speed_t speed, const char *name,
    317     const match_id_list_t *mids)
    318 {
    319         assert(parent);
    320 
    321         char default_name[10] = { 0 }; /* usbxyz-ss */
    322         if (!name) {
    323                 snprintf(default_name, sizeof(default_name) - 1,
    324                     "usb%u-%cs", address, usb_str_speed(speed)[0]);
    325                 name = default_name;
    326         }
    327 
    328         ddf_fun_t *fun = ddf_fun_create(parent, fun_inner, name);
    329         if (!fun)
    330                 return ENOMEM;
    331         usb_dev_t *info = ddf_fun_data_alloc(fun, sizeof(usb_dev_t));
    332         if (!info) {
    333                 ddf_fun_destroy(fun);
    334                 return ENOMEM;
    335         }
    336         info->address = address;
    337         info->speed = speed;
    338         info->fun = fun;
    339         info->port = port;
    340         info->tt_address = hub_dev ? hub_dev->tt_address : -1;
    341         link_initialize(&info->link);
    342         list_initialize(&info->devices);
    343         fibril_mutex_initialize(&info->guard);
    344 
    345         if (hub_dev && hub_dev->speed == USB_SPEED_HIGH && usb_speed_is_11(speed))
    346                 info->tt_address = hub_dev->address;
    347 
    348         ddf_fun_set_ops(fun, &usb_ops);
    349         list_foreach(mids->ids, link, const match_id_t, mid) {
    350                 ddf_fun_add_match_id(fun, mid->id, mid->score);
    351         }
    352 
    353         errno_t ret = ddf_fun_bind(fun);
    354         if (ret != EOK) {
    355                 ddf_fun_destroy(fun);
    356                 return ret;
    357         }
    358 
    359         if (hub_dev) {
    360                 fibril_mutex_lock(&hub_dev->guard);
    361                 list_append(&info->link, &hub_dev->devices);
    362                 fibril_mutex_unlock(&hub_dev->guard);
    363         } else {
    364                 hc_dev_t *hc_dev = dev_to_hc_dev(parent);
    365                 assert(hc_dev->root_hub == NULL);
    366                 hc_dev->root_hub = info;
    367         }
    368         return EOK;
    369 }
    370342
    371343#define ADD_MATCHID_OR_RETURN(list, sc, str, ...) \
     
    394366        assert(l);
    395367        assert(d);
    396        
     368
    397369        if (d->vendor_id != 0) {
    398370                /* First, with release number. */
     
    401373                    d->vendor_id, d->product_id, (d->device_version >> 8),
    402374                    (d->device_version & 0xff));
    403        
     375
    404376                /* Next, without release number. */
    405377                ADD_MATCHID_OR_RETURN(l, 90, "usb&vendor=%#04x&product=%#04x",
     
    415387
    416388        return EOK;
    417 
    418 }
    419 
    420 static errno_t hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub,
    421     unsigned port)
    422 {
    423         assert(device);
    424 
    425         hcd_t *hcd = dev_to_hcd(device);
    426         assert(hcd);
    427 
    428         hc_dev_t *hc_dev = dev_to_hc_dev(device);
    429         assert(hc_dev);
    430 
    431         fibril_mutex_lock(&hub->guard);
    432 
    433         usb_dev_t *victim = NULL;
    434 
    435         list_foreach(hub->devices, link, usb_dev_t, it) {
    436                 if (it->port == port) {
    437                         victim = it;
    438                         break;
    439                 }
    440         }
    441         if (victim) {
    442                 assert(victim->port == port);
    443                 list_remove(&victim->link);
    444                 fibril_mutex_unlock(&hub->guard);
    445                 const errno_t ret = ddf_fun_unbind(victim->fun);
    446                 if (ret == EOK) {
    447                         usb_address_t address = victim->address;
    448                         ddf_fun_destroy(victim->fun);
    449                         hcd_release_address(hcd, address);
    450                 } else {
    451                         usb_log_warning("Failed to unbind device `%s': %s\n",
    452                             ddf_fun_get_name(victim->fun), str_error(ret));
    453                 }
    454                 return EOK;
    455         }
    456         fibril_mutex_unlock(&hub->guard);
    457         return ENOENT;
    458 }
    459 
    460 static errno_t hcd_ddf_new_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port)
    461 {
    462         assert(device);
    463 
    464         hcd_t *hcd = dev_to_hcd(device);
    465         assert(hcd);
    466 
    467         usb_speed_t speed = USB_SPEED_MAX;
    468 
    469         /* This checks whether the default address is reserved and gets speed */
    470         errno_t ret = usb_bus_get_speed(&hcd->bus, USB_ADDRESS_DEFAULT, &speed);
    471         if (ret != EOK) {
    472                 usb_log_error("Failed to verify speed: %s.", str_error(ret));
    473                 return ret;
    474         }
    475 
    476         usb_log_debug("Found new %s speed USB device.", usb_str_speed(speed));
    477 
    478         static const usb_target_t default_target = {{
    479                 .address = USB_ADDRESS_DEFAULT,
    480                 .endpoint = 0,
    481         }};
    482 
    483         usb_address_t address;
    484         ret = hcd_request_address(hcd, speed, &address);
    485         if (ret != EOK) {
    486                 usb_log_error("Failed to reserve new address: %s.",
    487                     str_error(ret));
    488                 return ret;
    489         }
    490 
    491         usb_log_debug("Reserved new address: %d\n", address);
    492 
    493         const usb_target_t target = {{
    494                 .address = address,
    495                 .endpoint = 0,
    496         }};
    497 
    498         const usb_address_t tt_address = hub ? hub->tt_address : -1;
    499 
    500         /* Add default pipe on default address */
    501         usb_log_debug("Device(%d): Adding default target(0:0)\n", address);
    502         ret = hcd_add_ep(hcd,
    503             default_target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,
    504             CTRL_PIPE_MIN_PACKET_SIZE, CTRL_PIPE_MIN_PACKET_SIZE, 1,
    505             tt_address, port);
    506         if (ret != EOK) {
    507                 usb_log_error("Device(%d): Failed to add default target: %s.",
    508                     address, str_error(ret));
    509                 hcd_release_address(hcd, address);
    510                 return ret;
    511         }
    512 
    513         /* Get max packet size for default pipe */
    514         usb_standard_device_descriptor_t desc = { 0 };
    515         const usb_device_request_setup_packet_t get_device_desc_8 =
    516             GET_DEVICE_DESC(CTRL_PIPE_MIN_PACKET_SIZE);
    517 
    518         // TODO CALLBACKS
    519         usb_log_debug("Device(%d): Requesting first 8B of device descriptor.",
    520             address);
    521         size_t got;
    522         ret = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_IN,
    523             &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8,
    524             "read first 8 bytes of dev descriptor", &got);
    525 
    526         if (ret == EOK && got != CTRL_PIPE_MIN_PACKET_SIZE) {
    527                 ret = EOVERFLOW;
    528         }
    529 
    530         if (ret != EOK) {
    531                 usb_log_error("Device(%d): Failed to get 8B of dev descr: %s.",
    532                     address, str_error(ret));
    533                 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);
    534                 hcd_release_address(hcd, address);
    535                 return ret;
    536         }
    537 
    538         /* Register EP on the new address */
    539         usb_log_debug("Device(%d): Registering control EP.", address);
    540         ret = hcd_add_ep(hcd, target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,
    541             ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)),
    542             ED_MPS_TRANS_OPPORTUNITIES_GET(uint16_usb2host(desc.max_packet_size)),
    543             ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)),
    544             tt_address, port);
    545         if (ret != EOK) {
    546                 usb_log_error("Device(%d): Failed to register EP0: %s",
    547                     address, str_error(ret));
    548                 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);
    549                 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
    550                 hcd_release_address(hcd, address);
    551                 return ret;
    552         }
    553 
    554         /* Set new address */
    555         const usb_device_request_setup_packet_t set_address =
    556             SET_ADDRESS(target.address);
    557 
    558         usb_log_debug("Device(%d): Setting USB address.", address);
    559         ret = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_OUT,
    560             NULL, 0, *(uint64_t *)&set_address, "set address", &got);
    561 
    562         usb_log_debug("Device(%d): Removing default (0:0) EP.", address);
    563         hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);
    564 
    565         if (ret != EOK) {
    566                 usb_log_error("Device(%d): Failed to set new address: %s.",
    567                     address, str_error(ret));
    568                 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
    569                 hcd_release_address(hcd, address);
    570                 return ret;
    571         }
    572 
    573         /* Get std device descriptor */
    574         const usb_device_request_setup_packet_t get_device_desc =
    575             GET_DEVICE_DESC(sizeof(desc));
    576 
    577         usb_log_debug("Device(%d): Requesting full device descriptor.",
    578             address);
    579         ret = hcd_send_batch_sync(hcd, target, USB_DIRECTION_IN,
    580             &desc, sizeof(desc), *(uint64_t *)&get_device_desc,
    581             "read device descriptor", &got);
    582         if (ret != EOK) {
    583                 usb_log_error("Device(%d): Failed to set get dev descriptor: %s",
    584                     address, str_error(ret));
    585                 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
    586                 hcd_release_address(hcd, target.address);
    587                 return ret;
    588         }
     389}
     390
     391device_t *hcd_ddf_fun_create(hc_device_t *hc, usb_speed_t speed)
     392{
     393        /* Create DDF function for the new device */
     394        ddf_fun_t *fun = ddf_fun_create(hc->ddf_dev, fun_inner, NULL);
     395        if (!fun)
     396                return NULL;
     397
     398        ddf_fun_set_ops(fun, &usb_ops);
     399
     400        /* Create USB device node for the new device */
     401        device_t *dev = ddf_fun_data_alloc(fun, hc->bus->device_size);
     402        if (!dev) {
     403                ddf_fun_destroy(fun);
     404                return NULL;
     405        }
     406
     407        bus_device_init(dev, hc->bus);
     408        dev->fun = fun;
     409        dev->speed = speed;
     410        return dev;
     411}
     412
     413void hcd_ddf_fun_destroy(device_t *dev)
     414{
     415        assert(dev);
     416        assert(dev->fun);
     417        ddf_fun_destroy(dev->fun);
     418}
     419
     420errno_t hcd_ddf_setup_match_ids(device_t *device, usb_standard_device_descriptor_t *desc)
     421{
     422        errno_t err;
     423        match_id_list_t mids;
     424
     425        init_match_ids(&mids);
    589426
    590427        /* Create match ids from the device descriptor */
    591         match_id_list_t mids;
    592         init_match_ids(&mids);
    593 
    594         usb_log_debug("Device(%d): Creating match IDs.", address);
    595         ret = create_match_ids(&mids, &desc);
    596         if (ret != EOK) {
    597                 usb_log_error("Device(%d): Failed to create match ids: %s",
    598                     address, str_error(ret));
    599                 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
    600                 hcd_release_address(hcd, target.address);
    601                 return ret;
    602         }
    603 
    604         /* Register device */
    605         usb_log_debug("Device(%d): Registering DDF device.", address);
    606         ret = hcd_ddf_add_device(device, hub, port, address, speed, NULL, &mids);
    607         clean_match_ids(&mids);
    608         if (ret != EOK) {
    609                 usb_log_error("Device(%d): Failed to register: %s.",
    610                     address, str_error(ret));
    611                 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
    612                 hcd_release_address(hcd, target.address);
    613         }
    614 
    615         return ret;
    616 }
    617 
    618 /** Announce root hub to the DDF
    619  *
    620  * @param[in] device Host controller ddf device
    621  * @return Error code
    622  */
    623 errno_t hcd_ddf_setup_root_hub(ddf_dev_t *device)
    624 {
    625         assert(device);
    626         hcd_t *hcd = dev_to_hcd(device);
    627         assert(hcd);
    628 
    629         hcd_reserve_default_address(hcd, hcd->bus.max_speed);
    630         const errno_t ret = hcd_ddf_new_device(device, NULL, 0);
    631         hcd_release_default_address(hcd);
    632         return ret;
     428        usb_log_debug("Device(%d): Creating match IDs.", device->address);
     429        if ((err = create_match_ids(&mids, desc))) {
     430                return err;
     431        }
     432
     433        list_foreach(mids.ids, link, const match_id_t, mid) {
     434                ddf_fun_add_match_id(device->fun, mid->id, mid->score);
     435        }
     436
     437        return EOK;
    633438}
    634439
     
    643448 * This function does all the ddf work for hc driver.
    644449 */
    645 errno_t hcd_ddf_setup_hc(ddf_dev_t *device, usb_speed_t max_speed,
    646     size_t bw, bw_count_func_t bw_count)
     450errno_t hcd_ddf_setup_hc(ddf_dev_t *device, size_t size)
    647451{
    648452        assert(device);
    649453
    650         hc_dev_t *instance = ddf_dev_data_alloc(device, sizeof(hc_dev_t));
     454        hc_device_t *instance = ddf_dev_data_alloc(device, size);
    651455        if (instance == NULL) {
    652                 usb_log_error("Failed to allocate HCD ddf structure.\n");
     456                usb_log_error("Failed to allocate HCD ddf structure.");
    653457                return ENOMEM;
    654458        }
    655         instance->root_hub = NULL;
    656         hcd_init(&instance->hcd, max_speed, bw, bw_count);
     459        instance->ddf_dev = device;
    657460
    658461        errno_t ret = ENOMEM;
    659462        instance->ctl_fun = ddf_fun_create(device, fun_exposed, "ctl");
    660463        if (!instance->ctl_fun) {
    661                 usb_log_error("Failed to create HCD ddf fun.\n");
     464                usb_log_error("Failed to create HCD ddf fun.");
    662465                goto err_destroy_fun;
    663466        }
     
    665468        ret = ddf_fun_bind(instance->ctl_fun);
    666469        if (ret != EOK) {
    667                 usb_log_error("Failed to bind ctl_fun: %s.\n", str_error(ret));
     470                usb_log_error("Failed to bind ctl_fun: %s.", str_error(ret));
    668471                goto err_destroy_fun;
    669472        }
     
    671474        ret = ddf_fun_add_to_category(instance->ctl_fun, USB_HC_CATEGORY);
    672475        if (ret != EOK) {
    673                 usb_log_error("Failed to add fun to category: %s.\n",
     476                usb_log_error("Failed to add fun to category: %s.",
    674477                    str_error(ret));
    675478                ddf_fun_unbind(instance->ctl_fun);
     
    686489}
    687490
    688 void hcd_ddf_clean_hc(ddf_dev_t *device)
    689 {
    690         assert(device);
    691         hc_dev_t *hc = dev_to_hc_dev(device);
    692         assert(hc);
    693         const errno_t ret = ddf_fun_unbind(hc->ctl_fun);
    694         if (ret == EOK)
    695                 ddf_fun_destroy(hc->ctl_fun);
    696 }
    697 
    698 //TODO: Cache parent session in HCD
     491void hcd_ddf_clean_hc(hc_device_t *hcd)
     492{
     493        if (ddf_fun_unbind(hcd->ctl_fun) == EOK)
     494                ddf_fun_destroy(hcd->ctl_fun);
     495}
     496
    699497/** Call the parent driver with a request to enable interrupt
    700498 *
     
    703501 * @return Error code.
    704502 */
    705 errno_t hcd_ddf_enable_interrupt(ddf_dev_t *device, int inum)
    706 {
    707         async_sess_t *parent_sess = ddf_dev_parent_sess_get(device);
     503errno_t hcd_ddf_enable_interrupt(hc_device_t *hcd, int inum)
     504{
     505        async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev);
    708506        if (parent_sess == NULL)
    709507                return EIO;
     
    712510}
    713511
    714 //TODO: Cache parent session in HCD
    715 errno_t hcd_ddf_get_registers(ddf_dev_t *device, hw_res_list_parsed_t *hw_res)
    716 {
    717         async_sess_t *parent_sess = ddf_dev_parent_sess_get(device);
     512errno_t hcd_ddf_get_registers(hc_device_t *hcd, hw_res_list_parsed_t *hw_res)
     513{
     514        async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev);
    718515        if (parent_sess == NULL)
    719516                return EIO;
     
    726523}
    727524
    728 // TODO: move this someplace else
    729 static inline void irq_code_clean(irq_code_t *code)
    730 {
    731         if (code) {
    732                 free(code->ranges);
    733                 free(code->cmds);
    734                 code->ranges = NULL;
    735                 code->cmds = NULL;
    736                 code->rangecount = 0;
    737                 code->cmdcount = 0;
    738         }
    739 }
    740 
    741 /** Register interrupt handler
    742  *
    743  * @param[in] device Host controller DDF device
    744  * @param[in] regs Register range
    745  * @param[in] irq Interrupt number
    746  * @paran[in] handler Interrupt handler
    747  * @param[in] gen_irq_code IRQ code generator.
    748  *
    749  * @param[out] handle  IRQ capability handle on success.
    750  *
    751  * @return Error code.
    752  */
    753 errno_t hcd_ddf_setup_interrupts(ddf_dev_t *device,
    754     const hw_res_list_parsed_t *hw_res,
    755     interrupt_handler_t handler,
    756     errno_t (*gen_irq_code)(irq_code_t *, const hw_res_list_parsed_t *, int *),
    757     cap_handle_t *handle)
    758 {
    759 
    760         assert(device);
    761         if (!handler || !gen_irq_code)
    762                 return ENOTSUP;
    763 
    764         irq_code_t irq_code = {0};
    765 
    766         int irq;
    767         errno_t ret = gen_irq_code(&irq_code, hw_res, &irq);
    768         if (ret != EOK) {
    769                 usb_log_error("Failed to generate IRQ code: %s.\n",
    770                     str_error(ret));
    771                 return ret;
    772         }
    773 
    774         /* Register handler to avoid interrupt lockup */
    775         ret = register_interrupt_handler(device, irq, handler,
    776             &irq_code, handle);
    777         irq_code_clean(&irq_code);
    778         if (ret != EOK) {
    779                 usb_log_error("Failed to register interrupt handler: %s.\n",
    780                     str_error(ret));
    781                 return ret;
    782         }
    783 
    784         /* Enable interrupts */
    785         ret = hcd_ddf_enable_interrupt(device, irq);
    786         if (ret != EOK) {
    787                 usb_log_error("Failed to register interrupt handler: %s.\n",
    788                     str_error(ret));
    789                 unregister_interrupt_handler(device, *handle);
    790         }
    791         return ret;
    792 }
    793 
    794 /** IRQ handling callback, forward status from call to diver structure.
    795  *
    796  * @param[in] dev DDF instance of the device to use.
    797  * @param[in] call Pointer to the call from kernel.
    798  */
    799 void ddf_hcd_gen_irq_handler(ipc_call_t *call, ddf_dev_t *dev)
    800 {
    801         assert(dev);
    802         hcd_t *hcd = dev_to_hcd(dev);
    803         if (!hcd || !hcd->ops.irq_hook) {
    804                 usb_log_error("Interrupt on not yet initialized device.\n");
    805                 return;
    806         }
    807         const uint32_t status = IPC_GET_ARG1(*call);
    808         hcd->ops.irq_hook(hcd, status);
    809 }
    810 
    811 static errno_t interrupt_polling(void *arg)
    812 {
    813         hcd_t *hcd = arg;
    814         assert(hcd);
    815         if (!hcd->ops.status_hook || !hcd->ops.irq_hook)
    816                 return ENOTSUP;
    817         uint32_t status = 0;
    818         while (hcd->ops.status_hook(hcd, &status) == EOK) {
    819                 hcd->ops.irq_hook(hcd, status);
    820                 status = 0;
    821                 /* We should wait 1 frame - 1ms here, but this polling is a
    822                  * lame crutch anyway so don't hog the system. 10ms is still
    823                  * good enough for emergency mode */
    824                 async_usleep(10000);
    825         }
    826         return EOK;
    827 }
    828 
    829 /** Initialize hc and rh DDF structures and their respective drivers.
    830  *
    831  * @param device DDF instance of the device to use
    832  * @param speed Maximum supported speed
    833  * @param bw Available bandwidth (arbitrary units)
    834  * @param bw_count Bandwidth computing function
    835  * @param irq_handler IRQ handling function
    836  * @param gen_irq_code Function to generate IRQ pseudocode
    837  *                     (it needs to return used irq number)
    838  * @param driver_init Function to initialize HC driver
    839  * @param driver_fini Function to cleanup HC driver
    840  * @return Error code
    841  *
    842  * This function does all the preparatory work for hc and rh drivers:
    843  *  - gets device's hw resources
    844  *  - attempts to enable interrupts
    845  *  - registers interrupt handler
    846  *  - calls driver specific initialization
    847  *  - registers root hub
    848  */
    849 errno_t hcd_ddf_add_hc(ddf_dev_t *device, const ddf_hc_driver_t *driver)
    850 {
    851         assert(driver);
    852         static const struct { size_t bw; bw_count_func_t bw_count; }bw[] = {
    853             [USB_SPEED_FULL] = { .bw = BANDWIDTH_AVAILABLE_USB11,
    854                                  .bw_count = bandwidth_count_usb11 },
    855             [USB_SPEED_HIGH] = { .bw = BANDWIDTH_AVAILABLE_USB11,
    856                                  .bw_count = bandwidth_count_usb11 },
    857         };
    858 
    859         errno_t ret = EOK;
    860         const usb_speed_t speed = driver->hc_speed;
    861         if (speed >= ARRAY_SIZE(bw) || bw[speed].bw == 0) {
    862                 usb_log_error("Driver `%s' reported unsupported speed: %s",
    863                     driver->name, usb_str_speed(speed));
    864                 return ENOTSUP;
    865         }
    866 
    867         hw_res_list_parsed_t hw_res;
    868         ret = hcd_ddf_get_registers(device, &hw_res);
    869         if (ret != EOK) {
    870                 usb_log_error("Failed to get register memory addresses "
    871                     "for `%s': %s.\n", ddf_dev_get_name(device),
    872                     str_error(ret));
    873                 return ret;
    874         }
    875 
    876         ret = hcd_ddf_setup_hc(device, speed, bw[speed].bw, bw[speed].bw_count);
    877         if (ret != EOK) {
    878                 usb_log_error("Failed to setup generic HCD.\n");
    879                 hw_res_list_parsed_clean(&hw_res);
    880                 return ret;
    881         }
    882 
    883         interrupt_handler_t *irq_handler =
    884             driver->irq_handler ? driver->irq_handler : ddf_hcd_gen_irq_handler;
    885         int irq_cap;
    886         errno_t irq_ret = hcd_ddf_setup_interrupts(device, &hw_res,
    887             irq_handler, driver->irq_code_gen, &irq_cap);
    888         bool irqs_enabled = (irq_ret == EOK);
    889         if (irqs_enabled) {
    890                 usb_log_debug("Hw interrupts enabled.\n");
    891         }
    892 
    893         if (driver->claim) {
    894                 ret = driver->claim(device);
    895                 if (ret != EOK) {
    896                         usb_log_error("Failed to claim `%s' for driver `%s'",
    897                             ddf_dev_get_name(device), driver->name);
    898                         return ret;
    899                 }
    900         }
    901 
    902 
    903         /* Init hw driver */
    904         hcd_t *hcd = dev_to_hcd(device);
    905         ret = driver->init(hcd, &hw_res, irqs_enabled);
    906         hw_res_list_parsed_clean(&hw_res);
    907         if (ret != EOK) {
    908                 usb_log_error("Failed to init HCD: %s.\n", str_error(ret));
    909                 goto irq_unregister;
    910         }
    911 
    912         /* Need working irq replacement to setup root hub */
    913         if (!irqs_enabled && hcd->ops.status_hook) {
    914                 hcd->polling_fibril = fibril_create(interrupt_polling, hcd);
    915                 if (hcd->polling_fibril == 0) {
    916                         usb_log_error("Failed to create polling fibril\n");
    917                         ret = ENOMEM;
    918                         goto irq_unregister;
    919                 }
    920                 fibril_add_ready(hcd->polling_fibril);
    921                 usb_log_warning("Failed to enable interrupts: %s."
    922                     " Falling back to polling.\n", str_error(irq_ret));
    923         }
    924 
    925         /*
    926          * Creating root hub registers a new USB device so HC
    927          * needs to be ready at this time.
    928          */
    929         ret = hcd_ddf_setup_root_hub(device);
    930         if (ret != EOK) {
    931                 usb_log_error("Failed to setup HC root hub: %s.\n",
    932                     str_error(ret));
    933                 driver->fini(dev_to_hcd(device));
    934 irq_unregister:
    935                 /* Unregistering non-existent should be ok */
    936                 unregister_interrupt_handler(device, irq_cap);
    937                 hcd_ddf_clean_hc(device);
    938                 return ret;
    939         }
    940 
    941         usb_log_info("Controlling new `%s' device `%s'.\n",
    942             driver->name, ddf_dev_get_name(device));
    943         return EOK;
    944 }
    945525/**
    946526 * @}
Note: See TracChangeset for help on using the changeset viewer.