Ignore:
File:
1 edited

Legend:

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

    rda55d5b r7972b51  
    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>
     
    4040#include <bool.h>
    4141#include <errno.h>
     42#include <str_error.h>
    4243#include <usb/classes/hub.h>
    4344
    44 #define USB_HUB_DEVICE_NAME "usbhub"
    45 
    46 #define USB_KBD_DEVICE_NAME "hid"
    47 
    48 
    49 
    50 
    51 /** List of handled host controllers. */
    52 static LIST_INITIALIZE(hc_list);
    53 
    54 /** Our HC driver. */
    55 static usb_hc_driver_t *hc_driver = NULL;
    56 
    57 static usbhc_iface_t usb_interface = {
    58         .interrupt_out = NULL,
    59         .interrupt_in = NULL
    60 };
    61 
    62 static device_ops_t usb_device_ops = {
    63         .interfaces[USBHC_DEV_IFACE] = &usb_interface
    64 };
    65 
    66 size_t USB_HUB_MAX_DESCRIPTOR_SIZE = 71;
    67 
    68 uint8_t USB_HUB_DESCRIPTOR_TYPE = 0x29;
    69 
    70 //*********************************************
    71 //
    72 //  various utils
    73 //
    74 //*********************************************
    75 
    76 void * usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor) {
    77         //base size
    78         size_t size = 7;
    79         //variable size according to port count
    80         size_t var_size = descriptor->ports_count / 8 + ((descriptor->ports_count % 8 > 0) ? 1 : 0);
    81         size += 2 * var_size;
    82         uint8_t * result = (uint8_t*) malloc(size);
    83         //size
    84         result[0] = size;
    85         //descriptor type
    86         result[1] = USB_DESCTYPE_HUB;
    87         result[2] = descriptor->ports_count;
    88         /// @fixme handling of endianness??
    89         result[3] = descriptor->hub_characteristics / 256;
    90         result[4] = descriptor->hub_characteristics % 256;
    91         result[5] = descriptor->pwr_on_2_good_time;
    92         result[6] = descriptor->current_requirement;
    93 
    94         size_t i;
    95         for (i = 0; i < var_size; ++i) {
    96                 result[7 + i] = descriptor->devices_removable[i];
    97         }
    98         for (i = 0; i < var_size; ++i) {
    99                 result[7 + var_size + i] = 255;
    100         }
    101         return result;
    102 }
    103 
    104 usb_hub_descriptor_t * usb_deserialize_hub_desriptor(void * serialized_descriptor) {
    105         uint8_t * sdescriptor = (uint8_t*) serialized_descriptor;
    106         if (sdescriptor[1] != USB_DESCTYPE_HUB) return NULL;
    107         usb_hub_descriptor_t * result = (usb_hub_descriptor_t*) malloc(sizeof (usb_hub_descriptor_t));
    108         //uint8_t size = sdescriptor[0];
    109         result->ports_count = sdescriptor[2];
    110         /// @fixme handling of endianness??
    111         result->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3];
    112         result->pwr_on_2_good_time = sdescriptor[5];
    113         result->current_requirement = sdescriptor[6];
    114         size_t var_size = result->ports_count / 8 + ((result->ports_count % 8 > 0) ? 1 : 0);
    115         result->devices_removable = (uint8_t*) malloc(var_size);
    116 
    117         size_t i;
    118         for (i = 0; i < var_size; ++i) {
    119                 result->devices_removable[i] = sdescriptor[7 + i];
    120         }
    121         return result;
    122 }
    123 
    124 
    125 //*********************************************
    126 //
    127 //  hub driver code
    128 //
    129 //*********************************************
    130 
    131 static void set_hub_address(usb_hc_device_t *hc, usb_address_t address);
    132 
    133 usb_hcd_hub_info_t * usb_create_hub_info(device_t * device) {
    134         usb_hcd_hub_info_t* result = (usb_hcd_hub_info_t*) malloc(sizeof (usb_hcd_hub_info_t));
    135         //get parent device
    136         /// @TODO this code is not correct
    137         device_t * my_hcd = device;
    138         while (my_hcd->parent)
    139                 my_hcd = my_hcd->parent;
    140         //dev->
    141         printf("%s: owner hcd found: %s\n", hc_driver->name, my_hcd->name);
    142         //we add the hub into the first hc
    143         //link_t *link_hc = hc_list.next;
    144         //usb_hc_device_t *hc = list_get_instance(link_hc,
    145         //              usb_hc_device_t, link);
    146         //must get generic device info
    147 
    148 
    149         return result;
    150 }
     45#include "hcdhubd_private.h"
    15146
    15247/** Callback when new device is detected and must be handled by this driver.
    15348 *
    15449 * @param dev New device.
    155  * @return Error code.hub added, hurrah!\n"
     50 * @return Error code.
    15651 */
    15752static int add_device(device_t *dev) {
    158         /*
    159          * FIXME: use some magic to determine whether hub or another HC
    160          * was connected.
    161          */
    16253        bool is_hc = str_cmp(dev->name, USB_HUB_DEVICE_NAME) != 0;
    16354        printf("%s: add_device(name=\"%s\")\n", hc_driver->name, dev->name);
     
    16758                 * We are the HC itself.
    16859                 */
    169                 usb_hc_device_t *hc_dev = malloc(sizeof (usb_hc_device_t));
    170                 list_initialize(&hc_dev->link);
    171                 hc_dev->transfer_ops = NULL;
    172 
    173                 hc_dev->generic = dev;
    174                 dev->ops = &usb_device_ops;
    175                 hc_dev->generic->driver_data = hc_dev;
    176 
    177                 int rc = hc_driver->add_hc(hc_dev);
    178                 if (rc != EOK) {
    179                         free(hc_dev);
    180                         return rc;
    181                 }
    182 
     60                return usb_add_hc_device(dev);
     61        } else {
    18362                /*
    184                  * FIXME: The following line causes devman to hang.
    185                  * Will investigate later why.
    186                  */
    187                 // add_device_to_class(dev, "usbhc");
    188 
    189                 list_append(&hc_dev->link, &hc_list);
    190 
    191                 //add keyboard
    192                 /// @TODO this is not correct code
    193                
    194                 /*
    195                  * Announce presence of child device.
    196                  */
    197                 device_t *kbd = NULL;
    198                 match_id_t *match_id = NULL;
    199 
    200                 kbd = create_device();
    201                 if (kbd == NULL) {
    202                         printf("ERROR: enomem\n");
    203                 }
    204                 kbd->name = USB_KBD_DEVICE_NAME;
    205 
    206                 match_id = create_match_id();
    207                 if (match_id == NULL) {
    208                         printf("ERROR: enomem\n");
    209                 }
    210 
    211                 char *id;
    212                 rc = asprintf(&id, USB_KBD_DEVICE_NAME);
    213                 if (rc <= 0) {
    214                         printf("ERROR: enomem\n");
    215                         return rc;
    216                 }
    217 
    218                 match_id->id = id;
    219                 match_id->score = 30;
    220 
    221                 add_match_id(&kbd->match_ids, match_id);
    222 
    223                 rc = child_device_register(kbd, dev);
    224                 if (rc != EOK) {
    225                         printf("ERROR: cannot register kbd\n");
    226                         return rc;
    227                 }
    228 
    229                 printf("%s: registered root hub\n", dev->name);
    230                 return EOK;
    231 
    232 
    233 
    234         } else {
    235                 usb_hc_device_t *hc = list_get_instance(hc_list.next, usb_hc_device_t, link);
    236                 set_hub_address(hc, 5);
    237 
    238                 /*
    239                  * We are some (probably deeply nested) hub.
     63                 * We are some (maybe deeply nested) hub.
    24064                 * Thus, assign our own operations and explore already
    24165                 * connected devices.
    24266                 */
    243                 //insert hub into list
    244                 //find owner hcd
    245                 device_t * my_hcd = dev;
    246                 while (my_hcd->parent)
    247                         my_hcd = my_hcd->parent;
    248                 //dev->
    249                 printf("%s: owner hcd found: %s\n", hc_driver->name, my_hcd->name);
    250                 my_hcd = dev;
    251                 while (my_hcd->parent)
    252                         my_hcd = my_hcd->parent;
    253                 //dev->
    254 
    255                 printf("%s: owner hcd found: %s\n", hc_driver->name, my_hcd->name);
    256                
    257                 //create the hub structure
    258                 usb_hcd_hub_info_t * hub_info = usb_create_hub_info(dev);
    259 
    260 
    261                 //append into the list
    262                 //we add the hub into the first hc
    263                 list_append(&hub_info->link, &hc->hubs);
    264 
    265 
    266 
    267                 return EOK;
    268                 //return ENOTSUP;
    269         }
    270 }
    271 
    272 /** Sample usage of usb_hc_async functions.
    273  * This function sets hub address using standard SET_ADDRESS request.
    274  *
    275  * @warning This function shall be removed once you are familiar with
    276  * the usb_hc_ API.
    277  *
    278  * @param hc Host controller the hub belongs to.
    279  * @param address New hub address.
    280  */
    281 static void set_hub_address(usb_hc_device_t *hc, usb_address_t address) {
    282         printf("%s: setting hub address to %d\n", hc->generic->name, address);
    283         usb_target_t target = {0, 0};
    284         usb_handle_t handle;
    285         int rc;
    286 
    287         usb_device_request_setup_packet_t setup_packet = {
    288                 .request_type = 0,
    289                 .request = USB_DEVREQ_SET_ADDRESS,
    290                 .index = 0,
    291                 .length = 0,
    292         };
    293         setup_packet.value = address;
    294 
    295         rc = usb_hc_async_control_write_setup(hc, target,
    296                         &setup_packet, sizeof (setup_packet), &handle);
    297         if (rc != EOK) {
    298                 return;
    299         }
    300 
    301         rc = usb_hc_async_wait_for(handle);
    302         if (rc != EOK) {
    303                 return;
    304         }
    305 
    306         rc = usb_hc_async_control_write_status(hc, target, &handle);
    307         if (rc != EOK) {
    308                 return;
    309         }
    310 
    311         rc = usb_hc_async_wait_for(handle);
    312         if (rc != EOK) {
    313                 return;
    314         }
    315 
    316         printf("%s: hub address changed\n", hc->generic->name);
    317 }
    318 
    319 /** Check changes on all known hubs.
    320  */
    321 static void check_hub_changes(void) {
    322         /*
    323          * Iterate through all HCs.
    324          */
    325         link_t *link_hc;
    326         for (link_hc = hc_list.next;
    327                         link_hc != &hc_list;
    328                         link_hc = link_hc->next) {
    329                 usb_hc_device_t *hc = list_get_instance(link_hc,
    330                                 usb_hc_device_t, link);
    331                 /*
    332                  * Iterate through all their hubs.
    333                  */
    334                 link_t *link_hub;
    335                 for (link_hub = hc->hubs.next;
    336                                 link_hub != &hc->hubs;
    337                                 link_hub = link_hub->next) {
    338                         usb_hcd_hub_info_t *hub = list_get_instance(link_hub,
    339                                         usb_hcd_hub_info_t, link);
    340 
    341                         /*
    342                          * Check status change pipe of this hub.
    343                          */
    344                         usb_target_t target = {
    345                                 .address = hub->device->address,
    346                                 .endpoint = 1
    347                         };
    348 
    349                         // FIXME: count properly
    350                         size_t byte_length = (hub->port_count / 8) + 1;
    351 
    352                         void *change_bitmap = malloc(byte_length);
    353                         size_t actual_size;
    354                         usb_handle_t handle;
    355 
    356                         /*
    357                          * Send the request.
    358                          * FIXME: check returned value for possible errors
    359                          */
    360                         usb_hc_async_interrupt_in(hc, target,
    361                                         change_bitmap, byte_length, &actual_size,
    362                                         &handle);
    363 
    364                         usb_hc_async_wait_for(handle);
    365 
    366                         /*
    367                          * TODO: handle the changes.
    368                          */
    369                 }
     67                return usb_add_hub_device(dev);
    37068        }
    37169}
     
    39189        hc_driver = hc;
    39290        hc_driver_generic.name = hc->name;
    393 
    394         /*
    395          * Launch here fibril that will periodically check all
    396          * attached hubs for status change.
    397          * WARN: This call will effectively do nothing.
    398          */
    399         check_hub_changes();
    40091
    40192        /*
     
    414105 * @return Error code.
    415106 */
    416 int usb_hcd_add_root_hub(usb_hc_device_t *dev) {
     107int usb_hcd_add_root_hub(usb_hc_device_t *dev)
     108{
     109        char *id;
     110        int rc = asprintf(&id, "usb&hc=%s&hub", hc_driver->name);
     111        if (rc <= 0) {
     112                return rc;
     113        }
     114
     115        rc = usb_hc_add_child_device(dev->generic, USB_HUB_DEVICE_NAME, id, true);
     116        if (rc != EOK) {
     117                free(id);
     118        }
     119
     120        return rc;
     121}
     122
     123/** Info about child device. */
     124struct child_device_info {
     125        device_t *parent;
     126        const char *name;
     127        const char *match_id;
     128};
     129
     130/** Adds a child device fibril worker. */
     131static int fibril_add_child_device(void *arg)
     132{
     133        struct child_device_info *child_info
     134            = (struct child_device_info *) arg;
    417135        int rc;
    418136
    419         /*
    420          * Announce presence of child device.
    421          */
    422         device_t *hub = NULL;
     137        async_usleep(1000);
     138
     139        device_t *child = create_device();
    423140        match_id_t *match_id = NULL;
    424141
    425         hub = create_device();
    426         if (hub == NULL) {
     142        if (child == NULL) {
    427143                rc = ENOMEM;
    428144                goto failure;
    429145        }
    430         hub->name = USB_HUB_DEVICE_NAME;
     146        child->name = child_info->name;
    431147
    432148        match_id = create_match_id();
     
    435151                goto failure;
    436152        }
    437 
    438         char *id;
    439         rc = asprintf(&id, "usb&hc=%s&hub", dev->generic->name);
    440         if (rc <= 0) {
    441                 rc = ENOMEM;
    442                 goto failure;
    443         }
    444 
    445         match_id->id = id;
    446         match_id->score = 30;
    447 
    448         add_match_id(&hub->match_ids, match_id);
    449 
    450         rc = child_device_register(hub, dev->generic);
     153        match_id->id = child_info->match_id;
     154        match_id->score = 10;
     155        add_match_id(&child->match_ids, match_id);
     156
     157        printf("%s: adding child device `%s' with match \"%s\"\n",
     158            hc_driver->name, child->name, match_id->id);
     159        rc = child_device_register(child, child_info->parent);
     160        printf("%s: child device `%s' registration: %s\n",
     161            hc_driver->name, child->name, str_error(rc));
     162
    451163        if (rc != EOK) {
    452164                goto failure;
    453165        }
    454166
    455         printf("%s: registered root hub\n", dev->generic->name);
     167        goto leave;
     168
     169failure:
     170        if (child != NULL) {
     171                child->name = NULL;
     172                delete_device(child);
     173        }
     174
     175        if (match_id != NULL) {
     176                match_id->id = NULL;
     177                delete_match_id(match_id);
     178        }
     179
     180leave:
     181        free(arg);
    456182        return EOK;
    457 
    458 failure:
    459         if (hub != NULL) {
    460                 hub->name = NULL;
    461                 delete_device(hub);
    462         }
    463         delete_match_id(match_id);
    464 
    465         return rc;
     183}
     184
     185/** Adds a child.
     186 * Due to deadlock in devman when parent registers child that oughts to be
     187 * driven by the same task, the child adding is done in separate fibril.
     188 * Not optimal, but it works.
     189 * Update: not under all circumstances the new fibril is successful either.
     190 * Thus the last parameter to let the caller choose.
     191 *
     192 * @param parent Parent device.
     193 * @param name Device name.
     194 * @param match_id Match id.
     195 * @param create_fibril Whether to run the addition in new fibril.
     196 * @return Error code.
     197 */
     198int usb_hc_add_child_device(device_t *parent, const char *name,
     199    const char *match_id, bool create_fibril)
     200{
     201        printf("%s: about to add child device `%s' (%s)\n", hc_driver->name,
     202            name, match_id);
     203
     204        /*
     205         * Seems that creating fibril which postpones the action
     206         * is the best solution.
     207         */
     208        create_fibril = true;
     209
     210        struct child_device_info *child_info
     211            = malloc(sizeof(struct child_device_info));
     212
     213        child_info->parent = parent;
     214        child_info->name = name;
     215        child_info->match_id = match_id;
     216
     217        if (create_fibril) {
     218                fid_t fibril = fibril_create(fibril_add_child_device, child_info);
     219                if (!fibril) {
     220                        return ENOMEM;
     221                }
     222                fibril_add_ready(fibril);
     223        } else {
     224                fibril_add_child_device(child_info);
     225        }
     226
     227        return EOK;
     228}
     229
     230/** Tell USB address of given device.
     231 *
     232 * @param handle Devman handle of the device.
     233 * @return USB device address or error code.
     234 */
     235usb_address_t usb_get_address_by_handle(devman_handle_t handle)
     236{
     237        /* TODO: search list of attached devices. */
     238        return ENOENT;
    466239}
    467240
Note: See TracChangeset for help on using the changeset viewer.