usb_host_hub.c

Go to the documentation of this file.
00001 /*This file has been prepared for Doxygen automatic documentation generation.*/
00013 
00014 /* Copyright (c) 2007, Atmel Corporation All rights reserved.
00015  *
00016  * Redistribution and use in source and binary forms, with or without
00017  * modification, are permitted provided that the following conditions are met:
00018  *
00019  * 1. Redistributions of source code must retain the above copyright notice,
00020  * this list of conditions and the following disclaimer.
00021  *
00022  * 2. Redistributions in binary form must reproduce the above copyright notice,
00023  * this list of conditions and the following disclaimer in the documentation
00024  * and/or other materials provided with the distribution.
00025  *
00026  * 3. The name of ATMEL may not be used to endorse or promote products derived
00027  * from this software without specific prior written permission.
00028  *
00029  * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
00030  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00031  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY AND
00032  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
00033  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00034  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00035  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00036  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00037  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00038  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00039  */
00040 
00041 //_____  I N C L U D E S ___________________________________________________
00042 
00043 
00044 #include "config.h"
00045 #include "conf_usb.h"
00046 #include "usb_host_hub.h"
00047 #include "modules/usb/host_chap9/usb_host_task.h"
00048 #include "modules/usb/host_chap9/usb_host_enum.h"
00049 #include "modules/usb/host_chap9/usb_host_hub.h"
00050 #include "lib_mcu/usb/usb_drv.h"
00051 
00052 
00053 #if (USB_HUB_SUPPORT == ENABLE)
00054 
00055 #ifndef HUB_MAX_NB_PORT
00056 #warning Using default value for HUB_MAX_NB_PORT
00057    #define HUB_MAX_NB_PORT   4
00058 #endif
00059 
00060 //_____ M A C R O S ________________________________________________________
00061 
00062 //_____ D E F I N I T I O N S ______________________________________________
00063 
00064 //_____ D E C L A R A T I O N S ____________________________________________
00065 
00066 
00068 U8 hub_port_state[USB_MAX_HUB_NUMBER][HUB_MAX_NB_PORT];
00069 
00071 U8 hub_device_address[USB_MAX_HUB_NUMBER];
00072 
00074 U8 f_hub_port_disconnect=FALSE;
00075 
00077 U8 nb_hub_present;
00078 
00079 
00088 void hub_init(U8 hub_number)
00089 {
00090    U8 i;
00091 
00092    for(i=0;i<HUB_MAX_NB_PORT;i++)
00093    {
00094       hub_port_state[hub_number][i]=HUB_DEVICE_POWERED;
00095    }
00096 }
00097 
00098 
00099 
00108 U32 get_port_status(U8 port_number)
00109 {
00110    U32 to_return;
00111    
00112    Get_port_status(port_number);
00113    LSB3(to_return)=data_stage[3];
00114    LSB2(to_return)=data_stage[2];
00115    LSB1(to_return)=data_stage[1];
00116    LSB0(to_return)=data_stage[0];
00117    return to_return;
00118 }
00119 
00120 
00121 
00134 void hub_manage_port_change_status(U8 port_change_status, U8 hub_number)
00135 {
00136    U8 i,c;
00137    U32 port_status;
00138    U8 port_addr_0_in_use=0;
00139    
00140    // There should be one and only one device on the bus responding to device address 0
00141    // Look in the hub_port_state state machine if one device is currently using this address
00142    // If another hub is currently using address zero, the function returns imediately
00143    for(i=0;i<USB_MAX_HUB_NUMBER;i++)
00144    {
00145       for(c=1;c<=HUB_MAX_NB_PORT;c++)
00146       {
00147          if((hub_port_state[i][c-1] != HUB_DEVICE_POWERED) && (hub_port_state[i][c-1] != HUB_DEVICE_READY))
00148          {
00149             //Found one port with one device using the address 0
00150             // memorize this port number
00151             if(i!=(hub_number-1)) 
00152             {  return; } //Other hub currently using address zero
00153             // ok the hub using the device address zero is the hub that currently generates the event (port_change_status)
00154             port_addr_0_in_use=c; 
00155             break;        
00156          }
00157       }
00158    }
00159    
00160    // For all ports 
00161    for(c=1;c<=HUB_MAX_NB_PORT;c++)
00162    {
00163       // One device connected to one port is using device address zero
00164       // Skip all other port activity management
00165       if((port_addr_0_in_use!=0) && (c!=port_addr_0_in_use) )
00166       {
00167          continue;
00168       }
00169       
00170       // Does this port generates port change status ?
00171       if(port_change_status & (1<<c))
00172       {
00173          // Get port status bytes
00174          port_status=get_port_status(c);
00175          // For each port event, send this event to the function that manage the 
00176          // state of the device connected to the hub port
00177          if( port_status & ((U32)1<<C_PORT_CONNECTION))
00178          {
00179             Clear_port_feature(C_PORT_CONNECTION,c);
00180             if(port_status&((U32)1<<PORT_CONNECTION))
00181             {
00182                // Port connection low speed -> Unsupported (no PRE token in current OTG interface implementation)
00183                if(port_status&((U32)1<<PORT_LOW_SPEED))
00184                {
00185 
00186                }
00187                else // Port Connection full speed : OK
00188                {
00189                   enumerate_hub_port_device(c,HUB_PORT_CONNECTION,hub_number);
00190                }
00191             }
00192             else
00193             {
00194                // Port disconnection
00195                enumerate_hub_port_device(c,HUB_PORT_DISCONNECT,hub_number);
00196             }
00197          }
00198          else if( port_status & ((U32)1<<C_PORT_SUSPEND))
00199          {
00200             // Port Suspend state
00201             Clear_port_feature(C_PORT_SUSPEND,c);
00202          }
00203          else if( port_status & ((U32)1<<C_PORT_RESET))
00204          {
00205             // Port Reset sent
00206             Clear_port_feature(C_PORT_RESET,c);
00207             enumerate_hub_port_device(c,HUB_PORT_RESET,hub_number);            
00208          }
00209       }
00210 
00211       // Previous port using device address zero abort all port device management  
00212       // (There should be one and only device with adddress zero on the USB tree)
00213       if((hub_port_state[hub_number-1][c-1] != HUB_DEVICE_POWERED) && (hub_port_state[hub_number-1][c-1] != HUB_DEVICE_READY))
00214       {
00215          break;  // Break port loop and exit from function      
00216       }
00217    }
00218 }
00219 
00229 void enumerate_hub_port_device(U8 hub_port, U8 port_ev, U8 hub_number)
00230 {
00231    U8 device_index=0;
00232    U8 hub_device_index=0;
00233    U8 nb_port,c;
00234    
00235    // Find the device index of the hub_number
00236    for(c=0;c<MAX_DEVICE_IN_USB_TREE;c++)
00237    {
00238       if(usb_tree.device[c].device_address==hub_device_address[hub_number-1])
00239       {
00240          hub_device_index=c;         
00241       }
00242    }
00243    
00244    // Find the device index in linked to the specified hub port    
00245    // -> look in the usb_tree structure
00246    for(c=0;c<MAX_DEVICE_IN_USB_TREE;c++)
00247    {
00248       if((usb_tree.device[c].hub_port_nb == hub_port) && (usb_tree.device[c].parent_hub_number==hub_number))
00249       {
00250          device_index=c;
00251          break;
00252       }
00253    }
00254 
00255    // Port disconnection detected -> delete device entry and RAZ state machine
00256    // and return ...
00257    if(port_ev==HUB_PORT_DISCONNECT)
00258    {
00259       remove_device_entry(device_index);  // Remove device entry in usb tree
00260       usb_tree.nb_device--; 
00261       hub_port_state[hub_number-1][hub_port-1]=HUB_DEVICE_POWERED; // RAZ state machine 
00262       f_hub_port_disconnect = TRUE;   // Flag for device disconnection signaling
00263       return;
00264    }
00265    
00266    // Device enumeration state machine for hub port
00267    switch(hub_port_state[hub_number-1][hub_port-1])
00268    {
00269       // New device connection
00270       // -> Generate first USB reset for the device
00271       case HUB_DEVICE_POWERED:
00272          if(port_ev==HUB_PORT_CONNECTION)
00273          {
00274             device_index=usb_tree.nb_device++;
00275             usb_tree.device[device_index].hub_port_nb=hub_port;
00276             usb_tree.device[device_index].parent_hub_number=hub_number;
00277             Host_select_device(hub_device_index);
00278             Set_port_reset(hub_port);
00279             hub_port_state[hub_number-1][hub_port-1]=HUB_DEVICE_WAIT_RST_1;
00280          }
00281          break;
00282          
00283       // Wait First reset successfully generated then:
00284       // -> Get device descriptor to get endpoint zero lenght
00285       // -> Generate second USB reset for the device
00286       case HUB_DEVICE_WAIT_RST_1:
00287          if(port_ev==HUB_PORT_RESET)
00288          {
00289             c = 0;
00290             while (c<250)               // wait 250ms after USB reset
00291             {
00292                if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); c++; }// Count Start Of frame
00293                if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) 
00294                {hub_port_state[hub_number-1][hub_port-1]=HUB_DEVICE_POWERED; return;}
00295             }
00296             Host_select_device(device_index);
00297             // By default assumes its ctrl endpoint is 8 bytes only
00298             usb_tree.device[device_index].ep_ctrl_size=8;
00299             // Get its device descriptor to get ctrl endpoint size 
00300             if( CONTROL_GOOD == host_get_device_descriptor_uncomplete())
00301             {
00302                Host_select_device(hub_device_index);
00303                usb_tree.device[device_index].ep_ctrl_size=data_stage[OFFSET_FIELD_MAXPACKETSIZE];
00304                Set_port_reset(hub_port);         // Second USB reset
00305                hub_port_state[hub_number-1][hub_port-1]=HUB_DEVICE_WAIT_RST_2;
00306             }
00307          }
00308          break;
00309 
00310       // Wait Second USB reset successfully generated then:
00311       // -> Enumerate the new device
00312       case HUB_DEVICE_WAIT_RST_2:
00313          if(port_ev==HUB_PORT_RESET)
00314          {
00315             c = 0;
00316             while (c<250)               // wait 250ms after USB reset
00317             {
00318                if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); c++; }// Count Start Of frame
00319                if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) 
00320                {hub_port_state[hub_number-1][hub_port-1]=HUB_DEVICE_POWERED; return;}
00321             }
00322             // Select this new device
00323             Host_select_device(device_index);
00324 
00325             // Give an absolute device address
00326             host_set_address(DEVICE_BASE_ADDRESS+device_index);
00327             usb_tree.device[+device_index].device_address=DEVICE_BASE_ADDRESS+device_index;
00328 
00329             // Select this new address
00330             Host_select_device(device_index); 
00331 
00332             // Get the device descriptor 
00333             if (CONTROL_GOOD == host_get_device_descriptor())
00334             {
00335                // Check if the device connected belongs to the supported devices table
00336                if (HOST_TRUE == host_check_VID_PID())
00337                {
00338                   Host_set_device_supported();
00339                   Host_device_supported_action();
00340                }
00341                else
00342                {
00343                #if (HOST_STRICT_VID_PID_TABLE==ENABLE)
00344                   Host_device_not_supported_action();
00345                   return
00346                #endif
00347                }
00348                // Get Confiuration descriptor
00349                if (CONTROL_GOOD == host_get_configuration_descriptor())
00350                {
00351                   if (HOST_FALSE != host_check_class()) // Class support OK?
00352                   {
00353                   #if (HOST_AUTO_CFG_ENDPOINT==ENABLE)
00354                      if (host_auto_configure_endpoint())
00355                   #else
00356                      if(User_configure_endpoint()) // User call here instead of autoconfig
00357                   #endif
00358                      {
00359                         if (CONTROL_GOOD == host_set_configuration(1))  // Send Set_configuration
00360                         {
00361                            hub_port_state[hub_number-1][hub_port-1] = HUB_DEVICE_READY;
00362                             // Check if the connected device is a HUB
00363                            if(Get_class(0)==HUB_CLASS )
00364                            {
00365                                  // Get hub descriptor
00366                                  if( Get_hub_descriptor()==CONTROL_GOOD)
00367                                  {
00368                                     // Power each port of the hub
00369                                     nb_port=data_stage[NB_PORT_OFFSET];
00370                                     for(c=1;c<=nb_port;c++)
00371                                     {
00372                                        Set_port_feature(PORT_POWER,c);
00373                                     }
00374                                     nb_hub_present++;
00375                                     hub_init(nb_hub_present-1);
00376                                     hub_device_address[nb_hub_present-1]=usb_tree.device[device_index].device_address;
00377                                  }
00378                            }
00379                            else // New device is not a hub -> Signals device connection
00380                            {
00381                               new_device_connected=TRUE;
00382                            }
00383                         }
00384                      }
00385                   }
00386                }
00387             }
00388          }
00389          break;
00390          
00391       case HUB_DEVICE_READY:
00392          break;
00393       default:
00394          break;
00395    }
00396 }
00397 
00398 
00399 #endif

Generated on Fri May 15 15:41:36 2009 for ATMEL by  doxygen 1.5.3