linux0.99网络模块-网络设备初始化
2015-10-15 16:05
281 查看
在《llinux0.99网络模块-网络模块初始化》中我们分析了网络模块的初始化过程,其中关于设备初始化我们单独拿到这里来分析。
对于linux0.99内核来说,它初始化了两个设备-loopback和wd8003.
1.数据结构
net/tcp/dev.h
47 #define DEV_NUMBUFFS 3
48 #define MAX_ADDR_LEN 6
49 #define MAX_HEADER 14
50 #define MAX_ROUTE 16
52 struct device
53 {
54 char *name; //设备名
55 unsigned long rmem_end; //接收内存结束地址
56 unsigned long rmem_start; //接收内存起始地址
57 unsigned long mem_end; //设备发送内存结束地址
58 unsigned long mem_start; //设备发送内存起始地址
59 unsigned short base_addr; //寄存器基地址(见tcp/wereg.h:128)
60 unsigned char irq; //中断
61 unsigned char start:1, //启动标志
62 tbusy:1, //设备忙
63 loopback:1, //回环设备标志
64 interrupt:1, //是否有中断
65 up:1; //发送标志
66 struct device *next; //连接下一个设备
67 int (*init)(struct device *dev); //初始化函数指针
68 unsigned long trans_start; //传输开始
69 struct sk_buff *buffs[DEV_NUMBUFFS]; //缓冲区
70 struct sk_buff *backlog; /* no longer used. */ //积压队列
71 int (*open)(struct device *dev); //打开设备函数指针
72 int (*stop)(struct device *dev); //停止设备函数指针
73 int (*hard_start_xmit) (struct sk_buff *skb, struct device *dev); //向硬件发送数据
74 int (*hard_header) (unsigned char *buff, struct device *dev, //生成首部
75 unsigned short type, unsigned long daddr,
76 unsigned long saddr, unsigned len);
77 void (*add_arp) (unsigned long addr, struct sk_buff *skb, //向arp表中添加表项
78 struct device *dev);
79 void (*queue_xmit)(struct sk_buff *skb, struct device *dev, int pri); //向链路层传递数据的函数
80 int (*rebuild_header)(void *eth, struct device *dev); //重建首部
81 unsigned short (*type_trans) (struct sk_buff *skb, struct device *dev); //类型转换
82 void (*send_packet)(struct sk_buff *skb, struct device *dev); //发送数据报
83 void *private; //私有数据
84
85 unsigned short type; //设备类型
86 unsigned short hard_header_len; //首部长度
87 unsigned short mtu; //最大传输单元
88 unsigned char broadcast[MAX_ADDR_LEN]; //广播地址
89 unsigned char dev_addr[MAX_ADDR_LEN]; //设备MAC地址
90 unsigned char addr_len; //硬件地址长度
91 };
net/tcp/sock.h
155 struct sk_buff //描述数据报的
156 {
157 struct sk_buff *next; //
158 struct sk_buff *prev; //链接成双向链表
159 struct sk_buff *link3; //重传队列
160 volatile struct sock *sk; //描述TCP连接
161 unsigned long when; /* used to compute rtt's. */
162 struct device *dev; //属于哪个设备
163 void *mem_addr; //内存地址
164 union
165 {
166 struct tcp_header *th;
167 struct enet_header *eth;
168 struct ip_header *iph;
169 struct udp_header *uh;
170 struct arp *arp;
171 unsigned char *raw;
172 unsigned long seq;
173 } h; //首部,对于不同协议,意义不同
174 unsigned long mem_len; //包括结构体和数据在内的长度
175 unsigned long len; //数据部分的长度
176 unsigned long saddr; //源地址
177 unsigned long daddr; //目的地址
178 int magic; //魔数
179 unsigned long acked:1,used:1,free:1,arp:1, urg_used:1, lock:1; //
180 };
51 struct sock //描述TCP连接的
52 {
53 struct options *opt; //选项
54 unsigned long wmem_alloc; //写内存大小
55 unsigned long rmem_alloc; //读内存大小
56 unsigned long send_seq; //发送序号
57 unsigned long acked_seq; //确认序号
58 unsigned long copied_seq; //拷贝序号
59 unsigned long rcv_ack_seq; //接收确认序号
60 unsigned long window_seq; //窗口序号
61 unsigned long fin_seq; //fin序号
62 unsigned long inuse:1, dead:1, urginline:1,
63 intr:1, blog:1, done:1, reuse:1, keepopen:1, linger:1,
64 delay_acks:1, timeout:3, destroy:1, ack_timed:1, no_check:1,
65 exp_growth:1;
66 int proc; //进程?
67 volatile struct sock *next; //链接下一个
68 volatile struct sock *pair; //
69 struct sk_buff *send_tail; //重传队列尾
70 struct sk_buff *send_head; //重传队列头
71 struct sk_buff *back_log; //积压
72 struct sk_buff *send_tmp; //临时发送缓冲
73 long retransmits; //重新发送
74 struct sk_buff *wback, *wfront, *rqueue; //写队列,接收队列
75 struct proto *prot; //协议
76 struct wait_queue **sleep; //等待队列
77 unsigned long daddr; //目的地址
78 unsigned long saddr; //源地址
79 unsigned short max_unacked; //最大未确认
80 unsigned short window; //窗口大小
81 unsigned short bytes_rcv; //接收字节数
82 unsigned short mtu; //maximum transmit unit
83 unsigned short num; //
84 unsigned short cong_window; //拥塞窗口
85 unsigned short packets_out; //可以发送的数据报数量
86 unsigned short urg; //紧急字段
87 unsigned short shutdown; //
88 unsigned short mss; //max segment size
89 short rtt; //往返
90 short err;
91 unsigned char protocol; //协议名
92 unsigned char state; //状态
93 unsigned char ack_backlog; //确认积压队列
94 unsigned char max_ack_backlog; //队列大小,防止内存耗尽
95 unsigned char priority; //优先级
96 struct tcp_header dummy_th; /* I may be able to get rid of this. *///用来描述连接的另一端
97 struct timer time_wait; //等待定时器
98 };
上面的数据结构已经给出了注释,有些地方我也不是很确定,大致看一下就可以了,具体的含义会在后面的源码中逐步推断出来。
2.
loopback
132 int
133 loopback_init(struct device *dev)
134 {
135 printk ("Loopback device init\n");
136 /* initialize the rest of the device structure. */
137 dev->mtu = 2000; /* mtu */
138 dev->hard_start_xmit = loopback_xmit; //将数据发送给设备
139 dev->open = NULL;
140 dev->hard_header = eth_hard_header; //生成头
141 dev->add_arp = NULL; //不需要arp,因为不会发送给其他主机
142 dev->hard_header_len = sizeof (struct enet_header); //首部长度
143 dev->addr_len = ETHER_ADDR_LEN; //硬件地址长度
144 dev->type = ETHER_TYPE; //设备类型
145 dev->queue_xmit = dev_queue_xmit; //向链路层传递数据的函数
146 dev->rebuild_header = eth_rebuild_header; //重建首部
147 dev->type_trans = eth_type_trans; //类型转换(返回sk_buff首部type字段)
148 dev->loopback = 1; //回环设备标志
149 return (0);
150 }
可以看到初始化函数非常简单,通俗的说 loopback_xmit指明数据从哪来,dev_queue_xmit指明数据到哪去,剩余的则指明数据和设备本身的相关属性。
3.wd8003
647 int
648 wd8003_init(struct device *dev)
649 {
650 unsigned char csum;
651 int i;
652 csum = 0;
653 for (i = 0; i < 8; i++)
654 {
655 csum += inb_p(WD_ROM+i);
656 }
657 if (csum != WD_CHECK)
658 {
659 printk ("Warning WD8013 board not found at i/o = %X.\n",dev->base_addr);
660
661 /* make sure no one can attempt to open the device. */
662 status = OPEN;
663 return (1);
664 }
665 printk("wd8013");
上面是校验工作。(怎么校验的?)
666 /* initialize the rest of the device structure. */
667 dev->mtu = 1500; /* eth_mtu */以太网MTU
668 dev->hard_start_xmit = wd8003_start_xmit; //发送数据到硬件的函数
669 dev->open = wd8003_open; //打开函数
670 dev->hard_header = eth_hard_header; //头部生成函数
671 dev->add_arp = eth_add_arp; //在arp表中添加表项函数
672 dev->type_trans = eth_type_trans; //类型转换函数
673 dev->hard_header_len = sizeof (struct enet_header); //首部长度
674 dev->addr_len = ETHER_ADDR_LEN; //地址长度 6
675 dev->type = ETHER_TYPE; //类型
676 dev->queue_xmit = dev_queue_xmit; //向链路层发送数据函数
677 dev->rebuild_header = eth_rebuild_header; //重建首部函数
678 for (i = 0; i < DEV_NUMBUFFS; i++)
679 dev->buffs[i] = NULL; //初始化缓冲区为NULL
681 #ifndef FORCE_8BIT
682 /* check for 16 bit board - it doesn't have register 0/8 aliasing */
683 for (i = 0; i < 8; i++) {
684 if( inb_p( EN_SAPROM+i ) != inb_p( EN_CMD+i) ){
685 csum = inb_p( EN_REG1 ); /* fiddle with 16bit bit */
686 outb( csum ^ BUS16, EN_REG1 ); /* attempt to clear 16bit bit */
687 if( (csum & BUS16) == (inb_p( EN_REG1 ) & BUS16) ) {
688 printk(", using 16 bit I/F ");
689 dconfig |= 1; /* use word mode of operation */
690 outb_p( LAN16ENABLE|MEMMASK, EN_REG5);
691 outb( csum , EN_REG1 );
692 break; /* We have a 16bit board here! */
693 }
694 outb( csum , EN_REG1 );
695 }
696 }
697 #endif /* FORCE_8BIT */
699 /* mapin the interface memory. */
700 outb_p(WD_IMEM,WD_CTL);
702 /* clear the interface memory */
703 for (i = dev->mem_start; i < dev->mem_end; i++)
704 {
705 *((unsigned char *)i) = 0;
706 if (*((unsigned char *)i) != 0)
707 {
708 printk ("WD Memory error.\n");
709 if( (i - dev->mem_start) > 4096 )
710 break;
711 else
712 status = OPEN;
713 }
714 }
假设一切顺利,也就是706行为false,i最终等于mem_end。如果为true也就是MD发生内存错误,那么如果此时有超过一个内存页的可用内存,就用i来记录这个位置。否则,设置status为OPEN,保证没有人会打开此设备。这里说明至少要有4K空间可用。
715 /* Calculate how many pages of memory on board */
716 max_pages = ( i - dev->mem_start )/256;
计算网卡适配器(?)内存页数
718 /* need to set up the dev->mem_end and dev->rmem_end */
719 dev->rmem_end = i;
720 dev->mem_end = i;
722 /* print the initialization message, and the
723 ethernet address. */
724 printk (", %d pages memory, ethernet Address: ", max_pages );
725 for (i = 0; i <ETHER_ADDR_LEN; i++)
726 {
727 dev->dev_addr[i]=inb_p(WD_ROM+i); //读取硬件地址
728 dev->broadcast[i]=0xff; //广播地址设为全1
729 printk ("%2.2X ",dev->dev_addr[i]);
730 }
732 /* Clear the statistics */
733 for( i = 0; i < sizeof( struct enet_statistics ); i++ )
734 ((char *)&stats)[i] = 0;
清空statics,这是用来统计数据的
736 printk ("\n");
737 status = 0;
739 if (irqaction (dev->irq, &wd8003_sigaction))
740 {
741 printk ("Unable to get IRQ%d for wd8013 board\n", dev->irq);
742 return (1);
743 }
注册中断请求处理函数为wd8003_sigaction,它会把耗时操作交给上一篇文章中提到的下半部来处理
744 return (0);
745 }
硬件初始化就分析到这里。
对于linux0.99内核来说,它初始化了两个设备-loopback和wd8003.
1.数据结构
net/tcp/dev.h
47 #define DEV_NUMBUFFS 3
48 #define MAX_ADDR_LEN 6
49 #define MAX_HEADER 14
50 #define MAX_ROUTE 16
52 struct device
53 {
54 char *name; //设备名
55 unsigned long rmem_end; //接收内存结束地址
56 unsigned long rmem_start; //接收内存起始地址
57 unsigned long mem_end; //设备发送内存结束地址
58 unsigned long mem_start; //设备发送内存起始地址
59 unsigned short base_addr; //寄存器基地址(见tcp/wereg.h:128)
60 unsigned char irq; //中断
61 unsigned char start:1, //启动标志
62 tbusy:1, //设备忙
63 loopback:1, //回环设备标志
64 interrupt:1, //是否有中断
65 up:1; //发送标志
66 struct device *next; //连接下一个设备
67 int (*init)(struct device *dev); //初始化函数指针
68 unsigned long trans_start; //传输开始
69 struct sk_buff *buffs[DEV_NUMBUFFS]; //缓冲区
70 struct sk_buff *backlog; /* no longer used. */ //积压队列
71 int (*open)(struct device *dev); //打开设备函数指针
72 int (*stop)(struct device *dev); //停止设备函数指针
73 int (*hard_start_xmit) (struct sk_buff *skb, struct device *dev); //向硬件发送数据
74 int (*hard_header) (unsigned char *buff, struct device *dev, //生成首部
75 unsigned short type, unsigned long daddr,
76 unsigned long saddr, unsigned len);
77 void (*add_arp) (unsigned long addr, struct sk_buff *skb, //向arp表中添加表项
78 struct device *dev);
79 void (*queue_xmit)(struct sk_buff *skb, struct device *dev, int pri); //向链路层传递数据的函数
80 int (*rebuild_header)(void *eth, struct device *dev); //重建首部
81 unsigned short (*type_trans) (struct sk_buff *skb, struct device *dev); //类型转换
82 void (*send_packet)(struct sk_buff *skb, struct device *dev); //发送数据报
83 void *private; //私有数据
84
85 unsigned short type; //设备类型
86 unsigned short hard_header_len; //首部长度
87 unsigned short mtu; //最大传输单元
88 unsigned char broadcast[MAX_ADDR_LEN]; //广播地址
89 unsigned char dev_addr[MAX_ADDR_LEN]; //设备MAC地址
90 unsigned char addr_len; //硬件地址长度
91 };
net/tcp/sock.h
155 struct sk_buff //描述数据报的
156 {
157 struct sk_buff *next; //
158 struct sk_buff *prev; //链接成双向链表
159 struct sk_buff *link3; //重传队列
160 volatile struct sock *sk; //描述TCP连接
161 unsigned long when; /* used to compute rtt's. */
162 struct device *dev; //属于哪个设备
163 void *mem_addr; //内存地址
164 union
165 {
166 struct tcp_header *th;
167 struct enet_header *eth;
168 struct ip_header *iph;
169 struct udp_header *uh;
170 struct arp *arp;
171 unsigned char *raw;
172 unsigned long seq;
173 } h; //首部,对于不同协议,意义不同
174 unsigned long mem_len; //包括结构体和数据在内的长度
175 unsigned long len; //数据部分的长度
176 unsigned long saddr; //源地址
177 unsigned long daddr; //目的地址
178 int magic; //魔数
179 unsigned long acked:1,used:1,free:1,arp:1, urg_used:1, lock:1; //
180 };
51 struct sock //描述TCP连接的
52 {
53 struct options *opt; //选项
54 unsigned long wmem_alloc; //写内存大小
55 unsigned long rmem_alloc; //读内存大小
56 unsigned long send_seq; //发送序号
57 unsigned long acked_seq; //确认序号
58 unsigned long copied_seq; //拷贝序号
59 unsigned long rcv_ack_seq; //接收确认序号
60 unsigned long window_seq; //窗口序号
61 unsigned long fin_seq; //fin序号
62 unsigned long inuse:1, dead:1, urginline:1,
63 intr:1, blog:1, done:1, reuse:1, keepopen:1, linger:1,
64 delay_acks:1, timeout:3, destroy:1, ack_timed:1, no_check:1,
65 exp_growth:1;
66 int proc; //进程?
67 volatile struct sock *next; //链接下一个
68 volatile struct sock *pair; //
69 struct sk_buff *send_tail; //重传队列尾
70 struct sk_buff *send_head; //重传队列头
71 struct sk_buff *back_log; //积压
72 struct sk_buff *send_tmp; //临时发送缓冲
73 long retransmits; //重新发送
74 struct sk_buff *wback, *wfront, *rqueue; //写队列,接收队列
75 struct proto *prot; //协议
76 struct wait_queue **sleep; //等待队列
77 unsigned long daddr; //目的地址
78 unsigned long saddr; //源地址
79 unsigned short max_unacked; //最大未确认
80 unsigned short window; //窗口大小
81 unsigned short bytes_rcv; //接收字节数
82 unsigned short mtu; //maximum transmit unit
83 unsigned short num; //
84 unsigned short cong_window; //拥塞窗口
85 unsigned short packets_out; //可以发送的数据报数量
86 unsigned short urg; //紧急字段
87 unsigned short shutdown; //
88 unsigned short mss; //max segment size
89 short rtt; //往返
90 short err;
91 unsigned char protocol; //协议名
92 unsigned char state; //状态
93 unsigned char ack_backlog; //确认积压队列
94 unsigned char max_ack_backlog; //队列大小,防止内存耗尽
95 unsigned char priority; //优先级
96 struct tcp_header dummy_th; /* I may be able to get rid of this. *///用来描述连接的另一端
97 struct timer time_wait; //等待定时器
98 };
上面的数据结构已经给出了注释,有些地方我也不是很确定,大致看一下就可以了,具体的含义会在后面的源码中逐步推断出来。
2.
loopback
132 int
133 loopback_init(struct device *dev)
134 {
135 printk ("Loopback device init\n");
136 /* initialize the rest of the device structure. */
137 dev->mtu = 2000; /* mtu */
138 dev->hard_start_xmit = loopback_xmit; //将数据发送给设备
139 dev->open = NULL;
140 dev->hard_header = eth_hard_header; //生成头
141 dev->add_arp = NULL; //不需要arp,因为不会发送给其他主机
142 dev->hard_header_len = sizeof (struct enet_header); //首部长度
143 dev->addr_len = ETHER_ADDR_LEN; //硬件地址长度
144 dev->type = ETHER_TYPE; //设备类型
145 dev->queue_xmit = dev_queue_xmit; //向链路层传递数据的函数
146 dev->rebuild_header = eth_rebuild_header; //重建首部
147 dev->type_trans = eth_type_trans; //类型转换(返回sk_buff首部type字段)
148 dev->loopback = 1; //回环设备标志
149 return (0);
150 }
可以看到初始化函数非常简单,通俗的说 loopback_xmit指明数据从哪来,dev_queue_xmit指明数据到哪去,剩余的则指明数据和设备本身的相关属性。
3.wd8003
647 int
648 wd8003_init(struct device *dev)
649 {
650 unsigned char csum;
651 int i;
652 csum = 0;
653 for (i = 0; i < 8; i++)
654 {
655 csum += inb_p(WD_ROM+i);
656 }
657 if (csum != WD_CHECK)
658 {
659 printk ("Warning WD8013 board not found at i/o = %X.\n",dev->base_addr);
660
661 /* make sure no one can attempt to open the device. */
662 status = OPEN;
663 return (1);
664 }
665 printk("wd8013");
上面是校验工作。(怎么校验的?)
666 /* initialize the rest of the device structure. */
667 dev->mtu = 1500; /* eth_mtu */以太网MTU
668 dev->hard_start_xmit = wd8003_start_xmit; //发送数据到硬件的函数
669 dev->open = wd8003_open; //打开函数
670 dev->hard_header = eth_hard_header; //头部生成函数
671 dev->add_arp = eth_add_arp; //在arp表中添加表项函数
672 dev->type_trans = eth_type_trans; //类型转换函数
673 dev->hard_header_len = sizeof (struct enet_header); //首部长度
674 dev->addr_len = ETHER_ADDR_LEN; //地址长度 6
675 dev->type = ETHER_TYPE; //类型
676 dev->queue_xmit = dev_queue_xmit; //向链路层发送数据函数
677 dev->rebuild_header = eth_rebuild_header; //重建首部函数
678 for (i = 0; i < DEV_NUMBUFFS; i++)
679 dev->buffs[i] = NULL; //初始化缓冲区为NULL
681 #ifndef FORCE_8BIT
682 /* check for 16 bit board - it doesn't have register 0/8 aliasing */
683 for (i = 0; i < 8; i++) {
684 if( inb_p( EN_SAPROM+i ) != inb_p( EN_CMD+i) ){
685 csum = inb_p( EN_REG1 ); /* fiddle with 16bit bit */
686 outb( csum ^ BUS16, EN_REG1 ); /* attempt to clear 16bit bit */
687 if( (csum & BUS16) == (inb_p( EN_REG1 ) & BUS16) ) {
688 printk(", using 16 bit I/F ");
689 dconfig |= 1; /* use word mode of operation */
690 outb_p( LAN16ENABLE|MEMMASK, EN_REG5);
691 outb( csum , EN_REG1 );
692 break; /* We have a 16bit board here! */
693 }
694 outb( csum , EN_REG1 );
695 }
696 }
697 #endif /* FORCE_8BIT */
699 /* mapin the interface memory. */
700 outb_p(WD_IMEM,WD_CTL);
702 /* clear the interface memory */
703 for (i = dev->mem_start; i < dev->mem_end; i++)
704 {
705 *((unsigned char *)i) = 0;
706 if (*((unsigned char *)i) != 0)
707 {
708 printk ("WD Memory error.\n");
709 if( (i - dev->mem_start) > 4096 )
710 break;
711 else
712 status = OPEN;
713 }
714 }
假设一切顺利,也就是706行为false,i最终等于mem_end。如果为true也就是MD发生内存错误,那么如果此时有超过一个内存页的可用内存,就用i来记录这个位置。否则,设置status为OPEN,保证没有人会打开此设备。这里说明至少要有4K空间可用。
715 /* Calculate how many pages of memory on board */
716 max_pages = ( i - dev->mem_start )/256;
计算网卡适配器(?)内存页数
718 /* need to set up the dev->mem_end and dev->rmem_end */
719 dev->rmem_end = i;
720 dev->mem_end = i;
722 /* print the initialization message, and the
723 ethernet address. */
724 printk (", %d pages memory, ethernet Address: ", max_pages );
725 for (i = 0; i <ETHER_ADDR_LEN; i++)
726 {
727 dev->dev_addr[i]=inb_p(WD_ROM+i); //读取硬件地址
728 dev->broadcast[i]=0xff; //广播地址设为全1
729 printk ("%2.2X ",dev->dev_addr[i]);
730 }
732 /* Clear the statistics */
733 for( i = 0; i < sizeof( struct enet_statistics ); i++ )
734 ((char *)&stats)[i] = 0;
清空statics,这是用来统计数据的
736 printk ("\n");
737 status = 0;
739 if (irqaction (dev->irq, &wd8003_sigaction))
740 {
741 printk ("Unable to get IRQ%d for wd8013 board\n", dev->irq);
742 return (1);
743 }
注册中断请求处理函数为wd8003_sigaction,它会把耗时操作交给上一篇文章中提到的下半部来处理
744 return (0);
745 }
硬件初始化就分析到这里。
相关文章推荐
- centos minimal 网络配置
- 计算机网络七层协议模型
- 浅谈HTTP中Get与Post的区别(转)
- Openstack Murano(Kilo) 网络排错
- java 网络编程之Socket详解
- java web基础之mvc模式设计(一)--使用httpservlet实现mvc分层设计,DAO层使用的是dbutils实现与数据库的链接
- 神经网络neural networks+决策树decision tree 组合算法
- HTTP协议
- HTTP 请求报头详解
- IOS网络笔记--文件下载练习
- 深入浅出 Cocoa 之 Bonjour 网络编程
- httpclient调用方法
- Okhttp的简单使用
- node.js中http.respone.end方法概述
- 转自:超全超详细的HTTP状态码
- 从网络获取数据的几种方法
- java使用siger 轻松获取本机硬件信息(CPU 内存 网络 io等)
- C/S结构网络开发与B/S结构网络开发认识
- 黑马程序员--网络编程
- Http协议与TCP协议简单理解(转)