1. 程式人生 > >Linux pci驅動源碼

Linux pci驅動源碼

lag rds null print led troy 映射 保存 空間大小

#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);


Linux pci驅動源碼