dm9000的驱动分析
m9000_init
platform_driver_register(
&dm9000_driver);
dm9000_probe
/*获取平台数据*/
struct dm9000_plat_data
*pdata
= pdev
-
>dev.platform_data;
/*表示一个网络设备*/
struct net_device
*ndev;
/*为网络设备分配空间*/
ndev
= alloc_etherdev(
sizeof(
struct board_info));
/*获取资源*/
db
-
>addr_res
= platform_get_resource(pdev, IORESOURCE_MEM,
0);
db
-
>data_res
= platform_get_resource(pdev, IORESOURCE_MEM,
1);
db
-
>irq_res
= platform_get_resource(pdev, IORESOURCE_IRQ,
0);
/*映射地址端口*/
db
-
>io_addr
= ioremap(db
-
>addr_res
-
>start, iosize);
/*映射数据端口*/
db
-
>io_data
= ioremap(db
-
>data_res
-
>start, iosize);
/*硬件相关的操作*/
/*1.设置读写操作函数*/
dm9000_set_io(db,
2);
case
2
:
db
-
>dumpblk
= dm9000_dumpblk_16bit;
db
-
>outblk
= dm9000_outblk_16bit;
db
-
>inblk
= dm9000_inblk_16bit;
break;
/*2.复位 */
dm9000_reset(db);
/*3.读dm9000的ID号 */
id_val
= ior(db, DM9000_VIDL);
id_val
|= (u32)ior(db, DM9000_VIDH)
<<
8;
id_val
|= (u32)ior(db, DM9000_PIDL)
<<
16;
id_val
|= (u32)ior(db, DM9000_PIDH)
<<
24;
/* 获取芯片型号 */
id_val
= ior(db, DM9000_CHIPR);
ether_setup(ndev);
/*设置操作方法*/
ndev
-
>netdev_ops
=
&dm9000_netdev_ops;
/*注册网络设备*/
register_netdev(ndev);
//register_chrdev
cs8900a网卡驱动分析
/*分配一个网络设备*/
struct net_device
*dev
= alloc_etherdev(
sizeof(
struct net_local));
dev
-
>irq
= irq;
dev
-
>base_addr
= io;
cs89x0_probe1(dev, io,
1);
/*识别芯片*/
/*操作方法的设置*/
dev
-
>netdev_ops
=
&net_ops;
/*注册网络设备*/
register_netdev(dev);
static
const
struct net_device_ops dm9000_netdev_ops
= {
.ndo_open
= dm9000_open,
//必须的
.ndo_stop
= dm9000_stop,
//必须的
.ndo_start_xmit
= dm9000_start_xmit,
//必须的
.ndo_tx_timeout
= dm9000_timeout,
//必须的
.ndo_set_multicast_list
= dm9000_hash_table,
.ndo_do_ioctl
= dm9000_ioctl,
.ndo_change_mtu
= eth_change_mtu,
.ndo_validate_addr
= eth_validate_addr,
.ndo_set_mac_address
= eth_mac_addr,
#
ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller
= dm9000_poll_controller,
#
endif
};
网卡驱动的数据接收发送流程?
初始化设备
dm9000_open(
struct net_device
*dev)
{
if (request_irq(dev
-
>irq, dm9000_interrupt, irqflags, dev
-
>name, dev))
return
-EAGAIN;
/* Initialize DM9000 board */
dm9000_reset(db);
/* RESET device */
writeb(DM9000_NCR, db
-
>io_addr);
udelay(
200);
writeb(NCR_RST, db
-
>io_data);
udelay(
200);
/* dm9000的初始化,芯片厂商会支持 */
dm9000_init_dm9000(dev);
/* 启动发送队列 */
netif_start_queue(dev);
}
数据接收流程
dm9000_interrupt(
int irq,
void
*dev_id)
/* Save previous register address */
reg_save
= readb(db
-
>io_addr);
/* Disable all interrupts */
iow(db, DM9000_IMR, IMR_PAR);
/* Got DM9000 interrupt status */
int_status
= ior(db, DM9000_ISR);
/* Got ISR */
iow(db, DM9000_ISR, int_status);
/* Clear ISR status */
/* Received the coming packet 读中断*/
if (int_status
& ISR_PRS)
dm9000_rx(dev);
ior(db, DM9000_MRCMDX);
/* Dummy read 地址不自动增加*/
rxbyte
= readb(db
-
>io_data);
if (rxbyte
& DM9000_PKT_ERR) {
dev_warn(db
-
>dev,
"status check fail: %d\n", rxbyte);
iow(db, DM9000_RCR, 0x00);
/* Stop Device */
iow(db, DM9000_ISR, IMR_PAR);
/* Stop INT request */
return;
}
writeb(DM9000_MRCMD, db
-
>io_addr);
/*地址自动增加的*/
/* 读取状态信息 */
(db
-
>inblk)(db
-
>io_data,
&rxhdr,
sizeof(rxhdr));
//dm9000_inblk_16bit
RxLen
= le16_to_cpu(rxhdr.RxLen);
/*数据的状态判断*/
if (rxhdr.RxStatus
& (RSR_FOE
| RSR_CE
| RSR_AE
|
RSR_PLE
| RSR_RWTO
|
RSR_LCS
| RSR_RF)) {
struct sk_buff
*skb;
skb
= dev_alloc_skb(RxLen
+
4))
/*分配一个sk_buff数据包*/
skb_reserve(skb,
2);
//data指针和tail指针同时下移
rdptr
= (u8
*) skb_put(skb, RxLen
-
4);
(db
-
>inblk)(db
-
>io_data, rdptr, RxLen);
//dm9000_inblk_16bit //读真正的有效数据(MAC头,TCP头,IP头,网络数据)
dev
-
>stats.rx_bytes
+= RxLen;
/* Pass to upper layer,去掉MAC头 */
skb
-
>protocol
= eth_type_trans(skb, dev);
/* 将数据上报到上层 */
netif_rx(skb);
dev
-
>stats.rx_packets
++;
数据发送流程
sk_buff
dm9000_start_xmit
/* 将数据写入到DM9000的SRAM中 */
/* Move data to DM9000 TX RAM */
writeb(DM9000_MWCMD, db
-
>io_addr);
//设置为自动增加
//dm9000_outblk_16bit
(db
-
>outblk)(db
-
>io_data, skb
-
>data, skb
-
>len);
//dm9000_outblk_16bit
dev
-
>stats.tx_bytes
+= skb
-
>len;
db
-
>tx_pkt_cnt
++;
/*设置发送属性*/
dm9000_send_packet(
struct net_device
*dev,
int ip_summed,
u16 pkt_len)
/*指定数据包的长度*/
iow(dm, DM9000_TXPLL, pkt_len);
iow(dm, DM9000_TXPLH, pkt_len
>>
8);
/*启动发送:数据发送完成,产生中断*/
iow(dm, DM9000_TCR, TCR_TXREQ);
/* Cleared after TX complete */
netif_stop_queue(dev);
dm9000_interrupt(
int irq,
void
*dev_id)
/* Save previous register address */
reg_save
= readb(db
-
>io_addr);
//让他不自动增加
/* 关中断 */
iow(db, DM9000_IMR, IMR_PAR);
/*获取中断状态*/
int_status
= ior(db, DM9000_ISR);
/* Got ISR */
iow(db, DM9000_ISR, int_status);
/* Clear ISR status */
/* Trnasmit Interrupt check,数据发送完成 */
if (int_status
& ISR_PTS)
dm9000_tx_done(dev, db);
db
-
>tx_pkt_cnt
--;
dev
-
>stats.tx_packets
++;
if (db
-
>tx_pkt_cnt
>
0)
dm9000_send_packet(dev, db
-
>queue_ip_summed,db
-
>queue_pkt_len);
/*指定数据包的长度*/
iow(dm, DM9000_TXPLL, pkt_len);
iow(dm, DM9000_TXPLH, pkt_len
>>
8);
/*启动发送:数据发送完成,产生中断*/
iow(dm, DM9000_TCR, TCR_TXREQ);
/* Cleared after TX complete */
netif_wake_queue(dev);
/* Re-enable interrupt mask */
iow(db, DM9000_IMR, db
-
>imr_all);
/* Restore previous register address */
writeb(reg_save, db
-
>io_addr);
//恢复为自动增加
怎么写网卡驱动
1.cs89x0.c
1.1 分配一个net_device结构体
alloc_etherdev
1.2 设置
dev
-
>open
= net_open;
dev
-
>stop
= net_close;
dev
-
>tx_timeout
= net_timeout;
dev
-
>watchdog_timeo
= HZ;
dev
-
>hard_start_xmit
= net_send_packet;
dev
-
>get_stats
= net_get_stats;
dev
-
>set_multicast_list
= set_multicast_list;
dev
-
>set_mac_address
= set_mac_address;
1.3 注册
register_netdev
2. DM9000.c
2.1 分配一个net_device结构体
ndev = alloc_etherdev(sizeof (struct board_info));
2.2 设置
ether_setup(ndev);
ndev
-
>open
=
&dm9000_open;
ndev
-
>hard_start_xmit
=
&dm9000_start_xmit;
ndev
-
>tx_timeout
=
&dm9000_timeout;
ndev
-
>watchdog_timeo
= msecs_to_jiffies(watchdog);
ndev
-
>stop
=
&dm9000_stop;
ndev
-
>get_stats
=
&dm9000_get_stats;
ndev
-
>set_multicast_list
=
&dm9000_hash_table;
2.3 注册
ret = register_netdev(ndev);
任何设备的核心都是收发数据
1. 发数据:
上层要发送数据时,构造一个sk_buff,然后调用net_device的hard_start_xmit来发送
2. 收数据:
网卡收到数据后,发生中断
在中断服务程序里:
从硬件上读出数据,然后构造一个sk_buff,上报:
a. 分配一个sk_buff结构体:
dev_alloc_skb
b. 使用硬件上得到数据填充这个结构体
c. 上报:netif_rx
测试方法
1. 编译/安装驱动 farsight_net_1.c
ifconfig fs_net0 up
ifconfig fs_net0
192.
188.
1.
1
ping
192.
188.
1.
1 成功,证明ping自己的话,不经过硬件
ping
192.
188.
1.
2 多次调用fsnet_hard_start_tx
PING
192.
188.
1.
2 (
192.
188.
1.
2)
:
56 data bytes
fsnet_hard_start_tx
fsnet_hard_start_tx
再次ifconfig发现fs_net0的rx/tx都是0
2. 编译/安装驱动 farsight_net_2.c: 添加统计信息
3. 编译/安装驱动 farsight_net_3.c: 设MAC地址
ifconfig fs_net0
ifconfig 可以看到MAC地址
4. 编译/安装驱动 farsight_net_4.c: 构造ping的返回包
ifconfig fs_net0 up
ifconfig fs_net0 192.188.1.1
ping 192.188.1.2 成功
怎么移植网卡驱动
网卡基本上都是内存接口(ram-like)
1. 根据原理图确定访问地址, 在驱动里修改相应项
2. 为了能通过这些地址访问网卡,对于2410还要设置memory controller
比如设置位宽、时间参数
3. 根据原理图确定中断号, 在驱动里修改相应项(包括中断号、中断触发方式(高/低有效))
@成鹏致远
(blogs:http://lcw.cnblogs.com)
(email:[email protected])
(qq:552158509)