Ignore:
File:
1 edited

Legend:

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

    rc50941f r8123695a  
    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                async_usleep(1000 * 1000 * 10 );/// \TODO proper number once
     77                errorCode = usb_hub_check_hub_changes(hub_info);
     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
     
    400400
    401401/**
     402 * Reset the port with new device and reserve the default address.
     403 * @param hub hub representation
     404 * @param port port number, starting from 1
     405 * @param speed transfer speed of attached device, one of low, full or high
     406 */
     407static void usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port,
     408                usb_speed_t speed) {
     409        //if this hub already uses default address, it cannot request it once more
     410        if(hub->is_default_address_used) return;
     411        usb_log_debug("some connection changed\n");
     412        assert(hub->control_pipe->hc_phone);
     413        int opResult = usb_hub_clear_port_feature(hub->control_pipe,
     414                                port, USB_HUB_FEATURE_C_PORT_CONNECTION);
     415        if(opResult != EOK){
     416                usb_log_warning("could not clear port-change-connection flag\n");
     417        }
     418        usb_device_request_setup_packet_t request;
     419       
     420        //get default address
     421        opResult = usb_hc_reserve_default_address(&hub->connection, speed);
     422       
     423        if (opResult != EOK) {
     424                usb_log_warning("cannot assign default address, it is probably used %d\n",
     425                                opResult);
     426                return;
     427        }
     428        hub->is_default_address_used = true;
     429        //reset port
     430        usb_hub_set_reset_port_request(&request, port);
     431        opResult = usb_pipe_control_write(
     432                        hub->control_pipe,
     433                        &request,sizeof(usb_device_request_setup_packet_t),
     434                        NULL, 0
     435                        );
     436        if (opResult != EOK) {
     437                usb_log_error("something went wrong when reseting a port %d\n",opResult);
     438                usb_hub_release_default_address(hub);
     439        }
     440        return;
     441}
     442
     443/**
     444 * Finalize adding new device after port reset
     445 *
     446 * Set device`s address and start it`s driver.
     447 * @param hub hub representation
     448 * @param port port number, starting from 1
     449 * @param speed transfer speed of attached device, one of low, full or high
     450 */
     451static void usb_hub_finalize_add_device( usb_hub_info_t * hub,
     452                uint16_t port, usb_speed_t speed) {
     453
     454        int opResult;
     455        usb_log_debug("finalizing add device\n");
     456        opResult = usb_hub_clear_port_feature(hub->control_pipe,
     457            port, USB_HUB_FEATURE_C_PORT_RESET);
     458
     459        if (opResult != EOK) {
     460                usb_log_error("failed to clear port reset feature\n");
     461                usb_hub_release_default_address(hub);
     462                return;
     463        }
     464        //create connection to device
     465        usb_pipe_t new_device_pipe;
     466        usb_device_connection_t new_device_connection;
     467        usb_device_connection_initialize_on_default_address(
     468                        &new_device_connection,
     469                        &hub->connection
     470                        );
     471        usb_pipe_initialize_default_control(
     472                        &new_device_pipe,
     473                        &new_device_connection);
     474        usb_pipe_probe_default_control(&new_device_pipe);
     475
     476        /* Request address from host controller. */
     477        usb_address_t new_device_address = usb_hc_request_address(
     478                        &hub->connection,
     479                        speed
     480                        );
     481        if (new_device_address < 0) {
     482                usb_log_error("failed to get free USB address\n");
     483                opResult = new_device_address;
     484                usb_hub_release_default_address(hub);
     485                return;
     486        }
     487        usb_log_debug("setting new address %d\n",new_device_address);
     488        //opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
     489        //    new_device_address);
     490        usb_pipe_start_session(&new_device_pipe);
     491        opResult = usb_request_set_address(&new_device_pipe,new_device_address);
     492        usb_pipe_end_session(&new_device_pipe);
     493        if (opResult != EOK) {
     494                usb_log_error("could not set address for new device %d\n",opResult);
     495                usb_hub_release_default_address(hub);
     496                return;
     497        }
     498
     499        //opResult = usb_hub_release_default_address(hc);
     500        opResult = usb_hub_release_default_address(hub);
     501        if(opResult!=EOK){
     502                return;
     503        }
     504
     505        devman_handle_t child_handle;
     506        //??
     507    opResult = usb_device_register_child_in_devman(new_device_address,
     508            hub->connection.hc_handle, hub->usb_device->ddf_dev, &child_handle,
     509            NULL, NULL, NULL);
     510
     511        if (opResult != EOK) {
     512                usb_log_error("could not start driver for new device %d\n",opResult);
     513                return;
     514        }
     515        hub->attached_devs[port].handle = child_handle;
     516        hub->attached_devs[port].address = new_device_address;
     517
     518        //opResult = usb_drv_bind_address(hc, new_device_address, child_handle);
     519        opResult = usb_hc_register_device(
     520                        &hub->connection,
     521                        &hub->attached_devs[port]);
     522        if (opResult != EOK) {
     523                usb_log_error("could not assign address of device in hcd %d\n",opResult);
     524                return;
     525        }
     526        usb_log_info("Detected new device on `%s' (port %d), " \
     527            "address %d (handle %llu).\n",
     528            hub->usb_device->ddf_dev->name, (int) port,
     529            new_device_address, child_handle);
     530}
     531
     532/**
    402533 * routine called when a device on port has been removed
    403534 *
     
    408539 * @param port port number, starting from 1
    409540 */
    410 void usb_hub_removed_device(
     541static void usb_hub_removed_device(
    411542    usb_hub_info_t * hub,uint16_t port) {
    412543
     
    421552       
    422553        //close address
    423         if(hub->ports[port].attached_device.address >= 0){
     554        if(hub->attached_devs[port].address!=0){
    424555                /*uncomment this code to use it when DDF allows device removal
    425556                opResult = usb_hc_unregister_device(
     
    448579 * @param port port number, starting from 1
    449580 */
    450 void usb_hub_over_current( usb_hub_info_t * hub,
     581static void usb_hub_over_current( usb_hub_info_t * hub,
    451582                uint16_t port){
    452583        int opResult;
     
    459590}
    460591
     592/**
     593 * Process interrupts on given hub port
     594 *
     595 * Accepts connection, over current and port reset change.
     596 * @param hub hub representation
     597 * @param port port number, starting from 1
     598 */
     599static void usb_hub_process_interrupt(usb_hub_info_t * hub,
     600        uint16_t port) {
     601        usb_log_debug("interrupt at port %d\n", port);
     602        //determine type of change
     603        usb_pipe_t *pipe = hub->control_pipe;
     604       
     605        int opResult;
     606
     607        usb_port_status_t status;
     608        size_t rcvd_size;
     609        usb_device_request_setup_packet_t request;
     610        //int opResult;
     611        usb_hub_set_port_status_request(&request, port);
     612        //endpoint 0
     613
     614        opResult = usb_pipe_control_read(
     615                        pipe,
     616                        &request, sizeof(usb_device_request_setup_packet_t),
     617                        &status, 4, &rcvd_size
     618                        );
     619        if (opResult != EOK) {
     620                usb_log_error("could not get port status\n");
     621                return;
     622        }
     623        if (rcvd_size != sizeof (usb_port_status_t)) {
     624                usb_log_error("received status has incorrect size\n");
     625                return;
     626        }
     627        //something connected/disconnected
     628        if (usb_port_connect_change(&status)) {
     629                usb_log_debug("connection change on port\n");
     630                if (usb_port_dev_connected(&status)) {
     631                        usb_log_debug("some connection changed\n");
     632                        usb_hub_init_add_device(hub, port, usb_port_speed(&status));
     633                } else {
     634                        usb_hub_removed_device(hub, port);
     635                }
     636        }
     637        //over current
     638        if (usb_port_overcurrent_change(&status)) {
     639                //check if it was not auto-resolved
     640                usb_log_debug("overcurrent change on port\n");
     641                if(usb_port_over_current(&status)){
     642                        usb_hub_over_current(hub,port);
     643                }else{
     644                        usb_log_debug("over current condition was auto-resolved on port %d\n",
     645                                        port);
     646                }
     647        }
     648        //port reset
     649        if (usb_port_reset_completed(&status)) {
     650                usb_log_debug("port reset complete\n");
     651                if (usb_port_enabled(&status)) {
     652                        usb_hub_finalize_add_device(hub, port, usb_port_speed(&status));
     653                } else {
     654                        usb_log_warning("port reset, but port still not enabled\n");
     655                }
     656        }
     657        usb_log_debug("status %x\n ",status);
     658
     659        usb_port_set_connect_change(&status, false);
     660        usb_port_set_reset(&status, false);
     661        usb_port_set_reset_completed(&status, false);
     662        usb_port_set_dev_connected(&status, false);
     663        if (status>>16) {
     664                usb_log_info("there was some unsupported change on port %d: %X\n",
     665                                port,status);
     666
     667        }
     668}
     669
     670/**
     671 * check changes on hub
     672 *
     673 * Handles changes on each port with a status change.
     674 * @param hub_info hub representation
     675 * @return error code
     676 */
     677int usb_hub_check_hub_changes(usb_hub_info_t * hub_info){
     678        int opResult;
     679        opResult = usb_pipe_start_session(
     680                        hub_info->status_change_pipe);
     681        if(opResult != EOK){
     682                usb_log_error("could not initialize communication for hub; %d\n",
     683                                opResult);
     684                return opResult;
     685        }
     686
     687        size_t port_count = hub_info->port_count;
     688
     689        /// FIXME: count properly
     690        size_t byte_length = ((port_count+1) / 8) + 1;
     691                void *change_bitmap = malloc(byte_length);
     692        size_t actual_size;
     693
     694        /*
     695         * Send the request.
     696         */
     697        opResult = usb_pipe_read(
     698                        hub_info->status_change_pipe,
     699                        change_bitmap, byte_length, &actual_size
     700                        );
     701
     702        if (opResult != EOK) {
     703                free(change_bitmap);
     704                usb_log_warning("something went wrong while getting status of hub\n");
     705                usb_pipe_end_session(hub_info->status_change_pipe);
     706                return opResult;
     707        }
     708        unsigned int port;
     709        opResult = usb_pipe_start_session(hub_info->control_pipe);
     710        if(opResult!=EOK){
     711                usb_log_error("could not start control pipe session %d\n", opResult);
     712                usb_pipe_end_session(hub_info->status_change_pipe);
     713                return opResult;
     714        }
     715        opResult = usb_hc_connection_open(&hub_info->connection);
     716        if(opResult!=EOK){
     717                usb_log_error("could not start host controller session %d\n",
     718                                opResult);
     719                usb_pipe_end_session(hub_info->control_pipe);
     720                usb_pipe_end_session(hub_info->status_change_pipe);
     721                return opResult;
     722        }
     723
     724        ///todo, opresult check, pre obe konekce
     725        for (port = 1; port < port_count+1; ++port) {
     726                bool interrupt =
     727                                (((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
     728                if (interrupt) {
     729                        usb_hub_process_interrupt(
     730                                hub_info, port);
     731                }
     732        }
     733        usb_hc_connection_close(&hub_info->connection);
     734        usb_pipe_end_session(hub_info->control_pipe);
     735        usb_pipe_end_session(hub_info->status_change_pipe);
     736        free(change_bitmap);
     737        return EOK;
     738}
     739
     740
    461741
    462742/**
Note: See TracChangeset for help on using the changeset viewer.