📄 haison.c
字号:
//////////////////////////////////////////////////////////////////////////////
// //
// //
// //
// //
// // //
// //
//////////////////////////////////////////////////////////////////////////////
// //
// 以下为驱动程序所要用到的内核头文件 //
// //
///////////////////////////////////////////
#include<linux/kernel.h> //printk()
#include<linux/module.h> //版权等相关信息
#include<linux/stddef.h> //空指针NULL的定义
#include<linux/pci.h> //pci相关操作函数
#include<linux/skbuff.h> //sk_buff()结构
#include<linux/init.h> //加载卸载模块
#include<linux/config.h> //包含<linux/autoconfig.h>
#include<linux/netdevice.h> //net_device()、net_device_stats()结构
#include<linux/etherdevice.h> //alloc_ethdev()
#include<linux/string.h> //memset()、memcpy()等
#include<linux/sched.h> //request_irq()
#include<linux/ioport.h> //IOESOURCE_MEM 宏定义
#include<linux/delay.h> //包含<asm/delay.h>后者包含udelay()
#include<linux/types.h> //包含<asm/types.h>后者宏定义了dma_addr_t
#include<asm/io.h> //redb() writeb()
/*以下的头文件暂时未用上*/
#include<linux/compiler.h>
#include<linux/rtnetlink.h>
#include<linux/ethtool.h>
#include<linux/mii.h>
#include<asm/uaccess.h>
/////////////////////////////////////////
// //
//以下为一些宏定义以及全局变量 //
// //
/////////////////////////////////////////
#define REALTEK_VID 0x10EC //生产厂商ID
#define REALTEK_DID 0x8139 //网卡型号
#define DRIVER "rtl8139" //驱动程序模块名称
/*发送相关宏定义*/
#define NUM_TX_DESC 4 //8139发送描述符
#define TX_BUF_SIZE 1536 //should be atleast MTU + 14 + 4
#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC)
#define ETH_MIN_LEN 60 //以太网协议规定的数据包的最小长度
/*接收相关宏定义*/
#define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */
#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
#define RX_BUF_PAD 16 /* see 11th and 12th bit of RCR: 0x44 */
#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle pkt wrap */
#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)//
/*定义两个全局变量*/
static struct net_device *rtl8139_dev;//指向net_device()结构的全局变量
static long counter=0; //统计get_stats()被调用的次数
/*以下为8139相关寄存器的偏移地址宏定义*/
#define TSD0 0x10 //transmission status of descriptor 0
#define TSAD0 0x20 //transmission start address descriptor
#define RBSTART 0x30 //RX buffer start address
#define CR 0x37 //command register
#define CAPR 0x38 //current address of packet read
#define IMR 0x3c //interrupt mask register
#define ISR 0x3e //interrupt status register
#define TCR 0x40 //transmission(tx) configuration register
#define RCR 0x44 //receive (rx)configuration register
#define MPC 0x4c //missed packet counter
#define MULINT 0x5c //mutiple interrupt select
/* TSD register commands */
#define TxHostOwns 0x2000
#define TxUnderrun 0x4000
#define TxStatOK 0x8000
#define TxOutOfWindow 0x20000000
#define TxAborted 0x40000000
#define TxCarrierLost 0x80000000
/* CR register commands */
#define RxBufEmpty 0x01 //there is no packet stored in the Rxbuffer ring
#define CmdTxEnb 0x04 //tansmitter enable
#define CmdRxEnb 0x08 //receiver enable
#define CmdReset 0x10
/* ISR Bits */
#define RxOK 0x01
#define RxErr 0x02
#define TxOK 0x04
#define TxErr 0x08
#define RxOverFlow 0x10
#define RxUnderrun 0x20
#define RxFIFOOver 0x40
#define CableLen 0x2000
#define TimeOut 0x4000
#define SysErr 0x8000
/*中断屏蔽字*/
#define INT_MASK (RxOK|RxErr|TxOK|TxErr|RxOverFlow|RxUnderrun|RxFIFOOver|CableLen|TimeOut|SysErr)
#define RxAckBits (RxOK|RxOverFlow|RxFIFOOver)
/////////////////////////////////////////
// //
//以下宏定义一些寄存器读写操作 //
// //
/////////////////////////////////////////
/*寄存器写操作*/
#define RTL_W8(reg, val8) writeb((val8), ioaddr + (reg))
#define RTL_W16(reg, val16) writew((val16), ioaddr + (reg))
#define RTL_W32(reg, val32) writel((val32), ioaddr + (reg))
/*寄存器读操作*/
#define RTL_R8(reg) readb(ioaddr + (reg))
#define RTL_R16(reg) readw(ioaddr + (reg))
#define RTL_R32(reg) ((unsigned long) readl(ioaddr + (reg)))
/*寄存器先写后读操作,效果与对芯片进行刷新(flush)等效*/
#define RTL_W8_F(reg, val8) do { writeb((val8), ioaddr + (reg)); readb(ioaddr + (reg));} while (0)
#define RTL_W16_F(reg, val16) do { writew((val16), ioaddr + (reg)); readw(ioaddr + (reg));} while (0)
#define RTL_W32_F(reg, val32) do { writel((val32), ioaddr + (reg)); readl(ioaddr + (reg));} while (0)
///////////////////////////////////////////
// //
// 用于控制输出信息的全部开或关 //
// //
///////////////////////////////////////////
#udef RTL8139_DEBUG
#ifdef RTL8139_DEBUG
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
#define DPRINTK(fmt, args...)
#endif
///////////////////////////////////////////
// //
// rtl8139私有内存,用于存放接口的 //
// 统计信息 //
// //
///////////////////////////////////////////
struct rtl8139_private
{
struct pci_dev *pci_dev; // PCI device
void *mmio_addr; // memory mapped IO addr
unsigned long regs_len; //length of IO or MMIO region
unsigned int tx_flag;
unsigned int cur_tx; //当前发送描述符
unsigned int dirty_tx; //第一个发送描述符
unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
unsigned char *tx_bufs; /* Tx bounce buffer region. */
dma_addr_t tx_bufs_dma;//用于存放发送物理地址
struct net_device_stats stats;
unsigned char *rx_ring;
dma_addr_t rx_ring_dma;//用于存放接收物理地址
unsigned int cur_rx; //当前接收描述符
};
////////////////////////////////////
// //
//以下为函数声明 //
// //
///////////////////////////////////
/*when use the command : insmod rtl8139.o*/
static int rtl8139_insmod(void);
static struct pci_dev *probe_for_realtek8139(void);
static int rtl8139_init(struct pci_dev *pdev, struct net_device **dev_out);
static void rtl8139_cleanup_dev(struct net_device *dev);
/*when use the command : ifconfig rtl8139 up*/
static int rtl8139_open(struct net_device *dev);
static void rtl8139_interrupt(int irq,void *dev_instance,struct pt_regs *regs);
static void rtl8139_init_ring(struct net_device *dev);
static void rtl8139_hw_start(struct net_device *dev);
static void rtl8139_chip_reset(void *ioaddr);
/*when use the command : ifconfig -a*/
static struct net_device_stats* rtl8139_get_stats(struct net_device *dev);
/*when use the command : ifconfig rtl8139 down*/
static int rtl8139_stop(struct net_device *dev);
static void rtl8139_tx_clear(struct rtl8139_private *tp);
/*when the packet is tansmitted*/
static int rtl8139_start_xmit(struct sk_buff *skb, struct net_device *dev);
/*when use the command :rmmod rtl8139*/
static void rtl8139_rmmod(void);
////////////////////////////////////
// //
// 加载模块时调用该函数 //
// 命令为:insmod rtl8139.o //
// //
////////////////////////////////////
static int rtl8139_insmod(void)
{
struct pci_dev *pdev;
unsigned long mmio_start, mmio_end, mmio_len, mmio_flags;
void *ioaddr;
struct rtl8139_private *tp;
int i;
printk("<1>============rtl8139_insmod function called============\n");
pdev = probe_for_realtek8139( );//探测网卡
if(!pdev) return 0;
if(rtl8139_init(pdev, &rtl8139_dev))
{
printk("Could not initialize device\n");
return 0;
}
else printk("<1>Initialize successully!\n");
tp = rtl8139_dev->priv; // rtl8139 private information
/* get PCI memory mapped I/O space base address from BAR1 */
mmio_start = pci_resource_start(pdev, 1);
mmio_end = pci_resource_end(pdev, 1);
mmio_len = pci_resource_len(pdev, 1);
mmio_flags = pci_resource_flags(pdev, 1);
/* make sure above region is MMIO */
if(!(mmio_flags & IORESOURCE_MEM))
{
printk("region not MMIO region\n");
goto err_out;
}
else printk("<1>region is MMIO region\n");
if(pci_request_regions(pdev, DRIVER)) /*申请I/O资源*/
{
printk("<1>Could not get PCI region\n");
goto err_out;
}
else printk("<1>Get PCI region successlly!\n");
pci_set_master(pdev);//设置成总线主DMA模式
/* ioremap MMIO region */
ioaddr = ioremap(mmio_start, mmio_len);
if(!ioaddr)
{
printk("<1>Could not ioremap\n");
goto err_out;
}
else printk("<1>ioremap successully!\n");
rtl8139_dev->base_addr = (long)ioaddr;
tp->mmio_addr = ioaddr;
tp->regs_len = mmio_len;
/*填充net_device 结构的各个域*/
for(i = 0; i < 6; i++) //获得网卡物理地址,填充dev->broadcast为全1
{
rtl8139_dev->dev_addr[i] = RTL_R8(i);
rtl8139_dev->broadcast[i] = 0xff;
}
rtl8139_dev->hard_header_len = 14;
memcpy(rtl8139_dev->name, DRIVER, sizeof(DRIVER)); /* Device Name */
rtl8139_dev->irq = pdev->irq; /* Interrupt Number */
/*网络设备回调函数赋值 */
rtl8139_dev->open = rtl8139_open;
rtl8139_dev->stop = rtl8139_stop;
rtl8139_dev->hard_start_xmit = rtl8139_start_xmit;
rtl8139_dev->get_stats = rtl8139_get_stats;
if(register_netdev(rtl8139_dev))//在全局表中注册网络设备
{
printk("<1>Could not register netdevice\n");
goto err_out;
}
else printk("<1>Register netdevice successlly!\n");
// pci_set_drvdata(pdev, dev); //把网络设备指针地址放入PCI设备中的设备指针中
printk("<1>============rtl8139_insmod function end============\n");
return 0;
err_out: rtl8139_cleanup_dev(rtl8139_dev);
printk("<1>============rtl8139_insmod function with error end ============\n");
return 0;
}
/////////////////////////////////////////
// //
// 探测rtl8139网卡是否存在 //
// //
/////////////////////////////////////////
static struct pci_dev *probe_for_realtek8139(void)
{
struct pci_dev *pdev = NULL;//PCI设备中的设备指针赋空
printk("<1>============probe_for_realtek8139 function called============\n");
/* 确保所探测是PCI设备 */
if(!pci_present( ))
{
printk("<1>pci not present\n");
return pdev;
}
else printk("<1>pci present\n");
/* 探测rtl8139网卡 */
pdev = pci_find_device(REALTEK_VID, REALTEK_DID, NULL);
if(pdev) //如果探测到
{
printk("Device found\n");
if(pci_enable_device(pdev))//则启动PCI设备
{
printk("Could not enable the device\n");//启动PCI设备失败
return NULL;
}
else printk("Device enabled\n");//启动PCI设备成功
}
else //未探测到
{
printk("device not found\n");
return pdev;
}
printk("<1>============probe_for_realtek8139 function end============\n");
return pdev;
}
////////////////////////////////////////////
// //
// 对探测到的rtl8139进行分配内存操作 //
// //
////////////////////////////////////////////
static int rtl8139_init(struct pci_dev *pdev, struct net_device **dev_out)
{
struct net_device *dev;
struct rtl8139_private *tp;
printk("<1>============rtl8139_init function called============\n");
dev = alloc_etherdev(sizeof(struct rtl8139_private));//分配并设置网络设备
if(!dev) //分配不成功
{
printk("<1>Could not allocate etherdev\n");
return -1;
}
else printk("<1>Allocate successfully!\n");
/*初始化私有结构中各成员的值*/
tp = dev->priv;
tp->pci_dev = pdev;
*dev_out = dev;
printk("<1>============rtl8139_init function end============\n");
return 0;
}
//////////////////////////////////////////////
// //
//在init_module不成功时的退出处理 //
// //
//////////////////////////////////////////////
static void rtl8139_cleanup_dev(struct net_device *dev)
{
struct rtl8139_private *tp;
struct pci_dev *pdev;
tp=dev->priv;
pdev=tp->pci_dev;
pci_release_regions(pdev);//释放PCI资源
kfree(dev);//释放网络设备
pci_set_drvdata (pdev, NULL); //PCI设备中的设备指针赋空
}
/////////////////////////////////////////////////
// //
// open()函数,当使用命令ifconfig rtl8139 up //
// 时调用该函数 //
// //
/////////////////////////////////////////////////
static int rtl8139_open(struct net_device *dev)
{
int retval;
struct rtl8139_private *tp = dev->priv;
printk("<1>============rtl8139_open function called============\n");
/*注册中断函数rtl8139_interrupt*/
retval = request_irq(dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev);
if(retval)return retval;
/*初始化8139所需的发送缓冲区,用于暂时存放将要发送出去的数据包
且要保证缓冲区内存是可以进行DMA传送的,第三个参数存放分
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -