Changeset b371844 in mainline


Ignore:
Timestamp:
2010-10-10T11:53:05Z (14 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
b8100da
Parents:
bc9a629
Message:

Virtual HCD refactoring

Splitted into more files, added more comments.

Location:
uspace/srv/hw/bus/usb/hcd/virtual
Files:
3 added
7 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/hw/bus/usb/hcd/virtual/Makefile

    rbc9a629 rb371844  
    3333
    3434SOURCES = \
     35        conndev.c \
     36        connhost.c \
    3537        devices.c \
    3638        hc.c \
  • uspace/srv/hw/bus/usb/hcd/virtual/devices.c

    rbc9a629 rb371844  
    3131 */
    3232/** @file
    33  * @brief
     33 * @brief Virtual device management (implementation).
    3434 */
    3535
     
    5353LIST_INITIALIZE(devices);
    5454
     55/** Recognise device by id.
     56 *
     57 * @param id Device id.
     58 * @param phone Callback phone.
     59 */
     60virtdev_connection_t *virtdev_recognise(int id, int phone)
     61{
     62        virtdev_connection_t * dev = NULL;
     63        switch (id) {
     64                case USB_VIRTDEV_KEYBOARD_ID:
     65                        dev = virtdev_add_device(
     66                            USB_VIRTDEV_KEYBOARD_ADDRESS, phone);
     67                        break;
     68                default:
     69                        break;
     70        }
     71       
     72        /*
     73         * We do not want to mess-up the virtdev_add_device() as
     74         * the id is needed only before device probing/detection
     75         * is implemented.
     76         *
     77         * However, that does not mean that this will happen soon.
     78         */
     79        if (dev) {
     80                dev->id = id;
     81        }
     82       
     83        return dev;
     84}
     85
     86/** Find virtual device by its USB address.
     87 *
     88 * @retval NULL No virtual device at given address.
     89 */
    5590virtdev_connection_t *virtdev_find_by_address(usb_address_t address)
    5691{
     
    67102}
    68103
     104/** Create virtual device.
     105 *
     106 * @param address USB address.
     107 * @param phone Callback phone.
     108 * @return New device.
     109 * @retval NULL Out of memory or address already occupied.
     110 */
    69111virtdev_connection_t *virtdev_add_device(usb_address_t address, int phone)
    70112{
     113        link_t *pos;
     114        list_foreach(pos, &devices) {
     115                virtdev_connection_t *dev
     116                    = list_get_instance(pos, virtdev_connection_t, link);
     117                if (dev->address == address) {
     118                        return NULL;
     119                }
     120        }
     121       
    71122        virtdev_connection_t *dev = (virtdev_connection_t *)
    72123            malloc(sizeof(virtdev_connection_t));
     
    78129}
    79130
    80  void virtdev_destroy_device(virtdev_connection_t *dev)
     131/** Destroy virtual device.
     132 */
     133void virtdev_destroy_device(virtdev_connection_t *dev)
    81134{
    82135        list_remove(&dev->link);
  • uspace/srv/hw/bus/usb/hcd/virtual/devices.h

    rbc9a629 rb371844  
    3131 */
    3232/** @file
    33  * @brief
     33 * @brief Virtual device management.
    3434 */
    3535#ifndef VHCD_DEVICES_H_
     
    3939#include <usb/hcd.h>
    4040
     41/** Connected virtual device. */
    4142typedef struct {
    4243        /** Assigned USB address. */
     
    4445        /** Phone used when sending data to device. */
    4546        int phone;
     47        /** Device id. */
     48        int id;
    4649        /** Linked-list handle. */
    4750        link_t link;
    4851} virtdev_connection_t;
    4952
     53virtdev_connection_t *virtdev_recognise(int, int);
    5054virtdev_connection_t *virtdev_find_by_address(usb_address_t);
    5155virtdev_connection_t *virtdev_add_device(usb_address_t, int);
  • uspace/srv/hw/bus/usb/hcd/virtual/hc.c

    rbc9a629 rb371844  
    6868static link_t transaction_from_device_list;
    6969
    70 
     70/** Pending transaction details. */
    7171typedef struct {
     72        /** Linked-list link. */
    7273        link_t link;
     74        /** Device address. */
    7375        usb_target_t target;
     76        /** Direction of the transaction. */
    7477        usb_direction_t direction;
     78        /** Transfer type. */
    7579        usb_transfer_type_t type;
     80        /** Transaction data buffer. */
    7681        void * buffer;
     82        /** Transaction data length. */
    7783        size_t len;
     84        /** Callback after transaction is done. */
    7885        hc_transaction_done_callback_t callback;
     86        /** Argument to the callback. */
    7987        void * callback_arg;
    8088} transaction_t;
     
    96104}
    97105
     106/** Call transaction callback.
     107 * Calling this callback informs the backend that transaction was processed.
     108 */
    98109static void process_transaction_with_outcome(transaction_t * transaction,
    99110    usb_transaction_outcome_t outcome)
     
    103114            usb_str_transaction_outcome(outcome));
    104115       
    105         dprintf("  callback %p (%p, %u, %d, %p)", transaction->callback,
    106             transaction->buffer, transaction->len, outcome,
    107             transaction->callback_arg);
    108        
    109116        transaction->callback(transaction->buffer, transaction->len, outcome,
    110117            transaction->callback_arg);
    111         dprintf("callback processed");
    112 }
    113 
    114 #if 0
    115 static void process_transaction(transaction_t * transaction)
    116 {
    117         static unsigned int seed = 4089;
    118        
    119         unsigned int roulette = pseudo_random(&seed);
    120         usb_transaction_outcome_t outcome = USB_OUTCOME_OK;
    121        
    122         PROB_TEST(outcome, USB_OUTCOME_BABBLE, PROB_OUTCOME_BABBLE, roulette);
    123         PROB_TEST(outcome, USB_OUTCOME_CRCERROR, PROB_OUTCOME_CRCERROR, roulette);
    124        
    125         process_transaction_with_outcome(transaction, outcome);
    126 }
    127 #endif
    128 
     118}
     119
     120/** Host controller manager main function.
     121 */
    129122void hc_manager(void)
    130123{
     
    150143                virtdev_connection_t *dev = virtdev_find_by_address(
    151144                    transaction->target.address);
     145                usb_transaction_outcome_t outcome = USB_OUTCOME_OK;
     146               
    152147                if (dev != NULL) {
    153                         dprintf("sending data to device at %d.%d (phone %d)\n",
     148                        dprintf("sending data to device at %d.%d (phone %d)",
    154149                            dev->address, transaction->target.endpoint,
    155150                            dev->phone);
     
    173168                                rc = (int)answer_rc;
    174169                        }
     170                       
     171                        if (rc != EOK) {
     172                                outcome = USB_OUTCOME_BABBLE;
     173                        }
    175174                } else {
    176                         process_transaction_with_outcome(transaction,
    177                             USB_OUTCOME_OK);
     175                        outcome = USB_OUTCOME_CRCERROR;
    178176                }
    179177               
     178                process_transaction_with_outcome(transaction, outcome);
     179               
    180180                free(transaction);
    181181        }
    182182}
    183183
     184/** Create new transaction
     185 */
    184186static transaction_t *transaction_create(usb_transfer_type_t type, usb_target_t target,
    185187    usb_direction_t direction,
     
    201203}
    202204
    203 
     205/** Add transaction directioned towards the device.
     206 */
    204207void hc_add_transaction_to_device(usb_transfer_type_t type, usb_target_t target,
    205208    void * buffer, size_t len,
     
    211214}
    212215
     216/** Add transaction directioned from the device.
     217 */
    213218void hc_add_transaction_from_device(usb_transfer_type_t type, usb_target_t target,
    214219    void * buffer, size_t len,
     
    220225}
    221226
     227/** Fill data to existing transaction from device.
     228 */
    222229int hc_fillin_transaction_from_device(usb_transfer_type_t type, usb_target_t target,
    223230    void * buffer, size_t len)
    224231{
    225232        dprintf("finding transaction to fill data in...");
     233        int rc;
     234       
    226235        /*
    227236         * Find correct transaction envelope in the list.
    228237         */
    229238        if (list_empty(&transaction_from_device_list)) {
    230                 return ENOENT;
     239                rc = ENOENT;
     240                goto leave;
    231241        }
    232242       
     
    243253        }
    244254        if (transaction == NULL) {
    245                 return ENOENT;
     255                rc = ENOENT;
     256                goto leave;
    246257        }
    247258       
     
    253264        if (transaction->len < len) {
    254265                process_transaction_with_outcome(transaction, USB_OUTCOME_BABBLE);
    255                 return ENOMEM;
     266                rc = ENOMEM;
     267                goto leave;
    256268        }
    257269       
     
    264276        process_transaction_with_outcome(transaction, USB_OUTCOME_OK);
    265277       
    266         dprintf(" ...transaction " TRANSACTION_FORMAT " sent back",
     278        dprintf("  ...transaction " TRANSACTION_FORMAT " sent back",
    267279            TRANSACTION_PRINTF(*transaction));
    268280       
    269281       
    270282        free(transaction);
    271        
    272         return EOK;
     283        rc = EOK;
     284       
     285leave:
     286        dprintf("  ...fill-in transaction: %s", str_error(rc));
     287       
     288        return rc;
    273289}
    274290
  • uspace/srv/hw/bus/usb/hcd/virtual/hc.h

    rbc9a629 rb371844  
    3838#include <usb/hcd.h>
    3939
    40 typedef void (*hc_transaction_done_callback_t)(void *, size_t, usb_transaction_outcome_t, void *);
     40/** Callback after transaction is sent to USB.
     41 *
     42 * @param buffer Transaction data buffer.
     43 * @param size Transaction data size.
     44 * @param outcome Transaction outcome.
     45 * @param arg Custom argument.
     46 */
     47typedef void (*hc_transaction_done_callback_t)(void *buffer, size_t size,
     48    usb_transaction_outcome_t outcome, void *arg);
    4149
    4250void hc_manager(void);
  • uspace/srv/hw/bus/usb/hcd/virtual/hcd.c

    rbc9a629 rb371844  
    4949#include "hc.h"
    5050#include "devices.h"
     51#include "conn.h"
    5152
    52 static usb_transaction_handle_t g_handle_seed = 1;
    53 static usb_transaction_handle_t create_transaction_handle(int phone)
    54 {
    55         return g_handle_seed++;
    56 }
    57 
    58 typedef struct {
    59         int phone;
    60         usb_transaction_handle_t handle;
    61 } transaction_details_t;
    62 
    63 static void out_callback(void * buffer, size_t len, usb_transaction_outcome_t outcome, void * arg)
    64 {
    65         dprintf("out_callback(buffer, %u, %d, %p)", len, outcome, arg);
    66         (void)len;
    67         transaction_details_t * trans = (transaction_details_t *)arg;
    68        
    69         async_msg_2(trans->phone, IPC_M_USB_HCD_DATA_SENT, trans->handle, outcome);
    70        
    71         free(trans);
    72         free(buffer);
    73 }
    74 
    75 static void in_callback(void * buffer, size_t len, usb_transaction_outcome_t outcome, void * arg)
    76 {
    77         dprintf("in_callback(buffer, %u, %d, %p)", len, outcome, arg);
    78         transaction_details_t * trans = (transaction_details_t *)arg;
    79        
    80         ipc_call_t answer_data;
    81         ipcarg_t answer_rc;
    82         aid_t req;
    83         int rc;
    84        
    85         req = async_send_3(trans->phone,
    86             IPC_M_USB_HCD_DATA_RECEIVED,
    87             trans->handle, outcome,
    88             len,
    89             &answer_data);
    90        
    91         rc = async_data_write_start(trans->phone, buffer, len);
    92         if (rc != EOK) {
    93                 async_wait_for(req, NULL);
    94                 goto leave;
    95         }
    96        
    97         async_wait_for(req, &answer_rc);
    98         rc = (int)answer_rc;
    99         if (rc != EOK) {
    100                 goto leave;
    101         }
    102        
    103 leave:
    104         free(trans);
    105         free(buffer);
    106 }
    107 
    108 
    109 
    110 static void handle_data_to_function(ipc_callid_t iid, ipc_call_t icall, int callback_phone)
    111 {
    112         usb_transfer_type_t transf_type = IPC_GET_ARG3(icall);
    113         usb_target_t target = {
    114                 .address = IPC_GET_ARG1(icall),
    115                 .endpoint = IPC_GET_ARG2(icall)
    116         };
    117        
    118         dprintf("pretending transfer to function (dev=%d:%d, type=%s)",
    119             target.address, target.endpoint,
    120             usb_str_transfer_type(transf_type));
    121        
    122         if (callback_phone == -1) {
    123                 ipc_answer_0(iid, ENOENT);
    124                 return;
    125         }
    126        
    127         usb_transaction_handle_t handle
    128             = create_transaction_handle(callback_phone);
    129        
    130         size_t len;
    131         void * buffer;
    132         int rc = async_data_write_accept(&buffer, false,
    133             1, USB_MAX_PAYLOAD_SIZE,
    134             0, &len);
    135        
    136         if (rc != EOK) {
    137                 ipc_answer_0(iid, rc);
    138                 return;
    139         }
    140        
    141         transaction_details_t * trans = malloc(sizeof(transaction_details_t));
    142         trans->phone = callback_phone;
    143         trans->handle = handle;
    144        
    145         dprintf("adding transaction to HC", NAME);
    146         hc_add_transaction_to_device(transf_type, target,
    147             buffer, len,
    148             out_callback, trans);
    149        
    150         ipc_answer_1(iid, EOK, handle);
    151         dprintf("transfer to function scheduled (handle %d)", handle);
    152 }
    153 
    154 static void handle_data_from_function(ipc_callid_t iid, ipc_call_t icall, int callback_phone)
    155 {
    156         usb_transfer_type_t transf_type = IPC_GET_ARG3(icall);
    157         usb_target_t target = {
    158                 .address = IPC_GET_ARG1(icall),
    159                 .endpoint = IPC_GET_ARG2(icall)
    160         };
    161         size_t len = IPC_GET_ARG4(icall);
    162        
    163         dprintf("pretending transfer from function (dev=%d:%d, type=%s)",
    164             target.address, target.endpoint,
    165             usb_str_transfer_type(transf_type));
    166        
    167         if (callback_phone == -1) {
    168                 ipc_answer_0(iid, ENOENT);
    169                 return;
    170         }
    171        
    172         usb_transaction_handle_t handle
    173             = create_transaction_handle(callback_phone);
    174        
    175         void * buffer = malloc(len);
    176        
    177         transaction_details_t * trans = malloc(sizeof(transaction_details_t));
    178         trans->phone = callback_phone;
    179         trans->handle = handle;
    180        
    181         dprintf("adding transaction to HC", NAME);
    182         hc_add_transaction_from_device(transf_type, target,
    183             buffer, len,
    184             in_callback, trans);
    185        
    186         ipc_answer_1(iid, EOK, handle);
    187         dprintf("transfer from function scheduled (handle %d)", handle);
    188 }
    189 
    190 static void handle_data_from_device(ipc_callid_t iid, ipc_call_t icall, virtdev_connection_t *dev)
    191 {
    192         usb_endpoint_t endpoint = IPC_GET_ARG1(icall);
    193         usb_target_t target = {
    194                 .address = dev->address,
    195                 .endpoint = endpoint
    196         };
    197         size_t len;
    198         void * buffer;
    199         int rc = async_data_write_accept(&buffer, false,
    200             1, USB_MAX_PAYLOAD_SIZE,
    201             0, &len);
    202        
    203         if (rc != EOK) {
    204                 ipc_answer_0(iid, rc);
    205                 return;
    206         }
    207        
    208         rc = hc_fillin_transaction_from_device(USB_TRANSFER_INTERRUPT, target, buffer, len);
    209        
    210         ipc_answer_0(iid, rc);
    211 }
    212 
    213 static virtdev_connection_t *recognise_device(int id, int callback_phone)
    214 {
    215         switch (id) {
    216                 case USB_VIRTDEV_KEYBOARD_ID:
    217                         return virtdev_add_device(
    218                             USB_VIRTDEV_KEYBOARD_ADDRESS, callback_phone);
    219                 default:
    220                         return NULL;
    221         }               
    222 }
    223 
    224 static void device_client_connection(int callback_phone, int device_id)
    225 {
    226         virtdev_connection_t *dev = recognise_device(device_id, callback_phone);
    227         if (!dev) {
    228                 if (callback_phone != -1) {
    229                         ipc_hangup(callback_phone);
    230                 }
    231                 return;
    232         }
    233         dprintf("device %d connected", device_id);
    234         while (true) {
    235                 ipc_callid_t callid;
    236                 ipc_call_t call;
    237                
    238                 callid = async_get_call(&call);
    239                
    240                 switch (IPC_GET_METHOD(call)) {
    241                         case IPC_M_PHONE_HUNGUP:
    242                                 if (callback_phone != -1) {
    243                                         ipc_hangup(callback_phone);
    244                                 }
    245                                 ipc_answer_0(callid, EOK);
    246                                 dprintf("hung-up on device %d", device_id);
    247                                 virtdev_destroy_device(dev);
    248                                 return;
    249                         case IPC_M_CONNECT_TO_ME:
    250                                 ipc_answer_0(callid, ELIMIT);
    251                                 break;
    252                         case IPC_M_USB_VIRTDEV_DATA_FROM_DEVICE:
    253                                 dprintf("data from device %d", device_id);
    254                                 handle_data_from_device(callid, call, dev);
    255                                 break;
    256                         default:
    257                                 ipc_answer_0(callid, EINVAL);
    258                                 break;
    259                 }
    260         }
    261 }
    26253
    26354static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
     
    26859        printf("%s: new client connected (phone %#x).\n", NAME, phone_hash);
    26960       
    270         int callback_phone = -1;
    271        
    27261        while (true) {
    27362                ipc_callid_t callid;
     
    27564               
    27665                callid = async_get_call(&call);
    277                 dprintf("%#x calls method %d", phone_hash, IPC_GET_METHOD(call));
    278                 switch (IPC_GET_METHOD(call)) {
    279                         case IPC_M_PHONE_HUNGUP:
    280                                 if (callback_phone != -1) {
    281                                         ipc_hangup(callback_phone);
     66               
     67                /*
     68                 * We can do nothing until we have the callback phone.
     69                 * Thus, we will wait for the callback and start processing
     70                 * after that.
     71                 */
     72                int method = (int) IPC_GET_METHOD(call);
     73               
     74                if (method == IPC_M_PHONE_HUNGUP) {
     75                        ipc_answer_0(callid, EOK);
     76                        return;
     77                }
     78               
     79                if (method == IPC_M_CONNECT_TO_ME) {
     80                        int kind = IPC_GET_ARG1(call);
     81                        int callback = IPC_GET_ARG5(call);
     82                       
     83                        /*
     84                         * Determine whether host connected to us
     85                         * or a device.
     86                         */
     87                        if (kind == 0) {
     88                                ipc_answer_0(callid, EOK);
     89                                connection_handler_host(phone_hash, callback);
     90                                return;
     91                        } else if (kind == 1) {
     92                                int device_id = IPC_GET_ARG2(call);
     93                                virtdev_connection_t *dev
     94                                    = virtdev_recognise(device_id, callback);
     95                                if (!dev) {
     96                                        ipc_answer_0(callid, EEXISTS);
     97                                        ipc_hangup(callback);
     98                                        return;
    28299                                }
    283100                                ipc_answer_0(callid, EOK);
    284                                 printf("%s: hung-up on %#x.\n", NAME, phone_hash);
     101                                connection_handler_device(phone_hash, dev);
     102                                virtdev_destroy_device(dev);
    285103                                return;
    286                        
    287                         case IPC_M_CONNECT_TO_ME:
    288                                 if (callback_phone != -1) {
    289                                         ipc_answer_0(callid, ELIMIT);
    290                                 } else {
    291                                         callback_phone = IPC_GET_ARG5(call);
    292                                         ipc_answer_0(callid, EOK);
    293                                 }
    294                                 if (IPC_GET_ARG1(call) == 1) {
    295                                         /* Virtual device was just connected
    296                                          * to us. This is handled elsewhere.
    297                                          */
    298                                         device_client_connection(callback_phone,
    299                                             IPC_GET_ARG2(call));
    300                                         return;
    301                                 }
    302                                 break;
    303                        
    304                         case IPC_M_USB_HCD_SEND_DATA:
    305                                 handle_data_to_function(callid, call, callback_phone);
    306                                 break;
    307                        
    308                         case IPC_M_USB_HCD_RECEIVE_DATA:
    309                                 handle_data_from_function(callid, call, callback_phone);
    310                                 break;
    311                        
    312                         case IPC_M_USB_HCD_TRANSACTION_SIZE:
    313                                 ipc_answer_1(callid, EOK, USB_MAX_PAYLOAD_SIZE);
    314                                 break;
    315                        
    316                         default:
     104                        } else {
    317105                                ipc_answer_0(callid, EINVAL);
    318                                 break;
     106                                ipc_hangup(callback);
     107                                return;
     108                        }
    319109                }
     110               
     111                /*
     112                 * No other methods could be served now.
     113                 */
     114                ipc_answer_0(callid, ENOTSUP);
    320115        }
    321116}
  • uspace/srv/hw/bus/usb/hcd/virtual/vhcd.h

    rbc9a629 rb371844  
    4141#define DEVMAP_PATH NAMESPACE "/" NAME
    4242
     43/** Debugging printf.
     44 * @see printf
     45 */
    4346static inline void dprintf(const char * format, ...)
    4447{
Note: See TracChangeset for help on using the changeset viewer.