Changeset 84439d7 in mainline for uspace/lib/usb/src/hcdhubd.c


Ignore:
Timestamp:
2010-12-05T09:34:46Z (13 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
75732da
Parents:
56b962d (diff), 35537a7 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge with development/

File:
1 edited

Legend:

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

    r56b962d r84439d7  
    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)
     92int usb_hcd_add_root_hub(device_t *dev)
    26493{
     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        struct child_device_info *child_info
     118                        = (struct child_device_info *) arg;
    265119        int rc;
    266120
    267         /*
    268          * Announce presence of child device.
    269          */
    270         device_t *hub = NULL;
     121        async_usleep(1000);
     122
     123        device_t *child = create_device();
    271124        match_id_t *match_id = NULL;
    272125
    273         hub = create_device();
    274         if (hub == NULL) {
     126        if (child == NULL) {
    275127                rc = ENOMEM;
    276128                goto failure;
    277129        }
    278         hub->name = USB_HUB_DEVICE_NAME;
     130        child->name = child_info->name;
    279131
    280132        match_id = create_match_id();
     
    283135                goto failure;
    284136        }
    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);
     137        match_id->id = child_info->match_id;
     138        match_id->score = 10;
     139        add_match_id(&child->match_ids, match_id);
     140
     141        printf("%s: adding child device `%s' with match \"%s\"\n",
     142                        hc_driver->name, child->name, match_id->id);
     143        rc = child_device_register(child, child_info->parent);
     144        printf("%s: child device `%s' registration: %s\n",
     145                        hc_driver->name, child->name, str_error(rc));
     146
    299147        if (rc != EOK) {
    300148                goto failure;
    301149        }
    302150
    303         printf("%s: registered root hub\n", dev->generic->name);
     151        goto leave;
     152
     153failure:
     154        if (child != NULL) {
     155                child->name = NULL;
     156                delete_device(child);
     157        }
     158
     159        if (match_id != NULL) {
     160                match_id->id = NULL;
     161                delete_match_id(match_id);
     162        }
     163
     164leave:
     165        free(arg);
    304166        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;
     167}
     168
     169/** Adds a child.
     170 * Due to deadlock in devman when parent registers child that oughts to be
     171 * driven by the same task, the child adding is done in separate fibril.
     172 * Not optimal, but it works.
     173 * Update: not under all circumstances the new fibril is successful either.
     174 * Thus the last parameter to let the caller choose.
     175 *
     176 * @param parent Parent device.
     177 * @param name Device name.
     178 * @param match_id Match id.
     179 * @param create_fibril Whether to run the addition in new fibril.
     180 * @return Error code.
     181 */
     182int usb_hc_add_child_device(device_t *parent, const char *name,
     183                const char *match_id, bool create_fibril) {
     184        printf("%s: about to add child device `%s' (%s)\n", hc_driver->name,
     185                        name, match_id);
     186
     187        /*
     188         * Seems that creating fibril which postpones the action
     189         * is the best solution.
     190         */
     191        create_fibril = true;
     192
     193        struct child_device_info *child_info
     194                        = malloc(sizeof (struct child_device_info));
     195
     196        child_info->parent = parent;
     197        child_info->name = name;
     198        child_info->match_id = match_id;
     199
     200        if (create_fibril) {
     201                fid_t fibril = fibril_create(fibril_add_child_device, child_info);
     202                if (!fibril) {
     203                        return ENOMEM;
     204                }
     205                fibril_add_ready(fibril);
     206        } else {
     207                fibril_add_child_device(child_info);
     208        }
     209
     210        return EOK;
     211}
     212
     213/** Tell USB address of given device.
     214 *
     215 * @param handle Devman handle of the device.
     216 * @return USB device address or error code.
     217 */
     218usb_address_t usb_get_address_by_handle(devman_handle_t handle) {
     219        /* TODO: search list of attached devices. */
     220        return ENOENT;
     221}
     222
     223usb_address_t usb_use_free_address(usb_hc_device_t * this_hcd) {
     224        //is there free address?
     225        link_t * addresses = &this_hcd->addresses;
     226        if (list_empty(addresses)) return -1;
     227        link_t * link_addr = addresses;
     228        bool found = false;
     229        usb_address_list_t * range = NULL;
     230        while (!found) {
     231                link_addr = link_addr->next;
     232                if (link_addr == addresses) return -2;
     233                range = list_get_instance(link_addr,
     234                                usb_address_list_t, link);
     235                if (range->upper_bound - range->lower_bound > 0) {
     236                        found = true;
     237                }
     238        }
     239        //now we have interval
     240        int result = range->lower_bound;
     241        ++(range->lower_bound);
     242        if (range->upper_bound - range->lower_bound == 0) {
     243                list_remove(&range->link);
     244                free(range);
     245        }
     246        return result;
     247}
     248
     249void usb_free_used_address(usb_hc_device_t * this_hcd, usb_address_t addr) {
     250        //check range
     251        if (addr < usb_lowest_address || addr > usb_highest_address)
     252                return;
     253        link_t * addresses = &this_hcd->addresses;
     254        link_t * link_addr = addresses;
     255        //find 'good' interval
     256        usb_address_list_t * found_range = NULL;
     257        bool found = false;
     258        while (!found) {
     259                link_addr = link_addr->next;
     260                if (link_addr == addresses) {
     261                        found = true;
     262                } else {
     263                        usb_address_list_t * range = list_get_instance(link_addr,
     264                                        usb_address_list_t, link);
     265                        if (    (range->lower_bound - 1 == addr) ||
     266                                        (range->upper_bound == addr)) {
     267                                found = true;
     268                                found_range = range;
     269                        }
     270                        if (range->lower_bound - 1 > addr) {
     271                                found = true;
     272                        }
     273
     274                }
     275        }
     276        if (found_range == NULL) {
     277                //no suitable range found
     278                usb_address_list_t * result_range =
     279                                (usb_address_list_t*) malloc(sizeof (usb_address_list_t));
     280                result_range->lower_bound = addr;
     281                result_range->upper_bound = addr + 1;
     282                list_insert_before(&result_range->link, link_addr);
     283        } else {
     284                //we have good range
     285                if (found_range->lower_bound - 1 == addr) {
     286                        --found_range->lower_bound;
     287                } else {
     288                        //only one possible case
     289                        ++found_range->upper_bound;
     290                        if (found_range->link.next != addresses) {
     291                                usb_address_list_t * next_range =
     292                                                list_get_instance( &found_range->link.next,
     293                                                usb_address_list_t, link);
     294                                //check neighbour range
     295                                if (next_range->lower_bound == addr + 1) {
     296                                        //join ranges
     297                                        found_range->upper_bound = next_range->upper_bound;
     298                                        list_remove(&next_range->link);
     299                                        free(next_range);
     300                                }
     301                        }
     302                }
     303        }
     304
    314305}
    315306
Note: See TracChangeset for help on using the changeset viewer.