和所有其他模块一样,函数init_module是cs8900的入口:
cs8900_init函数填充net_device结构体。net_device是网络驱动中最为重要的一个结构,需要认真阅读,其原型在 include/linux/netdevice.h中。为了填充如此复杂的结构,内核提供了ether_setup函数作为辅助。关于ether_setup函数,你只要知道它的功能就可以了。当然,ether_setup不是万能的,你还要手工完成类似如下一些内容:
而下面语句的含义也非常明确:
cs8900_probe是初始化函数(Driver initialization routines),主要完成一些初始化操作,我们在下一章中介绍。cs8900_init中使用了另外一个函数还没有说-->alloc_etherdev。alloc_etherdev是alloc_netdev的封装函数,它负责在内核空间为 net_device结构体分配内存(kmalloc)。alloc_etherdev的原型在include/linux/etherdevice.h中。
在函数最后,通过register_netdev完成设备注册。register_netdev函数原型在net/core/dev.c中,但是如果你就是为了写驱动,你可以不往下看了。
一句话总结:cs8900_init在使用各种手段填充了net_device结构体后,通过register_netdev向系统注册了一个网络设备。
cs8900_probe函数本身并不难,但是你必须清楚probe函数的重要职能。因为你很有可能要为属于你的设备编写一个probe函数。
先来看一行最易懂的代码: printk(VERSION_STRING"/n"); 显然,内核启动时显示的相关信息就是这句话打印出来的。
net_device中的dev_addr就是网卡的MAC地址,你应该提供:
#if defined(CONFIG_ARCH_SMDK2410) dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x00; dev->dev_addr[2] = 0x3e; dev->dev_addr[3] = 0x26; dev->dev_addr[4] = 0x0a; dev->dev_addr[5] = 0x00; #endif
使用类似的代码,为我们的网络芯片提供 dev->if_port = IF_PORT_10BASET; (支持的多种接口) dev->priv = (void *) &priv; (设备私有数据结构)
哦,还要多说一句,IF_PORT_10BASET在include/linux/netdevice.h中定义,你通过这个枚举类型,可以了解更多的接口信息:
enum { IF_PORT_UNKNOWN = 0, IF_PORT_10BASE2, IF_PORT_10BASET, IF_PORT_AUI, IF_PORT_100BASET, IF_PORT_100BASETX, IF_PORT_100BASEFX };
下面的代码对于移植是非常关键的。vSMDK2410_ETH_IO是网卡的虚拟地址,IRQ_EINT9是硬件中断。这两个值和另外一个地址(网卡的物理地址)必须在头文件中定义,而且要正确的定义。
#if defined(CONFIG_ARCH_SMDK2410) dev->base_addr = vSMDK2410_ETH_IO + 0x300; dev->irq = IRQ_EINT9; #endif /* #if defined(CONFIG_ARCH_SMDK2410) */
接下来分配I/O端口资源。使用的函数是check_mem_region和request_mem_region。LDD中的理论结合这里的实践,相信你很快就掌握驱动编程中的这个API了。
下面的代码实现了硬件的读写。使用的函数是cs8900_read和cs8900_write。虽然只需很短的篇幅就可以解释这对读写函数,但是为了不分散你对cs8900_probe函数的注意力,我还是留到下一节中说,不要着急:) 哦,差点忘了,这里使用了内核的自旋锁(spin_lock_init),不过关于自旋锁的机制已经超出本文的范围了。你现在只需要知道自旋锁用于并发控制,以及如何动态初始化自旋锁就可以了。如果你还想继续了解,请自行学习与自旋锁相关的API,它们是:
spinlock_t spin; //定义自旋锁 spin_lock(lock); //获得自旋锁 spin_trylock(lock); //尝试获得自旋锁 spin_unlock(lock); //释放自旋锁
一句话总结:cs8900_probe函数继续为设备进行初始化,并申请各种资源。
return (inw (dev->base_addr + PP_Data));
outw (value,dev->base_addr + PP_Data);
#define PP_Data0x0c/* PacketPage Data Port (Section 4.10.10) */
cpu_to_le32(v),__io(p))
#define inw(p)({ __u16 __v = le16_to_cpu((__force __le16) /
__raw_readl(__io(p))); __v; })
#define outsb(p,d,l)__raw_writesb(__io(p),d,l)
#define insl(p,d,l)__raw_readsl(__io(p),d,l)
ndev->open= cs8900_start;
cs8900_set (dev,PP_RxCTL,RxOKA | IndividualA | BroadcastA);
cs8900_set (dev,PP_TxCFG,TxOKiE | Out_of_windowiE | JabberiE);
cs8900_set (dev,PP_BufCFG,Rdy4TxiE | RxMissiE | TxUnderruniE | TxColOvfiE | MissOvfloiE);
cs8900_set (dev,PP_LineCTL,SerRxON | SerTxON);
cs8900_set (dev,PP_BusCTL,EnableRQ);
clear_bit(__LINK_STATE_XOFF, &dev->state);
if (netpoll_trap()) {
clear_bit(__LINK_STATE_XOFF, &dev->state);
return;
if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
__netif_schedule(dev);
2.
case RxEvent:
case TxEvent:
case BufEvent:
if ((RegContent (status) & RxMiss)) {
priv->stats.rx_errors += missed;
priv->stats.rx_missed_errors += missed;
if ((RegContent (status) & TxUnderrun)) {
priv->stats.tx_errors++;
priv->stats.tx_fifo_errors++;
priv->txlen = 0;
netif_wake_queue (dev);
/* FIXME: if Rdy4Tx, transmit last sent packet (if any) */
case TxCOL:
case RxMISS:
status = MissCount (cs8900_read (dev,PP_RxMISS));
priv->stats.rx_errors += status;
priv->stats.rx_missed_errors += status;
一句话总结:中断处理函数是中断产生时执行的函数,它根据中断种类进行处理。
/* These two members must be first. */
struct sk_buff*next;
struct sk_buff*prev;
struct sock*sk;
ktime_ttstamp;
struct net_device*dev;
structdst_entry*dst;
structsec_path*sp;
/*
....................................................................
* layer. Please put your private variables there. If you
* want to keep them across layers you have to do a skb_clone()
* first. This is owned by whoever has the skb queued ATM.
*/
charcb[48];
unsigned intlen,
data_len;
__u16mac_len,
hdr_len;
union {
__wsumcsum;
struct {
__u16csum_start;
__u16csum_offset;
__u32priority;
__u8local_df:1,
cloned:1,
ip_summed:2,
nohdr:1,
nfctinfo:3;
__u8pkt_type:3,
fclone:2,
ipvs_property:1,
peeked:1,
nf_trace:1;
__be16protocol;
void(*destructor)(struct sk_buff *skb);
struct nf_conntrack*nfct;
struct sk_buff*nfct_reasm;
struct nf_bridge_info*nf_bridge;
intiif;
__u16queue_mapping;
__u16tc_index;/* traffic control index */
__u16tc_verd;/* traffic control verdict */
/* 2 byte hole */
dma_cookie_tdma_cookie;
__u32secmark;
__u32mark;
sk_buff_data_ttransport_header;
sk_buff_data_tnetwork_header;
sk_buff_data_tmac_header;
/* These elements must be at the end, see alloc_skb() for details.*/
sk_buff_data_ttail;
sk_buff_data_tend;
unsigned char*head,
*data;
unsigned inttruesize;
atomic_tusers;
NET_RX_SUCCESS(no congestion)
NET_RX_DROP(packet was dropped)
相关推荐
CS8900A网卡驱动程序分析 CS8900A网卡驱动程序分析 CS8900A网卡驱动程序分析 CS8900A网卡驱动程序分析 CS8900A网卡驱动程序分析
cs8900网卡驱动源码,以及用ARM-LINXU-GCC编译出来的文件
cs8900a网卡驱动分析,我们老师讲的,不错,比较适合初学网卡驱动的同学!
移植到linux2.6内核的cs8900网卡驱动,一个可以移植到linux2.6内核的网卡驱动,已经经过移植到s3c2410的开发板上
cs8900a linux驱动程序
网卡驱动采用3.4.2内核里提供的cs89x0.c 移植到fs2410中
cs8900 驱动示例(cs8900的配置过程和发送过程)基于s3c2440
linux 下的网络芯片CS8900的驱动源码,大家一起学习!
网卡驱动移植网卡驱动移植网卡驱动移植网卡驱动移植网卡驱动移植
Linux2.6.30上移植好的基于S3C2440的CS8900网卡驱动,这份网卡驱动源码在扬创utu2440-F开发板已验证通过! 如果有什么问题,可以参考我CSDN上的博客:http://blog.csdn.net/reille/上相关文章
好不容易弄出来的,上传了一次 居然 不见了! 再次补上。很辛苦的。网上很难找到这两个驱动文件
编译环境arm-linux-gcc 分别有查询与中断两种工作方式
(国嵌)Cs8900a网卡驱动分析;中文翻译,对英文不好的开发者很有帮助。
在嵌入式linux2.4.18内核中实现CS8900A网卡驱动,李会艳,胡荣强,本文首先论述了在嵌入式系统中增加以太网接口的两种方法;接着给出了微处理器S3C2410X与网卡CS8900A接线图;然后根据该接线图论述了将
直接在/drivers/net下的cs89x0的基础上修改,里面的源码已经是我修改过了的,经过实验已经可以 用了!
CS8900A网卡驱动cs8900.c和cs8900.h
本文主要分析基于优龙FS2410开发板中CS8900A网卡芯片在u-boot-1.3.4中的使用流程及方法。涵盖硬件接口电路的简单分析、CS8900A I/O模式分析、u-boot-1.3.4中的CS8900A驱动主要代码注释、及tftp/ping命令在u-boot执行...
开发板:成都博睿科技 MC2410.(三星的 s3c2410芯片, 网卡芯片cs8900a) cs8900.h, cs8900.c 这两个文件我在网上搜索很久都没有结果。最后在一个帖子里面别人贴出来了,所以我把代码copy下来自己建立cs8900.h cs...
943602CS网卡驱动,亲测可用,苹果官方驱动提取,保证能用,解压直接安装就可以
cs8900网卡硬件手册 The CS8900A is a low-cost Ethernet LAN Controller optimized for the Industry Standard Architecture (ISA) bus and general purpose microcontroller busses. Its highlyintegrated design ...