裸机 时序
1. 读寄存器:
1. *(unsigned int *)0x5000000 = reg;
是地址,又因为WE有效故是写,这样DM9000就会锁存SD[16:0]上的电平作为接下来即将操作的寄存器地址。
2. int a = *(unsigned int *)0x5000004;
是数据,有因为RE有效故是读,这样DM9000就会把数据送到SD[16:0]上。
封装函数为 int DM9000_read_reg(u32 reg);
2.写寄存器:
1. *(unsigned int *)0x5000000 = reg;
2. *(unsigned int *)0x5000004 = data;
封装函数为 void DM9000_write_reg(u32 reg, u32 data);
3.读SRAM:
从DM9000的SRAM中某个地址处读取数据
DM9000_write_reg(MDRAH, ADDR_H);
DM9000_write_reg(MDRAL, ADDR_L);
int a = DM9000_read_reg(MRCMD);
int a = DM9000_read_reg(MRCMD);
4.写SRAM:
把一个数写到DM9000的SRAM(一般总共16K低3K用于发送,高13K用于接收)
DM9000_write_reg(MDRAH, ADDR_H);
DM9000_write_reg(MDRAL, ADDR_L);
DM9000_write_reg(MWCMD, data);
DM9000_write_reg(MWCMD, data1);
5.将SRAM中的数发向RJ45:
这个过程是DM9000内部的一次DMA传输
DM9000_write_reg(TXPLL_L, len_L);
DM9000_write_reg(TXPLL_H, len_H);
DM9000_write_reg(TXPLL_H, len_H);
6.从RJ45接收数据到DM9000的SRAM中:
内核提供的接口函数:
1.数据结构:
<include/linux/netdevice.h>
struct net_device {
char name[IFNAMSIZ];
struct hlist_node name_hlist;
char *ifalias;
unsigned long mem_end;
unsigned long mem_start;
unsigned long base_addr;
int irq;
netdev_features_t features;
netdev_features_t hw_features;
unsigned int flags;
unsigned int priv_flags;
const struct net_device_ops *netdev_ops;
const struct ethtool_ops *ethtool_ops;
const struct header_ops *header_ops;
unsigned char if_port;
unsigned int mtu;
unsigned short type;
unsigned short hard_header_len;
unsigned char perm_addr[MAX_ADDR_LEN];
unsigned char addr_len;
unsigned short dev_id;
struct in_device __rcu *ip_ptr;
...
};
<include/linux/netdevcice.h>
struct net_device_ops {
int (*ndo_init)(struct net_device *dev);
void (*ndo_uninit)(struct net_device *dev);
int (*ndo_open)(struct net_device *dev);
int (*ndo_stop)(struct net_device *dev);
netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb,
struct net_device *dev);
int (*ndo_set_mac_address)(struct net_device *dev,
void *addr);
int (*ndo_validate_addr)(struct net_device *dev);
int (*ndo_do_ioctl)(struct net_device *dev,
struct ifreq *ifr, int cmd);
int (*ndo_set_config)(struct net_device *dev,
struct ifmap *map);
int (*ndo_change_mtu)(struct net_device *dev,
int new_mtu);
void (*ndo_tx_timeout) (struct net_device *dev);
...
2.通用的函数:
步骤性的:
/*
* 功能:创建一个以太网设备对象
* 输入参数:私有数据大小
* 返回值:成功:设备句柄 失败:NULL
*/
struct net_device *alloc_etherdev(sizeof_priv)
/*
* 功能:创建一个网络设备对象
* 输入参数:sizeof_priv:私有数据大小
* name:网卡名字(名称+%d)
* name_assign_type:NET_NAME_UNKNOWN
* setup:初始化函数指针(回调函数)
* 返回值:成功:设备句柄 失败:NULL
*/
struct net_device *alloc_netdev(sizeof_priv, name, name_assign_type, setu
/*
* 功能:释放一个网络设备对象
* 输入参数:设备句柄
* 返回值:none
*/
void free_net_devive(struct net_device *dev);
/*
* 功能:以太网设备初始化
* 输入参数:设备句柄
* 返回值:none
*/
void ether_setup(struct net_device *dev);
/*
* 功能:注册网络设备
* 输入参数:设备句柄
* 返回值:成功:0 失败:负数
*/
int register_netdev(struct net_device *dev);
/*
* 功能:注销网络设备
* 输入参数:设备句柄
* 返回值:成功:0 失败:负数
*/
int unregister_netdevice(struct net_device *dev);
设置参数的:
/*
* 功能:提取私有数据
* 输入参数:设备句柄
* 返回值:成功:私有数据首地址 失败:NULL
*/
void *netdev_priv(struct net_device *dev)
/*
* 功能:设置mac地址
* 输入参数:设备句柄
* p:MAC地址所在首地址
* 返回值:成功:0 失败:负数
*/
int eth_mac_addr(struct net_device *dev, void *p)
/*
* 功能:随机生成mac地址,并将生成的mac地址填充到传入的dev结构体的对应域
* 输入输出参数:设备句柄
* 返回值:none
*/
void eth_hw_addr_random(struct net_device *dev)
/*
* 功能:随机生成mac地址
* 输出参数:addr:将得到的结果放在addr中
* 返回值:none
*/
void eth_random_addr(u8 *addr);
/*
* 功能:检查mac地址是否有效
* 输入参数:设备句柄
* 返回值:有效:1 无效:0
*/
int eth_validate_addr(struct net_device *dev);
int eth_change_mtu(struct net_device *dev, int new_mtu);
发送相关的:
类比块设备的请求队列记忆,每一个发送请求都是经过调度算法处理后放在发送队列
中,驱动层的发送回调函数只要从队列中取出任务处理每个发送请求就行。故要响应
用户层的发送请求就必须开启请求队列。
/*
* 功能:开启发送队列
* 输入参数:dev: 设备句柄
* 返回值:none
*/
void netif_start_queue(struct net_device *dev)
/*
* 功能:关闭发送队列
* 输入参数:dev: 设备句柄
* 返回值:none
*/
void netif_stop_queue(struct net_device *dev)
/*
* 功能:打开载波调制
* 输入参数:dev: 设备句柄
* 返回值:none
*/
void netif_carrier_on(struct net_device *dev)
/*
* 功能:关闭载波调制
* 输入参数:dev: 设备句柄
* 返回值:none
*/
void netif_carrier_off(struct net_device *dev)
套接字缓冲区相关的:
/*
* 功能:开辟一块套接字缓冲区
* 输入参数:unsigned int size:大小
* gfp_t priority: 权限
* 返回值:缓冲区首地址
*/
struct sk_buff *alloc_skb(unsigned int size, gfp_t priority)
struct sk_buff *netdev_alloc_skb(struct net_device *dev,
unsigned int length)
void kfree_skb(struct sk_buff *skb);
void dev_kfree_skb_any(struct sk_buff *skb);
unsigned char *skb_put(struct sk_buff *skb, unsigned int len);
unsigned char *skb_push(struct sk_buff *skb, unsigned int len);
void skb_reserve(struct sk_buff *skb, int len)
int netif_rx(struct sk_buff *skb)
/*
* 功能:得到协议编号
* 输入参数: struct sk_buff *skb: 缓冲区首地址
* struct net_device *dev: 网络设备句柄
* 返回值:成功:得到的编号 失败:负数
*/
__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
例程:
1.c文件
2.h文件
源码追踪:
见思维导图
源码下载: https://git.coding.net/xxgui1992/LinuxDriver-net.git