网络子系统:
比如网络编程里面通过socket创建好了一个文件操作符,然后对其进行write操作,这个write对应的入口其实是一个socket_file_ops结构对应的函数操作集:
可以看到write对应的入口函数是sock_aio_write函数
这个函数又对应着do_sock_write
一层又一层,这个函数又调用了__sock_sendmsg函数,下面来看看这个函数
总结一下,这里write调用了sock_aio_write,然后sock_aio_write调用了do_sock_write,然后do_sock_write又调用了__sock_sendmsg函数,其实这三个函数是属于SCI层和协议无关层,(系统调用接口层、协议无关层、协议栈、设备无关层、设备驱动层,网络子系统)
网卡数据的发送流程图:
网卡数据接收架构分析流程图:
下面来逐步深入分析DM9000网卡驱动,首先还是先找到驱动的入口函数dm9000.c中的module_init
可以看到dm9000_init函数里面实际上是注册了一个平台设备驱动,也就是说网卡驱动实际上是一平台驱动的方式来编写的,还记得之前说到的probe函数吗?和设备进行一个匹配,当匹配的上的时候就会执行一些相应的操作
上图中第一个箭头指向的部分可以看到dm9000_probe这个函数内部第一步就是分配一个net_device结构!这个可以结和上篇博客的来对照着看!
接着比较重要的一步是获取相关资源:
这里先来分析一下上面的资源!可以看到这里取出了基地址、数据、中断号。结合前面的驱动基础可以知道,平台驱动和平台设备是通过设备的name来进行匹配的!从上面的struct platform_driver dm9000_driver这个结构体中可以看到.name =dm9000,也就说在这个平台设备对于的.name为dm9000,那么对应的平台驱动肯定也有一个与之对应的dm9000(这里要分清平台设备,平台驱动之间的区别和关系,平台设备指的像这里分析的网卡,平台驱动是一种驱动模型,也可以理解为一种总线模型),直接在内核源码中搜索dm9000,可以找到如下一个结构体:
对比着之前的平台设备驱动(上图是平台驱动)里面的一个结构体看看:
平台设备驱动和平台驱动就是通过名字来匹配的,当然这里我先来重点关心一下.resource = dm9000_resources
先来瞅瞅里面的资源:
然后下面接着比较重要的一步是将获取到的地址使用ioremap进行映射:
db->io_addr = ioremap(db->addr_res->start, iosize);
分析过程实在是太长了!(未完,待续。。。)
其实呢?linux驱动基本上可以分为两个部分,一个就是linux驱动模型,一个就是裸机驱动硬件操作部分,将这两个结合就是Linux驱动了!前边的裸机驱动的博客还没写!这里先只实现一部分,发送部分代码,修改还是参照之前的分析流程来的:
/* * Hardware start transmission. * Send a packet to media from the upper layer. */ static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) { board_info_t *db = netdev_priv(dev); //1. 通知协议栈,暂停向驱动传送数据 netif_stop_queue(dev); //2. 将skb中的数据写入寄存器 iow(db, DM9000_TXPLL,skb->len); iow(db, DM9000_TXPLH,skb->len>>8); writeb(DM9000_MWCMD, db->io_addr); (db->outblk)(db->io_data,skb->data,skb->len); iow(db, DM9000_TCR,TCR_TCREQ);//启动发送 //3. 释放skb dev_kfree_skb(skb); return NETDEV_TX_OK; }
1. 通知协议栈,暂停向驱动传送数据
2. 将skb中的数据写入寄存器
3. 释放skb
4. 在发送中断处理程序中通知协议栈发送数据//这个前边也分析了的
一个子系统的驱动的学习时间还是相当漫长的!看来绝不是短期内能掌握的!这里先记一部分笔记,后边回过头来逐步深入研究,这里笔记也只是记录相当小的一部分知识,网络子系统知识实在是有点庞大,想吃透还是要费点脑壳的(未完,后边持续更新完善本篇笔记。。。)