Changeset ca07cd3 in mainline for uspace/lib/usbvirt/main.c


Ignore:
Timestamp:
2010-10-25T13:23:33Z (14 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
23cb44b
Parents:
355f7c2
Message:

Code cleanup, various bugfixes

The internal functions of virtual device framework always get
device structure as parameter, thus possible enabling more devices
within single task (that is not possible because currently there
is no way to pass extra argument into callback_connection()).

Also, added some missing comments and completely removed the device
id nonsense (devices can send their descriptors and the hub is able
to enable/disable its ports).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usbvirt/main.c

    r355f7c2 rca07cd3  
    3131 */
    3232/** @file
    33  * @brief Main handler for virtual USB device.
     33 * @brief Device registration with virtual USB framework.
    3434 */
    3535#include <devmap.h>
     
    3939#include <stdlib.h>
    4040#include <mem.h>
     41#include <assert.h>
    4142
    4243#include "hub.h"
     
    4647#define NAMESPACE "usb"
    4748
    48 usbvirt_device_t *device = NULL;
    49 
    50 static void handle_setup_transaction(ipc_callid_t iid, ipc_call_t icall)
    51 {
    52         usb_address_t address = IPC_GET_ARG1(icall);
    53         usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
    54         size_t expected_len = IPC_GET_ARG3(icall);
    55        
    56         if (address != device->address) {
    57                 ipc_answer_0(iid, EADDRNOTAVAIL);
    58                 return;
    59         }
    60        
    61         if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
    62                 ipc_answer_0(iid, EINVAL);
    63                 return;
    64         }
    65        
    66         if (expected_len == 0) {
    67                 ipc_answer_0(iid, EINVAL);
    68                 return;
    69         }
    70        
    71         size_t len = 0;
    72         void * buffer = NULL;
    73         int rc = async_data_write_accept(&buffer, false,
    74             1, USB_MAX_PAYLOAD_SIZE, 0, &len);
    75                
    76         if (rc != EOK) {
    77                 ipc_answer_0(iid, rc);
    78                 return;
    79         }
    80        
    81         rc = device->transaction_setup(device, endpoint, buffer, len);
    82        
    83         ipc_answer_0(iid, rc);
    84 }
    85 
    86 
    87 static void handle_out_transaction(ipc_callid_t iid, ipc_call_t icall)
    88 {
    89         usb_address_t address = IPC_GET_ARG1(icall);
    90         usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
    91         size_t expected_len = IPC_GET_ARG3(icall);
    92        
    93         if (address != device->address) {
    94                 ipc_answer_0(iid, EADDRNOTAVAIL);
    95                 return;
    96         }
    97        
    98         if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
    99                 ipc_answer_0(iid, EINVAL);
    100                 return;
    101         }
    102        
    103         int rc = EOK;
    104        
    105         size_t len = 0;
    106         void *buffer = NULL;
    107        
    108         if (expected_len > 0) {
    109                 rc = async_data_write_accept(&buffer, false,
    110                     1, USB_MAX_PAYLOAD_SIZE, 0, &len);
    111                        
    112                 if (rc != EOK) {
    113                         ipc_answer_0(iid, rc);
    114                         return;
     49/** Virtual device wrapper. */
     50typedef struct {
     51        /** Actual device. */
     52        usbvirt_device_t *device;
     53        /** Phone to host controller. */
     54        int vhcd_phone;
     55        /** Device id. */
     56        ipcarg_t id;
     57        /** Linked-list member. */
     58        link_t link;
     59} virtual_device_t;
     60
     61/*** List of known device. */
     62static LIST_INITIALIZE(device_list);
     63
     64/** Find virtual device wrapper based on the contents. */
     65static virtual_device_t *find_device(usbvirt_device_t *device)
     66{
     67        if (list_empty(&device_list)) {
     68                return NULL;
     69        }
     70       
     71        link_t *pos;
     72        for (pos = device_list.next; pos != &device_list; pos = pos->next) {
     73                virtual_device_t *dev
     74                    = list_get_instance(pos, virtual_device_t, link);
     75                if (dev->device == device) {
     76                        return dev;
    11577                }
    11678        }
    11779       
    118         rc = device->transaction_out(device, endpoint, buffer, len);
    119        
    120         if (buffer != NULL) {
    121                 free(buffer);
    122         }
    123        
    124         ipc_answer_0(iid, rc);
    125 }
    126 
    127 
    128 
    129 static void handle_in_transaction(ipc_callid_t iid, ipc_call_t icall)
    130 {
    131         usb_address_t address = IPC_GET_ARG1(icall);
    132         usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
    133         size_t expected_len = IPC_GET_ARG3(icall);
    134        
    135         if (address != device->address) {
    136                 ipc_answer_0(iid, EADDRNOTAVAIL);
    137                 return;
    138         }
    139        
    140         if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
    141                 ipc_answer_0(iid, EINVAL);
    142                 return;
    143         }
    144        
    145         int rc = EOK;
    146        
    147         void *buffer = expected_len > 0 ? malloc(expected_len) : NULL;
    148         size_t len;
    149        
    150         rc = device->transaction_in(device, endpoint, buffer, expected_len, &len);
    151         /*
    152          * If the request was processed, we will send data back.
    153          */
    154         if (rc == EOK) {
    155                 size_t receive_len;
    156                 if (!async_data_read_receive(&iid, &receive_len)) {
    157                         ipc_answer_0(iid, EINVAL);
    158                         return;
     80        return NULL;
     81}
     82
     83/** Find virtual device wrapper by its id. */
     84static virtual_device_t *find_device_by_id(ipcarg_t id)
     85{
     86        if (list_empty(&device_list)) {
     87                return NULL;
     88        }
     89       
     90        link_t *pos;
     91        for (pos = device_list.next; pos != &device_list; pos = pos->next) {
     92                virtual_device_t *dev
     93                    = list_get_instance(pos, virtual_device_t, link);
     94                if (dev->id == id) {
     95                        return dev;
    15996                }
    160                 async_data_read_finalize(iid, buffer, receive_len);
    161         }
    162        
    163         ipc_answer_0(iid, rc);
    164 }
    165 
    166 
    167 
    168 static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
    169 {
    170         ipc_answer_0(iid, EOK);
    171        
    172         while (true) {
    173                 ipc_callid_t callid;
    174                 ipc_call_t call;
    175                
    176                 callid = async_get_call(&call);
    177                 switch (IPC_GET_METHOD(call)) {
    178                         case IPC_M_PHONE_HUNGUP:
    179                                 ipc_answer_0(callid, EOK);
    180                                 return;
    181                        
    182                         case IPC_M_USBVIRT_TRANSACTION_SETUP:
    183                                 handle_setup_transaction(callid, call);
    184                                 break;
    185                        
    186                         case IPC_M_USBVIRT_TRANSACTION_OUT:
    187                                 handle_out_transaction(callid, call);
    188                                 break;
    189                                
    190                         case IPC_M_USBVIRT_TRANSACTION_IN:
    191                                 handle_in_transaction(callid, call);
    192                                 break;
    193                        
    194                         default:
    195                                 ipc_answer_0(callid, EINVAL);
    196                                 break;
    197                 }
    198         }
    199 }
    200 
    201 static int control_transfer_reply(struct usbvirt_device *device,
     97        }
     98       
     99        return NULL;
     100}
     101
     102/** Reply to a control transfer. */
     103static int control_transfer_reply(usbvirt_device_t *device,
    202104            usb_endpoint_t endpoint, void *buffer, size_t size)
    203105{
     
    213115}
    214116
     117/** Initialize virtual device. */
    215118static void device_init(usbvirt_device_t *dev)
    216119{
     
    223126        dev->state = USBVIRT_STATE_DEFAULT;
    224127        dev->address = 0;
     128        dev->new_address = -1;
    225129       
    226130        size_t i;
     
    235139}
    236140
     141/** Add a virtual device.
     142 * The returned device (if not NULL) shall be destroy via destroy_device().
     143 */
     144static virtual_device_t *add_device(usbvirt_device_t *dev)
     145{
     146        assert(find_device(dev) == NULL);
     147        virtual_device_t *new_device
     148            = (virtual_device_t *) malloc(sizeof(virtual_device_t));
     149       
     150        new_device->device = dev;
     151        link_initialize(&new_device->link);
     152       
     153        list_append(&new_device->link, &device_list);
     154       
     155        return new_device;
     156}
     157
     158/** Destroy virtual device. */
     159static void destroy_device(virtual_device_t *dev)
     160{
     161        if (dev->vhcd_phone > 0) {
     162                ipc_hangup(dev->vhcd_phone);
     163        }
     164       
     165        list_remove(&dev->link);
     166       
     167        free(dev);
     168}
     169
     170/** Callback connection handler. */
     171static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
     172{
     173        // FIXME - determine which device just called back
     174        virtual_device_t *dev = find_device_by_id(0);
     175        if (dev == NULL) {
     176                ipc_answer_0(iid, EINVAL);
     177                printf("Ooops\n");
     178                return;
     179        }
     180       
     181        device_callback_connection(dev->device, iid, icall);
     182}
     183
    237184/** Create necessary phones for comunication with virtual HCD.
    238185 * This function wraps following calls:
     
    254201int usbvirt_connect(usbvirt_device_t *dev, const char *hcd_path)
    255202{
     203        virtual_device_t *virtual_device = find_device(dev);
     204        if (virtual_device != NULL) {
     205                return EEXISTS;
     206        }
     207       
    256208        char dev_path[DEVMAP_NAME_MAXLEN + 1];
    257209        snprintf(dev_path, DEVMAP_NAME_MAXLEN,
     
    270222       
    271223        ipcarg_t phonehash;
    272         int rc = ipc_connect_to_me(hcd_phone, 1, dev->device_id_, 0, &phonehash);
     224        int rc = ipc_connect_to_me(hcd_phone, 1, 0, 0, &phonehash);
    273225        if (rc != EOK) {
    274226                return rc;
    275227        }
    276228       
    277         dev->vhcd_phone_ = hcd_phone;
    278229        device_init(dev);
    279230       
    280         device = dev;
     231        virtual_device = add_device(dev);
     232        virtual_device->vhcd_phone = hcd_phone;
     233        virtual_device->id = 0;
    281234       
    282235        async_new_connection(phonehash, 0, NULL, callback_connection);
     
    290243 *
    291244 * @param dev Device to connect.
    292  * @return Always EOK.
     245 * @return Error code.
     246 * @retval EOK Device connected.
     247 * @retval EEXISTS This device is already connected.
    293248 */
    294249int usbvirt_connect_local(usbvirt_device_t *dev)
    295250{
    296         dev->vhcd_phone_ = -1;
     251        virtual_device_t *virtual_device = find_device(dev);
     252        if (virtual_device != NULL) {
     253                return EEXISTS;
     254        }
     255       
    297256        device_init(dev);
    298257       
    299         device = dev;
     258        virtual_device = add_device(dev);
     259        virtual_device->vhcd_phone = -1;
     260        virtual_device->id = 0;
    300261       
    301262        return EOK;
     
    304265/** Disconnects device from HCD.
    305266 *
    306  * @return Always EOK.
    307  */
    308 int usbvirt_disconnect(void)
    309 {
    310         ipc_hangup(device->vhcd_phone_);
    311        
    312         device = NULL;
     267 * @param dev Device to be disconnected.
     268 * @return Error code.
     269 * @retval EOK Device connected.
     270 * @retval ENOENT This device is not connected.
     271 */
     272int usbvirt_disconnect(usbvirt_device_t *dev)
     273{
     274        virtual_device_t *virtual_device = find_device(dev);
     275        if (virtual_device == NULL) {
     276                return ENOENT;
     277        }
     278       
     279        destroy_device(virtual_device);
    313280       
    314281        return EOK;
Note: See TracChangeset for help on using the changeset viewer.