Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usb/src/hcdhubd.c

    r8f62b0f r4317827  
    3131 */
    3232/** @file
    33  * @brief HC driver and hub driver (implementation).
     33 * @brief Common stuff for both HC driver and hub driver.
    3434 */
    3535#include <usb/hcdhubd.h>
    3636#include <usb/devreq.h>
    3737#include <usbhc_iface.h>
     38#include <usb/descriptor.h>
    3839#include <driver.h>
    3940#include <bool.h>
    4041#include <errno.h>
    41 
    42 #define USB_HUB_DEVICE_NAME "usbhub"
    43 
    44 /** List of handled host controllers. */
    45 static LIST_INITIALIZE(hc_list);
    46 
    47 /** Our HC driver. */
    48 static usb_hc_driver_t *hc_driver = NULL;
    49 
    50 static usbhc_iface_t usb_interface = {
    51         .interrupt_out = NULL,
    52         .interrupt_in = NULL
    53 };
    54 
    55 static device_ops_t usb_device_ops = {
    56         .interfaces[USBHC_DEV_IFACE] = &usb_interface
    57 };
    58 
    59 static void set_hub_address(usb_hc_device_t *hc, usb_address_t address);
     42#include <str_error.h>
     43#include <usb/classes/hub.h>
     44
     45#include "hcdhubd_private.h"
    6046
    6147/** Callback when new device is detected and must be handled by this driver.
     
    6450 * @return Error code.
    6551 */
    66 static int add_device(device_t *dev)
    67 {
    68         /*
    69          * FIXME: use some magic to determine whether hub or another HC
    70          * was connected.
    71          */
    72         bool is_hc = str_cmp(dev->name, USB_HUB_DEVICE_NAME) != 0;
    73         printf("%s: add_device(name=\"%s\")\n", hc_driver->name, dev->name);
    74 
    75         if (is_hc) {
    76                 /*
    77                  * We are the HC itself.
    78                  */
    79                 usb_hc_device_t *hc_dev = malloc(sizeof(usb_hc_device_t));
    80                 list_initialize(&hc_dev->link);
    81                 hc_dev->transfer_ops = NULL;
    82 
    83                 hc_dev->generic = dev;
    84                 dev->ops = &usb_device_ops;
    85                 hc_dev->generic->driver_data = hc_dev;
    86 
    87                 int rc = hc_driver->add_hc(hc_dev);
    88                 if (rc != EOK) {
    89                         free(hc_dev);
    90                         return rc;
    91                 }
    92 
    93                 /*
    94                  * FIXME: The following line causes devman to hang.
    95                  * Will investigate later why.
    96                  */
    97                 // add_device_to_class(dev, "usbhc");
    98 
    99                 list_append(&hc_dev->link, &hc_list);
    100 
    101                 return EOK;
    102         } else {
    103                 usb_hc_device_t *hc = list_get_instance(hc_list.next, usb_hc_device_t, link);
    104                 set_hub_address(hc, 5);
    105 
    106                 /*
    107                  * We are some (probably deeply nested) hub.
    108                  * Thus, assign our own operations and explore already
    109                  * connected devices.
    110                  */
    111 
    112                 return ENOTSUP;
    113         }
    114 }
    115 
    116 /** Sample usage of usb_hc_async functions.
    117  * This function sets hub address using standard SET_ADDRESS request.
    118  *
    119  * @warning This function shall be removed once you are familiar with
    120  * the usb_hc_ API.
    121  *
    122  * @param hc Host controller the hub belongs to.
    123  * @param address New hub address.
    124  */
    125 static void set_hub_address(usb_hc_device_t *hc, usb_address_t address)
    126 {
    127         printf("%s: setting hub address to %d\n", hc->generic->name, address);
    128         usb_target_t target = {0, 0};
    129         usb_handle_t handle;
    130         int rc;
    131 
    132         usb_device_request_setup_packet_t setup_packet = {
    133                 .request_type = 0,
    134                 .request = USB_DEVREQ_SET_ADDRESS,
    135                 .index = 0,
    136                 .length = 0,
    137         };
    138         setup_packet.value = address;
    139 
    140         rc = usb_hc_async_control_write_setup(hc, target,
    141             &setup_packet, sizeof(setup_packet), &handle);
    142         if (rc != EOK) {
    143                 return;
    144         }
    145 
    146         rc = usb_hc_async_wait_for(handle);
    147         if (rc != EOK) {
    148                 return;
    149         }
    150 
    151         rc = usb_hc_async_control_write_status(hc, target, &handle);
    152         if (rc != EOK) {
    153                 return;
    154         }
    155 
    156         rc = usb_hc_async_wait_for(handle);
    157         if (rc != EOK) {
    158                 return;
    159         }
    160 
    161         printf("%s: hub address changed\n", hc->generic->name);
    162 }
    163 
    164 /** Check changes on all known hubs.
    165  */
    166 static void check_hub_changes(void)
    167 {
    168         /*
    169          * Iterate through all HCs.
    170          */
    171         link_t *link_hc;
    172         for (link_hc = hc_list.next;
    173             link_hc != &hc_list;
    174             link_hc = link_hc->next) {
    175                 usb_hc_device_t *hc = list_get_instance(link_hc,
    176                     usb_hc_device_t, link);
    177                 /*
    178                  * Iterate through all their hubs.
    179                  */
    180                 link_t *link_hub;
    181                 for (link_hub = hc->hubs.next;
    182                     link_hub != &hc->hubs;
    183                     link_hub = link_hub->next) {
    184                         usb_hcd_hub_info_t *hub = list_get_instance(link_hub,
    185                             usb_hcd_hub_info_t, link);
    186 
    187                         /*
    188                          * Check status change pipe of this hub.
    189                          */
    190                         usb_target_t target = {
    191                                 .address = hub->device->address,
    192                                 .endpoint = 1
    193                         };
    194 
    195                         // FIXME: count properly
    196                         size_t byte_length = (hub->port_count / 8) + 1;
    197 
    198                         void *change_bitmap = malloc(byte_length);
    199                         size_t actual_size;
    200                         usb_handle_t handle;
    201 
    202                         /*
    203                          * Send the request.
    204                          * FIXME: check returned value for possible errors
    205                          */
    206                         usb_hc_async_interrupt_in(hc, target,
    207                             change_bitmap, byte_length, &actual_size,
    208                             &handle);
    209 
    210                         usb_hc_async_wait_for(handle);
    211 
    212                         /*
    213                          * TODO: handle the changes.
    214                          */
    215                 }
    216         }
     52static int add_device(device_t *dev) {
     53        return ENOTSUP;
    21754}
    21855
     
    23471 * @return Error code.
    23572 */
    236 int usb_hcd_main(usb_hc_driver_t *hc)
    237 {
     73int usb_hcd_main(usb_hc_driver_t *hc) {
    23874        hc_driver = hc;
    23975        hc_driver_generic.name = hc->name;
    240 
    241         /*
    242          * Launch here fibril that will periodically check all
    243          * attached hubs for status change.
    244          * WARN: This call will effectively do nothing.
    245          */
    246         check_hub_changes();
    24776
    24877        /*
     
    26190 * @return Error code.
    26291 */
    263 int usb_hcd_add_root_hub(usb_hc_device_t *dev)
    264 {
     92int usb_hcd_add_root_hub(device_t *dev)
     93{
     94        char *id;
     95        int rc = asprintf(&id, "usb&hub");
     96        if (rc <= 0) {
     97                return rc;
     98        }
     99
     100        rc = usb_hc_add_child_device(dev, USB_HUB_DEVICE_NAME, id, true);
     101        if (rc != EOK) {
     102                free(id);
     103        }
     104
     105        return rc;
     106}
     107
     108/** Info about child device. */
     109struct child_device_info {
     110        device_t *parent;
     111        const char *name;
     112        const char *match_id;
     113};
     114
     115/** Adds a child device fibril worker. */
     116static int fibril_add_child_device(void *arg)
     117{
     118        struct child_device_info *child_info
     119            = (struct child_device_info *) arg;
    265120        int rc;
    266121
    267         /*
    268          * Announce presence of child device.
    269          */
    270         device_t *hub = NULL;
     122        async_usleep(1000);
     123
     124        device_t *child = create_device();
    271125        match_id_t *match_id = NULL;
    272126
    273         hub = create_device();
    274         if (hub == NULL) {
     127        if (child == NULL) {
    275128                rc = ENOMEM;
    276129                goto failure;
    277130        }
    278         hub->name = USB_HUB_DEVICE_NAME;
     131        child->name = child_info->name;
    279132
    280133        match_id = create_match_id();
     
    283136                goto failure;
    284137        }
    285 
    286         char *id;
    287         rc = asprintf(&id, "usb&hc=%s&hub", dev->generic->name);
    288         if (rc <= 0) {
    289                 rc = ENOMEM;
    290                 goto failure;
    291         }
    292 
    293         match_id->id = id;
    294         match_id->score = 30;
    295 
    296         add_match_id(&hub->match_ids, match_id);
    297 
    298         rc = child_device_register(hub, dev->generic);
     138        match_id->id = child_info->match_id;
     139        match_id->score = 10;
     140        add_match_id(&child->match_ids, match_id);
     141
     142        printf("%s: adding child device `%s' with match \"%s\"\n",
     143            hc_driver->name, child->name, match_id->id);
     144        rc = child_device_register(child, child_info->parent);
     145        printf("%s: child device `%s' registration: %s\n",
     146            hc_driver->name, child->name, str_error(rc));
     147
    299148        if (rc != EOK) {
    300149                goto failure;
    301150        }
    302151
    303         printf("%s: registered root hub\n", dev->generic->name);
     152        goto leave;
     153
     154failure:
     155        if (child != NULL) {
     156                child->name = NULL;
     157                delete_device(child);
     158        }
     159
     160        if (match_id != NULL) {
     161                match_id->id = NULL;
     162                delete_match_id(match_id);
     163        }
     164
     165leave:
     166        free(arg);
    304167        return EOK;
    305 
    306 failure:
    307         if (hub != NULL) {
    308                 hub->name = NULL;
    309                 delete_device(hub);
    310         }
    311         delete_match_id(match_id);
    312 
    313         return rc;
     168}
     169
     170/** Adds a child.
     171 * Due to deadlock in devman when parent registers child that oughts to be
     172 * driven by the same task, the child adding is done in separate fibril.
     173 * Not optimal, but it works.
     174 * Update: not under all circumstances the new fibril is successful either.
     175 * Thus the last parameter to let the caller choose.
     176 *
     177 * @param parent Parent device.
     178 * @param name Device name.
     179 * @param match_id Match id.
     180 * @param create_fibril Whether to run the addition in new fibril.
     181 * @return Error code.
     182 */
     183int usb_hc_add_child_device(device_t *parent, const char *name,
     184    const char *match_id, bool create_fibril)
     185{
     186        printf("%s: about to add child device `%s' (%s)\n", hc_driver->name,
     187            name, match_id);
     188
     189        /*
     190         * Seems that creating fibril which postpones the action
     191         * is the best solution.
     192         */
     193        create_fibril = true;
     194
     195        struct child_device_info *child_info
     196            = malloc(sizeof(struct child_device_info));
     197
     198        child_info->parent = parent;
     199        child_info->name = name;
     200        child_info->match_id = match_id;
     201
     202        if (create_fibril) {
     203                fid_t fibril = fibril_create(fibril_add_child_device, child_info);
     204                if (!fibril) {
     205                        return ENOMEM;
     206                }
     207                fibril_add_ready(fibril);
     208        } else {
     209                fibril_add_child_device(child_info);
     210        }
     211
     212        return EOK;
     213}
     214
     215/** Tell USB address of given device.
     216 *
     217 * @param handle Devman handle of the device.
     218 * @return USB device address or error code.
     219 */
     220usb_address_t usb_get_address_by_handle(devman_handle_t handle)
     221{
     222        /* TODO: search list of attached devices. */
     223        return ENOENT;
    314224}
    315225
Note: See TracChangeset for help on using the changeset viewer.