diff --git a/cpu/avr/dev/usb/conf_usb.h b/cpu/avr/dev/usb/conf_usb.h index 23fcbf606..cdc15f53e 100644 --- a/cpu/avr/dev/usb/conf_usb.h +++ b/cpu/avr/dev/usb/conf_usb.h @@ -98,9 +98,9 @@ #define VCP_RX_EP 0x06 #define VCP_TX_EP 0x05 #define VCP_INT_EP 0x04 -#define TX_EP 0x02 -#define RX_EP 0x03 -#define INT_EP 0x01 +#define TX_EP 0x01 +#define RX_EP 0x02 +#define INT_EP 0x03 /** USB Mass Storage Setup **/ diff --git a/cpu/avr/dev/usb/rndis/rndis_task.c b/cpu/avr/dev/usb/rndis/rndis_task.c index b2a04ebcf..37c60105f 100644 --- a/cpu/avr/dev/usb/rndis/rndis_task.c +++ b/cpu/avr/dev/usb/rndis/rndis_task.c @@ -6,7 +6,7 @@ * * \addtogroup usbstick * - * \author + * \author * Colin O'Flynn * ******************************************************************************/ @@ -66,6 +66,12 @@ //_____ M A C R O S ________________________________________________________ +#define EEMCMD_ECHO 0x00 ///bmEEMCmd Echo +#define EEMCMD_ECHO_RESPONSE 0x01 ///bmEEMCmd Echo Response +#define EEMCMD_SUSPEND_HINT 0x02 ///bmEEMCmd Suspend Hint +#define EEMCMD_RESPONSE_HINT 0x03 ///bmEEMCmd Response Hint +#define EEMCMD_RESPONSE_COMPLETE_HINT 0x04 ///bmEEMCmd Response Complete Hint +#define EEMCMD_TICKLE 0x05 ///bmEEMCmd Tickle @@ -82,6 +88,8 @@ //_____ D E C L A R A T I O N S ____________________________________________ +uint8_t eem_send(uint8_t * senddata, uint16_t sendlen, uint8_t led); +uint8_t rndis_send(uint8_t * senddata, uint16_t sendlen, uint8_t led); //! Timers for LEDs uint8_t led1_timer, led2_timer; @@ -289,6 +297,9 @@ static uint16_t iad_fail_timeout, rndis_fail_timeout; //Subtract what we already took dataoffset -= sizeof(rndis_data_packet_t); + //Clear this flag + Usb_ack_nak_out(); + //Read to the start of data while(dataoffset) { Usb_read_byte(); @@ -302,10 +313,19 @@ static uint16_t iad_fail_timeout, rndis_fail_timeout; //Wait for new data - while (!Is_usb_receive_out()); - - + while (!Is_usb_receive_out() && (!Is_usb_receive_nak_out())); + + //Check for NAK + if (Is_usb_receive_nak_out()) { + Usb_ack_nak_out(); + break; + } + bytecounter = Usb_byte_counter_8(); + + //ZLP? + if (bytecounter == 0) + break; } } @@ -340,14 +360,154 @@ static uint16_t iad_fail_timeout, rndis_fail_timeout; mac_ethernetToLowpan(uip_buf); - } //if (PBUF->DataLength) + + } //if (PBUF->DataLength) } //if(Is_usb_receive_out() && (uip_len == 0)) } // if (rndis_data_intialized) + else if(Is_device_enumerated() && //Enumeration processs OK && + (usb_mode == eem) ) //USB Stick is using EEM + { + uint16_t datalength; - if ((usb_mode == rndis_only) || (usb_mode == rndis_debug)) { + if (doInit) { + 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)) { + + //Read how much (endpoint only stores up to 64 bytes anyway) + bytecounter = Usb_byte_counter_8(); + + //EEM uses 2 bytes as a header + headercounter = 2; + + uint8_t fail = 0; + + //Hmm.. what's going on here? + if (bytecounter < headercounter) { + Usb_ack_receive_out(); + //TODO CO done = 1; + } + + //Read EEM Header + i = 0; + while (headercounter) { + data_buffer[i] = Usb_read_byte(); + bytecounter--; + headercounter--; + i++; + } + + //Order is LSB/MSB, so MSN is in data_buffer[1] + //Bit 15 indicates command packet when set + if (data_buffer[1] & 0x80) { + //not a data payload + datalength = 0; + } else { + //'0' indicates data packet + //Length is lower 14 bits + datalength = data_buffer[0] | ((data_buffer[1] & 0x3F) << 8); + } + + /* EEM Command Packet */ + if ((datalength == 0) && (fail == 0)) + { + uint8_t command; + uint16_t echoLength; + + //Strip command off + command = data_buffer[1] & 0x38; + command = command >> 3; + + //Decode command type + switch (command) + { + /* Echo Request */ + case EEMCMD_ECHO: + + //Get echo length + echoLength = (data_buffer[1] & 0x07) << 8; //MSB + echoLength |= data_buffer[0]; //LSB + + //TODO: everything. oops. + + break; + + /* Everything else: Whatever. */ + case EEMCMD_ECHO_RESPONSE: + case EEMCMD_SUSPEND_HINT: + case EEMCMD_RESPONSE_HINT: + case EEMCMD_RESPONSE_COMPLETE_HINT: + case EEMCMD_TICKLE: + break; + + default: break; + } + } + /* EEM Data Packet */ + else if (datalength && (fail == 0)) + { + //Looks like we've got a live one + rx_start_led(); + + uint16_t bytes_received = 0; + uint16_t dataleft = datalength; + U8 * buffer = uip_buf; + + while(dataleft) + { + *buffer++ = Usb_read_byte(); + + dataleft--; + bytecounter--; + bytes_received++; + + //Check if endpoint is done but we are expecting more data + if ((bytecounter == 0) && (dataleft)) + { + //ACK previous data + Usb_ack_receive_out(); + + //Wait for new data + while (!Is_usb_receive_out()); + + //Get new data + bytecounter = Usb_byte_counter_8(); + + //ZLP? + if (bytecounter == 0) + { + //Incomplete!! + break; + } + } + } + + //Ack final data packet + Usb_ack_receive_out(); + + //Packet has CRC, nobody wants that garbage + datalength -= 4; + + //Send data over RF or to local stack + uip_len = datalength; //uip_len includes LLH_LEN + mac_ethernetToLowpan(uip_buf); + + } //if (datalength) + } //if(Is_usb_receive_out() && (uip_len == 0)) + } // if (Is_device_enumerated()) + + if ((usb_mode == rndis_only) || (usb_mode == rndis_debug) || (usb_mode == eem)) { etimer_set(&et, CLOCK_SECOND/80); } else { etimer_set(&et, CLOCK_SECOND); @@ -359,6 +519,107 @@ static uint16_t iad_fail_timeout, rndis_fail_timeout; PROCESS_END(); } +/** + \brief Sends a single ethernet frame over USB using appropriate low-level protocol (EEM or RNDIS) + \param senddata Data to send + \param sendlen Length of data to send + \param led Should the LED be light up for this frame? + */ +uint8_t usb_eth_send(uint8_t * senddata, uint16_t sendlen, uint8_t led) +{ + if (usb_mode == eem) + return eem_send(senddata, sendlen, led); + + if ((usb_mode == rndis_only) || (usb_mode == rndis_debug)) + return rndis_send(senddata, sendlen, led); + + return 0; +} + +/** + \brief Send a single ethernet frame using EEM + */ +uint8_t eem_send(uint8_t * senddata, uint16_t sendlen, uint8_t led) +{ + //Check device is set up + if (Is_device_enumerated() == 0) + return 0; + + //Make a header + uint8_t header[2]; + + //Fake CRC! Add 4 to length for CRC + sendlen += 4; + header[0] = (sendlen >> 8) & 0x3f; + header[1] = sendlen & 0xff; + + //We send CRC seperatly.. + sendlen -= 4; + + //Send Data + Usb_select_endpoint(TX_EP); + //Usb_send_in(); + + //Wait for ready + while(!Is_usb_write_enabled()); + + //Send header (LSB then MSB) + Usb_write_byte(header[1]); + Usb_write_byte(header[0]); + + //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()); + } + + } + + //CRC = 0xdeadbeef + //Linux kernel 2.6.31 needs 0xdeadbeef in wrong order, + //like this: uint8_t crc[4] = {0xef, 0xbe, 0xad, 0xde}; + //This is fixed in 2.6.32 to the correct order (0xde, 0xad, 0xbe, 0xef) + uint8_t crc[4] = {0xde, 0xad, 0xbe, 0xef}; + + sendlen = 4; + uint8_t i = 0; + + //Send fake CRC + while(sendlen) { + Usb_write_byte(crc[i]); + i++; + 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()); + } + + if (led) { + tx_end_led(); + } + } + + //Send last data in - also handles sending a ZLP if needed + Usb_send_in(); + + //Wait for ready + while(!Is_usb_write_enabled()); + + return 1; +} + /** \brief Send data over RNDIS interface, data is in uipbuf and length is uiplen */ diff --git a/cpu/avr/dev/usb/rndis/rndis_task.h b/cpu/avr/dev/usb/rndis/rndis_task.h index 832f899d2..6bbdc90c1 100644 --- a/cpu/avr/dev/usb/rndis/rndis_task.h +++ b/cpu/avr/dev/usb/rndis/rndis_task.h @@ -59,8 +59,8 @@ //_____ D E C L A R A T I O N S ____________________________________________ +uint8_t usb_eth_send(uint8_t * senddata, uint16_t sendlen, uint8_t led); -uint8_t rndis_send(uint8_t * senddata, uint16_t sendlen, uint8_t led); void sof_action(void); void rx_start_led(void); void tx_end_led(void); diff --git a/cpu/avr/dev/usb/usb_descriptors.c b/cpu/avr/dev/usb/usb_descriptors.c index dbf49a090..d2a172894 100644 --- a/cpu/avr/dev/usb/usb_descriptors.c +++ b/cpu/avr/dev/usb/usb_descriptors.c @@ -110,7 +110,7 @@ FLASH S_usb_user_configuration_descriptor_composite usb_conf_desc_composite = { 0xFF, // bFunctionProcotol (Vendor specific) 0x00 // iInterface },//8 - + /// RNDIS DEVICE { sizeof(S_usb_interface_descriptor) , INTERFACE_DESCRIPTOR @@ -443,6 +443,67 @@ FLASH S_usb_user_configuration_descriptor_mass usb_conf_desc_mass = { } }; +/************* EEM-ONLY ***************/ + +// usb_user_device_descriptor +FLASH S_usb_device_descriptor usb_dev_desc_eem = +{ + sizeof(usb_dev_desc_composite) +, DEVICE_DESCRIPTOR +, Usb_write_word_enum_struc(USB_SPECIFICATION) +, EEM_DEVICE_CLASS +, EEM_DEVICE_SUB_CLASS +, EEM_DEVICE_PROTOCOL +, EP_CONTROL_LENGTH +, Usb_write_word_enum_struc(VENDOR_ID) +, Usb_write_word_enum_struc(COMPOSITE_PRODUCT_ID) +, Usb_write_word_enum_struc(RELEASE_NUMBER) +, MAN_INDEX +, PROD_INDEX +, SN_INDEX +, NB_CONFIGURATION +}; + + +// usb_user_configuration_descriptor FS +FLASH S_usb_user_configuration_descriptor_eem usb_conf_desc_eem = { + { sizeof(S_usb_configuration_descriptor) + , CONFIGURATION_DESCRIPTOR + , Usb_write_word_enum_struc(sizeof(S_usb_user_configuration_descriptor_eem)) + , EEM_NB_INTERFACE + , CONF_NB + , CONF_INDEX + , CONF_ATTRIBUTES + , MAX_POWER + },//9 + /// EEM DEVICE + { sizeof(S_usb_interface_descriptor) + , INTERFACE_DESCRIPTOR + , EEM_INTERFACE0_NB + , EEM_ALTERNATE0 + , EEM_NB_ENDPOINT0 + , EEM_INTERFACE0_CLASS + , EEM_INTERFACE0_SUB_CLASS + , EEM_INTERFACE0_PROTOCOL + , EEM_INTERFACE0_INDEX + } //9 +, +{ sizeof(S_usb_endpoint_descriptor) + , ENDPOINT_DESCRIPTOR + , EEM_ENDPOINT_NB_1 + , EEM_EP_ATTRIBUTES_1 + , Usb_write_word_enum_struc(EEM_EP_SIZE_1) + , EEM_EP_INTERVAL_1 + } //7 + , + { sizeof(S_usb_endpoint_descriptor) + , ENDPOINT_DESCRIPTOR + , EEM_ENDPOINT_NB_2 + , EEM_EP_ATTRIBUTES_2 + , Usb_write_word_enum_struc(EEM_EP_SIZE_2) + , EEM_EP_INTERVAL_2 + } //7 +}; /************* COMMON *****************/ @@ -485,7 +546,7 @@ FLASH S_usb_language_id usb_user_language_id = { -PGM_VOID_P Usb_get_dev_desc_pointer(void) +PGM_VOID_P Usb_get_dev_desc_pointer(void) { if (usb_mode == rndis_only) return &(usb_dev_desc_network.bLength); @@ -493,6 +554,9 @@ PGM_VOID_P Usb_get_dev_desc_pointer(void) if (usb_mode == rndis_debug) return &(usb_dev_desc_composite.bLength); + if (usb_mode == eem) + return &(usb_dev_desc_eem.bLength); + return &(usb_dev_desc_mass.bLength); } @@ -506,11 +570,14 @@ U8 Usb_get_dev_desc_length(void) if (usb_mode == rndis_debug) return sizeof(usb_dev_desc_composite); + if (usb_mode == eem) + return sizeof(usb_dev_desc_eem); + return sizeof(usb_dev_desc_mass); } -PGM_VOID_P Usb_get_conf_desc_pointer(void) +PGM_VOID_P Usb_get_conf_desc_pointer(void) { if (usb_mode == rndis_only) return &(usb_conf_desc_network.cfg.bLength); @@ -518,6 +585,9 @@ PGM_VOID_P Usb_get_conf_desc_pointer(void) if (usb_mode == rndis_debug) return &(usb_conf_desc_composite.cfg.bLength); + if (usb_mode == eem) + return &(usb_conf_desc_eem.cfg.bLength); + return &(usb_conf_desc_mass.cfg.bLength); } @@ -531,6 +601,9 @@ U8 Usb_get_conf_desc_length(void) if (usb_mode == rndis_debug) return sizeof(usb_conf_desc_composite); + if (usb_mode == eem) + return sizeof(usb_conf_desc_eem); + return sizeof(usb_conf_desc_mass); } diff --git a/cpu/avr/dev/usb/usb_descriptors.h b/cpu/avr/dev/usb/usb_descriptors.h index dbdb1c932..808dcadb0 100644 --- a/cpu/avr/dev/usb/usb_descriptors.h +++ b/cpu/avr/dev/usb/usb_descriptors.h @@ -71,13 +71,17 @@ #define COMPOSITE_DEVICE_PROTOCOL 0x01 // IAD #define NETWORK_DEVICE_CLASS 0x02 // CDC ACM -#define NETWORK_DEVICE_SUB_CLASS 0x02 // +#define NETWORK_DEVICE_SUB_CLASS 0x02 // #define NETWORK_DEVICE_PROTOCOL 0xFF // Vendor-specific #define MASS_DEVICE_CLASS 0x00 // #define MASS_DEVICE_SUB_CLASS 0x00 // #define MASS_DEVICE_PROTOCOL 0x00 // +#define EEM_DEVICE_CLASS 0x02 // CDC +#define EEM_DEVICE_SUB_CLASS 0x0C // EEM +#define EEM_DEVICE_PROTOCOL 0x07 // EEM + #define EP_CONTROL_LENGTH 64 #define VENDOR_ID 0x03EB // Atmel vendor ID = 03EBh #define COMPOSITE_PRODUCT_ID 0x2021 //Product ID for composite device @@ -92,6 +96,7 @@ #define NETWORK_NB_INTERFACE 2 #define COMPOSITE_NB_INTERFACE 4 #define MASS_NB_INTERFACE 1 +#define EEM_NB_INTERFACE 1 #define CONF_NB 1 #define CONF_INDEX 0 #define CONF_ATTRIBUTES USB_CONFIG_BUSPOWERED @@ -196,7 +201,7 @@ #define MS_EP_ATTRIBUTES_1 0x02 // BULK = 0x02, INTERUPT = 0x03 #define MS_EP_IN_LENGTH 64 #define MS_EP_SIZE_1 MS_EP_IN_LENGTH -#define MS_EP_INTERVAL_1 0x00 +#define MS_EP_INTERVAL_1 0x00 // USB Endpoint 2 descriptor FS @@ -204,8 +209,32 @@ #define MS_EP_ATTRIBUTES_2 0x02 // BULK = 0x02, INTERUPT = 0x03 #define MS_EP_IN_LENGTH 64 #define MS_EP_SIZE_2 MS_EP_IN_LENGTH -#define MS_EP_INTERVAL_2 0x00 +#define MS_EP_INTERVAL_2 0x00 +/******* EEM Configuration *******/ + +// Interface 0 descriptor +#define EEM_INTERFACE0_NB 0 +#define EEM_ALTERNATE0 0 +#define EEM_NB_ENDPOINT0 2 +#define EEM_INTERFACE0_CLASS 0x02 // CDC ACM Com +#define EEM_INTERFACE0_SUB_CLASS 0x0C // EEM +#define EEM_INTERFACE0_PROTOCOL 0x07 // EEM +#define EEM_INTERFACE0_INDEX 0 + + // USB Endpoint 1 descriptor + // Bulk IN +#define EEM_ENDPOINT_NB_1 0x80 | TX_EP +#define EEM_EP_ATTRIBUTES_1 0x02 // BULK = 0x02, INTERUPT = 0x03 +#define EEM_EP_SIZE_1 0x40 //64 byte max size +#define EEM_EP_INTERVAL_1 0x00 + + // USB Endpoint 2 descriptor + // Bulk OUT +#define EEM_ENDPOINT_NB_2 RX_EP +#define EEM_EP_ATTRIBUTES_2 0x02 // BULK = 0x02, INTERUPT = 0x03 +#define EEM_EP_SIZE_2 0x40 //64 byte max size +#define EEM_EP_INTERVAL_2 0x00 #define DEVICE_STATUS 0x00 // TBD #define INTERFACE_STATUS 0x00 // TBD @@ -442,8 +471,17 @@ typedef struct } S_usb_user_configuration_descriptor_mass; +/* EEM */ +typedef struct +{ + S_usb_configuration_descriptor cfg; + S_usb_interface_descriptor ifc0; + S_usb_endpoint_descriptor ep1; + S_usb_endpoint_descriptor ep2; +} S_usb_user_configuration_descriptor_eem; -PGM_VOID_P Usb_get_dev_desc_pointer(void); + +PGM_VOID_P Usb_get_dev_desc_pointer(void); U8 Usb_get_dev_desc_length(void); PGM_VOID_P Usb_get_conf_desc_pointer(void) ; U8 Usb_get_conf_desc_length(void); diff --git a/cpu/avr/dev/usb/usb_drv.h b/cpu/avr/dev/usb/usb_drv.h index 699367b7d..cf56d0e75 100644 --- a/cpu/avr/dev/usb/usb_drv.h +++ b/cpu/avr/dev/usb/usb_drv.h @@ -532,6 +532,8 @@ typedef enum endpoint_parameter{ep_num, ep_type, ep_direction, ep_size, ep_bank, #define Usb_ack_receive_setup() (UEINTX &= ~(1<