嵌入式网络设备驱动程序设计(改).ppt_第1页
嵌入式网络设备驱动程序设计(改).ppt_第2页
嵌入式网络设备驱动程序设计(改).ppt_第3页
嵌入式网络设备驱动程序设计(改).ppt_第4页
嵌入式网络设备驱动程序设计(改).ppt_第5页
已阅读5页,还剩41页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第8章 嵌入式网络设备驱动程序设计,8.1 嵌入式网络设备驱动程序 8.2 基于以太网控制器AX88796的接口设计 8.3 Linux网络设备驱动程序实例,8.1 嵌入式网络设备驱动程序,8.1.1 Linux网络设备驱动程序的体系结构,8.1.2 Linux网络设备驱动程序的数据结构,在网络驱动程序的两个数据结构: 网络设备数据结构devic: 其中包括设备初始化时调用的init函数、打开和关闭网络设备的open和stop函数、处理数据包发送的hard_start_xmit函数等。 套接字缓冲区sk_buff: TCP/IP 中不同协议层间,以及与网络驱动程序之间数据包的传递都是通过这个s

2、k_buff结构体来完成的,这个结构体主要包括传输层、网络层、连接层需要的变量,决定数据区位置和大小的指针,以及发送接收数据包所用到的具体设备信息等。根据网络应用的特点,对链表的操作主要是删除链表头的元素和添加元素到链表尾。,device数据结构,net_device数据结构是为IP层访问该设备提供接口。 数据结构device操作的数据对象数据包是通过数据结构sk_buff来封装的,它是在/include/linux/netdevice.h中定义。,struct net_device char nameIFNAMSIZ; /*网络设备特殊文件,每一个名字表示其设备类型,以太网设备号为/dev/

3、eth0、/dev/eth1等。*/ unsigned longrmem_end;/* rmem域段表示接收内存末地址*/ unsigned longrmem_start;/* rmem域段表示接收内存首地址*/ unsigned longmem_end;/* mem域段表示发送内存末地址*/ unsigned longmem_start;/* mem域段表示发送内存首地址*/ unsigned longbase_addr;/* 设备I/O地址*/ unsigned intirq;/* 设备IRQ号*/ unsigned charif_port;/* 记录哪个硬件I/O口正在被接口所用*/ u

4、nsigned chardma;/* DMA通道*/ unsigned longstate; struct net_device*next;/*指向下一个网络设备*/ int(*init)(struct net_device *dev);/*指向驱动程序的初始化方法*/,struct net_device *next_sched; /*指向下一个调度*/ intifindex; /*设备标识符*/ intiflink; struct net_device_stats* (*get_stats)(struct net_device dev);/*返回一个enet_statistic结构,包括发送

5、、接收的统计计信息*/ struct iw_statistics* (*get_wireless_stats)(struct net_device *dev); unsigned longtrans_start; /*记录最后一次发送成功的时间*/,unsigned longlast_rx; /*记录最后一次接收成功的时间*/ unsigned shortflags; /*接口标示*/ unsigned shortgflags; unsigned shortunused_alignment_fixer; unsigned mtu; unsigned shorttype; /*物理硬件类型*/

6、unsigned shorthard_header_len;/*硬件帧头的长度*/ void*priv; /*私有区间指针*/ struct net_device*master; /*接口地址信息*/ unsigned charbroadcastMAX_ADDR_LEN;/*广播网地址*/ unsigned chardev_addrMAX_ADDR_LEN;/*硬件地址*/ unsigned charaddr_len; /*地址长度*/ struct dev_mc_list*mc_list; /* mac地址列表*/,struct Qdisc*qdisc_sleeping; struct Qd

7、isc*qdisc_list; struct Qdisc*qdisc_ingress; unsigned longtx_queue_len; /* Max frames per queue allowed */ /*传输函数指针同步器 */ spinlock_txmit_lock; intxmit_lock_owner; spinlock_tqueue_lock; atomic_trefcnt; intdeadbeaf; intfeatures; #define NETIF_F_SG1 /* Scatter/gather IO.*/ #define NETIF_F_IP_CSUM2 /* IP

8、v4上TCP/UDP的检错*/ #define NETIF_F_NO_CSUM4 /* 回环时不检错*/ #define NETIF_F_HW_CSUM8 /* 检查所有包*/ #define NETIF_F_DYNALLOC16 #define NETIF_F_HIGHDMA32 #define NETIF_F_FRAGLIST64,void(*uninit)(struct net_device *dev);/*释放网络设备时执行该函数*/ void(*destructor)(struct net_device *dev);/*撤销器*/ int(*open)(struct net_devi

