Linux内核驱动如何编写?我们先从字符驱动入门开始
发布日期:2021-06-30 21:33:54 浏览次数:2 分类:技术文章

本文共 21081 字,大约阅读时间需要 70 分钟。

几年前正式转到linux开发岗位的时候,由于项目急需编写linux驱动来控制项目采集设备(板卡),我便被安排做这一部分工作。那时候挺慌的…,在之前的一年多时间里基本都是window应用开发,对于linux理解也相对较少。还好那时候认识一些别的公司的大佬,给指点了一二,便开始“模仿造车之路”…

  记得那时候领导给了一个月调研时间,希望在一个月内能搞明白板卡的驱动采用哪种方式实现,需要购买什么书籍。

  那时候心里虽没有底…,但我也想完成这次挑战,就随便购买了一本《Linux设备驱动程序(中文版第三版)》,事后只能说这本书真香…

  好了,现在我们进入今天的主题:

    通常情况下,“应用程序”通过“内核驱动”来操作“硬件设备”,比如我们操作一块2A板卡,我们需要在应用程序中编写2A板卡的功能模块,然后通过驱动程序中映射出的虚拟地址写入这些信息,最终实现操作硬件设备(基于操作系统层面)。下面我们分析一下这个例子:

      假如我们的2A板卡功能有开启工作模式、关闭工作模式、开始采集数据、停止采集数据、获取采集状态, 地址方面为0x20(采集状态地址)、0x64(开启工作模式、关闭工作模式)、0x128(开始采集数据、停止采集数据),采集的数据量为一次2048字节(每次采集完成后即可开启下次采集)。

      通过这个设备信息可以分析出,功能较为简单,数据交互量也比较少,这种情况可以直接选择“字符驱动”。字符驱动较与别的驱动类型来说更简单、直接一些,适合用在各种“非触摸式”并且数据交互量较少的场景。

      接下来,我们在思路上模拟实现这个设备的驱动与应用:

        驱动思路:

          1. 首先我们得到这个设备的厂商ID和设备ID,注册为pci驱动,并实现探测函数(.probe)和卸载函数(.remove)。
          2. 执行探测函数并创建字符驱动和描述符(应用层通过它来访问驱动),然后映射bar(最多可以映射6个bar(6个不同的地址空间),相当于把设备物理地址映射到内核虚拟地址,通常情况下只有2至3个bar,bar0一般属于只读空间)。

        字符驱动主要通过ioctl访问映射的bar空间完成具体操作,如开启工作模式,8位的情况下可通过pci_write_config_byte(bkptr->pcie_dev, addr, (u8 )&val);或者*(unsigned char*)(bkptr->bar[1] + addr) = val;

        应用思路:

          1. 首先通过驱动描述符打开设备。
          2. 通过ioctl函数访问设备地址,根据业务需要执行相关的操作,如开启工作模式,ioctl(fd_A2, 0x64, data)),data1表示开启,0表示关闭;

      嗯…,字符驱动就是这么简单、直接,基本通过ioctl就可解决大部分问题,如果你的需求稍微复杂一些(带DMA芯片或echo等操作),则会用到write和read函数。

驱动示例:

   .h

