Ignore:
File:
1 edited

Legend:

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

    r1d758fc rb7fd2a0  
    3131 */
    3232/** @file
    33  * Helpers to work with the DDF interface.
    34  */
     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>
    3541
    3642#include <adt/list.h>
     
    4147#include <device/hw_res_parsed.h>
    4248#include <errno.h>
     49#include <fibril_synch.h>
     50#include <macros.h>
     51#include <stdio.h>
     52#include <stdlib.h>
    4353#include <str_error.h>
    44 #include <usb/classes/classes.h>
    45 #include <usb/debug.h>
    46 #include <usb/descriptor.h>
    47 #include <usb/usb.h>
    48 #include <usb/dma_buffer.h>
    4954#include <usb_iface.h>
    50 #include <usbhc_iface.h>
    51 
    52 #include "bus.h"
    53 #include "endpoint.h"
    5455
    5556#include "ddf_helpers.h"
    5657
    57 /**
    58  * DDF usbhc_iface callback. Passes the endpoint descriptors, fills the pipe
    59  * descriptor according to the contents of the endpoint.
    60  *
    61  * @param[in] fun DDF function of the device in question.
    62  * @param[out] pipe_desc The pipe descriptor to be filled.
    63  * @param[in] endpoint_desc Endpoint descriptors from the device.
     58#define CTRL_PIPE_MIN_PACKET_SIZE 8
     59
     60typedef 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
     71typedef struct hc_dev {
     72        ddf_fun_t *ctl_fun;
     73        hcd_t hcd;
     74        usb_dev_t *root_hub;
     75} hc_dev_t;
     76
     77static hc_dev_t *dev_to_hc_dev(ddf_dev_t *dev)
     78{
     79        return ddf_dev_data_get(dev);
     80}
     81
     82hcd_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
     93static errno_t hcd_ddf_new_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port);
     94static 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.
    64107 * @return Error code.
    65108 */
    66 static errno_t register_endpoint(ddf_fun_t *fun, usb_pipe_desc_t *pipe_desc,
    67      const usb_endpoint_descriptors_t *ep_desc)
     109static 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)
    68113{
    69114        assert(fun);
    70         hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    71         device_t *dev = ddf_fun_data_get(fun);
     115        hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
     116        usb_dev_t *dev = ddf_fun_data_get(fun);
    72117        assert(hcd);
    73         assert(hcd->bus);
    74118        assert(dev);
    75 
    76         endpoint_t *ep;
    77         const int err = bus_endpoint_add(dev, ep_desc, &ep);
    78         if (err)
    79                 return err;
    80 
    81         if (pipe_desc) {
    82                 pipe_desc->endpoint_no = ep->endpoint;
    83                 pipe_desc->direction = ep->direction;
    84                 pipe_desc->transfer_type = ep->transfer_type;
    85                 pipe_desc->max_transfer_size = ep->max_transfer_size;
    86                 pipe_desc->transfer_buffer_policy = ep->transfer_buffer_policy;
    87         }
    88         endpoint_del_ref(ep);
    89 
     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.
     136 * @return Error code.
     137 */
     138static 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);
     145        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
     153static 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
     166static 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
     178static 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
     190static 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 */
     208static 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);
    90213        return EOK;
    91214}
    92215
    93  /**
    94   * DDF usbhc_iface callback. Unregister endpoint that makes the other end of
    95   * the pipe described.
    96   *
    97   * @param fun DDF function of the device in question.
    98   * @param pipe_desc Pipe description.
    99   * @return Error code.
    100   */
    101 static errno_t unregister_endpoint(ddf_fun_t *fun, const usb_pipe_desc_t *pipe_desc)
    102 {
    103         assert(fun);
    104         hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    105         device_t *dev = ddf_fun_data_get(fun);
    106         assert(hcd);
    107         assert(hcd->bus);
    108         assert(dev);
    109 
    110         endpoint_t *ep = bus_find_endpoint(dev, pipe_desc->endpoint_no, pipe_desc->direction);
    111         if (!ep)
    112                 return ENOENT;
    113 
    114         const errno_t err = bus_endpoint_remove(ep);
    115 
    116         endpoint_del_ref(ep);
    117         return err;
    118 }
    119 
    120 /**
    121  * DDF usbhc_iface callback. Calls the respective bus operation directly.
    122  *
    123  * @param fun DDF function of the device (hub) requesting the address.
    124  */
    125 static errno_t default_address_reservation(ddf_fun_t *fun, bool reserve)
    126 {
    127         assert(fun);
    128         hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    129         device_t *dev = ddf_fun_data_get(fun);
    130         assert(hcd);
    131         assert(hcd->bus);
    132         assert(dev);
    133 
    134         usb_log_debug("Device %d %s default address", dev->address, reserve ? "requested" : "releasing");
    135         if (reserve) {
    136                 return bus_reserve_default_address(hcd->bus, dev);
    137         } else {
    138                 bus_release_default_address(hcd->bus, dev);
    139                 return EOK;
    140         }
    141 }
    142 
    143 /**
    144  * DDF usbhc_iface callback. Calls the bus operation directly.
    145  *
    146  * @param fun DDF function of the device (hub) requesting the address.
    147  * @param speed USB speed of the new device
    148  */
    149 static errno_t device_enumerate(ddf_fun_t *fun, unsigned port, usb_speed_t speed)
    150 {
    151         assert(fun);
    152         ddf_dev_t *hc = ddf_fun_get_dev(fun);
    153         assert(hc);
    154         hc_device_t *hcd = dev_to_hcd(hc);
    155         assert(hcd);
    156         device_t *hub = ddf_fun_data_get(fun);
    157         assert(hub);
    158 
    159         errno_t err;
    160 
    161         if (!usb_speed_is_valid(speed))
    162                 return EINVAL;
    163 
    164         usb_log_debug("Hub %d reported a new %s speed device on port: %u",
    165             hub->address, usb_str_speed(speed), port);
    166 
    167         device_t *dev = hcd_ddf_fun_create(hcd, speed);
    168         if (!dev) {
    169                 usb_log_error("Failed to create USB device function.");
    170                 return ENOMEM;
    171         }
    172 
    173         dev->hub = hub;
    174         dev->tier = hub->tier + 1;
    175         dev->port = port;
    176         dev->speed = speed;
    177 
    178         if ((err = bus_device_enumerate(dev))) {
    179                 usb_log_error("Failed to initialize USB dev memory structures.");
    180                 goto err_usb_dev;
    181         }
    182 
    183         /* If the driver didn't name the dev when enumerating,
    184          * do it in some generic way.
    185          */
    186         if (!ddf_fun_get_name(dev->fun)) {
    187                 bus_device_set_default_name(dev);
    188         }
    189 
    190         if ((err = ddf_fun_bind(dev->fun))) {
    191                 usb_log_error("Device(%d): Failed to register: %s.", dev->address, str_error(err));
    192                 goto err_usb_dev;
    193         }
    194 
    195         return EOK;
    196 
    197 err_usb_dev:
    198         hcd_ddf_fun_destroy(dev);
    199         return err;
    200 }
    201 
    202 static errno_t device_remove(ddf_fun_t *fun, unsigned port)
    203 {
    204         assert(fun);
    205         device_t *hub = ddf_fun_data_get(fun);
    206         assert(hub);
    207         usb_log_debug("Hub `%s' reported removal of device on port %u",
    208             ddf_fun_get_name(fun), port);
    209 
    210         device_t *victim = NULL;
    211 
    212         fibril_mutex_lock(&hub->guard);
    213         list_foreach(hub->devices, link, device_t, it) {
    214                 if (it->port == port) {
    215                         victim = it;
    216                         break;
    217                 }
    218         }
    219         fibril_mutex_unlock(&hub->guard);
    220 
    221         if (!victim) {
    222                 usb_log_warning("Hub '%s' tried to remove non-existent"
    223                     " device.", ddf_fun_get_name(fun));
    224                 return ENOENT;
    225         }
    226 
    227         assert(victim->fun);
    228         assert(victim->port == port);
    229         assert(victim->hub == hub);
    230 
    231         bus_device_gone(victim);
    232         return EOK;
    233 }
    234 
    235 /**
    236  * Gets description of the device that is calling.
    237  *
    238  * @param[in] fun Device function.
    239  * @param[out] desc Device descriptor to be filled.
    240  * @return Error code.
    241  */
    242 static errno_t get_device_description(ddf_fun_t *fun, usb_device_desc_t *desc)
    243 {
    244         assert(fun);
    245         device_t *dev = ddf_fun_data_get(fun);
    246         assert(dev);
    247 
    248         if (!desc)
    249                 return EOK;
    250 
    251         *desc = (usb_device_desc_t) {
    252                 .address = dev->address,
    253                 .depth = dev->tier,
    254                 .speed = dev->speed,
    255                 .handle = ddf_fun_get_handle(fun),
    256                 .iface = -1,
    257         };
    258         return EOK;
    259 }
    260 
    261 /**
    262  * Transfer issuing interface function.
    263  *
     216/** Inbound communication interface function.
    264217 * @param fun DDF function.
    265218 * @param target Communication target.
    266  * @param dir Communication direction.
    267219 * @param setup_data Data to use in setup stage (control transfers).
    268220 * @param data Pointer to data buffer.
     
    272224 * @return Error code.
    273225 */
    274 static errno_t transfer(ddf_fun_t *fun,
    275     const usbhc_iface_transfer_request_t *ifreq,
    276     usbhc_iface_transfer_callback_t callback, void *arg)
     226static 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)
    277229{
    278230        assert(fun);
    279         device_t *dev = ddf_fun_data_get(fun);
    280         assert(dev);
    281 
     231        usb_dev_t *usb_dev = ddf_fun_data_get(fun);
     232        assert(usb_dev);
    282233        const usb_target_t target = {{
    283                 .address = dev->address,
    284                 .endpoint = ifreq->endpoint,
    285                 .stream = ifreq->stream,
     234            .address =  usb_dev->address,
     235            .endpoint = endpoint,
    286236        }};
    287 
    288         if (!usb_target_is_valid(&target))
    289                 return EINVAL;
    290 
    291         if (ifreq->offset > 0 && ifreq->size == 0)
    292                 return EINVAL;
    293 
    294         if (ifreq->size > 0 && !dma_buffer_is_set(&ifreq->buffer))
    295                 return EBADMEM;
    296 
    297         if (!callback && arg)
    298                 return EBADMEM;
    299 
    300         const transfer_request_t request = {
    301                 .target = target,
    302                 .dir = ifreq->dir,
    303                 .buffer = ifreq->buffer,
    304                 .offset = ifreq->offset,
    305                 .size = ifreq->size,
    306                 .setup = ifreq->setup,
    307                 .on_complete = callback,
    308                 .arg = arg,
    309                 .name = (ifreq->dir == USB_DIRECTION_IN) ? "READ" : "WRITE",
    310         };
    311 
    312         return bus_issue_transfer(dev, &request);
     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 */
     252static 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");
    313266}
    314267
    315268/** USB device interface */
    316269static usb_iface_t usb_iface = {
    317         .get_my_description = get_device_description,
    318 };
    319 
    320 /** USB host controller interface */
    321 static usbhc_iface_t usbhc_iface = {
    322         .default_address_reservation = default_address_reservation,
     270        .get_my_device_handle = get_my_device_handle,
     271
     272        .reserve_default_address = reserve_default_address,
     273        .release_default_address = release_default_address,
    323274
    324275        .device_enumerate = device_enumerate,
     
    328279        .unregister_endpoint = unregister_endpoint,
    329280
    330         .transfer = transfer,
     281        .read = dev_read,
     282        .write = dev_write,
    331283};
    332284
     
    334286static ddf_dev_ops_t usb_ops = {
    335287        .interfaces[USB_DEV_IFACE] = &usb_iface,
    336         .interfaces[USBHC_DEV_IFACE] = &usbhc_iface,
    337288};
    338289
    339290
    340291/* 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
     315static 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}
    341370
    342371#define ADD_MATCHID_OR_RETURN(list, sc, str, ...) \
     
    365394        assert(l);
    366395        assert(d);
    367 
     396       
    368397        if (d->vendor_id != 0) {
    369398                /* First, with release number. */
     
    372401                    d->vendor_id, d->product_id, (d->device_version >> 8),
    373402                    (d->device_version & 0xff));
    374 
     403       
    375404                /* Next, without release number. */
    376405                ADD_MATCHID_OR_RETURN(l, 90, "usb&vendor=%#04x&product=%#04x",
     
    386415
    387416        return EOK;
    388 }
    389 
    390 device_t *hcd_ddf_fun_create(hc_device_t *hc, usb_speed_t speed)
    391 {
    392         /* Create DDF function for the new device */
    393         ddf_fun_t *fun = ddf_fun_create(hc->ddf_dev, fun_inner, NULL);
    394         if (!fun)
    395                 return NULL;
    396 
    397         ddf_fun_set_ops(fun, &usb_ops);
    398 
    399         /* Create USB device node for the new device */
    400         device_t *dev = ddf_fun_data_alloc(fun, hc->bus->device_size);
    401         if (!dev) {
    402                 ddf_fun_destroy(fun);
    403                 return NULL;
    404         }
    405 
    406         bus_device_init(dev, hc->bus);
    407         dev->fun = fun;
    408         dev->speed = speed;
    409         return dev;
    410 }
    411 
    412 void hcd_ddf_fun_destroy(device_t *dev)
    413 {
    414         assert(dev);
    415         assert(dev->fun);
    416         ddf_fun_destroy(dev->fun);
    417 }
    418 
    419 errno_t hcd_ddf_setup_match_ids(device_t *device, usb_standard_device_descriptor_t *desc)
    420 {
    421         errno_t err;
     417
     418}
     419
     420static 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
     460static 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        }
     589
     590        /* Create match ids from the device descriptor */
    422591        match_id_list_t mids;
    423 
    424592        init_match_ids(&mids);
    425593
    426         /* Create match ids from the device descriptor */
    427         usb_log_debug("Device(%d): Creating match IDs.", device->address);
    428         if ((err = create_match_ids(&mids, desc))) {
    429                 return err;
    430         }
    431 
    432         list_foreach(mids.ids, link, const match_id_t, mid) {
    433                 ddf_fun_add_match_id(device->fun, mid->id, mid->score);
    434         }
    435 
    436         return EOK;
     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 */
     623errno_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;
    437633}
    438634
     
    447643 * This function does all the ddf work for hc driver.
    448644 */
    449 errno_t hcd_ddf_setup_hc(ddf_dev_t *device, size_t size)
     645errno_t hcd_ddf_setup_hc(ddf_dev_t *device, usb_speed_t max_speed,
     646    size_t bw, bw_count_func_t bw_count)
    450647{
    451648        assert(device);
    452649
    453         hc_device_t *instance = ddf_dev_data_alloc(device, size);
     650        hc_dev_t *instance = ddf_dev_data_alloc(device, sizeof(hc_dev_t));
    454651        if (instance == NULL) {
    455                 usb_log_error("Failed to allocate HCD ddf structure.");
     652                usb_log_error("Failed to allocate HCD ddf structure.\n");
    456653                return ENOMEM;
    457654        }
    458         instance->ddf_dev = device;
     655        instance->root_hub = NULL;
     656        hcd_init(&instance->hcd, max_speed, bw, bw_count);
    459657
    460658        errno_t ret = ENOMEM;
    461659        instance->ctl_fun = ddf_fun_create(device, fun_exposed, "ctl");
    462660        if (!instance->ctl_fun) {
    463                 usb_log_error("Failed to create HCD ddf fun.");
     661                usb_log_error("Failed to create HCD ddf fun.\n");
    464662                goto err_destroy_fun;
    465663        }
     
    467665        ret = ddf_fun_bind(instance->ctl_fun);
    468666        if (ret != EOK) {
    469                 usb_log_error("Failed to bind ctl_fun: %s.", str_error(ret));
     667                usb_log_error("Failed to bind ctl_fun: %s.\n", str_error(ret));
    470668                goto err_destroy_fun;
    471669        }
     
    473671        ret = ddf_fun_add_to_category(instance->ctl_fun, USB_HC_CATEGORY);
    474672        if (ret != EOK) {
    475                 usb_log_error("Failed to add fun to category: %s.",
     673                usb_log_error("Failed to add fun to category: %s.\n",
    476674                    str_error(ret));
    477675                ddf_fun_unbind(instance->ctl_fun);
     
    488686}
    489687
    490 void hcd_ddf_clean_hc(hc_device_t *hcd)
    491 {
    492         if (ddf_fun_unbind(hcd->ctl_fun) == EOK)
    493                 ddf_fun_destroy(hcd->ctl_fun);
    494 }
    495 
     688void 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
    496699/** Call the parent driver with a request to enable interrupt
    497700 *
     
    500703 * @return Error code.
    501704 */
    502 errno_t hcd_ddf_enable_interrupt(hc_device_t *hcd, int inum)
    503 {
    504         async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev);
     705errno_t hcd_ddf_enable_interrupt(ddf_dev_t *device, int inum)
     706{
     707        async_sess_t *parent_sess = ddf_dev_parent_sess_get(device);
    505708        if (parent_sess == NULL)
    506709                return EIO;
     
    509712}
    510713
    511 errno_t hcd_ddf_get_registers(hc_device_t *hcd, hw_res_list_parsed_t *hw_res)
    512 {
    513         async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev);
     714//TODO: Cache parent session in HCD
     715errno_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);
    514718        if (parent_sess == NULL)
    515719                return EIO;
     
    522726}
    523727
     728// TODO: move this someplace else
     729static 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 */
     753errno_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 */
     799void 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
     811static 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 */
     849errno_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));
     934irq_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}
    524945/**
    525946 * @}
Note: See TracChangeset for help on using the changeset viewer.