linux pci驱动(转)

来源:互联网 发布:淘宝执政官衣服好不好 编辑:程序博客网 时间:2024/06/04 18:25

这是一个完整的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

原创粉丝点击