Ignore:
File:
1 edited

Legend:

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

    rf527f58 ra5b3de6  
    4141#include <errno.h>
    4242#include <usb_iface.h>
     43#include <str_error.h>
    4344
    4445#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  */
    51 static 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  */
    65 static 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  *    */
    78 static 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 }
    8546
    8647
     
    9354 * @param bw_count Bandwidth compute function, passed to endpoint manager.
    9455 */
    95 void hcd_init(hcd_t *hcd, usb_speed_t max_speed, size_t bandwidth,
    96     bw_count_func_t bw_count)
    97 {
     56void hcd_init(hcd_t *hcd) {
    9857        assert(hcd);
    99         usb_bus_init(&hcd->bus, bandwidth, bw_count, max_speed);
    10058
    101         hcd_set_implementation(hcd, NULL, NULL);
     59        hcd_set_implementation(hcd, NULL, NULL, NULL);
    10260}
    10361
     
    10664        assert(hcd);
    10765        usb_address_t address = 0;
    108         const int ret = usb_bus_request_address(
    109             &hcd->bus, &address, false, speed);
     66        const int ret = bus_request_address(hcd->bus, &address, false, speed);
    11067        if (ret != EOK)
    11168                return ret;
     
    11370}
    11471
    115 int 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 
    122 int 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 
    129 int 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 
    139 int 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 
    147 typedef 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 
    154 static 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 
    16872/** Prepare generic usb_transfer_batch and schedule it.
    16973 * @param hcd Host controller driver.
    170  * @param fun DDF fun
    17174 * @param target address and endpoint number.
    17275 * @param setup_data Data to use in setup stage (Control communication type)
     
    17780 * @return Error code.
    17881 */
    179 int 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)
     82int 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)
    18485{
    18586        assert(hcd);
     87        assert(device->address == target.address);
    18688
    187         endpoint_t *ep = usb_bus_find_ep(&hcd->bus,
    188             target.address, target.endpoint, direction);
    189         if (ep == NULL) {
    190                 usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
    191                     target.address, target.endpoint, name);
    192                 return ENOENT;
    193         }
    194 
    195         usb_log_debug2("%s %d:%d %zu(%zu).\n",
    196             name, target.address, target.endpoint, size, ep->max_packet_size);
    197 
    198         const size_t bw = bandwidth_count_usb11(
    199             ep->speed, ep->transfer_type, size, ep->max_packet_size);
    200         /* Check if we have enough bandwidth reserved */
    201         if (ep->bandwidth < bw) {
    202                 usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
    203                     "but only %zu is reserved.\n",
    204                     ep->address, ep->endpoint, name, bw, ep->bandwidth);
    205                 return ENOSPC;
    206         }
    20789        if (!hcd->ops.schedule) {
    20890                usb_log_error("HCD does not implement scheduler.\n");
     
    21092        }
    21193
    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                 }
     94        endpoint_t *ep = bus_find_endpoint(hcd->bus, device, target, direction);
     95        if (ep == NULL) {
     96                usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
     97                    device->address, target.endpoint, name);
     98                return ENOENT;
    23099        }
    231100
    232         usb_transfer_batch_t *batch = usb_transfer_batch_create(
    233             ep, data, size, setup_data, in, out, arg);
     101        // TODO cut here aka provide helper to call with instance of endpoint_t in hand
     102
     103        usb_log_debug2("%s %d:%d %zu(%zu).\n",
     104            name, target.address, target.endpoint, size, ep->max_packet_size);
     105
     106        const size_t bw = bus_count_bw(ep, size);
     107        /* Check if we have enough bandwidth reserved */
     108        if (ep->bandwidth < bw) {
     109                usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
     110                    "but only %zu is reserved.\n",
     111                    device->address, ep->endpoint, name, bw, ep->bandwidth);
     112                return ENOSPC;
     113        }
     114
     115        usb_transfer_batch_t *batch = usb_transfer_batch_create(ep);
    234116        if (!batch) {
    235117                usb_log_error("Failed to create transfer batch.\n");
     
    237119        }
    238120
     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
    239134        const int ret = hcd->ops.schedule(hcd, batch);
    240         if (ret != EOK)
     135        if (ret != EOK) {
     136                usb_log_warning("Batch %p failed to schedule: %s", batch, str_error(ret));
    241137                usb_transfer_batch_destroy(batch);
     138        }
    242139
    243140        /* Drop our own reference to ep. */
     
    248145
    249146typedef struct {
    250         volatile unsigned done;
    251         int ret;
    252         size_t size;
     147        fibril_mutex_t done_mtx;
     148        fibril_condvar_t done_cv;
     149        unsigned done;
     150
     151        size_t transfered_size;
     152        int error;
    253153} sync_data_t;
    254154
    255 static void transfer_in_cb(int ret, size_t size, void* data)
     155static int sync_transfer_complete(usb_transfer_batch_t *batch)
    256156{
    257         sync_data_t *d = data;
     157        sync_data_t *d = batch->on_complete_data;
    258158        assert(d);
    259         d->ret = ret;
     159        d->transfered_size = batch->transfered_size;
     160        d->error = batch->error;
     161        fibril_mutex_lock(&d->done_mtx);
    260162        d->done = 1;
    261         d->size = size;
     163        fibril_condvar_broadcast(&d->done_cv);
     164        fibril_mutex_unlock(&d->done_mtx);
     165        return EOK;
    262166}
    263167
    264 static 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 */
    273 ssize_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)
     168ssize_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)
    276171{
    277172        assert(hcd);
    278         sync_data_t sd = { .done = 0, .ret = EBUSY, .size = size };
     173        sync_data_t sd = { .done = 0 };
     174        fibril_mutex_initialize(&sd.done_mtx);
     175        fibril_condvar_initialize(&sd.done_cv);
    279176
    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);
     177        const int ret = hcd_send_batch(hcd, device, target, direction,
     178            data, size, setup_data,
     179            sync_transfer_complete, &sd, name);
    283180        if (ret != EOK)
    284181                return ret;
    285182
    286         while (!sd.done) {
    287                 async_usleep(1000);
    288         }
     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);
    289187
    290         if (sd.ret == EOK)
    291                 return sd.size;
    292         return sd.ret;
     188        return (sd.error == EOK)
     189                ? (ssize_t) sd.transfered_size
     190                : (ssize_t) sd.error;
    293191}
    294192
Note: See TracChangeset for help on using the changeset viewer.