Ignore:
File:
1 edited

Legend:

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

    r4317827 r8f62b0f  
    3131 */
    3232/** @file
    33  * @brief Common stuff for both HC driver and hub driver.
     33 * @brief HC driver and hub driver (implementation).
    3434 */
    3535#include <usb/hcdhubd.h>
    3636#include <usb/devreq.h>
    3737#include <usbhc_iface.h>
    38 #include <usb/descriptor.h>
    3938#include <driver.h>
    4039#include <bool.h>
    4140#include <errno.h>
    42 #include <str_error.h>
    43 #include <usb/classes/hub.h>
    44 
    45 #include "hcdhubd_private.h"
     41
     42#define USB_HUB_DEVICE_NAME "usbhub"
     43
     44/** List of handled host controllers. */
     45static LIST_INITIALIZE(hc_list);
     46
     47/** Our HC driver. */
     48static usb_hc_driver_t *hc_driver = NULL;
     49
     50static usbhc_iface_t usb_interface = {
     51        .interrupt_out = NULL,
     52        .interrupt_in = NULL
     53};
     54
     55static device_ops_t usb_device_ops = {
     56        .interfaces[USBHC_DEV_IFACE] = &usb_interface
     57};
     58
     59static void set_hub_address(usb_hc_device_t *hc, usb_address_t address);
    4660
    4761/** Callback when new device is detected and must be handled by this driver.
     
    5064 * @return Error code.
    5165 */
    52 static int add_device(device_t *dev) {
    53         return ENOTSUP;
     66static 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 */
     125static 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 */
     166static 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        }
    54217}
    55218
     
    71234 * @return Error code.
    72235 */
    73 int usb_hcd_main(usb_hc_driver_t *hc) {
     236int usb_hcd_main(usb_hc_driver_t *hc)
     237{
    74238        hc_driver = hc;
    75239        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();
    76247
    77248        /*
     
    90261 * @return Error code.
    91262 */
    92 int 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. */
    109 struct 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. */
    116 static int fibril_add_child_device(void *arg)
    117 {
    118         struct child_device_info *child_info
    119             = (struct child_device_info *) arg;
     263int usb_hcd_add_root_hub(usb_hc_device_t *dev)
     264{
    120265        int rc;
    121266
    122         async_usleep(1000);
    123 
    124         device_t *child = create_device();
     267        /*
     268         * Announce presence of child device.
     269         */
     270        device_t *hub = NULL;
    125271        match_id_t *match_id = NULL;
    126272
    127         if (child == NULL) {
     273        hub = create_device();
     274        if (hub == NULL) {
    128275                rc = ENOMEM;
    129276                goto failure;
    130277        }
    131         child->name = child_info->name;
     278        hub->name = USB_HUB_DEVICE_NAME;
    132279
    133280        match_id = create_match_id();
     
    136283                goto failure;
    137284        }
    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 
    148         if (rc != EOK) {
     285
     286        char *id;
     287        rc = asprintf(&id, "usb&hc=%s&hub", dev->generic->name);
     288        if (rc <= 0) {
     289                rc = ENOMEM;
    149290                goto failure;
    150291        }
    151292
    152         goto leave;
     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);
     299        if (rc != EOK) {
     300                goto failure;
     301        }
     302
     303        printf("%s: registered root hub\n", dev->generic->name);
     304        return EOK;
    153305
    154306failure:
    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 
    165 leave:
    166         free(arg);
    167         return EOK;
    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  */
    183 int 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  */
    220 usb_address_t usb_get_address_by_handle(devman_handle_t handle)
    221 {
    222         /* TODO: search list of attached devices. */
    223         return ENOENT;
     307        if (hub != NULL) {
     308                hub->name = NULL;
     309                delete_device(hub);
     310        }
     311        delete_match_id(match_id);
     312
     313        return rc;
    224314}
    225315
Note: See TracChangeset for help on using the changeset viewer.