linux网卡驱动之CS8900A网卡驱动程序_cs8900a 网卡驱动_飞翔的荷兰人号z的博客-程序员宅基地

技术标签: CS8900A  驱动  linux  嵌入式  

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,那么网卡芯片在全部数据写入后开始发送数据。

(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);
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_41782149/article/details/89764524

智能推荐

JS数组中的方法以及对应的Polyfill_flatmap polyfill mdn_小螃蟹er的博客-程序员宅基地

/** * copyWithin(): 方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。 * entries(): 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。 * Array.prototype.fill() : 用一个固定值填充一个数组中从起始索引到终止索引内的全部元素,arr.fill(value[, start...

实验9-8 通讯录排序(20 分)_你一直都在心间的博客-程序员宅基地

实验9-8 通讯录排序(20 分)输入n个朋友的信息,包括姓名、生日、电话号码,本题要求编写程序,按照年龄从大到小的顺序依次输出通讯录。题目保证所有人的生日均不相同。输入格式:输入第一行给出正整数n(<10)。随后n行,每行按照“姓名 生日 电话号码”的格式给出一位朋友的信息,其中“姓名”是长度不超过10的英文字母组成的字符串,“生日”是yyyymmdd格式的日期,“电话号码”是不超...

使用STM32编写一个简单的RTOS:3.线程管理_上发条的博客-程序员宅基地

文章目录RT-Thread的线程简介源码分析初始化线程线程脱离启动线程挂起线程线程睡眠线程让出测试参考资料:RTT官网文档关键字:分析RT-Thread源码、stm32、RTOS、线程管理器。RT-Thread的线程简介线程(thread)是系统能够进行调度的最小单位,在linux中也是这样定义的,但是和我们RTOS中的thread更像是linux中的进程,是系统进行资源分配的基本单位,但...

android 实现动态显示当前的时间_android当前时间动态_淡小蛋丶的博客-程序员宅基地

我们需要用到Timer和Handler来实现这个功能。首先,我们需要在代码声明Timer这个类timer = new Timer(); 编写一个timeTask方法,定时向handler发送消息,我选择的时间是1秒钟 private void timeTask(){ timer.schedule(new TimerTask() { @Override publ

JAVA 迭代器 next(),hasNext()初探_FARO_Z的博客-程序员宅基地

目录前言原码解析总结前言在使用迭代器的时候,我总是被next(),hasNext()到底指向哪一个元素给迷惑,这次自己读了读原码,总算对相关的知识有了一丁点了解,这次就来分享一下。原码解析对于hasNext()public boolean hasNext() { return cursor != size; }其实现方式是如果游标还没有达到容器的size大小,就返回true,这里与许多人解释的方式不一样, hasNext()不是指有没有下一个元素,

唐诗掠影:基于词移距离(Word Mover's Distance)的唐诗诗句匹配实践_deex13491的博客-程序员宅基地

词移距离(Word Mover's Distance)是在词向量的基础上发展而来的用来衡量文档相似性的度量。词移距离的具体介绍参考http://blog.csdn.net/qrlhl/article/details/78512598 或网上的其他资料词移距离的gensim官方例子在https://github.com/RaRe-Technologies/gensim/bl...

随便推点

从头认识Spring-2.3 注解装配[email protected](4)-required(1)_weixin_30881367的博客-程序员宅基地

这一章节我们来具体讨论一下@autowired里面的參数required。1.domain(重点)蛋糕类:package com.raylee.my_new_spring.my_new_spring.ch02.topic_1_9;public class Cake { private String name = ""; public String getName() {...

centos7使用iso镜像文件配置本地yum源_若存在一个centos-7-x86_64-dvd-1511.iso的镜像文件,使用这个镜像文件配置本_zhangdf0821的博客-程序员宅基地

0、准备CentOS完整光盘镜像CentOS-7-x86_64-DVD-1810.iso0.0 如果使用VMware,在“虚拟机设置->硬件->CD/DVD->连接中“选择”使用ISO映像文件“,选择上面的iso镜像文件。0.1 如果不用VMware,需要将iso文件上传之linux系统中。1、挂载镜像文件# 创建镜像挂载目录mkdir /media/cdrom# VMware方式mount /dev/cdrom /media/cdrom# 上传镜像文件方式,/pat

java按照商品价格排序,六、MapReduce排序例子--获取价格最高的商品信息_weixin_39528525的博客-程序员宅基地

1、需求获取每个订单中最贵的商品用到的知识点:自定义排序,包括普通排序,二次排序,分组排序自定义分区2、数据输入和输出格式数据输入格式:每个已售商品一条记录订单id 商品id 商品价格0000001 Pdt_01 222.80000002 Pdt_06 722.40000001 Pdt_05 25.80000003 Pdt_01 222.80000003 Pdt_01 33.80...

自适应控制设计(二)_自适应控制的设计方法_段星星的博客-程序员宅基地

自适应控制设计(二)《自适应控制基本思想》一文主要介绍了自适应控制设计的基本思路,但是针对控制率的设计没有具体说明,这里针对反馈控制率的设计步骤进行具体介绍控制器设计基本思想对于任何一个动态系统,我们都可以根据Lyapunov稳定性设计其控制器,具体的说就是 首先根据期望值 xdx_{d} ,将原系统改为误差系统,即将 x˙=f(x,u)\dot{x} =f( x,u) 转化为 e˙=f(

git-svn — 让git和svn协同工作_蓝色瞬间的博客-程序员宅基地

svn作为一个优秀源码版本的管理工具,可以适合绝大多数项目。但是因为它的采用中心化管理,不可避免的存在本地代码的备份和版本管理问题。也就是说对于尚未或暂无法提交到Subversion服务器的本地代码来说,存在着被误删除和版本更新无法回退两大情形。git作为一个分布式版本管理工具,可以很好的解决这个问题。因为它的大多数操作是在本地进行的。这里要说的是git是如何做到既可以管理好本

Tensorflow中注意力机制的实现:AttentionCellWrapper_tensorflow点云注意力机制代码_酒酿小圆子~的博客-程序员宅基地

文章目录注意力机制最早被用于机器翻译领域,其本质类似于人类在认知事物时的注意力,后因其有效性被广泛用于计算机视觉、语音识别、序列预测等领域。常见的注意力机制通常是基于Encoder-Decoder的。在Tensorflow中也有现成的注意力API可以使用,即AttentionCellWrapper。值得注意的是,Tensoflow中AttentionCellWrapper的实现并不是基于E...