9、ce *dev);/*打开网络接口*/ int(*stop)(struct net_device *dev);/*停止网络接口*/ int (*hard_start_xmit) (struct sk_buff skb,struct net_device dev);/发送int(*hard_header) (struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); /*硬件帧头*/ int(*rebuild_header)(struct sk

10、_buff *skb);/*在一个包被发送之前重建帧头*/ #define HAVE_MULTICAST /*设置多点传输地址链表*/ void(*set_multicast_list)(struct net_device *dev); #define HAVE_SET_MAC_ADDR/*当用户调用ioctl类型为SIOCSIFWADDR时需设置设备mac地址*/,int(*set_mac_address)(struct net_device *dev,void *addr); #define HAVE_PRIVATE_IOCTL /*当用户调用ioctl类型为SIOCDEVPRIVATE和

11、别SIOCDEVPRIVATE+15之间,系统会调用驱动程序的这个方法*/ int(*do_ioctl)(struct net_device *dev,struct ifreq *ifr, int cmd); #define HAVE_SET_CONFIG/*当用户调用ioctl类型为SIOCSIFMAP时,系统会调用驱动程序的set_config方法。用户传递一个ifmap结构*/ int(*set_config)(struct net_device *dev,struct ifmap *map); #define HAVE_HEADER_CACHE Int(*hard_header_cac

12、he)(struct neighbour *neigh,struct hh_cache *hh); void(*header_cache_update)(struct hh_cache *hh, struct net_device *dev,unsigned char * haddr); #define HAVE_CHANGE_MTU int(*change_mtu)(struct net_device *dev, int new_mtu); #define HAVE_TX_TIMEOUT/*传输超时*/ void (*tx_timeout) (struct net_device *dev);

13、,int(*hard_header_parse)(struct sk_buff *skb,unsigned char *haddr); int(*neigh_setup)(struct net_device *dev, struct neigh_parms *); int(*accept_fastpath)(struct net_device *, struct dst_entry*); struct module *owner; /* 打开、释放、使用时生成*/ struct net_bridge_port*br_port; /* 网桥接口*/ #ifdef CONFIG_NET_FASTR

14、OUTE #define NETDEV_FASTROUTE_HMASK 0 xF/半私有数据,保存在设备结构尾部rwlock_tfastpath_lock; struct dst_entry*fastpathNETDEV_FASTROUTE_HMASK+1; #endif #ifdef CONFIG_NET_DIVERT/* 每个类型接口初始化时调用*/ struct divert_blk*divert; #endif /* CONFIG_NET_DIVERT */ ;,2sk_buff数据结构 Linux网络各层之间的数据传送,如:TCP/IP 中不同协议层间,以及与网络驱动程序之间数据包的

15、传递都是通过这个套接字缓冲区sk_buff结构体来完成的,这个结构体主要包括传输层、网络层、连接层需要的变量,决定数据区位置和大小的指针,以及发送接收数据包所用到的具体设备信息等。根据网络应用的特点,对链表的操作主要是删除链表头的元素和添加元素到链表尾。sk_buff数据结构是在/include/linux/skbuff.h文件中定义。 struct sk_buff struct sk_buff* next;/ next指向sk_buff双向链表的后缓冲区结点struct sk_buff* prev;/* Prev指向前一个缓冲区结点*/ struct sk_buff_head * list;

16、/* sk_buff_head链表*/ struct sock*sk;/* 拥有的Socket套接口*/ struct timevalstamp;/* 到达时间*/ struct net_device*dev;/* 涉及的设备*/,union /* 传输层数据包头*/ struct tcphdr*th; struct udphdr*uh; struct icmphdr*icmph; struct igmphdr*igmph; struct iphdr*ipiph; struct spxhdr*spxh; unsigned char*raw; h; Union /* 网络层数据包头 */ str

17、uct iphdr*iph; struct ipv6hdr*ipv6h; struct arphdr*arph; struct ipxhdr*ipxh; unsigned char*raw; nh;,union /* 链路层数据包头 */ struct ethhdr*ethernet; unsigned char *raw; mac; struct dst_entry *dst; /* 发送地址*/ charcb48; /* 一般存放每层的控制指令和控制数据*/ unsigned int len; /* 数据包长度*/ unsigned int data_len; unsigned intcs

