文章目录
CS8900A芯片介绍
CS8900芯片是Cirrus Logic公司生产的一种局域网处理芯片,在嵌入式领域中使用非常常见。它的封装是100-pin TQFP,内部集成了在片RAM、10BASE-T收发滤波器,并且提供8位和16位两种接口,一般在单片机中,使用了CS8900的8位接口模式。
该芯片突出特点:
- 使用灵活
- 其物理层接口、数据传输模式和工作模式等都能根据需要而动态调整
- 通过内部寄存器的设置来适应不同的应用环境
以太网帧
CS8900A寄存器
(1)LINECTL 网卡状态设置
从上图看到,此寄存器的6,7位用于设置网卡的收发使能。8,9位用于设置网卡状态。是10BASE-T还是AUI。
如下图更详细介绍了8,9位如何设置:
驱动里给这个寄存器默认设置为0x00d3, 实际就是设置了网卡收发使能,并且状态设置为10BASE-T Only。
**(2) RxCTL 网卡数据包接收设置
驱动里默认设置为0x0d05,设置了网卡可以接收广播包。可以接收目的地址和本地地址一致的网络包。
(3) RxCFG 接收配置寄存器
驱动默认为0x0103即,设置第8位,当网卡正确的接收到一帧数据后,产生一个中断。
(4)BusCTL
驱动默认设置为0x8017,设置了第F位,打开了CS8900的中断开关。
(5)ISQ 中断状态寄存器
这个是只读寄存器,用来查询什么类型的中断发生。
(6)TxCMD 发送命令寄存器
如果写入数据00C0H,那么网卡芯片在全部数据写入后开始发送数据。
扫描二维码关注公众号,回复:
6142523 查看本文章
(7)PORT0
发送和接收数据时,CPU通过PORT0传递数据
(8)TXLENG 发送数据长度寄存器
发送 数据时,首先写入发送数据长度,然后将数据通过PORT0写入芯片
- 系统工作时,应该首先对网卡芯片进行初始化,即写寄存器:LINECTL、RXCTL、RCCFG、BUSCT
- 发数据时,写控制寄存器TXCMD,并将发送数据长度写入TXLENG,然后将数据依次写入PORT0口,网卡芯片将数据组织为链路层类型并添加填充位和CRC校验送到网络
代码分析
(1)模块注册
static int __init init_cs8900a_s3c6410(void)
{
struct net_local *ip;
int ret = 0;
dev_cs89x0.irq = irq;
dev_cs89x0.base_addr = ip;
dev_cs89x0.init = cs90x0_probe;
request_irq(dev_cs89x0.base_addr,NETCARD_IO_EXTENT,"cs8900a");
if(register_netdev(&dev_cs89x0)!=0)
......
}
(2)设备检测
static int __init cs89x0_probe(struct net_device *dev,int ioaddr)
{
//get the chip type
rev_type = readreg(dev,PRODUCT_ID_ADD);
ip->chip_type = rev_type & ~REVISION_BITS;
ip->chip_revision = ((rev_type & REVISION_BITS) >> 8) + 'A';
if(ip->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] = 0xf0;
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_colse;
dev->tx_timeout = net_timeout;
dev->watchdog_timeo = 3*HZ;
dev->hard_start_xmit = net_send_packet;
dev->get_stats = net_get_send_packet;
dev->set_multicast_list = set_multicast_list;
dev->set_mac_address = set_mac_address;
//fill in the fields of the device structure with ethernet values
ether_setup(dev);
}
(3)数据发送
static int net_send_packet(struct sk_buff *skb,struct net_device *dev)
{
//停止发送队列,固定,发送数据时把发送队列停止
netif_stop_queue(dev);
//inititate a transmit sequence
writeword(dev,TX_CMD_PORT,ip->send_cmd);
writeword(dev,TX_LEN_PORT,skb->len);
//test to see if thr chip has allocated memory for the packet
if((readreg(dev,PP_BusST) & READY_FOR_TX_NOW) == 0)
{
spin_unlock_irq(ip->lock);
DPRINTK(1,"cs89x0:Tx_buffer not free!\n");
return 1;
}
//write the contents of the packet
writeblock(dev,skb->data,skb->len);
return 0;
}
(4)中断
static void net_interrupt(int irq,void *dev_id,struct pt_regs *regs)
{
while((status == readword(dev,ISQ_PORT)))
{
switch(status & ISQ_EVENT_MASK)
{
case ISQ_RECEIVER_EVENT:
//get a packet
net_rx(dev);
break;
case ISQ_IRANSMITTER_EVENT:
ip->status.tx_packets;
netif_wake_queue(dev);
break;
}
}
}
(5)接收
static void net_rx(struct net_device *dev)
{
stauts = inw(ioaddr + RX_FRAME_PORT);
if((status & RX_OK) == O)
{
count_rx_errors(status,ip);
return ;
}
length = inw(ioaddr + RX_FRAME_PORT);
//Malloc up new buffer
skb = dev_alloc_skb(length+2);
if(skb == NULL)
{
ip->status.rx_droppe++;
return;
}
skb_reserve(skb,2);
//mac头是14个字节,一开始保留两个字节,主要是为了保证ip头的开始满足四字节对其(2+6+6+2)
skb->len = length;
skb->dev = dev;
readblock(dev,skb->data,skb->len);
skb->protocol = eth_trans(skb,dev);
netif_rx(skb);
}