/* * Pci_A.h * *  Created on: Sep 24, 2017 *      Author: linux */#ifndef PCI__H_#define PCI__H_#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#undef PDEBUG#ifdef PCI_DEBUG #ifdef __KERNEL__ #define PCI_DEBUG(fmt,args...) printk(KERN_DEBUG "PCI:" fmt,##args) #else #define PCI_DEBUG(fmt,args...) printf(stderr, "PCI:" fmt,##args) #endif#else#define PCI_DEBUG(fmt,args...)#endif#define DMA_BAR_NUM (6)#define DMA_DESCRIPTOR_NUM 128struct Pci_dev{ struct cdev cdev;};struct pcie_dma_bookkeep { struct pci_dev *pci_dev; u8 revision; u8 irq_pin; char msi_enabled; u8 irq_line; unsigned long bus; unsigned long deviceNo; unsigned long devfn; char dma_capable; void * __iomem bar[DMA_BAR_NUM]; size_t bar_length[DMA_BAR_NUM]; struct pci_dev *pcie_dev; struct dma_desc_table *table_rd_cpu_virt_addr; struct dma_desc_table *table_wr_cpu_virt_addr; struct lite_dma_desc_table *lite_table_rd_cpu_virt_addr; struct lite_dma_desc_table *lite_table_wr_cpu_virt_addr; dma_addr_t lite_table_rd_bus_addr; dma_addr_t table_rd_bus_addr; dma_addr_t lite_table_wr_bus_addr; dma_addr_t table_wr_bus_addr; int numpages; u8 *rp_rd_buffer_virt_addr; dma_addr_t rp_rd_buffer_bus_addr; u8 *rp_wr_buffer_virt_addr; dma_addr_t rp_wr_buffer_bus_addr; dev_t cdevno; struct cdev cdev; int user_pid; struct task_struct *user_task; wait_queue_head_t wait_q; atomic_t status; // struct dma_status dma_status; u32 prevalue;};static int Pci_open(struct inode *inode,struct file *filp);static int Pci_release(struct inode *inode,struct file *filp);static ssize_t Pci_read(struct file *filp,char __user *buf,size_t count,loff_t *f_pos);static ssize_t Pci_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_pos);static loff_t Pci_llseek(struct file *filp,loff_t off,int whence);static int Pci_ioctl(/*struct inode *inode,*/struct file *filp,unsigned int cmd,unsigned long arg);static int __init pci_probe(struct pci_dev *dev, const struct pci_device_id *id);static init_chrdev(struct pcie_dma_bookkeep *bk_ptr);static void unmap_bars(struct pcie_dma_bookkeep *bk_ptr, struct pci_dev *dev);static int __init map_bars(struct pcie_dma_bookkeep *bk_ptr, struct pci_dev *dev);static int scan_bars(struct pcie_dma_bookkeep *bk_ptr, struct pci_dev *dev);static int map_Pci(struct pcie_dma_bookkeep *bk_ptr, struct pci_dev *dev);#endif /* PCI__H_ */

   .c

