字符設備驅動-下
一、一個驅動支持多個設備
- 我們平時寫設備驅動程序的時候,肯定遇到過這種情況,一類設備有多個個體(比如系統上有兩個串口)。此時,我們可能會想到多一個設備我在多寫一個同樣的驅動程序就好啦,或者說同一中驅動程序寫兩份呢?這樣當然可以啦,但是呢,這樣並不是最好的解決辦法。如果我們一個設備上面的設備有10個八個呢,而我們的驅動程序是要編譯進內核的而內核又是對內存有着比較高的要求的,同一類設備你編譯進去那麼多的代碼自然很浪費內存又不夠簡潔。當然了,我們可以採用一個討巧的辦法來處理這一類問題了。那就是一個驅動程序支持多個設備。
- 這個我們應該怎麼做呢?首先我們應該向內核註冊多個設備號,其次就是添加cdev對象(這裏爲什麼不說結構體呢,因爲在驅動編程中我們用到了面向對象的編程方法,即把每一個設備當做一個對象來處理,爲其添加屬性和方法)時需要指明該cdev對象管理者多個設備。
- 話不多說,下面給出一個例子。我會在例子中給出註釋以方便理解。
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kfifo.h>
#define VSER_MAJOR 256
#define VSER_MINOR 0
#define VSER_DEV_CNT 2
#define VSER_DEV_NAME "vser"
static struct cdev vsdev;
static DEFINE_KFIFO(vsfifo0,char,32);
static DEFINE_FIFO(vsfifo1,char,32);
static int vser_open(struct inode *inode,struct file *filp)
{
switch (MINOR(inode->i_rdev))
{
default:
case 0:
filp->private_data = &vsfifo0;
break;
case 1:
filp->private_data = &vsfifo1;
break;
}
return 0;
}
static int vser_release(struct inode *inode,struct file *filp)
{
return 0;
}
static ssize_t vser_read(struct file *filp,char __vser *buf,size_t count,loff_t *ops)
{
unsigned int copied = 0;
struct kfifo *vsfifo = filp->private_data;
kfifo_to_user(vsfifo,buf,count,&copied);
return copied;
}
static ssize_t vser_write(struct file *filp,const char __user *buf,size_t count,loff_t *pos)
{
unsigned int copied = 0;
struct kfifo *vsfifo = filp->private_data;
kfifo_from_user(vsfifo,buf,count,&copied);
return copied;
}
static struct file_opeations vser_ops = {
.owner = THIS_MODULE,
.open = vser_open,
.release = vser_read,
.write = vser_write,
};
static int __init vser_init(void)
{
int ret;
dev_t dev;
dev = MKDEV(VSER_MAJOR,VSER_MINOR);
ret = register_chrdev_region(dev,VSER_DEV_CNT,VSER_DEV_NAME);
if(ret)
goto reg_err;
cdev_init(&vsdev,&vser_ops);
vsdev.owner = THIS_MODULE;
ret = cdev_add(&vsdev,dev,VSER_DEV_CNT);
if(ret)
{
goto add_err;
}
return 0;
add_err:
unregister_chrdev_region(dev,VSER_DEV_CNT);
reg_err:
return ret;
}
static void __exit vser_exit(void)
{
dev_t dev;
dev = MKDEV(VSER_MAJOR,VSER_MINOR);
cdev_del(&vsdev);
unregister_chrdev_region(dev,VSER_DEV_CNT);
}
module_init(vser_init);
module_exit(vser_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Fan <[email protected]>");
MODULE_DESCRIPTION("A simple character device driver");
MODULE_ALIAS("virtual-serial");
二、小結
- 到目前爲止呢,我們的字符設備的驅動程序已經近乎完成,當然了,其實並不是很完善。比如我們寫了一個LED的驅動,除了去進行讀寫,又該如何去控制其亮滅呢?再比如我們又如何去控制一個串口設備的波特率呢?等等。當然了,並不是無法解決的,只是我們的知識水平還不夠。爲了解決此問題呢,Linux專門開發出了ioctl函數用於做上面提到的問題。那麼ioctl是什麼呢?下一節我會做一個詳細的介紹。