18、um; /* 校验和*/ unsigned char _unused,/* 坏死区域,可以重新使用*/ cloned, pkt_type,ip_summed; _u32priority; atomic_tusers; unsigned shortprotocol;/* 包协议*/ unsigned shortsecurity;/* 包的安全等级*/ unsigned inttruesize;/* 缓冲区大小*/ unsigned char*head;/* 缓冲区头*/ unsigned char*data;/* 数据头指针*/ unsigned char*tail;/* 数据尾指针*/ uns

19、igned char *end;/* 结束指针(地址)*/ void (*destructor)(struct sk_buff *); /* 销毁器功能*/,#ifdef CONFIG_NETFILTER unsigned longnfmark; _u32nfcache; struct nf_ct_info *nfct; #ifdef CONFIG_NETFILTER_DEBUG unsigned int nf_debug; #endif #endif /*CONFIG_NETFILTER*/ #if defined(CONFIG_HIPPI) union _u32ifield; privat

20、e; #endif #ifdef CONFIG_NET_SCHED _u32 tc_index;/* 传输控制索引 */ #endif ;,在Linux的内核的/usr/src/linux--8/net/core/skbuff.c中定义了如下所述的一些对sk_buff操作的方法,通过这些方法可以控制sk_buff: alloc_skb()申请一个sk_buff并对它初始化。返回的是申请到的sk_buff。 dev_alloc_skb()类似alloc_skb,在申请好缓冲区后,保留16字节的帧头空间。主要用在Ethernet驱动程序。 kfree_skb()释放一个sk_buff

21、。 skb_clone()复制一个sk_buff,但不复制数据部分。 skb_copy()完全复制一个sk_buff。 skb_dequeue()从一个sk_buff链表里取出第一个元素。返回取出的sk_buff,如果链表空,则返回NULL。这是常用的一个操作。 skb_queue_head()在一个sk_buff链表头放入一个元素。 skb_queue_tail()在一个sk_buff链表尾放入一个元素。网络数据的处理主要是对一个先进先出队列的管理,skb_queue_tail()和skb_dequeue()完成这个工作。 skb_insert()在链表的某个元素前插入一个元素。,skb_a

22、ppend()在链表的某个元素后插入一个元素。一些协议(如TCP)对没按顺序到达的数据进行重组时用到skb_insert()和skb_append()。 skb_reserve()在一个申请好的sk_buff的缓冲区里保留一块空间。这个空间一般是用做下一层协议的头空间的。 skb_put()在一个申请好的sk_buff的缓冲区里为数据保留一块空间。在alloc_skb以后,申请到的sk_buff的缓冲区都是处于空(free)状态,有一个tail指针指向free空间,实际上开始时tail就指向缓冲区头。 skb_reserve()在free空间里申请协议头空间,skb_put()申请数据空间。

23、skb_push()把sk_buff缓冲区里数据空间往前移,即把Head room中的空间移一部分到Data area。 skb_pull()把sk_buff缓冲区里Data area中的空间移一部分到Head room中。 sk_buff的控制方法都很短小以尽量减少系统负荷。,8.1.3 网络驱动程序的基本方法,(1) 初始化(initialize) (2) 打开(open) (3) 数据包的发送与接收 (4)关闭(stop) (5) 实现模式,Linux网络设备驱动程序实现模式,8.2 基于以太网控制器AX88796的接口设计,图 8.3 AX88796结构框图,采用S3C2410X微处理

24、器的嵌入式系统中,采用以太网控制器AX88796来扩展以太网接。S3C2410X微处理器与以太网控制器AX88796的连接结构如图8.4所示。,图8-4 S3C2410X微处理器与AX88796连接结构,8.3 Linux网络设备驱动程序实例,由于Ax88796是NE2000兼容芯片,所以Linux kernel中的驱动ne.c、8390.c只需作较少的改动就可以用来驱动S3C2410X平台上的Ax88796。 以ne2000兼容网卡为例,来具体介绍基于模块的网络驱动程序的设计过程。下面主要介绍ne.c源程序代码,在ne.c源程序中调用了8390.c程序中的很多函数,详细的可以参考文件linu

