Changeset fd3940c1 in mainline


Ignore:
Timestamp:
2011-04-07T13:30:49Z (14 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
8f30c2e
Parents:
049eb87 (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 branch changes

Location:
uspace
Files:
1 added
1 deleted
6 edited
1 moved

Legend:

Unmodified
Added
Removed
  • uspace/drv/usbhub/Makefile

    r049eb87 rfd3940c1  
    3434SOURCES = \
    3535        main.c \
     36        ports.c \
    3637        utils.c \
    37         usbhub.c \
    38         usblist.c
     38        usbhub.c
    3939
    4040include $(USPACE_PREFIX)/Makefile.common
  • uspace/drv/usbhub/ports.h

    r049eb87 rfd3940c1  
    11/*
    2  * Copyright (c) 2010 Matus Dekanek
     2 * Copyright (c) 2011 Vojtech Horky
    33 * All rights reserved.
    44 *
     
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
     28
    2829/** @addtogroup drvusbhub
    2930 * @{
    3031 */
    3132/** @file
    32  * @brief usblist implementation
     33 * Hub ports related functions.
    3334 */
    34 #include <sys/types.h>
     35#ifndef DRV_USBHUB_PORTS_H
     36#define DRV_USBHUB_PORTS_H
    3537
    36 #include "usbhub_private.h"
     38#include <ipc/devman.h>
     39#include <usb/usb.h>
     40#include <ddf/driver.h>
     41#include <fibril_synch.h>
     42
     43#include <usb/hub.h>
     44
     45#include <usb/pipes.h>
     46#include <usb/devdrv.h>
     47
     48/** Information about single port on a hub. */
     49typedef struct {
     50        /** Mutex needed by CV for checking port reset. */
     51        fibril_mutex_t reset_mutex;
     52        /** CV for waiting to port reset completion. */
     53        fibril_condvar_t reset_cv;
     54        /** Whether port reset is completed.
     55         * Guarded by @c reset_mutex.
     56         */
     57        bool reset_completed;
     58
     59        /** Information about attached device. */
     60        usb_hc_attached_device_t attached_device;
     61} usb_hub_port_t;
     62
     63/** Initialize hub port information.
     64 *
     65 * @param port Port to be initialized.
     66 */
     67static inline void usb_hub_port_init(usb_hub_port_t *port) {
     68        port->attached_device.address = -1;
     69        port->attached_device.handle = 0;
     70        fibril_mutex_initialize(&port->reset_mutex);
     71        fibril_condvar_initialize(&port->reset_cv);
     72}
     73
     74bool hub_port_changes_callback(usb_device_t *, uint8_t *, size_t, void *);
    3775
    3876
    39 usb_general_list_t * usb_lst_create(void) {
    40         usb_general_list_t* result = usb_new(usb_general_list_t);
    41         usb_lst_init(result);
    42         return result;
    43 }
    44 
    45 void usb_lst_init(usb_general_list_t * lst) {
    46         lst->prev = lst;
    47         lst->next = lst;
    48         lst->data = NULL;
    49 }
    50 
    51 void usb_lst_prepend(usb_general_list_t* item, void* data) {
    52         usb_general_list_t* appended = usb_new(usb_general_list_t);
    53         appended->data = data;
    54         appended->next = item;
    55         appended->prev = item->prev;
    56         item->prev->next = appended;
    57         item->prev = appended;
    58 }
    59 
    60 void usb_lst_append(usb_general_list_t* item, void* data) {
    61         usb_general_list_t* appended = usb_new(usb_general_list_t);
    62         appended->data = data;
    63         appended->next = item->next;
    64         appended->prev = item;
    65         item->next->prev = appended;
    66         item->next = appended;
    67 }
    68 
    69 void usb_lst_remove(usb_general_list_t* item) {
    70         item->next->prev = item->prev;
    71         item->prev->next = item->next;
    72 }
    73 
    74 
    75 
     77#endif
    7678/**
    7779 * @}
    7880 */
    79 
    80 
  • uspace/drv/usbhub/usbhub.c

    r049eb87 rfd3940c1  
    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                 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 }
    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
     
    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  */
    407 static 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  */
    451 static 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 /**
    533402 * routine called when a device on port has been removed
    534403 *
     
    539408 * @param port port number, starting from 1
    540409 */
    541 static void usb_hub_removed_device(
     410void usb_hub_removed_device(
    542411    usb_hub_info_t * hub,uint16_t port) {
    543412
     
    552421       
    553422        //close address
    554         if(hub->attached_devs[port].address!=0){
     423        if(hub->ports[port].attached_device.address >= 0){
    555424                /*uncomment this code to use it when DDF allows device removal
    556425                opResult = usb_hc_unregister_device(
     
    579448 * @param port port number, starting from 1
    580449 */
    581 static void usb_hub_over_current( usb_hub_info_t * hub,
     450void usb_hub_over_current( usb_hub_info_t * hub,
    582451                uint16_t port){
    583452        int opResult;
     
    590459}
    591460
    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  */
    599 static 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  */
    677 int 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 
    741461
    742462/**
  • uspace/drv/usbhub/usbhub.h

    r049eb87 rfd3940c1  
    4747#include <usb/devdrv.h>
    4848
     49#include "ports.h"
     50
     51
    4952
    5053/** Information about attached hub. */
    5154typedef struct {
    5255        /** Number of ports. */
    53         int port_count;
     56        size_t port_count;
    5457
    55         /** attached device handles, for each port one */
    56         usb_hc_attached_device_t * attached_devs;
     58        /** Ports. */
     59        usb_hub_port_t *ports;
    5760       
    5861        /** connection to hcd */
     
    100103int usb_hub_check_hub_changes(usb_hub_info_t * hub_info_param);
    101104
     105void usb_hub_removed_device(usb_hub_info_t *, uint16_t);
     106void usb_hub_over_current(usb_hub_info_t *, uint16_t);
    102107
    103108int usb_hub_add_device(usb_device_t * usb_dev);
  • uspace/drv/usbhub/usbhub_private.h

    r049eb87 rfd3940c1  
    3838
    3939#include "usbhub.h"
    40 #include "usblist.h"
    4140
    4241#include <adt/list.h>
  • uspace/lib/usb/src/host/usb_endpoint_manager.c

    r049eb87 rfd3940c1  
    9191    size_t size, size_t max_packet_size)
    9292{
     93        /* We care about bandwidth only for interrupt and isochronous. */
     94        if ((type != USB_TRANSFER_INTERRUPT)
     95            && (type != USB_TRANSFER_ISOCHRONOUS)) {
     96                return 0;
     97        }
     98
    9399        const unsigned packet_count =
    94100            (size + max_packet_size - 1) / max_packet_size;
  • uspace/lib/usb/src/hub.c

    r049eb87 rfd3940c1  
    142142            DEV_IFACE_ID(USBHC_DEV_IFACE),
    143143            IPC_M_USBHC_RELEASE_ADDRESS, address);
     144}
     145
     146static void unregister_control_endpoint_on_default_address(
     147    usb_hc_connection_t *connection)
     148{
     149        usb_device_connection_t dev_conn;
     150        int rc = usb_device_connection_initialize_on_default_address(&dev_conn,
     151            connection);
     152        if (rc != EOK) {
     153                return;
     154        }
     155
     156        usb_pipe_t ctrl_pipe;
     157        rc = usb_pipe_initialize_default_control(&ctrl_pipe, &dev_conn);
     158        if (rc != EOK) {
     159                return;
     160        }
     161
     162        usb_pipe_unregister(&ctrl_pipe, connection);
    144163}
    145164
     
    235254                goto leave_release_default_address;
    236255        }
     256
     257        /* Before sending any traffic, we need to register this
     258         * endpoint.
     259         */
     260        rc = usb_pipe_register(&ctrl_pipe, 0, connection);
     261        if (rc != EOK) {
     262                rc = EREFUSED;
     263                goto leave_release_default_address;
     264        }
    237265        rc = usb_pipe_probe_default_control(&ctrl_pipe);
    238266        if (rc != EOK) {
     
    244272        if (rc != EOK) {
    245273                rc = ENOTCONN;
    246                 goto leave_release_default_address;
     274                goto leave_unregister_endpoint;
    247275        }
    248276
     
    256284
    257285        /*
     286         * Register the control endpoint for the new device.
     287         */
     288        rc = usb_pipe_register(&ctrl_pipe, 0, connection);
     289        if (rc != EOK) {
     290                rc = EREFUSED;
     291                goto leave_unregister_endpoint;
     292        }
     293
     294        /*
     295         * Release the original endpoint.
     296         */
     297        unregister_control_endpoint_on_default_address(connection);
     298
     299        /*
    258300         * Once the address is changed, we can return the default address.
    259301         */
    260302        usb_hc_release_default_address(connection);
     303
    261304
    262305        /*
     
    273316        }
    274317
     318
     319
    275320        /*
    276321         * And now inform the host controller about the handle.
     
    308353        usb_pipe_end_session(&ctrl_pipe);
    309354
     355leave_unregister_endpoint:
     356        usb_pipe_unregister(&ctrl_pipe, connection);
     357
    310358leave_release_default_address:
    311359        usb_hc_release_default_address(connection);
Note: See TracChangeset for help on using the changeset viewer.