导读:
RNDIS原理分析--PDD部分
---------------by nasiry
转载请说明出处,并通知我
1.初始化
首先我们从PDD_Init开始。
所谓初始化的动作通常包含对硬件设备的初始化,一般说来就是通过设置设备寄存器来对设备进行必要的配置,另外一个方面就是软件的初始化,包括全局数据变量的空间申请初始化,中断函数的挂接,其他函数指针的挂接。
既然需要读写设备的状态寄存器设备的端口/地址就是必不可少的,首先PDD_init先检查有没有从MDD传过来的设备地址,如果没有,通过PciFind2890找一下我们需要的2980有没有在PCI以查卡的形式在某一个插槽上,如果继没有由MDD传递过来的设备地址,PCI插槽上也没有我们需要的2890,怎么办?还能怎么办,既然没有的话,我也干不下去了,return False算了,88下次再见:P
如果在PCI插口上发现2890的话,就比较麻烦一点,因为需要去计算PCI总线上的设备偏移才能得到设备地址,不仅如次还要去摆弄一个叫9054的片子来符合和PCI的规范,其实我们要的只是一个地址和一个中断源,没有必要再PCI设备上搞来搞去,最简单的办法就是假设这个2890是直接挂在系统总线上的,事实上现在用得很普遍的ARM体系下通常都是没有PCI总线的,这样子我们就只用分析MDD直接传递了设备地址的情况,简单还不乏实用性。总之,我就是不分析PCI总线相关的部分,因为我不会。下面废话少说进入正题。
PDD_init有两个参数第一个是一个结构指针原形如下:
typedef struct _RNDIS_PDD_CHARACTERISTICS
{ PFN_PDD_SEND_RNDIS_MESSAGE SendRndisMessageHandler;
PFN_PDD_SEND_RNDIS_PACKET SendRndisPacketHandler;
PFN_PDD_INDICATE_RNDIS_PACKET_COMPLETE IndicateRndisPacketCompleteHandler;
PFN_PDD_SET SetHandler;
PFN_PDD_GET GetHandler;
PFN_PDD_ISR ISRHandler;
DWORD dwIRQ;
DWORD dwMaxRx;
DWORD dwBaseAddr;
// BUS specific information
// If it is PCI then this driver will be loaded by PCI enumerator through
// NDIS.
BOOL bPCIDevice;
// These are only needed for PCI type device AND if the driver chooses
// to use GIISR.DLL as default ISR.
BOOL CheckPort; // If true, check port to see if device is asserting IRQ
BOOL PortIsIO; // Port is IO port (possibly true only for x86)
BOOL UseMaskReg; // If true, read from MaskAddr to obtain mask
DWORD PortAddr; // Port Address
DWORD PortSize; // Port data width in bytes
DWORD Mask; // Mask to use on data port to determine if device is asserting IRQ
DWORD MaskAddr; // Address of register to use as mask
} RNDIS_PDD_CHARACTERISTICS, *PRNDIS_PDD_CHARACTERISTICS;
这个结构包含了一系列的函数指针和地址,中断,和最大接收数等信息,没有提到的这些个结构成员都是PCI设备所需的,这里我们仅仅需要把bPCIDevice设置为False也就是说我们并没有使用PCI设备就可以了。注意这个参数的类型是OUT,MDD也就是通过这里得到设备的信息的。因此在这里需要填充该结构,然后完成对硬件的初始化。
另外还有一个相当重要的结构,这个结构在全局范围内存在一个实例,是我们的PDD工作的中心,我们来看看这个结构的原形。
typedef struct
{ volatile PUCHAR pucBaseAddress;
volatile PUCHAR puc9054Address;
ULONG ulIRQ;
DWORD dwSysIntr;
BOOL bConnected;
BYTE bUsbAddress;
// EP0 related operations..
BOOL bSending;
LIST_ENTRY listTxRndisMessageQueue;
PDATA_WRAPPER pCurrentSendRndisMessage;
PBYTE pbCurrentSend;
DWORD dwCurrentSendSizeLeft;
UCHAR ucScratchBuffer;
BYTE pbEP0ReceiveBuffer[EP0_MAX_RECEIVE_BUFFER];
DATA_WRAPPER EP0DataWrapper;
DWORD dwExpectedRxSize;
DWORD dwTotalReceived;
PBYTE pbCurrentRx;
// EP1 related operations..
PDATA_WRAPPER pEP1DataWrapper;
// EP2 related operations..
PDATA_WRAPPER pEP2DataWrapper;
PBYTE pbEP2CurrentSend;
DWORD dwEP2TotalSent;
BOOL bEP2ShortPacketSent;
UCHAR MacAddress[6];
}RNDIS_2890;
pucBaseAddress是用于存放设备的基地址,puc9054Address仅仅是在使用PCI卡的时候使用,原因上面说过了。ulIRQ指硬件中断号,dwSysIntr
也是在PCI模式下用,因为这种模式下我们只能使用"可安装"的中断(因为PCI查卡位置不同中断不同)。bConnected是连接状态的标示,bUsbAddress则是来自于USB协议本身的要求。
硬件的初始化是在NET2890Init中完成的,进行的是一系列的寄存器操作以完成对USB各个ENDPoint的配置,如果对源码或者这个芯片本身有兴趣的话可以参考NET2890 USB Interface Controller For Revision 2 IC来看具体的代码,我这里仅仅将相应的配置总结出来如下:
RNDIS 2890配置
ENDPOINT
EP0 control(IN/OUT) enable
1.FIFO Valid Mode FIFO Flush
2.EP0 Packet Size =8byte
3.Handshake receive
EP1(EPA)OUT enable
RNDIS原理分析--PDD部分
---------------by nasiry
转载请说明出处,并通知我
1.初始化
首先我们从PDD_Init开始。
所谓初始化的动作通常包含对硬件设备的初始化,一般说来就是通过设置设备寄存器来对设备进行必要的配置,另外一个方面就是软件的初始化,包括全局数据变量的空间申请初始化,中断函数的挂接,其他函数指针的挂接。
既然需要读写设备的状态寄存器设备的端口/地址就是必不可少的,首先PDD_init先检查有没有从MDD传过来的设备地址,如果没有,通过PciFind2890找一下我们需要的2980有没有在PCI以查卡的形式在某一个插槽上,如果继没有由MDD传递过来的设备地址,PCI插槽上也没有我们需要的2890,怎么办?还能怎么办,既然没有的话,我也干不下去了,return False算了,88下次再见:P
如果在PCI插口上发现2890的话,就比较麻烦一点,因为需要去计算PCI总线上的设备偏移才能得到设备地址,不仅如次还要去摆弄一个叫9054的片子来符合和PCI的规范,其实我们要的只是一个地址和一个中断源,没有必要再PCI设备上搞来搞去,最简单的办法就是假设这个2890是直接挂在系统总线上的,事实上现在用得很普遍的ARM体系下通常都是没有PCI总线的,这样子我们就只用分析MDD直接传递了设备地址的情况,简单还不乏实用性。总之,我就是不分析PCI总线相关的部分,因为我不会。下面废话少说进入正题。
PDD_init有两个参数第一个是一个结构指针原形如下:
typedef struct _RNDIS_PDD_CHARACTERISTICS
{ PFN_PDD_SEND_RNDIS_MESSAGE SendRndisMessageHandler;
PFN_PDD_SEND_RNDIS_PACKET SendRndisPacketHandler;
PFN_PDD_INDICATE_RNDIS_PACKET_COMPLETE IndicateRndisPacketCompleteHandler;
PFN_PDD_SET SetHandler;
PFN_PDD_GET GetHandler;
PFN_PDD_ISR ISRHandler;
DWORD dwIRQ;
DWORD dwMaxRx;
DWORD dwBaseAddr;
// BUS specific information
// If it is PCI then this driver will be loaded by PCI enumerator through
// NDIS.
BOOL bPCIDevice;
// These are only needed for PCI type device AND if the driver chooses
// to use GIISR.DLL as default ISR.
BOOL CheckPort; // If true, check port to see if device is asserting IRQ
BOOL PortIsIO; // Port is IO port (possibly true only for x86)
BOOL UseMaskReg; // If true, read from MaskAddr to obtain mask
DWORD PortAddr; // Port Address
DWORD PortSize; // Port data width in bytes
DWORD Mask; // Mask to use on data port to determine if device is asserting IRQ
DWORD MaskAddr; // Address of register to use as mask
} RNDIS_PDD_CHARACTERISTICS, *PRNDIS_PDD_CHARACTERISTICS;
这个结构包含了一系列的函数指针和地址,中断,和最大接收数等信息,没有提到的这些个结构成员都是PCI设备所需的,这里我们仅仅需要把bPCIDevice设置为False也就是说我们并没有使用PCI设备就可以了。注意这个参数的类型是OUT,MDD也就是通过这里得到设备的信息的。因此在这里需要填充该结构,然后完成对硬件的初始化。
另外还有一个相当重要的结构,这个结构在全局范围内存在一个实例,是我们的PDD工作的中心,我们来看看这个结构的原形。
typedef struct
{ volatile PUCHAR pucBaseAddress;
volatile PUCHAR puc9054Address;
ULONG ulIRQ;
DWORD dwSysIntr;
BOOL bConnected;
BYTE bUsbAddress;
// EP0 related operations..
BOOL bSending;
LIST_ENTRY listTxRndisMessageQueue;
PDATA_WRAPPER pCurrentSendRndisMessage;
PBYTE pbCurrentSend;
DWORD dwCurrentSendSizeLeft;
UCHAR ucScratchBuffer;
BYTE pbEP0ReceiveBuffer[EP0_MAX_RECEIVE_BUFFER];
DATA_WRAPPER EP0DataWrapper;
DWORD dwExpectedRxSize;
DWORD dwTotalReceived;
PBYTE pbCurrentRx;
// EP1 related operations..
PDATA_WRAPPER pEP1DataWrapper;
// EP2 related operations..
PDATA_WRAPPER pEP2DataWrapper;
PBYTE pbEP2CurrentSend;
DWORD dwEP2TotalSent;
BOOL bEP2ShortPacketSent;
UCHAR MacAddress[6];
}RNDIS_2890;
pucBaseAddress是用于存放设备的基地址,puc9054Address仅仅是在使用PCI卡的时候使用,原因上面说过了。ulIRQ指硬件中断号,dwSysIntr
也是在PCI模式下用,因为这种模式下我们只能使用"可安装"的中断(因为PCI查卡位置不同中断不同)。bConnected是连接状态的标示,bUsbAddress则是来自于USB协议本身的要求。
硬件的初始化是在NET2890Init中完成的,进行的是一系列的寄存器操作以完成对USB各个ENDPoint的配置,如果对源码或者这个芯片本身有兴趣的话可以参考NET2890 USB Interface Controller For Revision 2 IC来看具体的代码,我这里仅仅将相应的配置总结出来如下:
RNDIS 2890配置
ENDPOINT
EP0 control(IN/OUT) enable
1.FIFO Valid Mode FIFO Flush
2.EP0 Packet Size =8byte
3.Handshake receive
EP1(EPA)OUT enable