- 浏览: 15997774 次
- 性别:
- 来自: 济南
最新评论
-
wu1236:
ef0793cd94337324b6fefc4c9474af5 ...
Android ApiDemos示例解析(87):Media->MediaPlayer -
77219634:
0127bf2236bee4dd1f632ce430f1af1 ...
本博客文章都为转载,没有任何版权! -
77219634:
0127bf2236bee4dd1f632ce430f1af1 ...
VPLEX - EMC的RAC -
77219634:
0127bf2236bee4dd1f632ce430f1af1 ...
qTip2 Show -
77219634:
0127bf2236bee4dd1f632ce430f1af1 ...
SecureCRT中文乱码、复制粘贴乱码解决办法(修改版)
/*********************************************************************************
*
* net_test.c a simple net device driver sample
*
*
*********************************************************************************
*/
#ifndef __KERNEL__
#define__KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#define __NO_VERSION__
#include
<linux kernel.h=""></linux>
#include
<linux module.h=""></linux>
#include
<linux sched.h=""></linux>
#include
<linux init.h=""></linux>
#include
<linux in.h=""></linux>
#include
<linux netdevice.h=""></linux>
#include
<linux etherdevice.h=""></linux>
#include
<linux ip.h=""></linux>
#include
<linux tcp.h=""></linux>
static int test_init(struct net_device *dev);
static int test_open(struct net_device *dev);
static int test_release(struct net_device *dev);
static int test_config(struct net_device *dev, struct ifmap *map);
static int test_tx(struct sk_buff *skb, struct net_device *dev);
inttest_init_module(void);
void test_cleanup(void);
#define DEVICE_NAME "test" //内核模块名称
module_init(test_init_module);
module_exit(test_cleanup);
//定义结构体变量并初始化必须的成员
static struct net_devicenet_test =
{
init:test_init,
};
static int test_init(struct net_device *dev)
{
ether_setup(dev);//初始化结构体变量中与硬件无关的成员
strcpy(dev->name,"eth0");
dev->open =test_open;
dev->stop =test_release;
dev->set_config =test_config;
dev->hard_start_xmit =test_tx;
dev->flags &=~(IFF_BROADCAST|IFF_LOOPBACK|IFF_MULTICAST);
//设置驱动中感兴趣的成员...
SET_MODULE_OWNER(dev);//设置owner成员
return 0;
}
//当网络设备驱动程序不能自动识别硬件配置时,系统管理员会使用配制工具将正确的硬件配置传递给
//驱动程序。实际上就是调用驱动程序的set_config()方法。
static int test_config(struct net_device *dev, struct ifmap *map)
{
return 0;
}
static int test_tx(struct sk_buff *skb, struct net_device *dev)
{
return 0;
}
static int test_open(struct net_device *dev)
{
MOD_INC_USE_COUNT;
netif_start_queue(dev);//第一次调用open()方法必须调用
return 0;
}
static int test_release(struct net_device *dev)
{
netif_stop_queue(dev);//最后一次调用stop()方法必须调用
MOD_DEC_USE_COUNT;
return 0;
}
inttest_init_module(void)
{
int result = 0;
//初始化模块自身(包括请求一些资源)
result = register_netdev(&net_test);//注册网络设备驱动程序
if(result < 0)
{
printk(KERN_ERR DEVICE_NAME":error % i registering device \"%s\"\n", result , net_test.name);
return result;
}
printk(KERN_ERR DEVICE_NAME ":init OK\n");
return 0;
}
void test_cleanup(void)
{
unregister_netdev(&net_test); //卸载驱动程序
}
//////////////////////////////////////////////////////////////
|
1.1.1 步骤三:网络驱动程序的数据结构和抽象接口
首先熟悉以下重要的数据结构,然后对照DM9000的驱动程序,察看具体数据结构的用法。
保存网络设备信息的结构体net_device
net_device结构存储了网络设备的操作方法和其他信息。其定义如下面的清单。仅仅列出了部分常用的成员,对于普通的网络设备驱动程序已足够。想详细了解的结构体参考LDD(Linux Device Driver)或内核源码/include/linux/netdevice.h
程序清单 0‑2
struct net_device { char name[IFNAMSIZ]; unsigned short flags; /* interface flags (a <personname w:st="on" productid="la BSD"></personname> la BSD) */ unsigned long base_addr; /* device I/O address */ unsigned int irq; /* device IRQ number */ unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */ unsigned char addr_len; /* hardware address length */ unsigned long trans_start; /* Time (in jiffies) of last Tx */ unsigned long last_rx; /* Time of last Rx */ int watchdog_timeo; void *priv; /* pointer to private data */ struct module *owner; /* open/release and usage marking */
int (*init)(struct net_device *dev); int (*open)(struct net_device *dev); int (*stop)(struct net_device *dev); int (*set_config)(struct net_device *dev, struct ifmap *map); int (*hard_start_xmit) (struct sk_buff *skb,struct net_device *dev); int (*set_mac_address)(struct net_device *dev, void *addr); //.............. }; |
网卡实现的抽象接口
init(),open(),stop(),set_config()方法在模板中已经清楚地介绍了,这里重点讲解hard_start_xmit()方法。当内核需要发送一个数据包时,他调用hard_start_xmit()方法将数据放到一个输出队列。数据包包含在一个套接字缓冲区结构体(struct sk_buff)变量中。对于驱动程序来说,sk_buff只是一个数据包,不用关心里面复杂的结构成员。
程序清单 0‑3
static int test_tx(struct sk_buff * skb , struct net_device * dev) { int len;
netif_stop_queue(dev); //让内核暂停调用hard_start_xmit()方法 len = skb->len < ETH_ZLEN ? ETH_ZLEN :skb->len; //把len个数据写入网络设备硬件缓冲区并启动发送; dev->trans_start = jiffies; //记录时间 dev_kfree_skb(skb); //等待数据发送完毕 netif_wake_queue(dev);
return 0; }
static int test_set_mac_address(struct net_device * dev, void *addr) { struct socketaddr * mac_addr;
mac_addr = addr; if(netif_running(dev)) { Return –EBUSY; } memcpy(dev->dev_addr , mac_addr->sa_data , dev->addr_len); //改变mac地址,与具体硬件相关。 return 0; } |
一般网络驱动程序不对发送数据进行缓存,而是直接使用硬件的发送功能把数据发送出去。接收数据则通过硬件中断来通知的。在中断处理程序中,把硬件帧信息填入一个sk_buff结构中,然后调用netif_rx()传递给上层处理。当然,在使用中断之前,需要向系统注册中断处理程序。
下面是中断服务程序的写法:
static void net_irq_handle(int irq, void * dev_id, struct pt_regs * regs) { struct net_device * dev; struct sk_buff *skb; unsigned int length; u8 * dec;
dev = (struct net_device *)dev_id; if(发送成功) { 清除发送中断标志; netif_wake_queue(dev); } if(接收成功) { 清除接受中断标志; length = 数据包长度; skb = dev_alloc_skb(length + 2); if(!skb) { return; } skb_reserve(skb, 2); dec = skb->data; //把数据包(length长度)读到dec指向的内存中; skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_UNNECESSARY; netif_rx(skb); dev->last_rx = jiffies; }
if(出错) 错误处理
清除中断源; } |
1.1.1 步骤四:分析DM9000的网卡驱动程序
驱动程序共包含三个文件dm9000x.c ,dm9000.c 和dm9000.h,都存放在drivers/net/目录下,其中dm9000x.c 主要包括以下函数:
底层硬件操作函数:这些函数与硬件相关,与驱动程序编写相关不大。
void outb(unsigned char value, unsigned long addr) void outw(unsigned short value, unsigned long addr) unsigned char inb(unsigned long addr) unsigned short inw(unsigned long addr)
u8 ior(board_info_t *db, int reg) // Read a byte from I/O port void iow(board_info_t *db, int reg, u8 value) // Write a byte to I/O port
|
驱动程序的函数接口,
int init_module(void) ; //加载设备驱动程序 void cleanup_module(void) //卸载设备驱动程序
static void dmfe_init_dm9000(struct DEVICE *dev) /* Initilize DM910X board */ dmfe_probe(struct DEVICE *dev); //初始化net_device 结构体 static int dmfe_open(struct DEVICE *dev) static int dmfe_stop(struct DEVICE *dev) static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) //发送一个数据包 static void dmfe_packet_receive(struct DEVICE *dev, board_info_t *db) //接收数据包,被中断调用
|
其中int init_module(void)函数调用了dmfe_probe(struct DEVICE *dev)来初始化net_device结构体
if(strcmp(dev->name,"eth0")==0) if(strcmp(dev->name,"eth1")==0) if(strcmp(dev->name,"eth3")==0)
outb(DM9000_VID_L, iobase); id_val = inb(iobase + 4); outb(DM9000_VID_H, iobase); id_val |= inb(iobase + 4) << 8; outb(DM9000_PID_L, iobase); id_val |= inb(iobase + 4) << 16; outb(DM9000_PID_H, iobase); id_val |= inb(iobase + 4) << 24;
if (id_val == DM9000_ID) { printk("HHTech DM9000 %s I/O: %x,VID: %x,MAC: ", dev->name,iobase, id_val); dm9000_count++; /* Init network device */ dev = init_etherdev(dev, 0);
/* Allocated board information structure */ irqline = 3; db = (void *)(kmalloc(sizeof(*db), GFP_KERNEL|GFP_DMA)); memset(db, 0, sizeof(*db)); dev->priv = db; /* link device and board info */ db->next_dev = dmfe_root_dev; dmfe_root_dev = dev; db->ioaddr = iobase; db->io_data = iobase + 4;
/* driver system function */ dev->base_addr = iobase; //dev->irq = 68; //INT4 166;//irqline; dev->open = &dmfe_open; dev->hard_start_xmit = &dmfe_start_xmit; dev->stop = &dmfe_stop; dev->get_stats = &dmfe_get_stats; dev->set_multicast_list = &dm9000_hash_table; dev->do_ioctl = &dmfe_do_ioctl;
|
在dmfe_open(struct DEVICE *dev)中,申请了中断处理程序,然后调用了
dmfe_init_dm9000(dev);初始化DM9000芯片。
static int dmfe_open(struct DEVICE *dev) { if(request_irq(dev->irq, &dmfe_interrupt,SA_INTERRUPT/*SA_SHIRQ*/, "DM9000 device",dev)) return -EAGAIN; /* Initilize DM910X board */ dmfe_init_dm9000(dev);
netif_wake_queue(dev); //add by simon 2001.9.4 for kernel 2.4 MOD_INC_USE_COUNT; } |
Stop()方法停止网络驱动程序:
static int dmfe_stop(struct DEVICE *dev) { netif_stop_queue(dev); //add by simon 2001.9.4 for kernel 2.4
/* free interrupt */ free_irq(dev->irq, dev);
/* RESET devie */ phy_write(db, 0x00, 0x8000); /* PHY RESET */ iow(db, 0x<chmetcnv w:st="on" unitname="F" sourcevalue="1" hasspace="False" negative="False" numbertype="1" tcsc="0"></chmetcnv>1f, 0x01); /* Power-Down PHY */ iow(db, 0xff, 0x80); /* Disable all interrupt */ iow(db, 0x05, 0x00); /* Disable RX */
MOD_DEC_USE_COUNT; 发表评论 |
相关推荐
嵌入式linux下DM9000网卡驱动的移植与实现.pdf
dm9000网卡驱动分析 dm9000网卡驱动分析 dm9000网卡驱动分析 dm9000网卡驱动分析 dm9000网卡驱动分析
嵌入式linux上的dm9000网卡驱动源代码和Makefile编译驱动文件源代码
linux内核的DM9000网卡驱动,注意:对于linux源码中已经存在的驱动文件,网络驱动内容只需要修改一下几点:网卡基地址,中断号,网卡工作模式,中断触发方式.
网卡开发必须要熟悉的驱动流程 dm9000网卡驱动分析
arm9开发板上 dm9000网卡驱动程序分析
此源码已调试通过,相比内核自带的源码,思路更清晰,非常适合入门者学习。
linux-2.6.28在mini2440上的移植之dm9000网卡驱动的移植
自己编写的DM9000网卡驱动(linux), 实现了网卡的基本功能, 供初学者参考。
Linux下DM9000网卡驱动实验.doc lwip 到 lxRTOS 移植实现.doc NIOS II网络驱动程序分析(1).doc 基于MFC的网络通讯.doc 基于嵌入式调试器的网络通信方法设计与实现.doc 网卡.doc 请问有会dm9000驱动的么.doc ...
linux dm9000网卡完全驱动 实现基本的网络通信经过大量测试 适合移植使用
S3C6410为基础的linux系统环境下的网卡DM9000驱动程序源代码
Linux下DM9000网卡驱动实验.doc lwip 到 lxRTOS 移植实现.doc NIOS II网络驱动程序分析(1).doc 基于MFC的网络通讯.doc 基于嵌入式调试器的网络通信方法设计与实现.doc 网卡.doc 请问有会dm9000驱动的么.doc ...
1. 移植DM9000网卡驱动 之前配置使用的SMDK2440开发板,默认不支持DM9000网卡驱动,但是其中的MINI2440开发板支持,所以要将MINI2440中的DM9000驱动移植到SMDK2440中。 进入内核源码目录里面,找到 arch/arm/mach-s3...
第一天 1.Linux驱动简介 2.字符设备驱动程序设计 3.驱动调试技术 4. 并发与竞态 第二天 1.Ioctl型驱动 ...3. Dm9000网卡驱动程序分析 4. 触摸屏驱动程序设计 第六天 1. PCI驱动程序设计 2. 串口驱动程序设计
dm9000网卡驱动、linux下驱动学习、国嵌的培训教程
Linux驱动修炼之道-DM9000A网卡驱动框架源码分析(下).pdf Linux驱动修炼之道-DM9000A网卡驱动框架源码分析(上).pdf Linux驱动修炼之道-clock框架.pdf Linux驱动修炼之道-ADC驱动.pdf Linux内核访问外设I...
1. 介绍网卡设备DM9000 特性LED,EFFROM,电源等引脚定义; 2. 基于mini 2440 介绍网卡驱动模型; 3. 网卡驱动的探测,增删,操作等等;
Linux网络设备驱动程序的体系结构可以分为4层,首先分析了各层的具体功能实现,并在此基础上充分利用S3C2440开发板完成DM9000网卡驱动的移植,编译内核生成内核镜像。最后介绍了网络驱动测试的三种方法,并采用第一...