相信自己,快乐每一天
分类: LINUX
2013-10-30 15:50:34
以太网帧
CS8900A
1. 寄存器
·LINECTL(0112H)
LINECTL决定CS8900的基本配置和物理接口。例如:设置初始值为00d3H,选择物理接口为10BASE-T,并使能设备的发送和接收控制位。
·RXCTL(0104H)
RXCTL控制CS8900接收特定数据报。设置RXTCL的初始值为0d05H,表示接收网络上的广播或者目标地址同本地物理地址相同的正确数据包。
·RXCFG(0102H)
RXCFG控制CS8900接收到特定数据报后会引发接收中断。RXCFG可设置为0103H,这样当收到一个正确的数据报后,CS8900会产生一个接收中断。
·BUSCT(0116H)
BUSCT可控制芯片的I/O接口的一些操作。设置初始值为8017H,打开CS8900的中断总控制位。
·ISQ(0120H)
ISQ是网卡芯片的中断状态寄存器,内部映射接收中断状态寄存器和发送中断状态寄存器的内容。
·PORT0(0000H)
发送和接收数据时,CPU通过PORT0传递数据。
·TXCMD(0004H)
发送控制寄存器,如果写入数据00C0H,那么网卡芯片在全部数据写入后开始发送数据。
·TXLENG(0006H)
发送数据长度寄存器,发送数据时,首先写入发送数据长度,然后将数据通过PORT0写入芯片。
以上为几个最主要的工作寄存器(为16位)。
系统工作时,应首先对网卡芯片进行初始化,即写寄存器LINECTL、RXCTL、 RCCFG、BUSCT。
发数据时,写控制寄存器TXCMD,并将发送数据长度写入TXLENG,然后将数据依次写入PORT0口,网卡芯片将数据组织为链路层类型并添加填充位和CRC校验送到网络。
接收数据时,初始化后,数据到达时,网卡产生中断,通过port0读出数据。
2. 程序框架
2.1 模块注册
static int __init init_cs8900a_s3c2410(void)
{
struct net_local *lp;
int ret = 0;
dev_cs89x0.irq = irq;
dev_cs89x0.base_addr = io;
dev_cs89x0.init= cs89x0_probe;
request_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT, "cs8900a");
申请io
if (register_netdev(&dev_cs89x0)!= 0)注册网卡,内核调用init函数,cs89x0_probe
}
2.2 设备检测
static int __init cs89x0_probe(struct net_device *dev, int ioaddr)
{
/* get the chip type */匹配网卡
rev_type = readreg(dev,PRODUCT_ID_ADD);
lp->chip_type = rev_type&~ REVISON_BITS;
lp->chip_revision =((rev_type & REVISON_BITS) >> 8) + 'A';
if (lp->chip_type !=CS8900)
{
printk(__FILE__ ":wrong device driver!\n");
ret = -ENODEV;
goto after_kmalloc;
}
初始化-----
dev->dev_addr[0]= 0x00;
dev->dev_addr[1]= 0x00;
dev->dev_addr[2]= 0xc0;
dev->dev_addr[3]= 0xff;
dev->dev_addr[4]= 0xee;
dev->dev_addr[5]= 0x08;
set_mac_address(dev,dev->dev_addr);
dev->irq = IRQ_LAN;
printk(", IRQ %d",dev->irq);
dev->open = net_open;
dev->stop = net_close;
dev->tx_timeout = net_timeout;
dev->watchdog_timeo = 3 * HZ;
dev->hard_start_xmit =net_send_packet;
dev->get_stats = net_get_stats;
dev->set_multicast_list =set_multicast_list;
dev->set_mac_address =set_mac_address;
/* Fill in the fields of thedevice structure with ethernet values. */
ether_setup(dev);帮助把其它成员初始化。
}
2.3 数据发送
static intnet_send_packet(struct sk_buff *skb, struct net_device *dev)
{
netif_stop_queue(dev);每个网卡有个发送队列,要发送,先停发送队列,
/* initiate a transmit sequence */
writeword(dev, TX_CMD_PORT,lp->send_cmd);
TX_CMD_PORT命令寄存器
writeword(dev, TX_LEN_PORT, skb->len);
TX_LEN_PORT长度寄存器
/* Test to see if the chip has allocatedmemory for the packet */
if ((readreg(dev, PP_BusST) &READY_FOR_TX_NOW) == 0)判断发送准备做好了吗
{
spin_unlock_irq(&lp->lock);
DPRINTK(1, "cs89x0: Tx buffer notfree!\n");
return 1;
}
/* Write the contents of the packet */
writeblock(dev, skb->data, skb->len);将数据写到寄存器零
return 0;
}
inline void writeblock(struct net_device *dev,char *pdata,int length)
{
int i;
for(i=0;i<(length/2);i++)
{
writeword(dev,TX_FRAME_PORT,*(u16 *)pdata);寄存器16位
pdata+=2;指针移动
}
if(length%2)
{
u16 oddwordvalue=*pdata;
writeword(dev,TX_FRAME_PORT,oddwordvalue);
}
}
2.4 中断
static void net_interrupt(intirq, void *dev_id, struct pt_regs * regs)
{
while ((status = readword(dev, ISQ_PORT))) ISQ_PORT中断状态,什么中断发生
{
switch(status & ISQ_EVENT_MASK) {
caseISQ_RECEIVER_EVENT:
/* Got a packet(s). */
net_rx(dev);
break;
case ISQ_TRANSMITTER_EVENT:
lp->stats.tx_packets++;
netif_wake_queue(dev); /* Inform upper layers. */
break;
}
2.5 接收
static void net_rx(struct net_device *dev) {
status =inw(ioaddr + RX_FRAME_PORT);
if ((status &RX_OK) == 0) {判断是否为一次正确的接收。
count_rx_errors(status, lp);
return;
}
length = inw(ioaddr +RX_FRAME_PORT);接收数据的长度取出来,用来分配skb
/* Malloc up new buffer. */
skb =dev_alloc_skb(length + 2);分配skb
if (skb == NULL) {
lp->stats.rx_dropped++;
return;
}
skb_reserve(skb,2);空出2个字节
/* mac头是14个字节,一开始保留两个字节,正是为了保证ip头的开始是四字节对齐的。*/
skb->len = length;
skb->dev = dev;
readblock(dev,skb->data, skb->len);从port0中将数据读到skb中。
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);数据交给协议栈
}