/* * Pci_A.c * *  Created on: Sep 24, 2017 *      Author: linux */#include "Pci_A.h"#define A_MANF_ID      0xAAAA     	   /*  Instrument manufacturer ID FOR AMC*/#define A_MODEL_CODE   0xaaaa          /*  Instrument model code  for switch    */#define BUFFER_SIZE         512L               /*  File I/O buffer size       */#define ADEVNAME      "Pci_A"#define ClassName           "class_A"#define DEMO_MAJOR 0#define DEMO_MINOR 0#define KER_RW_R8  0#define KER_RW_R16 1#define KER_RW_R32 6#define KER_RW_W8  3#define KER_RW_W16 4#define KER_RW_W32 5#define KER_RW_revision 7#define KER_RW_irq_pin  8#define KER_RW_irq_line 9#define KER_RW_bar 20#define KER_RW_Config_R8  30#define KER_RW_Config_R16 31#define KER_RW_Config_R32 32#define KER_RW_Config_W8  33#define KER_RW_Config_W16 34#define KER_RW_Config_W32 35#define KER_RW_VX_R8  40#define KER_RW_VX_R16 41#define KER_RW_VX_R32 42#define KER_RW_VX_W8  43#define KER_RW_VX_W16 44#define KER_RW_VX_W32 45#define KER_R_bus      50#define KER_R_deviceNo 51#define KER_R_devfn    52#define DBUG_PRINT 1struct class *mem_class;struct Pci_dev *demo_devices;struct pcie_dma_bookkeep *bkptr;static unsigned char demo_inc = 0;//Up to a Devstatic unsigned char demo_buffer[512L];static unsigned int  bufferLen = 512L;//dev_t dev;int npci_register;static int Pci_open(struct inode *inode,struct file *filp){	struct pcie_dma_bookkeep *dev_;	dev_ = container_of(inode->i_cdev,struct pcie_dma_bookkeep,cdev);	filp->private_data = dev_;	//dev->user_pid = current->pid;	return 0;}static int Pci_release(struct inode *inode,struct file *filp){	return 0;}static ssize_t Pci_read(struct file *filp,char __user *buf,size_t count,loff_t *f_pos){	int result;	loff_t pos = *f_pos; // pos :offset	if (pos >= bufferLen)	{		result = 0;		goto out;	}	if (count > (bufferLen - pos))	{		count = bufferLen - pos;	}	pos += count;	if (copy_to_user(buf,demo_buffer + *f_pos,count))	{		count = -2;		goto out;	}	*f_pos = pos;out:	return count;}static ssize_t Pci_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_pos){	size_t retval = -3;	loff_t pos = *f_pos;	if (pos > bufferLen)	{		goto out;	}	if (count > (bufferLen - pos))	{		count = bufferLen - pos;	}	pos += count;	if (copy_from_user(demo_buffer + *f_pos,buf,count))	{		retval = -2;		goto out;	}	*f_pos = pos;	retval = count;	out:	return retval;}static int Pci_ioctl(/*struct inode *inode,*/struct file *filp,unsigned int cmd,unsigned long arg){//reg	volatile unsigned char p8[1];	volatile unsigned short p16[1];	volatile unsigned int p32[1];	unsigned int val;//write reg to val	unsigned int addr;	unsigned int buf[2];	//unsigned short nbar = cmd >> 16;	//unsigned short ncmd = (unsigned short)cmd;	unsigned short nbar = ((cmd >> 16) & 0xFFFF);	unsigned short ncmd = (unsigned short)(cmd & 0x0000FFFF);	/*user to copy into the kernel*/	copy_from_user(buf,(const void __user *)arg,8);	//length 8	addr = buf[0];//addr	val = buf[1];//val	static unsigned long nNum = 0;	if(DBUG_PRINT)printk(KERN_ALERT "Pci_ioctl:addr:%u , val:%u ,bar:%u ,type:%u ,Num:%u ,cmd:%u  ,arg:%x  \n",addr,val,nbar,ncmd,++nNum,cmd,arg);	switch (ncmd)	{		case KER_RW_R8:		{			//val = ioread8(bkptr->bar[nbar] + addr);			val = *(unsigned char*)(bkptr->bar[nbar] + addr);//2017-11-2			if(DBUG_PRINT)printk(KERN_ALERT "ioread8 :addr: %u , bar from addr:%u ,bar:%u ,val:%u  \n",addr,(unsigned long)bkptr->bar[nbar],nbar,val);			copy_to_user((void __user*)(arg+4),&val,4);			//copy 4 bytes to user space ,The back four is value,In front of the 4 bytes in address			break;		}		case KER_RW_R16:		{			//val = ioread16(bkptr->bar[nbar] + addr);			val = *(unsigned short*)(bkptr->bar[nbar] + addr);//2017-11-2			if(DBUG_PRINT)printk(KERN_ALERT "ioread16 :addr: %u , bar from addr:%u ,bar:%u ,val:%u  \n",addr,(unsigned long)bkptr->bar[nbar],nbar,val);			copy_to_user((void __user*)(arg+4),&val,4);			break;		}		case KER_RW_R32:		{			//val = ioread32(bkptr->bar[nbar] + addr);			val = *(unsigned long*)(bkptr->bar[nbar] + addr);//2017-11-2  	                if(DBUG_PRINT)printk(KERN_ALERT "ioread32 :addr: %u , bar from addr:%u ,bar:%u ,val:%u  \n",addr,(unsigned long)bkptr->bar[nbar],nbar,val);			copy_to_user((void __user*)(arg+4),&val,4);			break;		}		case KER_RW_W8:		{						//*p8 = val;			if(DBUG_PRINT)printk(KERN_ALERT "iowrite8 :addr: %u , bar from addr:%u ,bar:%u ,val:%u  \n",addr,(unsigned long)bkptr->bar[nbar],nbar,val);			//iowrite8(bkptr->bar[nbar] + addr,(unsigned char)val);			*(unsigned char*)(bkptr->bar[nbar] + addr) = val;			break;		}		case KER_RW_W16:		{			//*p16 = val;		        if(DBUG_PRINT)printk(KERN_ALERT "iowrite8 :addr: %u , bar from addr:%u ,bar:%u ,val:%u  \n",addr,(unsigned long)bkptr->bar[nbar],nbar,val);			//iowrite16(bkptr->bar[nbar] + addr,(unsigned short)val);			*(unsigned short*)(bkptr->bar[nbar] + addr) = val;			break;		}		case KER_RW_W32:		{			//*p32 = val;			if(DBUG_PRINT)printk(KERN_ALERT "iowrite8 :addr: %u , bar from addr:%u ,bar:%u ,val:%u  \n",addr,(unsigned long)bkptr->bar[nbar],nbar,val);			//iowrite32(bkptr->bar[nbar] + addr,(unsigned long)val);			*(unsigned long*)(bkptr->bar[nbar] + addr) = val;			break;		}		case KER_RW_revision:		{	val = bkptr->revision;			copy_to_user((void __user*)(arg+4),&val,4);			break;		}		case KER_RW_irq_pin:		{	val = bkptr->irq_pin;			copy_to_user((void __user*)(arg+4),&val,4);			break;		}		case KER_RW_irq_line:		{	val = bkptr->irq_line;			copy_to_user((void __user*)(arg+4),&val,4);			break;		}				case KER_RW_bar:		{	val = (unsigned long)bkptr->bar[nbar];			copy_to_user((void __user*)(arg+4),&val,4);			break;		}		case KER_RW_Config_R8:		{			pci_read_config_byte(bkptr->pcie_dev,addr, (u8 *)&val);			if(DBUG_PRINT)printk(KERN_ALERT "KER_RW_Config_R8 , pcie_dev:%u ,addr:%u ,val:%u  \n",(unsigned long)bkptr->pcie_dev,addr,val);			copy_to_user((void __user*)(arg+4),&val,4);			break;		}		case KER_RW_Config_R16:		{			pci_read_config_word(bkptr->pcie_dev,addr, (u16 *)&val);			if(DBUG_PRINT)printk(KERN_ALERT "KER_RW_Config_R16 , pcie_dev:%u ,addr:%u ,val:%u  \n",(unsigned long)bkptr->pcie_dev,addr,val);			copy_to_user((void __user*)(arg+4),&val,4);			break;		}		case KER_RW_Config_R32:		{			pci_read_config_dword(bkptr->pcie_dev,addr, (u32 *)&val);			if(DBUG_PRINT)printk(KERN_ALERT "KER_RW_Config_R32 , pcie_dev:%u ,addr:%u ,val:%u  \n",(unsigned long)bkptr->pcie_dev,addr,val);			copy_to_user((void __user*)(arg+4),&val,4);			break;		}		case KER_RW_Config_W8:		{			pci_write_config_byte(bkptr->pcie_dev,addr, (u8 )&val);			if(DBUG_PRINT)printk(KERN_ALERT "KER_RW_Config_W8 , pcie_dev:%u ,addr:%u ,val:%u  \n",(unsigned long)bkptr->pcie_dev,addr,val);			break;		}		case KER_RW_Config_W16:		{			pci_write_config_word(bkptr->pcie_dev,addr, (u16 )&val);			if(DBUG_PRINT)printk(KERN_ALERT "KER_RW_Config_W16 , pcie_dev:%u ,addr:%u ,val:%u  \n",(unsigned long)bkptr->pcie_dev,addr,val);			break;		}		case KER_RW_Config_W32:		{			pci_write_config_dword(bkptr->pcie_dev,addr, (u32)&val);			if(DBUG_PRINT)printk(KERN_ALERT "KER_RW_Config_W32 , pcie_dev:%u ,addr:%u ,val:%u  \n",(unsigned long)bkptr->pcie_dev,addr,val);			break;		}		case KER_RW_VX_R8:		{			unsigned char * p8 = (volatile unsigned char *) ioremap(addr,4);			//val = ioread8(p8);			val = *p8;			if(DBUG_PRINT)printk(KERN_ALERT "KER_RW_VX_R8 :addr: %u,val:%u  \n",addr,val);			copy_to_user((void __user*)(arg+4),&val,4);			//copy 4 bytes to user space ,The back four is value,In front of the 4 bytes in address			iounmap(p8);			break;		}		case KER_RW_VX_R16:		{			unsigned short * p16 = (volatile unsigned short *) ioremap(addr,4);//test			//val = ioread16(p16);			val = *p16;			if(DBUG_PRINT)printk(KERN_ALERT "KER_RW_VX_R16 :addr: %u,val:%u  \n",addr,val);			copy_to_user((void __user*)(arg+4),&val,4);						iounmap(p16);//exit map*/			break;		}		case KER_RW_VX_R32:		{			unsigned long * p32 = (volatile unsigned long *) ioremap(addr,4);			//val = ioread32(p32);			val = *p32;  	               	if(DBUG_PRINT)printk(KERN_ALERT "KER_RW_VX_R32 :addr: %u,val:%u  \n",addr,val);			copy_to_user((void __user*)(arg+4),&val,4);			iounmap(p32);			break;		}		case KER_RW_VX_W8:		{			unsigned char * p8 = (volatile unsigned char *) ioremap(addr,4);						if(DBUG_PRINT)printk(KERN_ALERT "KER_RW_VX_W8 :addr: %u,val:%u  \n",p8,(unsigned char)val);			//iowrite8(p8,(unsigned char)val);			*p8 = val;			iounmap(p8);			break;		}		case KER_RW_VX_W16:		{          unsigned short * p16 = (volatile unsigned short *) ioremap(addr,4);		  if(DBUG_PRINT)printk(KERN_ALERT "KER_RW_VX_W16 :addr: %u,val:%u  \n",p16,(unsigned short)val);			*p16 = val;			iounmap(p16);//exit map*/			break;		}		case KER_RW_VX_W32:		{			unsigned long * p32 = (volatile unsigned long *) ioremap(addr,4);						if(DBUG_PRINT)printk(KERN_ALERT "KER_RW_VX_W32 :addr: %u,val:%u  \n",p32,(unsigned int)val);			*p32 = val;			iounmap(p32);			break;		}		case KER_R_bus:		{			val = bkptr->bus;			copy_to_user((void __user*)(arg+4),&val,4);			break;		}		case KER_R_deviceNo:		{			val = bkptr->deviceNo;			copy_to_user((void __user*)(arg+4),&val,4);			break;		}		case KER_R_devfn:		{			val = bkptr->devfn;			copy_to_user((void __user*)(arg+4),&val,4);			break;		}	}	return 0;}static loff_t Pci_llseek(struct file *filp,loff_t off,int whence){	loff_t pos;	pos = filp->f_pos;	switch (whence)	{	case 0:		pos = off;		break;	case 1:		pos += off;		break;	case 2:	default:		return -2;	}	if ((pos > 512) || (pos < 0))		return -2;	return filp->f_pos = pos;}static struct file_operations demo_fops = {.owner = THIS_MODULE,.llseek = Pci_llseek,.read = Pci_read,.write = Pci_write,.unlocked_ioctl = Pci_ioctl,.open = Pci_open,.release = Pci_release,};static int scan_bars(struct pcie_dma_bookkeep *bk_ptr, struct pci_dev *dev){    int i;    for (i = 0; i < DMA_BAR_NUM; i++) {        unsigned long bar_start = pci_resource_start(dev, i);        unsigned long bar_end = pci_resource_end(dev, i);        unsigned long bar_flags = pci_resource_flags(dev, i);        bk_ptr->bar_length[i] = pci_resource_len(dev, i);        dev_info(&dev->dev, "BAR[%d] 0x%08lx-0x%08lx flags 0x%08lx, length %d", i, bar_start, bar_end, bar_flags, (int)bk_ptr->bar_length[i]);    }    return 0; }static int __init map_bars(struct pcie_dma_bookkeep *bk_ptr, struct pci_dev *dev){    int i;    for (i = 0; i < DMA_BAR_NUM; i++) {        unsigned long bar_start = pci_resource_start(dev, i);        bk_ptr->bar_length[i] = pci_resource_len(dev, i);        if (!bk_ptr->bar_length[i]) {            bk_ptr->bar[i] = NULL;            continue;        }        bk_ptr->bar[i] = ioremap(bar_start, bk_ptr->bar_length[i]);	        if (!bk_ptr->bar[i]) {            dev_err(&dev->dev, "could not map BAR[%d]", i);            return -1;        } else            dev_info(&dev->dev, "BAR[%d] mapped to 0x%p, length %lu", i, bk_ptr->bar[i], (long unsigned int)bk_ptr->bar_length[i]);     }    return 0;}static void unmap_bars(struct pcie_dma_bookkeep *bk_ptr, struct pci_dev *dev){    int i;    for (i = 0; i < DMA_BAR_NUM; i++) {        if (bk_ptr->bar[i]) {            pci_iounmap(dev, bk_ptr->bar[i]);            bk_ptr->bar[i] = NULL;        }    }}static init_chrdev(struct pcie_dma_bookkeep *bk_ptr){	static nRun = 0;	int result;	if(DBUG_PRINT)printk(KERN_ALERT "init_chrdev nRun:%d \n",nRun);	if (0 == nRun){	bk_ptr->cdevno = 0;	result = alloc_chrdev_region(&bk_ptr->cdevno, 0, 2, ADEVNAME);		if(DBUG_PRINT)printk(KERN_ALERT "mem_class = class_create(THIS_MODULE,\"class_\"); \n");	mem_class = class_create(THIS_MODULE,ClassName);// /dev/ create devfile     	if (IS_ERR(mem_class))    	{		printk(KERN_ALERT "Err:failed in creating class!\n");		goto fail;  	}	if(DBUG_PRINT)printk(KERN_ALERT "device_create(mem_class,NULL,dev,NULL,ADEVNAME); \n");	device_create(mem_class,NULL,bk_ptr->cdevno,NULL,ADEVNAME);	if (result < 0)	{		printk(KERN_WARNING "can't get major %d\n",DEMO_MAJOR);		return result;	}	cdev_init(&bk_ptr->cdev,&demo_fops);	bk_ptr->cdev.owner = THIS_MODULE;	bk_ptr->cdev.ops = &demo_fops;//Create Dev and file_operations Connected		if(DBUG_PRINT)printk(KERN_ALERT "result = cdev_add(&bk_ptr->cdev,dev,1);\n");	result = cdev_add(&bk_ptr->cdev,bk_ptr->cdevno,1);	if (result){		printk(KERN_ALERT "error%d adding demo\n",result);		goto fail;	}	++nRun;	return result;fail:{	  if(DBUG_PRINT)printk(KERN_ALERT "init_chrdev :fail result:%d ~!\n",result);	  if (bk_ptr)	  {		cdev_del(&bk_ptr->cdev);		kfree(demo_devices);	  }	  unregister_chrdev_region(bk_ptr->cdevno,1);	}	return result;}		return 0;}static int __init pci_probe(struct pci_dev *dev, const struct pci_device_id *id){    if(DBUG_PRINT)printk(KERN_ALERT "pci_probe :begin !\n");    int rc = 0;    unsigned int last_id=0;    pci_set_drvdata(dev, bkptr);    if(DBUG_PRINT)printk(KERN_ALERT "init_chrdev :begin !\n");    rc = init_chrdev(bkptr);     if(DBUG_PRINT)printk(KERN_ALERT "init_chrdev :end !\n");    if (rc) {        dev_err(&dev->dev, "init_chrdev() failed\n");        goto err_initchrdev;    }        rc = pci_enable_device(dev);    if (rc) {        dev_err(&dev->dev, "pci_enable_device() failed\n");        goto err_enable;    } else {        dev_info(&dev->dev, "pci_enable_device() successful");    }    rc = pci_request_regions(dev, ADEVNAME);    if (rc) {        dev_err(&dev->dev, "pci_request_regions() failed\n");        goto err_regions;    }    pci_set_master(dev);    rc = pci_enable_msi(dev);    if (rc) {        dev_info(&dev->dev, "pci_enable_msi() failed\n");        bkptr->msi_enabled = 0;    } else {        dev_info(&dev->dev, "pci_enable_msi() successful\n");        bkptr->msi_enabled = 1;    }    pci_read_config_byte(dev, PCI_REVISION_ID, (u8 *)&bkptr->revision);    pci_read_config_byte(dev, PCI_INTERRUPT_PIN, (u8 *)&bkptr->irq_pin);    pci_read_config_byte(dev, PCI_INTERRUPT_LINE, (u8 *)&bkptr->irq_line);    if(DBUG_PRINT)printk(KERN_ALERT "PCI_REVISION_ID: %d , PCI_INTERRUPT_PIN:%d ,PCI_INTERRUPT_LINE:%d \n",bkptr->revision,bkptr->irq_pin,bkptr->irq_line);    dev_info(&dev->dev, "irq pin: %d\n", bkptr->irq_pin);    dev_info(&dev->dev, "irq line: %d\n", bkptr->irq_line);    dev_info(&dev->dev, "irq: %d\n", dev->irq);	    bkptr->bus = dev->bus->number;    bkptr->deviceNo = (((dev->devfn) >> 3) & 0x1f);    bkptr->devfn = ((dev->devfn) & 0x07);    dev_info(&dev->dev, "pci devfn: %u\n", bkptr->devfn);    dev_info(&dev->dev, "pci bus: %u\n", bkptr->bus);    dev_info(&dev->dev, "pci device: %u\n", bkptr->deviceNo);    rc = 0;    if (rc) {        dev_info(&dev->dev, "Could not request IRQ #%d", bkptr->irq_line);        bkptr->irq_line = -1;        goto err_irq;    } else {        dev_info(&dev->dev, "request irq: %d", bkptr->irq_line);    }    scan_bars(bkptr, dev);    map_bars(bkptr, dev);    //dev    bkptr->pcie_dev = dev;	    return 0;    // error clean uperr_wr_buffer:    dev_err(&dev->dev, "goto err_wr_buffer");    //pci_free_consistent(dev, PAGE_SIZE*bk_ptr->numpages, bk_ptr->rp_rd_buffer_virt_addr, bk_ptr->rp_rd_buffer_bus_addr);err_rd_buffer:    dev_err(&dev->dev, "goto err_rd_buffer");    //pci_free_consistent(dev, sizeof(struct dma_desc_table), bk_ptr->table_wr_cpu_virt_addr, bk_ptr->table_wr_bus_addr);err_wr_table:    dev_err(&dev->dev, "goto err_wr_table");    //pci_free_consistent(dev, sizeof(struct dma_desc_table), bk_ptr->table_rd_cpu_virt_addr, bk_ptr->table_rd_bus_addr);err_rd_table:    dev_err(&dev->dev, "goto err_rd_table");err_irq:    dev_err(&dev->dev, "goto err_regions");err_dma_mask:    dev_err(&dev->dev, "goto err_dma_mask");    pci_release_regions(dev);err_regions:    dev_err(&dev->dev, "goto err_irq");    pci_disable_device(dev);err_enable:    dev_err(&dev->dev, "goto err_enable");    unregister_chrdev_region (bkptr->cdevno, 1);err_initchrdev:    dev_err(&dev->dev, "goto err_initchrdev");    kfree(bkptr);err_bk_alloc:    dev_err(&dev->dev, "goto err_bk_alloc");if(DBUG_PRINT)printk(KERN_ALERT "pci_probe :end !\n");    return rc;}static void __exit pci_remove(struct pci_dev *dev){    unregister_chrdev_region(bkptr->cdevno, 1);    pci_disable_device(dev);    if(bkptr) {      if(bkptr->msi_enabled) {         pci_disable_msi(dev);         bkptr->msi_enabled = 0;        }    }    unmap_bars(bkptr, dev);    pci_release_regions(dev);         if (!IS_ERR(mem_class))    {	device_destroy(mem_class,bkptr->cdevno);	class_destroy(mem_class);	mem_class = 0;    }    if (&bkptr->cdev)    {		cdev_del(&bkptr->cdev);    }	    kfree(dev);}static struct pci_device_id pci_ids[] = {    { PCI_DEVICE(A_MANF_ID,A_MODEL_CODE) },    { 0 }};static struct pci_driver driver_ops = {    .name = ADEVNAME,    .id_table = pci_ids,    .probe = pci_probe,    .remove = pci_remove,};static void Pci_cleanupmodule(void){		if (0 == npci_register)    	  pci_unregister_driver(&driver_ops);	kfree(bkptr);}static int Pci_init_module(void){	npci_register = -1;	bkptr = kzalloc(sizeof(struct pcie_dma_bookkeep), GFP_KERNEL);	memset(bkptr,0,sizeof(struct pcie_dma_bookkeep));		if(printk_ratelimit())	if(DBUG_PRINT)printk(KERN_ALERT "pci_register_driver :Begin !\n");	npci_register = pci_register_driver(&driver_ops);    	if (npci_register) {        printk(KERN_ERR ADEVNAME ": PCI driver registration failed\n");        goto fail;    	}	if(DBUG_PRINT)printk(KERN_ALERT "pci_register_driver :end !\n");		return npci_register;	fail: 		if(DBUG_PRINT)printk(KERN_ALERT "Pci_init_module :fail !\n");	return npci_register;}module_init(Pci_init_module);module_exit(Pci_cleanupmodule);MODULE_AUTHOR(ADEVNAME);MODULE_LICENSE("GPL");

转载地址:https://lkyof.blog.csdn.net/article/details/117873761 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:不进大厂也能年入百万,专科生同样是顶级人才的苗子
下一篇:掌握spec只需读这一篇文章,CentOS、RedHat、SUSE粉的福利来了

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年05月01日 06时18分46秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章