http://hi.baidu.com/fighter0425/blog/item/269a3bca3bed5649b219a8cb.html
这是一个完整的Linux PCI驱动程序了,自己写的,而且可用。
当初领命编写驱动程序的时候,在网上搜索Linux设备驱动,却找不到一个现成的(不过抄袭也不是好事……)。现在索性把这贡献出来,希望给看到的人一点帮助。
至于其他的参考资料嘛,确实LDD这本书是很有帮助的,建议多读一读。
/*mypci.c*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/io.h>
//设备相关
#define MY_VENDOR_ID 0x1100
#define MY_DEVICE_ID 0x4258
#define MY_PCI_NAME "PCI-0x1100"
//端口读写变量
static int io;
static long range;
//中断申请
static int irq;
long tcount = 0;
/* 设备中断服务
*/
static void mypci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
tcount ++;
return;
}
/* 探测PCI设备
*/
static int __init mypci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{
int retval, intport, intmask;
//启动设备
if ( pci_enable_device (dev) )
{
printk (KERN_ERR "IO Error.\n");
return -EIO;
}
//设定端口地址及其范围,指定中断IRQ
irq = dev->irq;
io = pci_resource_start(dev, 0);
range = pci_resource_end(dev, 0) - io;
printk ("PCI Driver at %X, and Interrupt %d.\n", io, irq);
//申请IO端口
if ( check_region(io, range) )
{
printfk (KERN_ERR "I/O %d is not free.\n", io);
return -1;
}
request_region (io, range, MY_PCI_NAME);
//申请中断IRQ并设定中断服务子函数
retval = request_irq (irq, mypci_interrupt, SA_INTERRUPT | SA_SHIRQ, MY_PCI_NAME, NULL);
if (retval)
{
printfk (KERN_ERR "Can't get assigned IRQ %d.\n", irq);
return -1;
}
printfk ("Request IRQ %d.\n", retval);
//硬件使能中断
intport = irq < 8 ? 0x21 : 0xa1;
intmask = inb_p (intport);
outb_p (intmask & ~( 0x01 << (irq & 0x07) ), intport);
outw_p (4000, io + 0x08);
return 0;
}
/* 移除PCI设备
*/
static void __devexit mypci_remove(struct pci_dev *dev)
{
free_irq (irq, NULL);
release_region (io, range);
return;
}
/* 指明驱动程序适用的PCI设备ID
*/
static struct pci_device_id mypci_table[] __initdata =
{
{
MY_VENDOR_ID, //厂商ID
MY_DEVICE_ID, //设备ID
PCI_ANY_ID, //子厂商ID
PCI_ANY_ID, //子设备ID
},
{0, },
};
MODULE_DEVICE_TABLE(pci, mypci_table);
/* 设备模块信息
*/
static struct pci_driver mypci_driver_ops =
{
name: MY_PCI_NAME, //设备模块名称
id_table: mypci_table, //驱动设备表
probe: mypci_probe, //查找并初始化设备
remove: mypci_remove //卸载设备模块
};
static int __init mypci_init(void)
{
//注册硬件驱动程序
if ( !pci_register_driver(&mypci_driver_ops) )
{
printk (KERN_ERR "Can't register driver!\n");
return -ENODEV;
}
printk ("The PCI driver is loaded successfully.\n");
mdelay (5000);
printk ("Time Count: %ld\n", tcount);
return 0;
}
static void __exit mypci_exit(void)
{
pci_unregister_driver(&mypci_driver_ops);
}
module_init(mypci_init);
module_exit(mypci_exit);
MODULE_LICENSE("GPL");
/*pci_include.mk*/
CFLAGS = -D__KERNEL__ -DMODULE -O2 -Wall -g
INCLUDE= -I/usr/src/linux-2.4.20/include
ARCH = i386
CC = gcc
/*Makefile*/
include pci_include.mk
mypci.o:mypci.c
$(CC) $(CFLAGS) $(INCLUDE) -c -o mypci.o mypci.c