Addition of USB files
This commit is contained in:
parent
a520fe4646
commit
219846f408
36 changed files with 11046 additions and 0 deletions
422
cpu/avr/dev/usb/rndis/rndis_task.c
Normal file
422
cpu/avr/dev/usb/rndis/rndis_task.c
Normal file
|
@ -0,0 +1,422 @@
|
|||
/* This file has been prepared for Doxygen automatic documentation generation.*/
|
||||
/*! \file rndis_task.c *********************************************************
|
||||
*
|
||||
* \brief
|
||||
* Manages the RNDIS Dataclass for the USB Device
|
||||
*
|
||||
* \addtogroup usbstick
|
||||
*
|
||||
* \author
|
||||
* Colin O'Flynn <coflynn@newae.com>
|
||||
*
|
||||
******************************************************************************/
|
||||
/* Copyright (c) 2008 ATMEL Corporation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
\addtogroup RNDIS
|
||||
@{
|
||||
*/
|
||||
|
||||
//_____ I N C L U D E S ___________________________________________________
|
||||
|
||||
|
||||
#include "contiki.h"
|
||||
#include "usb_drv.h"
|
||||
#include "usb_descriptors.h"
|
||||
#include "usb_specific_request.h"
|
||||
#include "rndis/rndis_task.h"
|
||||
#include "rndis/rndis_protocol.h"
|
||||
#include "uip.h"
|
||||
#include "sicslow_ethernet.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
|
||||
#define PRINTF printf
|
||||
#define PRINTF_P printf_P
|
||||
|
||||
//_____ M A C R O S ________________________________________________________
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//_____ D E F I N I T I O N S ______________________________________________
|
||||
|
||||
|
||||
#define IAD_TIMEOUT_DETACH 400
|
||||
#define IAD_TIMEOUT_ATTACH 800
|
||||
|
||||
#define RNDIS_TIMEOUT_DETACH 900
|
||||
#define RNDIS_TIMEOUT_ATTACH 1000
|
||||
|
||||
#define PBUF ((rndis_data_packet_t *) data_buffer)
|
||||
|
||||
//_____ D E C L A R A T I O N S ____________________________________________
|
||||
|
||||
|
||||
//! Timers for LEDs
|
||||
uint8_t led1_timer, led2_timer;
|
||||
|
||||
//! Temp data buffer when adding RNDIS headers
|
||||
uint8_t data_buffer[64];
|
||||
|
||||
//! Usb is busy with RNDIS
|
||||
char usb_busy = 0;
|
||||
|
||||
|
||||
static struct etimer et;
|
||||
static struct timer flood_timer;
|
||||
static uint16_t iad_fail_timeout, rndis_fail_timeout;
|
||||
|
||||
static uint8_t doInit = 1;
|
||||
|
||||
extern uint8_t fingerPresent;
|
||||
|
||||
PROCESS(rndis_process, "RNDIS process");
|
||||
|
||||
/**
|
||||
* \brief RNDIS Process
|
||||
*
|
||||
* This is the link between USB and the "good stuff". In this routine data
|
||||
* is received and processed by RNDIS
|
||||
*/
|
||||
PROCESS_THREAD(rndis_process, ev, data_proc)
|
||||
{
|
||||
|
||||
PROCESS_BEGIN();
|
||||
uint8_t bytecounter, headercounter;
|
||||
uint16_t i, dataoffset;
|
||||
|
||||
while(1) {
|
||||
|
||||
// turn off LED's if necessary
|
||||
if (led1_timer) led1_timer--;
|
||||
else Led1_off();
|
||||
if (led2_timer) led2_timer--;
|
||||
else Led2_off();
|
||||
|
||||
/* Device is Enumerated but RNDIS not loading. We might
|
||||
have a system that does not support IAD (winXP). If so
|
||||
count the timeout then switch to just network interface. */
|
||||
if (usb_mode == rndis_debug) {
|
||||
//If we have timed out, detach
|
||||
if (iad_fail_timeout == IAD_TIMEOUT_DETACH) {
|
||||
|
||||
//Failed - BUT we are using "reverse logic", hence we force device
|
||||
//into this mode. This is used to allow Windows Vista have time to
|
||||
//install the drivers
|
||||
if (fingerPresent && (rndis_state != rndis_data_initialized) && Is_device_enumerated() ) {
|
||||
iad_fail_timeout = 0;
|
||||
} else {
|
||||
stdout = NULL;
|
||||
Usb_detach();
|
||||
doInit = 1; //Also mark system as needing intilizing
|
||||
}
|
||||
|
||||
//Then wait a few before re-attaching
|
||||
} else if (iad_fail_timeout == IAD_TIMEOUT_ATTACH) {
|
||||
|
||||
if (fingerPresent) {
|
||||
usb_mode = mass_storage;
|
||||
} else {
|
||||
usb_mode = rndis_only;
|
||||
}
|
||||
Usb_attach();
|
||||
}
|
||||
|
||||
//Increment timeout when device is not initializing, OR we have already detached,
|
||||
//OR the user had their finger on the device, indicating a reverse of logic
|
||||
if ( ( (rndis_state != rndis_data_initialized) && Is_device_enumerated() ) ||
|
||||
(iad_fail_timeout > IAD_TIMEOUT_DETACH) ||
|
||||
(fingerPresent) ) {
|
||||
iad_fail_timeout++;
|
||||
} else {
|
||||
iad_fail_timeout = 0;
|
||||
}
|
||||
} //usb_mode == rndis_debug
|
||||
|
||||
|
||||
/* Device is Enumerated but RNDIS STIL not loading. We just
|
||||
have RNDIS interface, so obviously no drivers on target.
|
||||
Just go ahead and mount ourselves as mass storage... */
|
||||
if (usb_mode == rndis_only) {
|
||||
//If we have timed out, detach
|
||||
if (rndis_fail_timeout == RNDIS_TIMEOUT_DETACH) {
|
||||
Usb_detach();
|
||||
//Then wait a few before re-attaching
|
||||
} else if (rndis_fail_timeout == RNDIS_TIMEOUT_ATTACH) {
|
||||
usb_mode = mass_storage;
|
||||
Usb_attach();
|
||||
}
|
||||
|
||||
//Increment timeout when device is not initializing, OR we are already
|
||||
//counting to detach
|
||||
if ( ( (rndis_state != rndis_data_initialized)) ||
|
||||
(rndis_fail_timeout > RNDIS_TIMEOUT_DETACH) ) {
|
||||
rndis_fail_timeout++;
|
||||
} else {
|
||||
rndis_fail_timeout = 0;
|
||||
}
|
||||
}//usb_mode == rnids_only
|
||||
|
||||
|
||||
if(rndis_state == rndis_data_initialized) //Enumeration processs OK ?
|
||||
{
|
||||
if (doInit) {
|
||||
//start flood timer
|
||||
timer_set(&flood_timer, CLOCK_SECOND / 5);
|
||||
|
||||
mac_ethernetSetup();
|
||||
doInit = 0;
|
||||
}
|
||||
|
||||
//Connected!
|
||||
Led0_on();
|
||||
|
||||
Usb_select_endpoint(RX_EP);
|
||||
|
||||
//If we have data and a free buffer
|
||||
if(Is_usb_receive_out() && (uip_len == 0)) {
|
||||
|
||||
//TODO: Fix this some better way
|
||||
//If you need a delay in RNDIS to slow down super-fast sending, insert it here
|
||||
//Also mark the USB as "in use"
|
||||
|
||||
//This is done as "flood control" by only allowing one IP packet per time limit
|
||||
clock_time_t timediff = clock_time() - flood_timer.start;
|
||||
|
||||
|
||||
//If timer not yet expired
|
||||
if (timediff < flood_timer.interval) {
|
||||
//Wait until timer expiers
|
||||
usb_busy = 1;
|
||||
etimer_set(&et, flood_timer.interval - timediff);
|
||||
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
|
||||
|
||||
//Reselect endpoint in case we lost it
|
||||
Usb_select_endpoint(RX_EP);
|
||||
usb_busy = 0;
|
||||
}
|
||||
|
||||
//Restart flood timer
|
||||
timer_restart(&flood_timer);
|
||||
|
||||
//Read how much (endpoint only stores up to 64 bytes anyway)
|
||||
bytecounter = Usb_byte_counter_8();
|
||||
|
||||
//Try and read the header in
|
||||
headercounter = sizeof(rndis_data_packet_t);
|
||||
|
||||
//Hmm.. what's going on here
|
||||
if (bytecounter < headercounter) {
|
||||
Usb_ack_receive_out();
|
||||
break;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (headercounter) {
|
||||
data_buffer[i] = Usb_read_byte();
|
||||
bytecounter--;
|
||||
headercounter--;
|
||||
i++;
|
||||
}
|
||||
|
||||
//This is no good. Probably lost syncronization... just drop it for now
|
||||
if(PBUF->MessageType != REMOTE_NDIS_PACKET_MSG) {
|
||||
Usb_ack_receive_out();
|
||||
break;
|
||||
}
|
||||
|
||||
//Looks like we've got a live one
|
||||
rx_start_led();
|
||||
|
||||
|
||||
//802.3 does not have OOB data, and we don't care about per-packet data
|
||||
//so that just leave regular packet data...
|
||||
if (PBUF->DataLength) {
|
||||
|
||||
//Get offset
|
||||
dataoffset = PBUF->DataOffset;
|
||||
|
||||
//Make it offset from start of message, not DataOffset field
|
||||
dataoffset += (sizeof(rndis_MessageType_t) + sizeof(rndis_MessageLength_t));
|
||||
|
||||
//Subtract what we already took
|
||||
dataoffset -= sizeof(rndis_data_packet_t);
|
||||
|
||||
//Read to the start of data
|
||||
while(dataoffset) {
|
||||
Usb_read_byte();
|
||||
dataoffset--;
|
||||
bytecounter--;
|
||||
|
||||
//If endpoint is done
|
||||
if (bytecounter == 0) {
|
||||
|
||||
Usb_ack_receive_out();
|
||||
|
||||
|
||||
//Wait for new data
|
||||
while (!Is_usb_receive_out());
|
||||
|
||||
|
||||
bytecounter = Usb_byte_counter_8();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Read the data itself in
|
||||
uint8_t * uipdata = uip_buf;
|
||||
uint16_t datalen = PBUF->DataLength;
|
||||
|
||||
while(datalen) {
|
||||
*uipdata++ = Usb_read_byte();
|
||||
datalen--;
|
||||
bytecounter--;
|
||||
|
||||
//If endpoint is done
|
||||
if (bytecounter == 0) {
|
||||
//Might be everything we need!
|
||||
if (datalen) {
|
||||
Usb_ack_receive_out();
|
||||
//Wait for new data
|
||||
while (!Is_usb_receive_out());
|
||||
bytecounter = Usb_byte_counter_8();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Ack final data packet
|
||||
Usb_ack_receive_out();
|
||||
|
||||
/*** SEND DATA TO UIP ***/
|
||||
if(BUF->type == htons(UIP_ETHTYPE_IPV6)) {
|
||||
|
||||
//Send data over RF or to local stack
|
||||
uip_len = PBUF->DataLength; //uip_len includes LLH_LEN
|
||||
mac_ethernetToLowpan(uip_buf);
|
||||
}
|
||||
|
||||
} //if (PBUF->DataLength)
|
||||
|
||||
|
||||
} //if(Is_usb_receive_out() && (uip_len == 0))
|
||||
|
||||
} // if (rndis_data_intialized)
|
||||
|
||||
if ((usb_mode == rndis_only) || (usb_mode == rndis_debug)) {
|
||||
etimer_set(&et, CLOCK_SECOND/80);
|
||||
} else {
|
||||
etimer_set(&et, CLOCK_SECOND);
|
||||
}
|
||||
|
||||
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
|
||||
} // while(1)
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Send data over RNDIS interface, data is in uipbuf and length is uiplen
|
||||
*/
|
||||
uint8_t rndis_send(uint8_t * senddata, uint16_t sendlen)
|
||||
{
|
||||
|
||||
|
||||
uint16_t i;
|
||||
|
||||
//Setup Header
|
||||
PBUF->MessageType = REMOTE_NDIS_PACKET_MSG;
|
||||
PBUF->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_MessageType_t) - sizeof(rndis_MessageLength_t);
|
||||
PBUF->DataLength = sendlen;
|
||||
PBUF->OOBDataLength = 0;
|
||||
PBUF->OOBDataOffset = 0;
|
||||
PBUF->NumOOBDataElements = 0;
|
||||
PBUF->PerPacketInfoOffset = 0;
|
||||
PBUF->PerPacketInfoLength = 0;
|
||||
PBUF->DeviceVcHandle = 0;
|
||||
PBUF->Reserved = 0;
|
||||
PBUF->MessageLength = sizeof(rndis_data_packet_t) + PBUF->DataLength;
|
||||
|
||||
//Send Data
|
||||
Usb_select_endpoint(TX_EP);
|
||||
Usb_send_in();
|
||||
|
||||
//Wait for ready
|
||||
while(!Is_usb_write_enabled());
|
||||
|
||||
//Setup first part of transfer...
|
||||
for(i = 0; i < sizeof(rndis_data_packet_t); i++) {
|
||||
Usb_write_byte(data_buffer[i]);
|
||||
}
|
||||
|
||||
//Send packet
|
||||
while(sendlen) {
|
||||
Usb_write_byte(*senddata);
|
||||
senddata++;
|
||||
sendlen--;
|
||||
|
||||
//If endpoint is full, send data in
|
||||
//And then wait for data to transfer
|
||||
if (!Is_usb_write_enabled()) {
|
||||
Usb_send_in();
|
||||
|
||||
while(!Is_usb_write_enabled());
|
||||
}
|
||||
|
||||
tx_end_led();
|
||||
}
|
||||
|
||||
Usb_send_in();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief This will enable the RX_START LED for a period
|
||||
*/
|
||||
void rx_start_led(void)
|
||||
{
|
||||
Led1_on();
|
||||
led1_timer = 10;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief This will enable the TRX_END LED for a period
|
||||
*/
|
||||
void tx_end_led(void)
|
||||
{
|
||||
Led2_on();
|
||||
led2_timer = 10;
|
||||
}
|
||||
/** @} */
|
Loading…
Add table
Add a link
Reference in a new issue