Ignore:
File:
1 edited

Legend:

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

    rc50941f rdf3ad97  
    5353#include "usb/classes/classes.h"
    5454
     55
     56static void usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port,
     57                usb_speed_t speed);
     58
    5559static int usb_hub_trigger_connecting_non_removable_devices(
    5660                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 */
     71int 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}
    5783
    5884
     
    126152        usb_log_debug("setting port count to %d\n",descriptor->ports_count);
    127153        hub_info->port_count = descriptor->ports_count;
    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]);
     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;
    132160        }
    133161        //handle non-removable devices
     
    231259        assert(rc == EOK);
    232260
    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         }
     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");
    264269
    265270        usb_log_info("Controlling hub `%s' (%d ports).\n",
    266271            hub_info->usb_device->ddf_dev->name, hub_info->port_count);
    267272        return EOK;
    268 
    269 leave:
    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_disable_port_feature_request(&request, port,
    320                                                 USB_HUB_FEATURE_PORT_CONNECTION);
     319                                usb_hub_set_enable_port_feature_request(&request, port,
     320                                                USB_HUB_FEATURE_C_PORT_CONNECTION);
    321321                                opResult = usb_pipe_control_read(
    322322                                                hub->control_pipe,
     
    326326                                if (opResult != EOK) {
    327327                                        usb_log_warning(
    328                                                         "could not clear port connection on port %d errno:%d\n",
     328                                                        "could not set port change 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");
    345331                        }
    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));
    377332                }
    378333        }
     
    397352        hub->is_default_address_used = false;
    398353        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 */
     362static 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 */
     406static 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);
    399485}
    400486
     
    408494 * @param port port number, starting from 1
    409495 */
    410 void usb_hub_removed_device(
     496static void usb_hub_removed_device(
    411497    usb_hub_info_t * hub,uint16_t port) {
    412498
     
    421507       
    422508        //close address
    423         if(hub->ports[port].attached_device.address >= 0){
     509        if(hub->attached_devs[port].address!=0){
    424510                /*uncomment this code to use it when DDF allows device removal
    425511                opResult = usb_hc_unregister_device(
     
    448534 * @param port port number, starting from 1
    449535 */
    450 void usb_hub_over_current( usb_hub_info_t * hub,
     536static void usb_hub_over_current( usb_hub_info_t * hub,
    451537                uint16_t port){
    452538        int opResult;
     
    459545}
    460546
     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 */
     554static 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 */
     629int 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
    461693
    462694/**
Note: See TracChangeset for help on using the changeset viewer.