Linux pci驱动源码

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#ifdef LINUX26
#include <linux/moduleparam.h>
#endif
#include "plx.h"
#define DEVICE_NAME "plxDriver"
#define PLX_8311
//static int iMajor;
static int plx_major = 0;
struct cdev cdev;
dev_t devno;
struct class *plx_class;
static struct Plx *cards[PLX_MAX_IFACES];
bool Found_card_flag = 0;

static void plx_release(struct Plx *plx)
{
	unsigned short val;
	val = 0x0;
	if (plx->freeregion_plx)
		release_mem_region(plx->region, plx->len);

	if (plx->addr)
		iounmap(plx->addr);

	if (plx) 
		kfree(plx);
	printk("Freed a plx card\n");

}

static int shrec_open(struct inode *inode, struct file *file)
{
	try_module_get( THIS_MODULE );

	printk("open driver\n");
	return 0;
}

static int shrec_release( struct inode *inode, struct file *file )
{
	module_put( THIS_MODULE );
    if (wc->freeregion_plx)
		release_mem_region(wc->plx_region, wc->plx_len);
	if (wc->freeregion_dsp)
		release_mem_region(wc->dsp_region, wc->dsp_len);
	if (wc->plx)
		iounmap(wc->plx);
	if (wc->dsp)
		iounmap(wc->dsp);
	if (wc) 
		vfree(wc);
	return 0;
}

static struct file_operations shrec_fops = {
    owner:		THIS_MODULE,
    open:			shrec_open,
    read:			shrec_read,
    write:		shrec_write,
    release:	shrec_release,
};

static int __devinit plx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
	int x;
    int ret;
	int res;
	struct Plx *plx;

	for (x=0;x<PLX_MAX_IFACES;x++)
	{
		if (!cards[x])   
			break;
	}
	if (x >= PLX_MAX_IFACES)
	{
		printk("Too many interfaces\n");
		return -EIO;
	}
	if (pci_enable_device(pdev))
	{
		res = -EIO;
	}
	else
	{
		plx = kmalloc(sizeof(struct Plx), GFP_KERNEL);
		if (!plx) return -ENOMEM;
		memset(plx, 0x0, sizeof(struct Plx));
		if (pdev->irq < 1)
		{
			if (plx) 
				kfree(plx);
			printk(KERN_ERR "No IRQ allocated for device\n");
			return -ENODEV;
		}

        cards[x] = plx;
		plx->dev = pdev;
		plx->region = pci_resource_start(pdev,0);  //1、获取plx地址空间基地址0的首地址,该地址为物理地址,由系统启动是保存在pdev结构体中
		plx->len = pci_resource_len(pdev,0);   //获取基地址0的空间大小

		if (check_mem_region(plx->region, plx->len))  //2、检查该区域是否可用
		{
			printk("plx region %lx-%lx already in use\n", plx->region, plx->region + plx->len);
			if (plx) 
				kfree(plx);
			return -EIO;
		}

		if (request_mem_region(plx->region, plx->len, "plx"))  //3、申请使用该区域
		{
			plx->freeregion_plx = 1;
		}
		plx->addr = ioremap(plx->region, plx->len);  //4、将该区域的物理地址映射为虚拟地址,程序对只能对虚拟地址进行读写
		if (!plx->addr)
		{
			printk("Cannot ioremap memory space at 0x%lx\n", plx->region);
			goto err_out_free_plx;
		}
    	pci_set_drvdata(pdev, plx);

    	printk("Found  plx card %d\n",x);
		Found_card_flag = 1;
		res = 0;
    }
	return res;

err_out_free_plx:
	if (plx->freeregion_plx)
		release_mem_region(plx->region, plx->len);
	if (plx->addr)
		iounmap(plx->addr);
	if (plx) 
		kfree(plx);
	return -EIO;

}

static void __devexit plx_remove_one(struct pci_dev *pdev)
{
	struct Plx *plx = pci_get_drvdata(pdev);
	unsigned short reg;

	if (plx)
	{
		reg = 0x0;
		wait_ms(5000);
		if (!plx->usecount)
			plx_release(plx);
		else
			plx->dead = 1;
	}
}

static struct pci_device_id plx_pci_tbl[] =
{
    /*probe pcie cards*/
	{ 0x10b5, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
    /*probe pci cards*/
	/*tejxapci*/
	{ 0x10b5, 0x00fa, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
	{ 0x10b5, 0x00fb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
	{ 0x10b5, 0x00fc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
};

MODULE_DEVICE_TABLE(pci, plx_pci_tbl);

static struct pci_driver plx_driver =
{
	name: 	"plx_driver",
	probe: 	plx_init_one,
	remove:	plx_remove_one,
	suspend: NULL,
	resume:	NULL,
	id_table: plx_pci_tbl, /*加载驱动时,会探测pci链表中的节点,如果有pci设备中有与
                          plx_pci_tbl信息匹配的,则调用plx_init_one,对该设备进行配置及初始化*/
};

static int __init plx_driver_init(void)
{
	int res;
	res = pci_register_driver(&plx_driver);/*注册pci驱动*/
	if (res)
		return -ENODEV;
	if(plx_major)
	{
		devno = MKDEV(plx_major,0);/*获取主设备号*/

		res = register_chrdev_region(devno,1,DEVICE_NAME);
	}
	else
	{
		res = alloc_chrdev_region(&devno,0,1,DEVICE_NAME);
		plx_major = MAJOR(devno);
		printk("major = %d\n",plx_major);
	}

  if(Found_card_flag)
  {
    /*注册设备*/
	cdev_init(&cdev,&shrec_fops);
	cdev.owner = THIS_MODULE;
	res = cdev_add(&cdev,devno,1);
	if (res)
		printk("Error %d adding plx",res);

    /*创建设备文件节点*/
	plx_class = class_create(THIS_MODULE, DEVICE_NAME);
   if(IS_ERR(plx_class))
        { printk("Err: failed in creating class.\n");
             return -1;
         } 
	device_create( plx_class, NULL, devno, DEVICE_NAME);
  }
  else 
      printk("Not found Synway card!\n");

  return 0;

}

static void __exit plx_driver_cleanup(void)
{
	unregister_chrdev_region(devno,1);/*注销设备号*/

	pci_unregister_driver(&plx_driver);/*注销pci驱动,会调用plx_remove_one函数*/

     /*注销文件节点*/
     if(Found_card_flag)
     { 
        device_destroy(plx_class, devno);
        class_destroy(plx_class);

        cdev_del(&cdev);/*注销字符设备*/

     }  
}
module_init(plx_driver_init);
module_exit(plx_driver_cleanup);


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值