Contiki 2.6

rndis_task.c

Go to the documentation of this file.
00001 /* This file has been prepared for Doxygen automatic documentation generation.*/
00002 /*! \file rndis_task.c *********************************************************
00003  *
00004  * \brief
00005  *      Manages the RNDIS Dataclass for the USB Device
00006  *
00007  * \addtogroup usbstick
00008  *
00009  * \author
00010  *        Colin O'Flynn <coflynn@newae.com>
00011  *
00012  ******************************************************************************/
00013 /* Copyright (c) 2008  ATMEL Corporation
00014    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    * Redistributions of source code must retain the above copyright
00020      notice, this list of conditions and the following disclaimer.
00021    * Redistributions in binary form must reproduce the above copyright
00022      notice, this list of conditions and the following disclaimer in
00023      the documentation and/or other materials provided with the
00024      distribution.
00025    * Neither the name of the copyright holders nor the names of
00026      contributors may be used to endorse or promote products derived
00027      from this software without specific prior written permission.
00028 
00029   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00030   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00031   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00032   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00033   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00034   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00035   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00036   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00037   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00038   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00039   POSSIBILITY OF SUCH DAMAGE.
00040 */
00041 /**
00042  \addtogroup RNDIS
00043  @{
00044  */
00045 
00046 //_____  I N C L U D E S ___________________________________________________
00047 
00048 
00049 #include "contiki.h"
00050 #include "usb_drv.h"
00051 #include "usb_descriptors.h"
00052 #include "usb_specific_request.h"
00053 #include "rndis/rndis_task.h"
00054 #include "rndis/rndis_protocol.h"
00055 #if RF230BB
00056 #include "rf230bb.h"
00057 #endif
00058 #include "uip.h"
00059 #include "sicslow_ethernet.h"
00060 #include <stdio.h>
00061 
00062 #include <avr/pgmspace.h>
00063 #include <util/delay.h>
00064 #include "watchdog.h"
00065 
00066 #include "rndis/cdc_ecm.h"
00067 #include "rndis/cdc_eem.h"
00068 
00069 #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
00070 #define PRINTF printf
00071 #define PRINTF_P printf_P
00072 
00073 //_____ M A C R O S ________________________________________________________
00074 
00075 
00076 
00077 
00078 
00079 //_____ D E F I N I T I O N S ______________________________________________
00080 
00081 
00082 #define IAD_TIMEOUT_DETACH 400
00083 #define IAD_TIMEOUT_ATTACH 800
00084 
00085 #define RNDIS_TIMEOUT_DETACH 900
00086 #define RNDIS_TIMEOUT_ATTACH 1000
00087 
00088 #define PBUF ((rndis_data_packet_t *) usb_eth_data_buffer)
00089 
00090 //! Temp data buffer when adding RNDIS headers
00091 uint8_t usb_eth_data_buffer[64];
00092 
00093 uint64_t usb_ethernet_addr = 0x010000000002ULL;
00094 
00095 //_____ D E C L A R A T I O N S ____________________________________________
00096 
00097 
00098 //! Timers for LEDs
00099 uint8_t led1_timer, led2_timer;
00100 
00101 uint8_t usb_eth_is_active = 1;
00102 
00103 
00104 uint8_t usb_eth_packet_is_available() {
00105         Usb_select_endpoint(RX_EP);
00106         return Is_usb_read_enabled();
00107 }
00108 
00109 
00110 uint8_t usb_eth_ready_for_next_packet() {
00111 #ifdef USB_ETH_HOOK_IS_READY_FOR_INBOUND_PACKET
00112         return USB_ETH_HOOK_IS_READY_FOR_INBOUND_PACKET();
00113 #else
00114         return 1;
00115 #endif
00116 
00117         return 1;
00118 }
00119 
00120 void rxtx_led_update(void)
00121 {
00122         // turn off LED's if necessary
00123         if (led1_timer) {
00124                 led1_timer--;
00125                 if(led1_timer&(1<<2))
00126                         Led1_on();
00127                 else
00128                         Led1_off();
00129         }
00130         else
00131                 Led1_off();
00132 
00133         if (led2_timer) {
00134                 led2_timer--;
00135                 if(led2_timer&(1<<2))
00136                         Led2_on();
00137                 else
00138                         Led2_off();
00139         }
00140         else
00141                 Led2_off();
00142 }
00143 
00144 /**
00145     @brief This will enable the RX_START LED for a period
00146 */
00147 void rx_start_led(void)
00148 {
00149         led1_timer|=(1<<3);
00150         if(((led1_timer-1)&(1<<2)))
00151                 Led1_on();
00152 }
00153 
00154 /**
00155     @brief This will enable the TRX_END LED for a period
00156 */
00157 void tx_end_led(void)
00158 {
00159         led2_timer|=(1<<3);
00160         if(((led2_timer-1)&(1<<2)))
00161                 Led1_on();
00162 }
00163 
00164 #if USB_ETH_CONF_MASS_STORAGE_FALLBACK
00165 static void
00166 usb_eth_setup_timeout_fallback_check() {
00167         extern uint8_t fingerPresent;
00168                 /* Device is Enumerated but RNDIS not loading. We might
00169                    have a system that does not support IAD (winXP). If so
00170                    count the timeout then switch to just network interface. */
00171         static uint16_t iad_fail_timeout, rndis_fail_timeout;   
00172         if (usb_mode == rndis_debug) {
00173                 //If we have timed out, detach
00174                 if (iad_fail_timeout == IAD_TIMEOUT_DETACH) {
00175                 
00176                         //Failed - BUT we are using "reverse logic", hence we force device
00177                         //into this mode. This is used to allow Windows Vista have time to
00178                         //install the drivers
00179                         if (fingerPresent && (rndis_state != rndis_data_initialized) && Is_device_enumerated() ) {
00180                                 iad_fail_timeout = 0;
00181                         } else {
00182                                         stdout = NULL;
00183                                         Usb_detach();
00184                                         doInit = 1; //Also mark system as needing intilizing
00185                         }
00186                         
00187                 //Then wait a few before re-attaching
00188                 } else if (iad_fail_timeout == IAD_TIMEOUT_ATTACH) {
00189                 
00190                         if (fingerPresent) {
00191                                 usb_mode = mass_storage;
00192                         } else {
00193                                 usb_mode = rndis_only;
00194                         }
00195                         Usb_attach();
00196                 }
00197 
00198                 //Increment timeout when device is not initializing, OR we have already detached,
00199                 //OR the user had their finger on the device, indicating a reverse of logic
00200                 if ( ( (rndis_state != rndis_data_initialized) && Is_device_enumerated() ) ||
00201                   (iad_fail_timeout > IAD_TIMEOUT_DETACH) || 
00202                    (fingerPresent) ) {
00203                         iad_fail_timeout++;
00204                 } else {        
00205                 iad_fail_timeout = 0;
00206                 }
00207         } //usb_mode == rndis_debug
00208 
00209 
00210          /* Device is Enumerated but RNDIS STIL not loading. We just
00211                 have RNDIS interface, so obviously no drivers on target.
00212                 Just go ahead and mount ourselves as mass storage... */
00213         if (usb_mode == rndis_only) {
00214                 //If we have timed out, detach
00215                 if (rndis_fail_timeout == RNDIS_TIMEOUT_DETACH) {
00216                         Usb_detach();
00217                 //Then wait a few before re-attaching
00218                 } else if (rndis_fail_timeout == RNDIS_TIMEOUT_ATTACH) {
00219                         usb_mode = mass_storage;
00220                         Usb_attach();
00221                 }
00222 
00223                 //Increment timeout when device is not initializing, OR we are already
00224                 //counting to detach
00225                 if ( ( (rndis_state != rndis_data_initialized)) ||
00226                   (rndis_fail_timeout > RNDIS_TIMEOUT_DETACH) ) {
00227                         rndis_fail_timeout++;
00228                 } else {        
00229                 rndis_fail_timeout = 0;
00230                 }
00231         }//usb_mode == rnids_only
00232 }
00233 #endif
00234 
00235 PROCESS(usb_eth_process, "USB Ethernet process");
00236 
00237 /**
00238  * \brief RNDIS Process
00239  *
00240  *   This is the link between USB and the "good stuff". In this routine data
00241  *   is received and processed by RNDIS, CDC-ECM, or CDC-EEM
00242  */
00243 PROCESS_THREAD(usb_eth_process, ev, data_proc)
00244 {
00245         static struct etimer et;
00246 
00247         PROCESS_BEGIN();
00248 
00249         while(1) {
00250                 rxtx_led_update();
00251 
00252 #if USB_ETH_CONF_MASS_STORAGE_FALLBACK
00253                 usb_eth_setup_timeout_fallback_check();
00254 #endif
00255                 
00256                 switch(usb_configuration_nb) {
00257                         case USB_CONFIG_RNDIS_DEBUG:
00258                         case USB_CONFIG_RNDIS:
00259                                 if(Is_device_enumerated()) {
00260                                         if(rndis_process()) {
00261                                                 etimer_set(&et, CLOCK_SECOND/80);
00262                                         } else {
00263                                                 Led0_toggle();
00264                                                 etimer_set(&et, CLOCK_SECOND/8);
00265                                         }
00266                                 }
00267                                 break;
00268                         case USB_CONFIG_EEM:
00269                                 if(Is_device_enumerated())
00270                                         cdc_eem_process();
00271                                 etimer_set(&et, CLOCK_SECOND/80);
00272                                 break;
00273                         case USB_CONFIG_ECM:
00274                         case USB_CONFIG_ECM_DEBUG:
00275                                 if(Is_device_enumerated()) {
00276                                         if(cdc_ecm_process()) {
00277                                                 etimer_set(&et, CLOCK_SECOND/80);
00278                                         } else {
00279                                                 Led0_toggle();
00280                                                 etimer_set(&et, CLOCK_SECOND/8);
00281                                         }
00282                                 }
00283                                 break;
00284                         default:
00285                                 Led0_toggle();
00286                                 etimer_set(&et, CLOCK_SECOND/4);
00287                                 break;
00288                 }
00289 
00290 
00291                 PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)||(usb_eth_packet_is_available()&&usb_eth_ready_for_next_packet()));
00292         } // while(1)
00293 
00294         PROCESS_END();
00295 }
00296 
00297 /**
00298  \brief Sends a single ethernet frame over USB using appropriate low-level protocol (EEM or RNDIS)
00299  \param senddata Data to send
00300  \param sendlen Length of data to send
00301  \param led Should the LED be light up for this frame?
00302  */
00303 uint8_t usb_eth_send(uint8_t * senddata, uint16_t sendlen, uint8_t led)
00304 {
00305         uint8_t ret = 0;
00306         
00307         if(!usb_eth_is_active) {
00308                 USB_ETH_HOOK_TX_ERROR("Inactive");
00309                 goto bail;
00310         }
00311 
00312         //Check device is set up
00313         if (Is_device_enumerated() == 0) {
00314                 USB_ETH_HOOK_TX_ERROR("Device not enumerated");
00315                 goto bail;
00316         }
00317 
00318         switch(usb_configuration_nb) {
00319                 case USB_CONFIG_RNDIS_DEBUG:
00320                 case USB_CONFIG_RNDIS:
00321                         ret = rndis_send(senddata, sendlen, led);
00322                         break;
00323                 case USB_CONFIG_EEM:
00324                         ret = eem_send(senddata, sendlen, led);
00325                         break;
00326                 case USB_CONFIG_ECM:
00327                 case USB_CONFIG_ECM_DEBUG:
00328                         ret = ecm_send(senddata, sendlen, led);
00329                         break;
00330         }
00331 
00332 bail:
00333 
00334         if(!ret) // Hit the watchdog if we have a successful send.
00335                 watchdog_periodic();
00336 
00337         return ret;
00338 }
00339 
00340 uint8_t
00341 usb_eth_set_active(uint8_t active) {
00342         if(usb_eth_is_active!=active) { 
00343                 switch(usb_configuration_nb) {
00344                         case USB_CONFIG_RNDIS_DEBUG:
00345                         case USB_CONFIG_RNDIS:
00346                                 usb_eth_is_active = active;
00347                                 rndis_send_interrupt();
00348                                 break;
00349                         case USB_CONFIG_EEM:
00350                                 break;
00351                         case USB_CONFIG_ECM:
00352                         case USB_CONFIG_ECM_DEBUG:
00353                                 cdc_ecm_set_active(active);
00354                                 usb_eth_is_active = active;
00355                                 break;
00356                 }
00357         }
00358         return 0;
00359 }
00360 
00361 void
00362 usb_eth_get_mac_address(uint8_t dest[6]) {
00363         memcpy(dest,&usb_ethernet_addr,6);
00364 }
00365 
00366 void
00367 usb_eth_set_mac_address(const uint8_t src[6]) {
00368         memcpy(&usb_ethernet_addr,src,6);
00369 }
00370 
00371 /** @}  */