25、x/drivers/net/ne.c、 linux/drivers/net/8390.c linux/drivers/net/8390.h。,1系统资源和宏定义 在ne.c文件的开始部分定义了一些系统资源和编程中用到的宏。 #include #include #include #include #include #include #include #include #include #include #include #include 8390.h #if defined(CONFIG_SMDK_THREEWATER1)/*-由设计者添加的*/ #include #include #defin

26、e IRQ_NE2000 IRQ_AX88796 /*定义IRQ_NE2000= IRQ_AX88796*/ unsigned char ne_defethaddr = 0 x00, 0 xd0, 0 xcf, 0 x00, 0 x00, 0 x01 ; #endif,#define SUPPORT_NE_BAD_CLONES /*定义支持其它类型的网卡*/ #ifndef MODULE static unsigned int netcard_portlist _initdata = 0 x300, 0 x280, 0 x320, 0 x340, 0 x360, 0 x380, 0 ; #en

27、dif static struct isapnp_device_id isapnp_clone_list _initdata = ISAPNP_ANY_ID, ISAPNP_ANY_ID,ISAPNP_VENDOR(E,D,I), ISAPNP_FUNCTION(0 x0216),(long) NN NE2000 , ISAPNP_ANY_ID, ISAPNP_ANY_ID,ISAPNP_VENDOR(P,N,P), ISAPNP_FUNCTION(0 x80d6),(long) Generic PNP ; MODULE_DEVICE_TABLE(isapnp, isapnp_clone_li

28、st); #ifdef SUPPORT_NE_BAD_CLONES static struct const char *name8, *name16; unsigned char SAprefix4;,bad_clone_list _initdata = DE100, DE200, 0 x00, 0 xDE, 0 x01, NE1000,NE2000-invalid, 0 x00, 0 x00, 0 xd8, /* Ancient real NE1000. */ NN1000, NN2000, 0 x08, 0 x03, 0 x08, /* Outlaw no-name clone. */ 0

29、, ; #endif #define NE_BASE (dev-base_addr) #define NE_CMD 0 x00 #define NE_DATAPORT 0 x10/* NatSemi-defined port window offset. */ #define NE_RESET 0 x1f/* Issue a read to reset, a write to clear. */ #define NE_IO_EXTENT0 x20 #define NE1SM_START_PG0 x20/* 发送缓冲区首页 */ #define NE1SM_STOP_PG 0 x40/* Las

30、t page +1 of RX ring */ #define NESM_START_PG0 x40/* First page of TX buffer */ #define NESM_STOP_PG0 x80/* Last page +1 of RX ring */,2初始化函数 初始化函数完成设备的初始化功能,由数据结构device中的init函数指针来调用。加载网络驱动模块后,就会调用初始化过程。首先通过检测物理设备的硬件特征来检测网络物理设备是否存在,之后配置设备所需要的资源。比如,中断。这些配置完成之后就要构造设备的数据结构device,用检测到的数据初始化device中的相关变量,

31、最后向Linux内核中注册该设备并申请内存空间。网络接口初始化是由ne_probe()函数来完成的,前面已经提到过,在init_module()函数中用它来初始化init函数指针。它主要对网卡进行检测,并且初始化系统中网络设备信息用于后面的网络数据的发送和接收。具体过程及解释如下:,int _init ne_probe(struct net_device *dev) unsigned int base_addr = dev-base_addr; #if defined(CONFIG_SMDK_THREEWATER1) static int once = 0; if (once) return

