Changeset b04967a in mainline for uspace/drv/usbhub/usbhub.c


Ignore:
Timestamp:
2011-04-07T15:53:46Z (13 years ago)
Author:
Matej Klonfar <maklf@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
c156c2d
Parents:
64dbc83 (diff), a82889e (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:

development merge

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/usbhub/usbhub.c

    r64dbc83 rb04967a  
    5353#include "usb/classes/classes.h"
    5454
    55 
    56 static void usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port,
    57                 usb_speed_t speed);
    58 
    5955static int usb_hub_trigger_connecting_non_removable_devices(
    6056                usb_hub_info_t * hub, usb_hub_descriptor_t * descriptor);
    61 
    62 /**
    63  * control loop running in hub`s fibril
    64  *
    65  * Hub`s fibril periodically asks for changes on hub and if needded calls
    66  * change handling routine.
    67  * @warning currently hub driver asks for changes once a second
    68  * @param hub_info_param hub representation pointer
    69  * @return zero
    70  */
    71 int usb_hub_control_loop(void * hub_info_param){
    72         usb_hub_info_t * hub_info = (usb_hub_info_t*)hub_info_param;
    73         int errorCode = EOK;
    74 
    75         while(errorCode == EOK){
    76                 errorCode = usb_hub_check_hub_changes(hub_info);
    77                 async_usleep(1000 * 1000 );/// \TODO proper number once
    78         }
    79         usb_log_error("something in ctrl loop went wrong, errno %d\n",errorCode);
    80 
    81         return 0;
    82 }
    8357
    8458
     
    152126        usb_log_debug("setting port count to %d\n",descriptor->ports_count);
    153127        hub_info->port_count = descriptor->ports_count;
    154         hub_info->attached_devs = (usb_hc_attached_device_t*)
    155             malloc((hub_info->port_count+1) * sizeof(usb_hc_attached_device_t));
    156         int i;
    157         for(i=0;i<hub_info->port_count+1;++i){
    158                 hub_info->attached_devs[i].handle=0;
    159                 hub_info->attached_devs[i].address=0;
     128        hub_info->ports = malloc(sizeof(usb_hub_port_t) * (hub_info->port_count+1));
     129        size_t port;
     130        for (port = 0; port < hub_info->port_count + 1; port++) {
     131                usb_hub_port_init(&hub_info->ports[port]);
    160132        }
    161133        //handle non-removable devices
     
    259231        assert(rc == EOK);
    260232
    261         //create fibril for the hub control loop
    262         fid_t fid = fibril_create(usb_hub_control_loop, hub_info);
    263         if (fid == 0) {
    264                 usb_log_error("failed to start monitoring fibril for new hub.\n");
    265                 return ENOMEM;
    266         }
    267         fibril_add_ready(fid);
    268         usb_log_debug("Hub fibril created.\n");
     233        /*
     234         * The processing will require opened control pipe and connection
     235         * to the host controller.
     236         * It is waste of resources but let's hope there will be less
     237         * hubs than the phone limit.
     238         * FIXME: with some proper locking over pipes and session
     239         * auto destruction, this could work better.
     240         */
     241        rc = usb_pipe_start_session(&usb_dev->ctrl_pipe);
     242        if (rc != EOK) {
     243                usb_log_error("Failed to start session on control pipe: %s.\n",
     244                    str_error(rc));
     245                goto leave;
     246        }
     247        rc = usb_hc_connection_open(&hub_info->connection);
     248        if (rc != EOK) {
     249                usb_pipe_end_session(&usb_dev->ctrl_pipe);
     250                usb_log_error("Failed to open connection to HC: %s.\n",
     251                    str_error(rc));
     252                goto leave;
     253        }
     254
     255        rc = usb_device_auto_poll(hub_info->usb_device, 0,
     256            hub_port_changes_callback, ((hub_info->port_count+1) / 8) + 1,
     257            NULL, hub_info);
     258        if (rc != EOK) {
     259                usb_log_error("Failed to create polling fibril: %s.\n",
     260                    str_error(rc));
     261                free(hub_info);
     262                return rc;
     263        }
    269264
    270265        usb_log_info("Controlling hub `%s' (%d ports).\n",
    271266            hub_info->usb_device->ddf_dev->name, hub_info->port_count);
    272267        return EOK;
     268
     269leave:
     270        free(hub_info);
     271
     272        return rc;
    273273}
    274274
     
    317317                        //set the status change bit, so it will be noticed in driver loop
    318318                        if(usb_port_dev_connected(&status)){
    319                                 usb_hub_set_enable_port_feature_request(&request, port,
    320                                                 USB_HUB_FEATURE_C_PORT_CONNECTION);
     319                                usb_hub_set_disable_port_feature_request(&request, port,
     320                                                USB_HUB_FEATURE_PORT_CONNECTION);
    321321                                opResult = usb_pipe_control_read(
    322322                                                hub->control_pipe,
     
    326326                                if (opResult != EOK) {
    327327                                        usb_log_warning(
    328                                                         "could not set port change on port %d errno:%d\n",
     328                                                        "could not clear port connection on port %d errno:%d\n",
    329329                                                        port, opResult);
    330330                                }
     331                                usb_log_debug("cleared port connection\n");
     332                                usb_hub_set_enable_port_feature_request(&request, port,
     333                                                USB_HUB_FEATURE_PORT_ENABLE);
     334                                opResult = usb_pipe_control_read(
     335                                                hub->control_pipe,
     336                                                &request, sizeof(usb_device_request_setup_packet_t),
     337                                                &status, 4, &rcvd_size
     338                                                );
     339                                if (opResult != EOK) {
     340                                        usb_log_warning(
     341                                                        "could not set port enabled on port %d errno:%d\n",
     342                                                        port, opResult);
     343                                }
     344                                usb_log_debug("port set to enabled - should lead to connection change\n");
    331345                        }
     346                }
     347        }
     348        /// \TODO this is just a debug code
     349        for(port=1;port<=descriptor->ports_count;++port){
     350                bool is_non_removable =
     351                                ((non_removable_dev_bitmap[port/8]) >> (port%8)) %2;
     352                if(is_non_removable){
     353                        usb_log_debug("port %d is non-removable\n",port);
     354                        usb_port_status_t status;
     355                        size_t rcvd_size;
     356                        usb_device_request_setup_packet_t request;
     357                        //int opResult;
     358                        usb_hub_set_port_status_request(&request, port);
     359                        //endpoint 0
     360                        opResult = usb_pipe_control_read(
     361                                        hub->control_pipe,
     362                                        &request, sizeof(usb_device_request_setup_packet_t),
     363                                        &status, 4, &rcvd_size
     364                                        );
     365                        if (opResult != EOK) {
     366                                usb_log_error("could not get port status %d\n",opResult);
     367                        }
     368                        if (rcvd_size != sizeof (usb_port_status_t)) {
     369                                usb_log_error("received status has incorrect size\n");
     370                        }
     371                        //something connected/disconnected
     372                        if (usb_port_connect_change(&status)) {
     373                                usb_log_debug("some connection changed\n");
     374                        }
     375                        usb_log_debug("status: %s\n",usb_debug_str_buffer(
     376                                        (uint8_t *)&status,4,4));
    332377                }
    333378        }
     
    352397        hub->is_default_address_used = false;
    353398        return EOK;
    354 }
    355 
    356 /**
    357  * Reset the port with new device and reserve the default address.
    358  * @param hub hub representation
    359  * @param port port number, starting from 1
    360  * @param speed transfer speed of attached device, one of low, full or high
    361  */
    362 static void usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port,
    363                 usb_speed_t speed) {
    364         //if this hub already uses default address, it cannot request it once more
    365         if(hub->is_default_address_used) return;
    366         usb_log_debug("some connection changed\n");
    367         assert(hub->control_pipe->hc_phone);
    368         int opResult = usb_hub_clear_port_feature(hub->control_pipe,
    369                                 port, USB_HUB_FEATURE_C_PORT_CONNECTION);
    370         if(opResult != EOK){
    371                 usb_log_warning("could not clear port-change-connection flag\n");
    372         }
    373         usb_device_request_setup_packet_t request;
    374        
    375         //get default address
    376         opResult = usb_hc_reserve_default_address(&hub->connection, speed);
    377        
    378         if (opResult != EOK) {
    379                 usb_log_warning("cannot assign default address, it is probably used %d\n",
    380                                 opResult);
    381                 return;
    382         }
    383         hub->is_default_address_used = true;
    384         //reset port
    385         usb_hub_set_reset_port_request(&request, port);
    386         opResult = usb_pipe_control_write(
    387                         hub->control_pipe,
    388                         &request,sizeof(usb_device_request_setup_packet_t),
    389                         NULL, 0
    390                         );
    391         if (opResult != EOK) {
    392                 usb_log_error("something went wrong when reseting a port %d\n",opResult);
    393                 usb_hub_release_default_address(hub);
    394         }
    395         return;
    396 }
    397 
    398 /**
    399  * Finalize adding new device after port reset
    400  *
    401  * Set device`s address and start it`s driver.
    402  * @param hub hub representation
    403  * @param port port number, starting from 1
    404  * @param speed transfer speed of attached device, one of low, full or high
    405  */
    406 static void usb_hub_finalize_add_device( usb_hub_info_t * hub,
    407                 uint16_t port, usb_speed_t speed) {
    408 
    409         int opResult;
    410         usb_log_debug("finalizing add device\n");
    411         opResult = usb_hub_clear_port_feature(hub->control_pipe,
    412             port, USB_HUB_FEATURE_C_PORT_RESET);
    413 
    414         if (opResult != EOK) {
    415                 usb_log_error("failed to clear port reset feature\n");
    416                 usb_hub_release_default_address(hub);
    417                 return;
    418         }
    419         //create connection to device
    420         usb_pipe_t new_device_pipe;
    421         usb_device_connection_t new_device_connection;
    422         usb_device_connection_initialize_on_default_address(
    423                         &new_device_connection,
    424                         &hub->connection
    425                         );
    426         usb_pipe_initialize_default_control(
    427                         &new_device_pipe,
    428                         &new_device_connection);
    429         usb_pipe_probe_default_control(&new_device_pipe);
    430 
    431         /* Request address from host controller. */
    432         usb_address_t new_device_address = usb_hc_request_address(
    433                         &hub->connection,
    434                         speed
    435                         );
    436         if (new_device_address < 0) {
    437                 usb_log_error("failed to get free USB address\n");
    438                 opResult = new_device_address;
    439                 usb_hub_release_default_address(hub);
    440                 return;
    441         }
    442         usb_log_debug("setting new address %d\n",new_device_address);
    443         //opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
    444         //    new_device_address);
    445         usb_pipe_start_session(&new_device_pipe);
    446         opResult = usb_request_set_address(&new_device_pipe,new_device_address);
    447         usb_pipe_end_session(&new_device_pipe);
    448         if (opResult != EOK) {
    449                 usb_log_error("could not set address for new device %d\n",opResult);
    450                 usb_hub_release_default_address(hub);
    451                 return;
    452         }
    453 
    454         //opResult = usb_hub_release_default_address(hc);
    455         opResult = usb_hub_release_default_address(hub);
    456         if(opResult!=EOK){
    457                 return;
    458         }
    459 
    460         devman_handle_t child_handle;
    461         //??
    462     opResult = usb_device_register_child_in_devman(new_device_address,
    463             hub->connection.hc_handle, hub->usb_device->ddf_dev, &child_handle,
    464             NULL, NULL, NULL);
    465 
    466         if (opResult != EOK) {
    467                 usb_log_error("could not start driver for new device %d\n",opResult);
    468                 return;
    469         }
    470         hub->attached_devs[port].handle = child_handle;
    471         hub->attached_devs[port].address = new_device_address;
    472 
    473         //opResult = usb_drv_bind_address(hc, new_device_address, child_handle);
    474         opResult = usb_hc_register_device(
    475                         &hub->connection,
    476                         &hub->attached_devs[port]);
    477         if (opResult != EOK) {
    478                 usb_log_error("could not assign address of device in hcd %d\n",opResult);
    479                 return;
    480         }
    481         usb_log_info("Detected new device on `%s' (port %d), " \
    482             "address %d (handle %llu).\n",
    483             hub->usb_device->ddf_dev->name, (int) port,
    484             new_device_address, child_handle);
    485399}
    486400
     
    494408 * @param port port number, starting from 1
    495409 */
    496 static void usb_hub_removed_device(
     410void usb_hub_removed_device(
    497411    usb_hub_info_t * hub,uint16_t port) {
    498412
     
    507421       
    508422        //close address
    509         if(hub->attached_devs[port].address!=0){
     423        if(hub->ports[port].attached_device.address >= 0){
    510424                /*uncomment this code to use it when DDF allows device removal
    511425                opResult = usb_hc_unregister_device(
     
    534448 * @param port port number, starting from 1
    535449 */
    536 static void usb_hub_over_current( usb_hub_info_t * hub,
     450void usb_hub_over_current( usb_hub_info_t * hub,
    537451                uint16_t port){
    538452        int opResult;
     
    545459}
    546460
    547 /**
    548  * Process interrupts on given hub port
    549  *
    550  * Accepts connection, over current and port reset change.
    551  * @param hub hub representation
    552  * @param port port number, starting from 1
    553  */
    554 static void usb_hub_process_interrupt(usb_hub_info_t * hub,
    555         uint16_t port) {
    556         usb_log_debug("interrupt at port %d\n", port);
    557         //determine type of change
    558         usb_pipe_t *pipe = hub->control_pipe;
    559        
    560         int opResult;
    561 
    562         usb_port_status_t status;
    563         size_t rcvd_size;
    564         usb_device_request_setup_packet_t request;
    565         //int opResult;
    566         usb_hub_set_port_status_request(&request, port);
    567         //endpoint 0
    568 
    569         opResult = usb_pipe_control_read(
    570                         pipe,
    571                         &request, sizeof(usb_device_request_setup_packet_t),
    572                         &status, 4, &rcvd_size
    573                         );
    574         if (opResult != EOK) {
    575                 usb_log_error("could not get port status\n");
    576                 return;
    577         }
    578         if (rcvd_size != sizeof (usb_port_status_t)) {
    579                 usb_log_error("received status has incorrect size\n");
    580                 return;
    581         }
    582         //something connected/disconnected
    583         if (usb_port_connect_change(&status)) {
    584                 if (usb_port_dev_connected(&status)) {
    585                         usb_log_debug("some connection changed\n");
    586                         usb_hub_init_add_device(hub, port, usb_port_speed(&status));
    587                 } else {
    588                         usb_hub_removed_device(hub, port);
    589                 }
    590         }
    591         //over current
    592         if (usb_port_overcurrent_change(&status)) {
    593                 //check if it was not auto-resolved
    594                 if(usb_port_over_current(&status)){
    595                         usb_hub_over_current(hub,port);
    596                 }else{
    597                         usb_log_debug("over current condition was auto-resolved on port %d\n",
    598                                         port);
    599                 }
    600         }
    601         //port reset
    602         if (usb_port_reset_completed(&status)) {
    603                 usb_log_debug("port reset complete\n");
    604                 if (usb_port_enabled(&status)) {
    605                         usb_hub_finalize_add_device(hub, port, usb_port_speed(&status));
    606                 } else {
    607                         usb_log_warning("port reset, but port still not enabled\n");
    608                 }
    609         }
    610 
    611         usb_port_set_connect_change(&status, false);
    612         usb_port_set_reset(&status, false);
    613         usb_port_set_reset_completed(&status, false);
    614         usb_port_set_dev_connected(&status, false);
    615         if (status>>16) {
    616                 usb_log_info("there was some unsupported change on port %d: %X\n",
    617                                 port,status);
    618 
    619         }
    620 }
    621 
    622 /**
    623  * check changes on hub
    624  *
    625  * Handles changes on each port with a status change.
    626  * @param hub_info hub representation
    627  * @return error code
    628  */
    629 int usb_hub_check_hub_changes(usb_hub_info_t * hub_info){
    630         int opResult;
    631         opResult = usb_pipe_start_session(
    632                         hub_info->status_change_pipe);
    633         if(opResult != EOK){
    634                 usb_log_error("could not initialize communication for hub; %d\n",
    635                                 opResult);
    636                 return opResult;
    637         }
    638 
    639         size_t port_count = hub_info->port_count;
    640 
    641         /// FIXME: count properly
    642         size_t byte_length = ((port_count+1) / 8) + 1;
    643                 void *change_bitmap = malloc(byte_length);
    644         size_t actual_size;
    645 
    646         /*
    647          * Send the request.
    648          */
    649         opResult = usb_pipe_read(
    650                         hub_info->status_change_pipe,
    651                         change_bitmap, byte_length, &actual_size
    652                         );
    653 
    654         if (opResult != EOK) {
    655                 free(change_bitmap);
    656                 usb_log_warning("something went wrong while getting status of hub\n");
    657                 usb_pipe_end_session(hub_info->status_change_pipe);
    658                 return opResult;
    659         }
    660         unsigned int port;
    661         opResult = usb_pipe_start_session(hub_info->control_pipe);
    662         if(opResult!=EOK){
    663                 usb_log_error("could not start control pipe session %d\n", opResult);
    664                 usb_pipe_end_session(hub_info->status_change_pipe);
    665                 return opResult;
    666         }
    667         opResult = usb_hc_connection_open(&hub_info->connection);
    668         if(opResult!=EOK){
    669                 usb_log_error("could not start host controller session %d\n",
    670                                 opResult);
    671                 usb_pipe_end_session(hub_info->control_pipe);
    672                 usb_pipe_end_session(hub_info->status_change_pipe);
    673                 return opResult;
    674         }
    675 
    676         ///todo, opresult check, pre obe konekce
    677         for (port = 1; port < port_count+1; ++port) {
    678                 bool interrupt =
    679                                 (((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
    680                 if (interrupt) {
    681                         usb_hub_process_interrupt(
    682                                 hub_info, port);
    683                 }
    684         }
    685         usb_hc_connection_close(&hub_info->connection);
    686         usb_pipe_end_session(hub_info->control_pipe);
    687         usb_pipe_end_session(hub_info->status_change_pipe);
    688         free(change_bitmap);
    689         return EOK;
    690 }
    691 
    692 
    693461
    694462/**
Note: See TracChangeset for help on using the changeset viewer.