Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/vhc/transfer.c

    rfeeac0d rf5f0cfb  
    2929#include <errno.h>
    3030#include <str_error.h>
     31#include <usb/debug.h>
    3132#include <usbvirt/device.h>
    3233#include <usbvirt/ipc.h>
    3334#include "vhcd.h"
    34 
    35 vhc_transfer_t *vhc_transfer_create(usb_address_t address, usb_endpoint_t ep,
    36     usb_direction_t dir, usb_transfer_type_t tr_type,
    37     ddf_fun_t *fun, void *callback_arg)
    38 {
    39         vhc_transfer_t *result = malloc(sizeof(vhc_transfer_t));
    40         if (result == NULL) {
    41                 return NULL;
    42         }
    43         link_initialize(&result->link);
    44         result->address = address;
    45         result->endpoint = ep;
    46         result->direction = dir;
    47         result->transfer_type = tr_type;
    48         result->setup_buffer = NULL;
    49         result->setup_buffer_size = 0;
    50         result->data_buffer = NULL;
    51         result->data_buffer_size = 0;
    52         result->ddf_fun = fun;
    53         result->callback_arg = callback_arg;
    54         result->callback_in = NULL;
    55         result->callback_out = NULL;
    56 
    57         usb_log_debug2("Created transfer %p (%d.%d %s %s)\n", result,
    58             address, ep, usb_str_transfer_type_short(tr_type),
    59             dir == USB_DIRECTION_IN ? "in" : "out");
    60 
    61         return result;
    62 }
     35#include "hub/virthub.h"
    6336
    6437static bool is_set_address_transfer(vhc_transfer_t *transfer)
    6538{
    66         if (transfer->endpoint != 0) {
    67                 return false;
    68         }
    69         if (transfer->transfer_type != USB_TRANSFER_CONTROL) {
    70                 return false;
    71         }
    72         if (transfer->direction != USB_DIRECTION_OUT) {
    73                 return false;
    74         }
    75         if (transfer->setup_buffer_size != sizeof(usb_device_request_setup_packet_t)) {
    76                 return false;
    77         }
    78         usb_device_request_setup_packet_t *setup = transfer->setup_buffer;
     39        if (transfer->batch->ep->endpoint != 0) {
     40                return false;
     41        }
     42        if (transfer->batch->ep->transfer_type != USB_TRANSFER_CONTROL) {
     43                return false;
     44        }
     45        if (usb_transfer_batch_direction(transfer->batch) != USB_DIRECTION_OUT) {
     46                return false;
     47        }
     48        const usb_device_request_setup_packet_t *setup =
     49            (void*)transfer->batch->setup_buffer;
    7950        if (setup->request_type != 0) {
    8051                return false;
     
    8758}
    8859
    89 int vhc_virtdev_add_transfer(vhc_data_t *vhc, vhc_transfer_t *transfer)
    90 {
    91         fibril_mutex_lock(&vhc->guard);
    92 
    93         bool target_found = false;
    94         list_foreach(vhc->devices, link, vhc_virtdev_t, dev) {
    95                 fibril_mutex_lock(&dev->guard);
    96                 if (dev->address == transfer->address) {
    97                         if (target_found) {
    98                                 usb_log_warning("Transfer would be accepted by more devices!\n");
    99                                 goto next;
    100                         }
    101                         target_found = true;
    102                         list_append(&transfer->link, &dev->transfer_queue);
    103                 }
    104 next:
    105                 fibril_mutex_unlock(&dev->guard);
    106         }
    107 
    108         fibril_mutex_unlock(&vhc->guard);
    109 
    110         if (target_found) {
    111                 return EOK;
     60static int process_transfer_local(usb_transfer_batch_t *batch,
     61    usbvirt_device_t *dev, size_t *actual_data_size)
     62{
     63        int rc;
     64       
     65        const usb_direction_t dir = usb_transfer_batch_direction(batch);
     66
     67        if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
     68                if (dir == USB_DIRECTION_IN) {
     69                        rc = usbvirt_control_read(dev,
     70                            batch->setup_buffer, batch->setup_size,
     71                            batch->buffer, batch->buffer_size,
     72                            actual_data_size);
     73                } else {
     74                        assert(dir == USB_DIRECTION_OUT);
     75                        rc = usbvirt_control_write(dev,
     76                            batch->setup_buffer, batch->setup_size,
     77                            batch->buffer, batch->buffer_size);
     78                }
    11279        } else {
    113                 return ENOENT;
    114         }
    115 }
    116 
    117 static int process_transfer_local(vhc_transfer_t *transfer,
    118     usbvirt_device_t *dev, size_t *actual_data_size)
     80                if (dir == USB_DIRECTION_IN) {
     81                        rc = usbvirt_data_in(dev, batch->ep->transfer_type,
     82                            batch->ep->endpoint,
     83                            batch->buffer, batch->buffer_size,
     84                            actual_data_size);
     85                } else {
     86                        assert(dir == USB_DIRECTION_OUT);
     87                        rc = usbvirt_data_out(dev, batch->ep->transfer_type,
     88                            batch->ep->endpoint,
     89                            batch->buffer, batch->buffer_size);
     90                }
     91        }
     92
     93        return rc;
     94}
     95
     96static int process_transfer_remote(usb_transfer_batch_t *batch,
     97    async_sess_t *sess, size_t *actual_data_size)
    11998{
    12099        int rc;
    121100
    122         if (transfer->transfer_type == USB_TRANSFER_CONTROL) {
    123                 if (transfer->direction == USB_DIRECTION_IN) {
    124                         rc = usbvirt_control_read(dev,
    125                             transfer->setup_buffer, transfer->setup_buffer_size,
    126                             transfer->data_buffer, transfer->data_buffer_size,
    127                             actual_data_size);
    128                 } else {
    129                         assert(transfer->direction == USB_DIRECTION_OUT);
    130                         rc = usbvirt_control_write(dev,
    131                             transfer->setup_buffer, transfer->setup_buffer_size,
    132                             transfer->data_buffer, transfer->data_buffer_size);
     101        const usb_direction_t dir = usb_transfer_batch_direction(batch);
     102
     103        if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
     104                if (dir == USB_DIRECTION_IN) {
     105                        rc = usbvirt_ipc_send_control_read(sess,
     106                            batch->setup_buffer, batch->setup_size,
     107                            batch->buffer, batch->buffer_size,
     108                            actual_data_size);
     109                } else {
     110                        assert(dir == USB_DIRECTION_OUT);
     111                        rc = usbvirt_ipc_send_control_write(sess,
     112                            batch->setup_buffer, batch->setup_size,
     113                            batch->buffer, batch->buffer_size);
    133114                }
    134115        } else {
    135                 if (transfer->direction == USB_DIRECTION_IN) {
    136                         rc = usbvirt_data_in(dev, transfer->transfer_type,
    137                             transfer->endpoint,
    138                             transfer->data_buffer, transfer->data_buffer_size,
    139                             actual_data_size);
    140                 } else {
    141                         assert(transfer->direction == USB_DIRECTION_OUT);
    142                         rc = usbvirt_data_out(dev, transfer->transfer_type,
    143                             transfer->endpoint,
    144                             transfer->data_buffer, transfer->data_buffer_size);
    145                 }
    146         }
    147 
    148         return rc;
    149 }
    150 
    151 static int process_transfer_remote(vhc_transfer_t *transfer,
    152     async_sess_t *sess, size_t *actual_data_size)
    153 {
    154         int rc;
    155 
    156         if (transfer->transfer_type == USB_TRANSFER_CONTROL) {
    157                 if (transfer->direction == USB_DIRECTION_IN) {
    158                         rc = usbvirt_ipc_send_control_read(sess,
    159                             transfer->setup_buffer, transfer->setup_buffer_size,
    160                             transfer->data_buffer, transfer->data_buffer_size,
    161                             actual_data_size);
    162                 } else {
    163                         assert(transfer->direction == USB_DIRECTION_OUT);
    164                         rc = usbvirt_ipc_send_control_write(sess,
    165                             transfer->setup_buffer, transfer->setup_buffer_size,
    166                             transfer->data_buffer, transfer->data_buffer_size);
    167                 }
    168         } else {
    169                 if (transfer->direction == USB_DIRECTION_IN) {
    170                         rc = usbvirt_ipc_send_data_in(sess, transfer->endpoint,
    171                             transfer->transfer_type,
    172                             transfer->data_buffer, transfer->data_buffer_size,
    173                             actual_data_size);
    174                 } else {
    175                         assert(transfer->direction == USB_DIRECTION_OUT);
    176                         rc = usbvirt_ipc_send_data_out(sess, transfer->endpoint,
    177                             transfer->transfer_type,
    178                             transfer->data_buffer, transfer->data_buffer_size);
     116                if (dir == USB_DIRECTION_IN) {
     117                        rc = usbvirt_ipc_send_data_in(sess, batch->ep->endpoint,
     118                            batch->ep->transfer_type,
     119                            batch->buffer, batch->buffer_size,
     120                            actual_data_size);
     121                } else {
     122                        assert(dir == USB_DIRECTION_OUT);
     123                        rc = usbvirt_ipc_send_data_out(sess, batch->ep->endpoint,
     124                            batch->ep->transfer_type,
     125                            batch->buffer, batch->buffer_size);
    179126                }
    180127        }
     
    195142}
    196143
    197 
    198144static void execute_transfer_callback_and_free(vhc_transfer_t *transfer,
    199145    size_t data_transfer_size, int outcome)
    200146{
    201147        assert(outcome != ENAK);
    202 
    203         usb_log_debug2("Transfer %p ended: %s.\n",
    204             transfer, str_error(outcome));
    205 
    206         if (transfer->direction == USB_DIRECTION_IN) {
    207                 transfer->callback_in(transfer->ddf_fun, outcome,
    208                     data_transfer_size, transfer->callback_arg);
    209         } else {
    210                 assert(transfer->direction == USB_DIRECTION_OUT);
    211                 transfer->callback_out(transfer->ddf_fun, outcome,
    212                     transfer->callback_arg);
    213         }
    214 
     148        assert(transfer);
     149        assert(transfer->batch);
     150        usb_transfer_batch_finish_error(transfer->batch, NULL,
     151            data_transfer_size, outcome);
     152        usb_transfer_batch_destroy(transfer->batch);
    215153        free(transfer);
     154}
     155
     156int vhc_init(vhc_data_t *instance)
     157{
     158        assert(instance);
     159        list_initialize(&instance->devices);
     160        fibril_mutex_initialize(&instance->guard);
     161        instance->magic = 0xDEADBEEF;
     162        return virthub_init(&instance->hub, "root hub");
     163}
     164
     165int vhc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
     166{
     167        assert(hcd);
     168        assert(batch);
     169        vhc_data_t *vhc = hcd->private_data;
     170        assert(vhc);
     171
     172        vhc_transfer_t *transfer = malloc(sizeof(vhc_transfer_t));
     173        if (!transfer)
     174                return ENOMEM;
     175        link_initialize(&transfer->link);
     176        transfer->batch = batch;
     177
     178        fibril_mutex_lock(&vhc->guard);
     179
     180        int targets = 0;
     181
     182        list_foreach(vhc->devices, pos) {
     183                vhc_virtdev_t *dev = list_get_instance(pos, vhc_virtdev_t, link);
     184                fibril_mutex_lock(&dev->guard);
     185                if (dev->address == transfer->batch->ep->address) {
     186                        if (!targets) {
     187                                list_append(&transfer->link, &dev->transfer_queue);
     188                        }
     189                        ++targets;
     190                }
     191                fibril_mutex_unlock(&dev->guard);
     192        }
     193
     194        fibril_mutex_unlock(&vhc->guard);
     195       
     196        if (targets > 1)
     197                usb_log_warning("Transfer would be accepted by more devices!\n");
     198
     199        return targets ? EOK : ENOENT;
    216200}
    217201
     
    234218                size_t data_transfer_size = 0;
    235219                if (dev->dev_sess) {
    236                         rc = process_transfer_remote(transfer, dev->dev_sess,
    237                             &data_transfer_size);
     220                        rc = process_transfer_remote(transfer->batch,
     221                            dev->dev_sess, &data_transfer_size);
    238222                } else if (dev->dev_local != NULL) {
    239                         rc = process_transfer_local(transfer, dev->dev_local,
    240                             &data_transfer_size);
     223                        rc = process_transfer_local(transfer->batch,
     224                            dev->dev_local, &data_transfer_size);
    241225                } else {
    242226                        usb_log_warning("Device has no remote phone nor local node.\n");
     
    251235                        if (is_set_address_transfer(transfer)) {
    252236                                usb_device_request_setup_packet_t *setup
    253                                     = transfer->setup_buffer;
     237                                    = (void*)transfer->batch->setup_buffer;
    254238                                dev->address = setup->value;
    255239                                usb_log_debug2("Address changed to %d\n",
     
    284268        return EOK;
    285269}
    286 
Note: See TracChangeset for help on using the changeset viewer.