Ignore:
File:
1 edited

Legend:

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

    ra5b3de6 rf527f58  
    4141#include <errno.h>
    4242#include <usb_iface.h>
    43 #include <str_error.h>
    4443
    4544#include "hcd.h"
     45
     46/** Calls ep_add_hook upon endpoint registration.
     47 * @param ep Endpoint to be registered.
     48 * @param arg hcd_t in disguise.
     49 * @return Error code.
     50 */
     51static int register_helper(endpoint_t *ep, void *arg)
     52{
     53        hcd_t *hcd = arg;
     54        assert(ep);
     55        assert(hcd);
     56        if (hcd->ops.ep_add_hook)
     57                return hcd->ops.ep_add_hook(hcd, ep);
     58        return EOK;
     59}
     60
     61/** Calls ep_remove_hook upon endpoint removal.
     62 * @param ep Endpoint to be unregistered.
     63 * @param arg hcd_t in disguise.
     64 */
     65static void unregister_helper(endpoint_t *ep, void *arg)
     66{
     67        hcd_t *hcd = arg;
     68        assert(ep);
     69        assert(hcd);
     70        if (hcd->ops.ep_remove_hook)
     71                hcd->ops.ep_remove_hook(hcd, ep);
     72}
     73
     74/** Calls ep_remove_hook upon endpoint removal. Prints warning.
     75 *  * @param ep Endpoint to be unregistered.
     76 *   * @param arg hcd_t in disguise.
     77 *    */
     78static void unregister_helper_warn(endpoint_t *ep, void *arg)
     79{
     80        assert(ep);
     81        usb_log_warning("Endpoint %d:%d %s was left behind, removing.\n",
     82            ep->address, ep->endpoint, usb_str_direction(ep->direction));
     83        unregister_helper(ep, arg);
     84}
    4685
    4786
     
    5493 * @param bw_count Bandwidth compute function, passed to endpoint manager.
    5594 */
    56 void hcd_init(hcd_t *hcd) {
    57         assert(hcd);
    58 
    59         hcd_set_implementation(hcd, NULL, NULL, NULL);
     95void hcd_init(hcd_t *hcd, usb_speed_t max_speed, size_t bandwidth,
     96    bw_count_func_t bw_count)
     97{
     98        assert(hcd);
     99        usb_bus_init(&hcd->bus, bandwidth, bw_count, max_speed);
     100
     101        hcd_set_implementation(hcd, NULL, NULL);
    60102}
    61103
     
    64106        assert(hcd);
    65107        usb_address_t address = 0;
    66         const int ret = bus_request_address(hcd->bus, &address, false, speed);
     108        const int ret = usb_bus_request_address(
     109            &hcd->bus, &address, false, speed);
    67110        if (ret != EOK)
    68111                return ret;
     
    70113}
    71114
     115int hcd_release_address(hcd_t *hcd, usb_address_t address)
     116{
     117        assert(hcd);
     118        return usb_bus_remove_address(&hcd->bus, address,
     119            unregister_helper_warn, hcd);
     120}
     121
     122int hcd_reserve_default_address(hcd_t *hcd, usb_speed_t speed)
     123{
     124        assert(hcd);
     125        usb_address_t address = 0;
     126        return usb_bus_request_address(&hcd->bus, &address, true, speed);
     127}
     128
     129int hcd_add_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir,
     130    usb_transfer_type_t type, size_t max_packet_size, unsigned packets,
     131    size_t size, usb_address_t tt_address, unsigned tt_port)
     132{
     133        assert(hcd);
     134        return usb_bus_add_ep(&hcd->bus, target.address,
     135            target.endpoint, dir, type, max_packet_size, packets, size,
     136            register_helper, hcd, tt_address, tt_port);
     137}
     138
     139int hcd_remove_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir)
     140{
     141        assert(hcd);
     142        return usb_bus_remove_ep(&hcd->bus, target.address,
     143            target.endpoint, dir, unregister_helper, hcd);
     144}
     145
     146
     147typedef struct {
     148        void *original_data;
     149        usbhc_iface_transfer_out_callback_t original_callback;
     150        usb_target_t target;
     151        hcd_t *hcd;
     152} toggle_t;
     153
     154static void toggle_reset_callback(int retval, void *arg)
     155{
     156        assert(arg);
     157        toggle_t *toggle = arg;
     158        if (retval == EOK) {
     159                usb_log_debug2("Reseting toggle on %d:%d.\n",
     160                    toggle->target.address, toggle->target.endpoint);
     161                usb_bus_reset_toggle(&toggle->hcd->bus,
     162                    toggle->target, toggle->target.endpoint == 0);
     163        }
     164
     165        toggle->original_callback(retval, toggle->original_data);
     166}
     167
    72168/** Prepare generic usb_transfer_batch and schedule it.
    73169 * @param hcd Host controller driver.
     170 * @param fun DDF fun
    74171 * @param target address and endpoint number.
    75172 * @param setup_data Data to use in setup stage (Control communication type)
     
    80177 * @return Error code.
    81178 */
    82 int hcd_send_batch(hcd_t *hcd, device_t *device, usb_target_t target,
    83     usb_direction_t direction, char *data, size_t size, uint64_t setup_data,
    84     usb_transfer_batch_callback_t on_complete, void *arg, const char *name)
    85 {
    86         assert(hcd);
    87         assert(device->address == target.address);
    88 
    89         if (!hcd->ops.schedule) {
    90                 usb_log_error("HCD does not implement scheduler.\n");
    91                 return ENOTSUP;
    92         }
    93 
    94         endpoint_t *ep = bus_find_endpoint(hcd->bus, device, target, direction);
     179int hcd_send_batch(
     180    hcd_t *hcd, usb_target_t target, usb_direction_t direction,
     181    void *data, size_t size, uint64_t setup_data,
     182    usbhc_iface_transfer_in_callback_t in,
     183    usbhc_iface_transfer_out_callback_t out, void *arg, const char* name)
     184{
     185        assert(hcd);
     186
     187        endpoint_t *ep = usb_bus_find_ep(&hcd->bus,
     188            target.address, target.endpoint, direction);
    95189        if (ep == NULL) {
    96190                usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
    97                     device->address, target.endpoint, name);
     191                    target.address, target.endpoint, name);
    98192                return ENOENT;
    99193        }
    100 
    101         // TODO cut here aka provide helper to call with instance of endpoint_t in hand
    102194
    103195        usb_log_debug2("%s %d:%d %zu(%zu).\n",
    104196            name, target.address, target.endpoint, size, ep->max_packet_size);
    105197
    106         const size_t bw = bus_count_bw(ep, size);
     198        const size_t bw = bandwidth_count_usb11(
     199            ep->speed, ep->transfer_type, size, ep->max_packet_size);
    107200        /* Check if we have enough bandwidth reserved */
    108201        if (ep->bandwidth < bw) {
    109202                usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
    110203                    "but only %zu is reserved.\n",
    111                     device->address, ep->endpoint, name, bw, ep->bandwidth);
     204                    ep->address, ep->endpoint, name, bw, ep->bandwidth);
    112205                return ENOSPC;
    113206        }
    114 
    115         usb_transfer_batch_t *batch = usb_transfer_batch_create(ep);
     207        if (!hcd->ops.schedule) {
     208                usb_log_error("HCD does not implement scheduler.\n");
     209                return ENOTSUP;
     210        }
     211
     212        /* Check for commands that reset toggle bit */
     213        if (ep->transfer_type == USB_TRANSFER_CONTROL) {
     214                const int reset_toggle = usb_request_needs_toggle_reset(
     215                    (usb_device_request_setup_packet_t *) &setup_data);
     216                if (reset_toggle >= 0) {
     217                        assert(out);
     218                        toggle_t *toggle = malloc(sizeof(toggle_t));
     219                        if (!toggle)
     220                                return ENOMEM;
     221                        toggle->target.address = target.address;
     222                        toggle->target.endpoint = reset_toggle;
     223                        toggle->original_callback = out;
     224                        toggle->original_data = arg;
     225                        toggle->hcd = hcd;
     226
     227                        arg = toggle;
     228                        out = toggle_reset_callback;
     229                }
     230        }
     231
     232        usb_transfer_batch_t *batch = usb_transfer_batch_create(
     233            ep, data, size, setup_data, in, out, arg);
    116234        if (!batch) {
    117235                usb_log_error("Failed to create transfer batch.\n");
     
    119237        }
    120238
    121         batch->target = target;
    122         batch->buffer = data;
    123         batch->buffer_size = size;
    124         batch->setup.packed = setup_data;
    125         batch->dir = direction;
    126         batch->on_complete = on_complete;
    127         batch->on_complete_data = arg;
    128 
    129         /* Check for commands that reset toggle bit */
    130         if (ep->transfer_type == USB_TRANSFER_CONTROL)
    131                 batch->toggle_reset_mode
    132                         = usb_request_get_toggle_reset_mode(&batch->setup.packet);
    133 
    134239        const int ret = hcd->ops.schedule(hcd, batch);
    135         if (ret != EOK) {
    136                 usb_log_warning("Batch %p failed to schedule: %s", batch, str_error(ret));
     240        if (ret != EOK)
    137241                usb_transfer_batch_destroy(batch);
    138         }
    139242
    140243        /* Drop our own reference to ep. */
     
    145248
    146249typedef struct {
    147         fibril_mutex_t done_mtx;
    148         fibril_condvar_t done_cv;
    149         unsigned done;
    150 
    151         size_t transfered_size;
    152         int error;
     250        volatile unsigned done;
     251        int ret;
     252        size_t size;
    153253} sync_data_t;
    154254
    155 static int sync_transfer_complete(usb_transfer_batch_t *batch)
    156 {
    157         sync_data_t *d = batch->on_complete_data;
     255static void transfer_in_cb(int ret, size_t size, void* data)
     256{
     257        sync_data_t *d = data;
    158258        assert(d);
    159         d->transfered_size = batch->transfered_size;
    160         d->error = batch->error;
    161         fibril_mutex_lock(&d->done_mtx);
     259        d->ret = ret;
    162260        d->done = 1;
    163         fibril_condvar_broadcast(&d->done_cv);
    164         fibril_mutex_unlock(&d->done_mtx);
    165         return EOK;
    166 }
    167 
    168 ssize_t hcd_send_batch_sync(hcd_t *hcd, device_t *device, usb_target_t target,
    169     usb_direction_t direction, char *data, size_t size, uint64_t setup_data,
    170     const char *name)
    171 {
    172         assert(hcd);
    173         sync_data_t sd = { .done = 0 };
    174         fibril_mutex_initialize(&sd.done_mtx);
    175         fibril_condvar_initialize(&sd.done_cv);
    176 
    177         const int ret = hcd_send_batch(hcd, device, target, direction,
    178             data, size, setup_data,
    179             sync_transfer_complete, &sd, name);
     261        d->size = size;
     262}
     263
     264static void transfer_out_cb(int ret, void* data)
     265{
     266        sync_data_t *d = data;
     267        assert(data);
     268        d->ret = ret;
     269        d->done = 1;
     270}
     271
     272/** this is really ugly version of sync usb communication */
     273ssize_t hcd_send_batch_sync(
     274    hcd_t *hcd, usb_target_t target, usb_direction_t dir,
     275    void *data, size_t size, uint64_t setup_data, const char* name)
     276{
     277        assert(hcd);
     278        sync_data_t sd = { .done = 0, .ret = EBUSY, .size = size };
     279
     280        const int ret = hcd_send_batch(hcd, target, dir, data, size, setup_data,
     281            dir == USB_DIRECTION_IN ? transfer_in_cb : NULL,
     282            dir == USB_DIRECTION_OUT ? transfer_out_cb : NULL, &sd, name);
    180283        if (ret != EOK)
    181284                return ret;
    182285
    183         fibril_mutex_lock(&sd.done_mtx);
    184         while (!sd.done)
    185                 fibril_condvar_wait(&sd.done_cv, &sd.done_mtx);
    186         fibril_mutex_unlock(&sd.done_mtx);
    187 
    188         return (sd.error == EOK)
    189                 ? (ssize_t) sd.transfered_size
    190                 : (ssize_t) sd.error;
     286        while (!sd.done) {
     287                async_usleep(1000);
     288        }
     289
     290        if (sd.ret == EOK)
     291                return sd.size;
     292        return sd.ret;
    191293}
    192294
Note: See TracChangeset for help on using the changeset viewer.