📄 rndisdev.c
字号:
#include <std.h>
#include <sem.h>
#include <lck.h>
#include <csl.h>
#include <csl_irq.h>
#include <stdio.h>
#include <assert.h>
#include "rndisdev.h"
#include "Hal4D13.h"
#include "Hal4sys.h"
#include "string.h"
#include "usb_cdc.h"
#define MANUFACTURER_STRING "Manufacturer string"
static struct rndis_dev ethdev;
static SEM_Handle semUsbIrq = NULL;
//all rndis data muster align on 4
#pragma DATA_ALIGN(ctrltrans,4); //4byte align
#pragma DATA_ALIGN(intrans,4); //4byte align
#pragma DATA_ALIGN(outtrans,4); //4byte align
static struct control_trans ctrltrans;
static struct generic_trans intrans, outtrans;
int rndis_dev_index = - 1; //rndis side selector
static Uint8 rndis_mac[6] = {0x00, 0x10, 0x07, 0x0b, 0x68, 0x58}; //host side mac
static u8 BufferTmp[MAX_PACKET_BUFFER_SIZE];
#define TX_QUEUE_SIZE (1024 * 8) //driver tx buffer
static u8 txQueueBuffer[TX_QUEUE_SIZE];
int usb_eth_init( struct ei_device * ei_local );
int usb_eth_send( struct ei_device * ei_local, PKT_Handle hPkt );
int usb_eth_raw_send( struct ei_device * ei_local, char * buf, unsigned int len );
int usb_eth_set_promisc( struct ei_device * ei_local );
struct ei_device usb_driver = {
usb_eth_init,
usb_eth_send,
usb_eth_raw_send,
usb_eth_set_promisc
};
static u16 dequeue_tx_msg( struct rndis_dev * dev, u8 * buf )
{
u16 len = 0;
struct LoopBuffCtl * queue = & dev->tx_queue;
if( LoopBuffDataLength( queue ))
{
usb_lock( dev->lock );
LoopBuffRead( queue,( u8 *)& len, sizeof( u16 ) ); //data len
LoopBuffRead( queue, buf, len );
usb_unlock( dev->lock );
}
assert( len < USB_RNDIS_MTU );
return len;
}
//if usb transmit busy,buffer the tcp/ip data
static int queue_tx_msg( struct rndis_dev * dev , PKT_Handle hPkt )
{
u16 res;
struct LoopBuffCtl * queue = & dev->tx_queue;
res = skb_getNbProtLen( hPkt );
assert( res < USB_RNDIS_MTU );
usb_lock( dev->lock );
if( LoopBuffFreeSpace( queue ) > ( 2 + res )) //check free space
{
LoopBuffWrite( queue,( u8 *)& res, sizeof( u16 ) ); //data len
LoopBuffWrite( queue,( u8 *)skb_getNbProt( hPkt ) + 2, res ); //skp require len 2
}
else
res = 0;
usb_unlock( dev->lock );
return res;
}
//packet buffer data into rndis packet
static u16 rndisdev_prepare_trans( struct generic_trans * trans, u8 * buf, u16 length )
{
struct rndis_packet_msg_type * msg = ( struct rndis_packet_msg_type *)trans->dataBuffer;
u32 msgsize = sizeof( struct rndis_packet_msg_type );
memset( msg, 0, msgsize );
msg->MessageType = constant_cpu_to_le32( REMOTE_NDIS_PACKET_MSG );
msg->MessageLength = cpu_to_le32( msgsize + length );
msg->DataOffset = cpu_to_le32( msgsize - 8 ); /*44 - 8 = 36*/
msg->DataLength = length;
memcpy( trans->dataBuffer + msgsize, buf, length );
trans->dataLength = msgsize + length;
trans->transmitLength = 0;
assert( length < USB_RNDIS_MTU );
return trans->dataLength;
}
extern SEM_Handle tcpTaskSem;
static void rndisdev_on_rxpacket( struct rndis_dev * dev, u8 * buf, u16 len )
{
u8 * data;
PKT_Handle hPtk;
struct net_device_stats1 * state = & dev->stats;
if( dev->usbstate == USB_STATE_CONFIGURED )
{ //skb require len 2,get buffer from tcp/ip
hPtk = get_skb( len + 2, ( char **)& data );
if( hPtk == NULL )
{
state->rx_dropped ++;
state->rx_errors ++;
}
else
{
memcpy( data + 2, buf, len ); //skb require len 2
set_skb( dev->net->iface, hPtk, len ); //send the packet to tcp/ip stack
state->tx_packets ++;
state->tx_bytes += len;
SEM_post( tcpTaskSem ); //triger tcp/ip process
}
}
}
extern int usb_setup( struct rndis_dev * dev );
static void rndisdev_setup( struct rndis_dev * dev )
{
u16 len;
int res;
struct usb_ep_control * ep = & dev->ctrl_ep;
res = usb_setup( dev );
if( res == 0 ) //no data return
ep->status = EP_STATUS_IDLE;
else if( res > 0 )
{ //start data transmit
if( ( ep->trans->DeviceRequest.bRequestType & USB_DIR_IN )
&& ( res > ep->trans->DeviceRequest.wLength ) )
res = ep->trans->DeviceRequest.wLength;
len = ( res < CONTROL_PACKET_SIZE ) ? res : CONTROL_PACKET_SIZE;
if( Hal4D13_WriteEndpoint( ep->index + 1, ep->trans->dataBuffer, len ) == len )
{
if( len == CONTROL_PACKET_SIZE )
{
ep->trans->dataLength = res;
ep->status = EP_STATUS_IN;
ep->trans->transmitLength = CONTROL_PACKET_SIZE;
}
else
ep->status = EP_STATUS_IDLE;
}
}
else /*ERR_NOTSUPP*/
Hal4D13_SingleTransmitEP0( 0, 0 );
}
/* CDC and RNDIS support the same host-chosen outgoing packet filters. */
#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
|USB_CDC_PACKET_TYPE_ALL_MULTICAST \
|USB_CDC_PACKET_TYPE_PROMISCUOUS \
|USB_CDC_PACKET_TYPE_DIRECTED)
static void ep_ctl_out_handle( struct rndis_dev * dev )
{
struct usb_ep_control * ep = & dev->ctrl_ep;
struct control_trans * trans = ep->trans;
struct usb_ctrlrequest * ctrl = ( struct usb_ctrlrequest *)(&( trans->DeviceRequest ));
u8 epstatus, len, dirin;
epstatus = Hal4D13_GetEndpointStatusWInteruptClear( ep->index );
if( epstatus & D13REG_EPSTS_SETUP )
{
len = Hal4D13_ReadEndpointWOClearBuffer( ep->index, ( u8 *)ctrl, CONTROL_PACKET_SIZE );
Hal4D13_AcknowledgeSETUP();
Hal4D13_ClearBuffer( ep->index );
trans->dataLength = ctrl->wLength;
ep->trans->transmitLength = len - sizeof( struct usb_ctrlrequest );
dirin = ctrl->bRequestType & USB_DIR_IN;
if( dirin || ( (! dirin ) && ctrl->wLength == 0 ) )
{
ep->status = EP_STATUS_IDLE;
rndisdev_setup( dev ); //complete setup packet received
}
else
ep->status = EP_STATUS_OUT;
}
else if( ep->status == EP_STATUS_OUT )
{
len = Hal4D13_ReadEndpoint( ep->index, trans->dataBuffer + trans->transmitLength, CONTROL_PACKET_SIZE );
trans->transmitLength += len;
if( len < CONTROL_PACKET_SIZE )
{
ep->status = EP_STATUS_IDLE;
rndisdev_setup( dev ); //complete setup packet received
}
}
else
ep->status = EP_STATUS_IDLE;
}
static void ep_ctl_in_handle( struct rndis_dev * dev )
{
struct usb_ep_control * ep = & dev->ctrl_ep;
struct control_trans * trans = ep->trans;
u8 len;
Hal4D13_GetEndpointStatusWInteruptClear( ep->index + 1 );
if( ep->status == EP_STATUS_IN )
{ //data in sending
len = trans->dataLength - trans->transmitLength;
if( len > CONTROL_PACKET_SIZE )
len = CONTROL_PACKET_SIZE;
if( Hal4D13_WriteEndpoint( ep->index + 1,
trans->dataBuffer + trans->transmitLength,
len ) == len )
{
trans->transmitLength += len;
if( len < CONTROL_PACKET_SIZE )//transmit over
ep->status = EP_STATUS_IDLE;
}
}
else
ep->status = EP_STATUS_IDLE;
}
static void ep_in_handle( struct rndis_dev * dev )
{
struct usb_ep_general * ep = & ( dev->in_ep );
struct generic_trans * trans = ep->trans;
u16 len, bufs, ep_last;
ep_last = Hal4D13_GetEndpointStatusWInteruptClear( ep->index );
if(( ep_last & ( D13REG_EPSTS_DBF0 | D13REG_EPSTS_DBF1 )) == 0x00 )
bufs = 2;
else
bufs = 1;
while( bufs )
{
if( ep->status == EP_STATUS_IN )
{ //data in processing
len = trans->dataLength - trans->transmitLength;
if( len > BULK_PACKET_SIZE )
len = BULK_PACKET_SIZE ;
if( Hal4D13_WriteEndpoint( ep->index, trans->dataBuffer +
trans->transmitLength, len ) == len )
{
trans->transmitLength += len;
if( len < BULK_PACKET_SIZE )
{ //packet transmit over
dev->stats.rx_packets ++;
dev->stats.rx_bytes += trans->transmitLength;
/*//start new packet transmit
len = dequeue_tx_msg( dev , BufferTmp );
if( len )
rndisdev_prepare_trans( trans, BufferTmp, len );
else
ep->status = EP_STATUS_IDLE;
*/
ep->status = EP_STATUS_IDLE;
}
}
}
else
ep->status = EP_STATUS_IDLE;
if( ep->status == EP_STATUS_IDLE )
{
len = dequeue_tx_msg( dev , BufferTmp );
if( len )
{
rndisdev_prepare_trans( trans, BufferTmp, len );
ep->status = EP_STATUS_IN;
}
}
bufs --;
}
}
static void ep_out_handle( struct rndis_dev * dev )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -