Contiki 2.5
rndis_task.c
Go to the documentation of this file.
1 /* This file has been prepared for Doxygen automatic documentation generation.*/
2 /*! \file rndis_task.c *********************************************************
3  *
4  * \brief
5  * Manages the RNDIS Dataclass for the USB Device
6  *
7  * \addtogroup usbstick
8  *
9  * \author
10  * Colin O'Flynn <coflynn@newae.com>
11  *
12  ******************************************************************************/
13 /* Copyright (c) 2008 ATMEL Corporation
14  All rights reserved.
15 
16  Redistribution and use in source and binary forms, with or without
17  modification, are permitted provided that the following conditions are met:
18 
19  * Redistributions of source code must retain the above copyright
20  notice, this list of conditions and the following disclaimer.
21  * Redistributions in binary form must reproduce the above copyright
22  notice, this list of conditions and the following disclaimer in
23  the documentation and/or other materials provided with the
24  distribution.
25  * Neither the name of the copyright holders nor the names of
26  contributors may be used to endorse or promote products derived
27  from this software without specific prior written permission.
28 
29  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
30  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
33  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39  POSSIBILITY OF SUCH DAMAGE.
40 */
41 /**
42  \addtogroup RNDIS
43  @{
44  */
45 
46 //_____ I N C L U D E S ___________________________________________________
47 
48 
49 #include "contiki.h"
50 #include "usb_drv.h"
51 #include "usb_descriptors.h"
52 #include "usb_specific_request.h"
53 #include "rndis/rndis_task.h"
54 #include "rndis/rndis_protocol.h"
55 #if RF230BB
56 #include "rf230bb.h"
57 #endif
58 #include "uip.h"
59 #include "sicslow_ethernet.h"
60 #include <stdio.h>
61 
62 #include <avr/pgmspace.h>
63 #include <util/delay.h>
64 #include "watchdog.h"
65 
66 #include "rndis/cdc_ecm.h"
67 #include "rndis/cdc_eem.h"
68 
69 #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
70 #define PRINTF printf
71 #define PRINTF_P printf_P
72 
73 //_____ M A C R O S ________________________________________________________
74 
75 
76 
77 
78 
79 //_____ D E F I N I T I O N S ______________________________________________
80 
81 
82 #define IAD_TIMEOUT_DETACH 400
83 #define IAD_TIMEOUT_ATTACH 800
84 
85 #define RNDIS_TIMEOUT_DETACH 900
86 #define RNDIS_TIMEOUT_ATTACH 1000
87 
88 #define PBUF ((rndis_data_packet_t *) usb_eth_data_buffer)
89 
90 //! Temp data buffer when adding RNDIS headers
91 uint8_t usb_eth_data_buffer[64];
92 
93 uint64_t usb_ethernet_addr = 0x010000000002ULL;
94 
95 //_____ D E C L A R A T I O N S ____________________________________________
96 
97 
98 //! Timers for LEDs
99 uint8_t led1_timer, led2_timer;
100 
101 uint8_t usb_eth_is_active = 1;
102 
103 
104 uint8_t usb_eth_packet_is_available() {
105  Usb_select_endpoint(RX_EP);
106  return Is_usb_read_enabled();
107 }
108 
109 
110 uint8_t usb_eth_ready_for_next_packet() {
111 #ifdef USB_ETH_HOOK_IS_READY_FOR_INBOUND_PACKET
112  return USB_ETH_HOOK_IS_READY_FOR_INBOUND_PACKET();
113 #else
114  return 1;
115 #endif
116 
117  return 1;
118 }
119 
120 void rxtx_led_update(void)
121 {
122  // turn off LED's if necessary
123  if (led1_timer) {
124  led1_timer--;
125  if(led1_timer&(1<<2))
126  Led1_on();
127  else
128  Led1_off();
129  }
130  else
131  Led1_off();
132 
133  if (led2_timer) {
134  led2_timer--;
135  if(led2_timer&(1<<2))
136  Led2_on();
137  else
138  Led2_off();
139  }
140  else
141  Led2_off();
142 }
143 
144 /**
145  @brief This will enable the RX_START LED for a period
146 */
147 void rx_start_led(void)
148 {
149  led1_timer|=(1<<3);
150  if(((led1_timer-1)&(1<<2)))
151  Led1_on();
152 }
153 
154 /**
155  @brief This will enable the TRX_END LED for a period
156 */
157 void tx_end_led(void)
158 {
159  led2_timer|=(1<<3);
160  if(((led2_timer-1)&(1<<2)))
161  Led1_on();
162 }
163 
164 #if USB_ETH_CONF_MASS_STORAGE_FALLBACK
165 static void
166 usb_eth_setup_timeout_fallback_check() {
167  extern uint8_t fingerPresent;
168  /* Device is Enumerated but RNDIS not loading. We might
169  have a system that does not support IAD (winXP). If so
170  count the timeout then switch to just network interface. */
171  static uint16_t iad_fail_timeout, rndis_fail_timeout;
172  if (usb_mode == rndis_debug) {
173  //If we have timed out, detach
174  if (iad_fail_timeout == IAD_TIMEOUT_DETACH) {
175 
176  //Failed - BUT we are using "reverse logic", hence we force device
177  //into this mode. This is used to allow Windows Vista have time to
178  //install the drivers
179  if (fingerPresent && (rndis_state != rndis_data_initialized) && Is_device_enumerated() ) {
180  iad_fail_timeout = 0;
181  } else {
182  stdout = NULL;
183  Usb_detach();
184  doInit = 1; //Also mark system as needing intilizing
185  }
186 
187  //Then wait a few before re-attaching
188  } else if (iad_fail_timeout == IAD_TIMEOUT_ATTACH) {
189 
190  if (fingerPresent) {
191  usb_mode = mass_storage;
192  } else {
193  usb_mode = rndis_only;
194  }
195  Usb_attach();
196  }
197 
198  //Increment timeout when device is not initializing, OR we have already detached,
199  //OR the user had their finger on the device, indicating a reverse of logic
200  if ( ( (rndis_state != rndis_data_initialized) && Is_device_enumerated() ) ||
201  (iad_fail_timeout > IAD_TIMEOUT_DETACH) ||
202  (fingerPresent) ) {
203  iad_fail_timeout++;
204  } else {
205  iad_fail_timeout = 0;
206  }
207  } //usb_mode == rndis_debug
208 
209 
210  /* Device is Enumerated but RNDIS STIL not loading. We just
211  have RNDIS interface, so obviously no drivers on target.
212  Just go ahead and mount ourselves as mass storage... */
213  if (usb_mode == rndis_only) {
214  //If we have timed out, detach
215  if (rndis_fail_timeout == RNDIS_TIMEOUT_DETACH) {
216  Usb_detach();
217  //Then wait a few before re-attaching
218  } else if (rndis_fail_timeout == RNDIS_TIMEOUT_ATTACH) {
219  usb_mode = mass_storage;
220  Usb_attach();
221  }
222 
223  //Increment timeout when device is not initializing, OR we are already
224  //counting to detach
225  if ( ( (rndis_state != rndis_data_initialized)) ||
226  (rndis_fail_timeout > RNDIS_TIMEOUT_DETACH) ) {
227  rndis_fail_timeout++;
228  } else {
229  rndis_fail_timeout = 0;
230  }
231  }//usb_mode == rnids_only
232 }
233 #endif
234 
235 PROCESS(usb_eth_process, "USB Ethernet process");
236 
237 /**
238  * \brief RNDIS Process
239  *
240  * This is the link between USB and the "good stuff". In this routine data
241  * is received and processed by RNDIS, CDC-ECM, or CDC-EEM
242  */
243 PROCESS_THREAD(usb_eth_process, ev, data_proc)
244 {
245  static struct etimer et;
246 
247  PROCESS_BEGIN();
248 
249  while(1) {
250  rxtx_led_update();
251 
252 #if USB_ETH_CONF_MASS_STORAGE_FALLBACK
253  usb_eth_setup_timeout_fallback_check();
254 #endif
255 
256  switch(usb_configuration_nb) {
257  case USB_CONFIG_RNDIS_DEBUG:
258  case USB_CONFIG_RNDIS:
259  if(Is_device_enumerated()) {
260  if(rndis_process()) {
261  etimer_set(&et, CLOCK_SECOND/80);
262  } else {
263  Led0_toggle();
264  etimer_set(&et, CLOCK_SECOND/8);
265  }
266  }
267  break;
268  case USB_CONFIG_EEM:
270  cdc_eem_process();
271  etimer_set(&et, CLOCK_SECOND/80);
272  break;
273  case USB_CONFIG_ECM:
274  case USB_CONFIG_ECM_DEBUG:
275  if(Is_device_enumerated()) {
276  if(cdc_ecm_process()) {
277  etimer_set(&et, CLOCK_SECOND/80);
278  } else {
279  Led0_toggle();
280  etimer_set(&et, CLOCK_SECOND/8);
281  }
282  }
283  break;
284  default:
285  Led0_toggle();
286  etimer_set(&et, CLOCK_SECOND/4);
287  break;
288  }
289 
290 
291  PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)||(usb_eth_packet_is_available()&&usb_eth_ready_for_next_packet()));
292  } // while(1)
293 
294  PROCESS_END();
295 }
296 
297 /**
298  \brief Sends a single ethernet frame over USB using appropriate low-level protocol (EEM or RNDIS)
299  \param senddata Data to send
300  \param sendlen Length of data to send
301  \param led Should the LED be light up for this frame?
302  */
303 uint8_t usb_eth_send(uint8_t * senddata, uint16_t sendlen, uint8_t led)
304 {
305  uint8_t ret = 0;
306 
307  if(!usb_eth_is_active) {
308  USB_ETH_HOOK_TX_ERROR("Inactive");
309  goto bail;
310  }
311 
312  //Check device is set up
313  if (Is_device_enumerated() == 0) {
314  USB_ETH_HOOK_TX_ERROR("Device not enumerated");
315  goto bail;
316  }
317 
318  switch(usb_configuration_nb) {
319  case USB_CONFIG_RNDIS_DEBUG:
320  case USB_CONFIG_RNDIS:
321  ret = rndis_send(senddata, sendlen, led);
322  break;
323  case USB_CONFIG_EEM:
324  ret = eem_send(senddata, sendlen, led);
325  break;
326  case USB_CONFIG_ECM:
327  case USB_CONFIG_ECM_DEBUG:
328  ret = ecm_send(senddata, sendlen, led);
329  break;
330  }
331 
332 bail:
333 
334  if(!ret) // Hit the watchdog if we have a successful send.
335  watchdog_periodic();
336 
337  return ret;
338 }
339 
340 uint8_t
341 usb_eth_set_active(uint8_t active) {
342  if(usb_eth_is_active!=active) {
343  switch(usb_configuration_nb) {
344  case USB_CONFIG_RNDIS_DEBUG:
345  case USB_CONFIG_RNDIS:
346  usb_eth_is_active = active;
348  break;
349  case USB_CONFIG_EEM:
350  break;
351  case USB_CONFIG_ECM:
352  case USB_CONFIG_ECM_DEBUG:
353  cdc_ecm_set_active(active);
354  usb_eth_is_active = active;
355  break;
356  }
357  }
358  return 0;
359 }
360 
361 void
362 usb_eth_get_mac_address(uint8_t dest[6]) {
363  memcpy(dest,&usb_ethernet_addr,6);
364 }
365 
366 void
367 usb_eth_set_mac_address(const uint8_t src[6]) {
368  memcpy(&usb_ethernet_addr,src,6);
369 }
370 
371 /** @} */