Contiki 2.6
|
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 /** @} */