⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 haison.c

📁 8139网卡驱动 for linux/unix 只针对2.4内核 其他内核不保证可用
💻 C
📖 第 1 页 / 共 2 页
字号:
//////////////////////////////////////////////////////////////////////////////
//                                                                          //
//                                                                          //
//                                                                          //
//	                                                                    //
//                                                                          //                                                                                                  //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////
//                                       //
// 以下为驱动程序所要用到的内核头文件    //
//                                       //
/////////////////////////////////////////// 
#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 + -