详细原理不介绍, 参照《Linux 设备驱动 Edition 3》中第16章块设备驱动,第12章 PCI 驱动开发,以及KVM虚拟化设备模拟,以及其他设备中断,端口读写等等, 涉及知识较多,应该是一个综合实例。多余不必叙述,可参考下面代码。由于该实例涉及知识较多,建议首先学习《Linux 设备驱动 Edition 3》中第16章块设备驱动,第12章 PCI 驱动开发,再尝试该实例。
因为需要PCI物理设备,学习一下qemu-kvm设备模拟,采用qemu-kvm模拟PCI物理设备,而虚拟机采用Linux系统,编写该物理驱动程序vblk.c,设备模拟代码参见hw/vblk.c.
虚拟机运行:
#x86_64-softmmu/qemu-system-x86_64 -hda /var/lib/libvirt/images/hxxx.img -m 1024 -device vblk
//模拟pci设备为vblk
//hxxx.img为 发行版CentOS Linux release 6.0 (Final),内核2.6.32-71.el6
1.内核版本:
# uname -r
2.6.32-71.el6
2.发行版:
# cat /etc/redhat-release
CentOS Linux release 6.0 (Final)
3.qemu-kvm版本
# rpm -qa | grep qemu-kvm
qemu-kvm-0.12.1.2-2.209.el6.x86_64
一.编写Linux PCI设备驱动
#vi vblk.c
######################################
##include <linux/init.h>
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/spinlock.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h> /* invalidate_bdev */
#include <linux/bio.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
static int major, index=0;
static int hardsect_size = 512;
static int nsectors = 1024*2*10; /* How big the drive is */
#define TRANSFER_OK 1
struct virt_dev {
spinlock_t lock;
int size; /* Device size in sectors */
u8 *data; /* The data array */
unsigned long ioaddr;
u8* mmioaddr;
unsigned int irq;
struct gendisk *disk;
};
static struct virt_dev *vbd;
static const struct block_device_operations vbd_fops = {
.owner = THIS_MODULE,
};
static struct pci_device_id vblk_pci_id_table[] = {
{ 0x1af4, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0},
};
/*
* * Handle an I/O request.
* */
static void sbull_transfer(struct virt_dev *dev, unsigned long sector,
unsigned long nsect, char *buffer, int write)
{
unsigned long offset = sector*512;
unsigned long nbytes = nsect*512;
if ((offset + nbytes) > dev->size) {
printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);
return;
}
if (write)
memcpy(dev->data + offset, buffer, nbytes);
else