32、-ENXIO; /*初始化总线宽度和等待控制寄存器。下面语句中的宏如:BWSCON_ST2、BWSCON_WS2是在linux/include/asm-arm/arch-s3c2410/S3C2410.h中定义*/ BWSCON = (BWSCON ,#if 1 if (base_addr = 0) dev-base_addr = base_addr = AX88796_BASE; /*ARM_NE2000_BASE;*/ dev-irq = IRQ_NE2000; /*中断号,ARM_NE2000_IRQ;*/ once+; #endif/结束 #if 0 #endif SET_MODULE

33、_OWNER(dev); /*初始化dev-owner成员,因为使用模块类型驱动,会将dev-owner指向对象modules结构指针。*/ if (base_addr 0 x1ff) /*检测dev-base_addr是否合法,是,则执行ne-probe1( )函数检测过程。不是,则需要自动检测。*/ return ne_probe1(dev, base_addr);,else if (base_addr != 0) /* 不检测 */ return -ENXIO; if (isapnp_present() 函数ne_probe_isapnp()和ne_probe1()的区别在于检测中断号上

34、面。PCI方式只需指定I/O基地址就可以自动获得irq,是由BIOS自动分配的。而ISA方式需要获得空闲的中断资源才能分配。,static int _init ne_probe_isapnp(struct net_device dev) /*调用ne_probe_isapnp( )检测ISAPnP设备这种类型的网卡*/ int i; for (i = 0; isapnp_clone_listi.vendor != 0; i+)/循环检测网络设备 struct pci_dev *idev = NULL; while (idev = isapnp_find_dev(NULL, isapnp_clo

35、ne_listi.vendor, isapnp_clone_listi.function, idev) /*检测ISAPnP设备*/ if (idev-prepare(idev) /* 查找的ISAPnP设备已初始化,继续查找下一设备*/ continue; if (idev-activate(idev) /* 查找的ISAPnP设备已激活,继续查找下一设备*/ continue; if (idev-irq_resource0.start = 0) /* 如果没有中断, 继续查找下一设备*/ continue; dev-base_addr = idev-resource0.start;/*检测

36、到,基地址送dev-base_addr */ dev-irq = idev-irq_resource0.start; /*中断号送dev-irq */ printk(KERN_INFO ne.c: ISAPnP reports %s at i/o %#lx, irq %d.n, (char *) isapnp_clone_listi.driver_data,dev-base_addr, dev-irq);,if (ne_probe1(dev, dev-base_addr) != 0) /*分配中断源,不成功则退出*/ printk(KERN_ERR ne.c: Probe of ISAPnP

37、card at %#lx failed.n, dev-base_addr); return -ENXIO; ei_status.priv = (unsigned long)idev; /*私有指针指向检测到的ISAPnP设备idev结构*/ break; if (!idev) /* struct pci_dev idev结构指针为空,则继续查找ISAPnP网络设备/ continue; return 0; return -ENODEV; ,static int _init ne_probe1(struct net_device *dev, int ioaddr) int i; unsigned

38、 char SA_prom32; int wordlength = 2; const char *name = NULL; int start_page, stop_page; int neX000, ctron, copam, bad_card; int reg0, ret; static unsigned version_printed; if (!request_region(ioaddr, NE_IO_EXTENT, dev-name) /*检查以ioaddr为起址,以NE_IO_EXTENT为长度的这段I/O端口是否被占用,若占用则返回*/ return -EBUSY;,reg0 =

39、 inb_p(ioaddr); /*从ioaddr端口读一字节*/ if (reg0 = 0 xFF) /*若所读端口的值为0 xFF,则转错误处理*/ ret = -ENODEV; goto err_out; /* Do a preliminary verification that we have a 8390. */ /*程序执行到以下花括号中的语句说明检测到有8390网卡,并对8390读写操作*/ int regd; outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);/*设置8390、不使用DMA、而使用第一页

40、*/ regd = inb_p(ioaddr + 0 x0d); /*读取8390网卡值, outb_p(0 xff, ioaddr + 0 x0d); outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD); inb_p(ioaddr + EN0_COUNTER0); /*通过读来清除计数器*/ if (inb_p(ioaddr + EN0_COUNTER0) != 0) /*若清除计数器不成功,则恢复原值*/ outb_p(reg0, ioaddr); /*恢复8390的原值*/ outb_p(regd, ioaddr + 0 x0d); /

41、*恢复8390的原值*/ ret = -ENODEV; /*把-ENODEV(无此设备)送ret*/ goto err_out; /*转错误处理*/ ,if (ei_debug ,outb_p(0 xff, ioaddr + EN0_ISR);/*向外部中断0输出0 xff 作为应答信号*/ /* 以下花括号中程序代码的作用是:为了可靠读取SAPROM 存贮单元的数据,必须从PROM 中读取对寄存器初始化的值,此过程类似于NS8390的初始化。*/ struct unsigned char value, offset; program_seq = E8390_NODMA+E8390_PAGE0

42、+E8390_STOP, E8390_CMD, /* 选择页0*/ 0 x48,EN0_DCFG, /* 设置存储的字节宽度 (0 x48) */ 0 x00,EN0_RCNTLO,/* 计数寄存器清零 */ 0 x00,EN0_RCNTHI, 0 x00,EN0_IMR, /* 屏蔽中断 */ 0 xFF,EN0_ISR, E8390_RXOFF, EN0_RXCR,/* 0 x20 设置监示器 */ E8390_TXOFF, EN0_TXCR,/* 0 x02 和 loopback 模式. */ 32,EN0_RCNTLO, 0 x00,EN0_RCNTHI, 0 x00,EN0_RSAR

43、LO, /* DMA 从0 x0000开始. */ 0 x00,EN0_RSARHI, E8390_RREAD+E8390_START, E8390_CMD, ;,for (i = 0; i sizeof(program_seq)/sizeof(program_seq0); i+) outb_p(program_seqi.value, ioaddr + program_seqi.offset); #if defined(CONFIG_ARCH_S3C2410) /*若定义了配置S3C2410,则按S3C2410对变量赋值*/ unsigned char *ep; static int nr =

44、 0; ep = (unsigned char *) #endif,if (wordlength = 2) #if !defined(CONFIG_ARCH_S3C2410)/-by threewater for (i = 0; i 16; i+) SA_promi = SA_promi+i; #endif /*在字模式下的 8390的设置 */ outb_p(0 x49, ioaddr + EN0_DCFG); start_page = NESM_START_PG; stop_page = NESM_STOP_PG; else start_page = NE1SM_START_PG; sto

45、p_page = NE1SM_STOP_PG; neX000 = (SA_prom14 = 0 x57 /* 其它参数的设置 */,if (neX000 | bad_card | copam) name = (wordlength = 2) ? NE2000 : NE1000; else if (ctron) name = (wordlength = 2) ? Ctron-8 : Ctron-16; start_page = 0 x01; stop_page = (wordlength = 2) ? 0 x40 : 0 x20; else if (! dev-irq) /*检测网络设备的中断号

46、*/ printk( failed to detect IRQ line.n); ret = -EAGAIN; goto err_out; ,if (ethdev_init(dev)/初始化8390的dev,不成功,则转错误处理 printk ( unable to get memory for dev-priv.n); ret = -ENOMEM; goto err_out; ret = request_irq(dev-irq, ei_interrupt, 0, name, dev);/*申请中断*/ if (ret) /*申请中断不成功,转申请中断出错处理*/ printk ( unabl

47、e to get IRQ %d (errno=%d).n, dev-irq, ret); goto err_out_kfree; /*转申请中断出错处理*/ dev-base_addr = ioaddr; for(i = 0; i dev_addri = SA_promi; /*显示网络设备基地址*/ printk(n%s: %s found at %#x, using IRQ %d.n,dev-name, name, ioaddr, dev-irq);,/*下面的一段代码用到了ei_status结构,它是在8390.h头文件中定义,它的定义形式如下: #define ei_status (*

48、(struct ei_device )(dev-priv);而结构struct ei_device也是在8390.h头文件中定义,它是设计人员自定义的一个网络设备数据结构。本网络设备驱动程序除使用了网络设备数据结构struct net_device外,设计人员添加了一个本网络驱动程序的网络设备数据结构采用struct ei_device,它包括了一些自定义的供系统访问和协议层调用的设备方法,还包括了一些有关在使用8390时要求设置的成员参数,具体的内容详见8390.h头文件。*/ ei_ = name; ei_status.tx_start_page = start_pa

49、ge; ei_status.stop_page = stop_page; ei_status.word16 = (wordlength = 2); ei_status.rx_start_page = start_page + TX_PAGES; #ifdef PACKETBUF_MEMSIZE /*若定义了包缓冲器大小,则可得停止页的位置*/ ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE; /*停止页*/ #endif,ei_status.reset_8390 = ,3网络接口设备打开和关闭 网络接口设备打开

50、就是激活网络接口,使它能接收来自网络的数据并且传递到网络协议栈的上面,也可以将数据发送到网络上。设备关闭就是停止操作。 在ne2000网络驱动程序中网络设备打开由dev_open( )和ne_open( )完成。设备关闭有dev_close( )和ne_close( )完成。它们相应调用底层函数ei_open( )和ei_close( )来完成。ei_open( )和ei_close( )是在linux/drivers/net/8390.c中定义。 static int ne_open(struct net_device *dev) ei_open(dev); return 0; static int ne_close(struct net_device *dev) if (ei_debug 1) printk(KERN_DEBUG %s: Shutting down ethercard.n, dev-nam

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论