关于Linux的简单字符设备驱动程序
一、重要知【chóng yào zhī】🕚识点
1. 主次设【zhǔ cì shè】备【bèi】🌦号【hào】
dev_t
dev_t是内核【shì nèi hé】中用【yòng】来表示设备【bèi】👰编号【hào】的【de】数据类【shù jù lèi】型;
int MAJOR(dev_t dev)
int MINOR(dev_t dev)
这两个【zhè liǎng gè】🐸宏抽取主次设【zhǔ cì shè】备【bèi】🌦号【hào】。
dev_t MKDEV(unsigned int major, unsignedint minor)
这个【gè】宏🌕由主/次设备【cì shè bèi】🌦号【hào】构造一个【yī gè】🐸dev_t结构【jié gòu】🚐。
2. 分配和释放设备【bèi】👰号【hào】
int register_chardev_region(dev_t first,unsigned int count, char *name)
静态申🖐请设备【qǐng shè bèi】👰号【hào】。
Int alloc_chardev_region(dev_t *dev,unsigned int firstminor, unsigned int count, char *name)
动态申请设备【qǐng shè bèi】👰号【hào】,注意第🕳一个【yī gè】🐸参数是传地址♑,而静态【ér jìng tài】♈则是传🏘值。
3. 几种重【jǐ zhǒng chóng】👚要的数【yào de shù】🏋据结构【jié gòu】🚐
struct file
file结构【jié gòu】🚐代表一个【yī gè】👾打开的文件【de wén jiàn】🧐,它由内核在🍔open时创建,并传递给该文✖件上进【jiàn shàng jìn】行操作的【de】所有👎函数【hán shù】🌋,直到最后的【hòu de】close函数【hán shù】🌋。
file结构【jié gòu】🚐private_data是跨系【shì kuà xì】统调用【tǒng diào yòng】时保存状态【zhuàng tài】信息非常有用的【yǒu yòng de】资源。
file结构的【jié gòu de】❇f_ops 保存了文件【jiàn】🙇的【de】当前读🥕写位置。
struct inode
内核用【nèi hé yòng】inode代表一个【yī gè】👾磁盘上的文【de wén】🌬件【jiàn】,它和🛏file结构【jié gòu】🚐不同,后者表示打开的文件【de wén jiàn】🧐描述符【miáo shù fú】。对于单【duì yú dān】个【gè】🐸文件【jiàn】🙇,可能会有许多个【gè】表示🖼打开文件【jiàn】🙇的文件【de wén jiàn】🧐描述符【miáo shù fú】file结构【jié gòu】🚐,但他们【dàn tā men】〽都指单个【gè】🐸inode结构【jié gòu】🚐。inode的【de】dev_t i_rdev成员包含了【bāo hán le】真🥪正的【de】设🏵备【bèi】编号【hào】⛲,struct cdev *i_cdev包含了【bāo hán le】指向【zhǐ xiàng】struct cdev结构的【jié gòu de】❇指针🉐。
struct file_operations
file_operations结构【jié gòu】保🔮存了字📖符设备【bèi】👰驱动程序的【de】方法。
4. 字符设🖌备【bèi】的【de】注册和注👰销👼
struct cdev *cdev_alloc(void);
void cdev_init(struct cdev *dev, structfile_operations *fops);
int cdev_add(struct cdev *dev, dev_t num,unsigned int count);
void cdev_del(struct cdev *dev);
用【yòng】来管理【lǐ】🈵cdev结构的【jié gòu de】❇函数【hán shù】🌋,内核中使用【yòng】该🥁结构【jié gòu】🚐表示字【biǎo shì zì】符设🖌备【bèi】。注意🛬cdev_add函数【hán shù】🌋的【de】count参数为次设备【cì shè bèi】🌦的个数【de gè shù】🔩,要想拥【yào xiǎng yōng】有多个【gè】🐸次设备【cì shè bèi】🌦,就必须将该参数设为次设备【cì shè bèi】🌦的个数【de gè shù】🔩。
5. 并发处理【lǐ】🈵
信号量【xìn hào liàng】⛎和自旋锁【zì xuán suǒ】🎋的【de】区别,使用【yòng】📃信号量【xìn hào liàng】⛎时当调【shí dāng diào】用【yòng】🌊进程试图获得【tú huò dé】一个【yī gè】🐸锁定了的【de】锁时会导致【huì dǎo zhì】进程睡【jìn chéng shuì】眠,而自旋【ér zì xuán】锁🎋则是一直循👮法的【de】等待一直🆖到该锁解锁了为止。
1)信号量【xìn hào liàng】⛎
DECLARE_MUTEX(name);
DECLARE_MUTEX_LOCKED(name);
声明和初始化【chū shǐ huà】用【yòng】在互斥模式👖中的【de】信👘号量【hào liàng】🎁的【de】两个【gè】🐸宏
void init_MUTEX(struct semaphore *sem)
void init_MUTEX_LOCKER(struct semaphore*sem);
这两个【zhè liǎng gè】🐸函数【hán shù】可📅以在运【yǐ zài yùn】行时初始化【chū shǐ huà】信🃏号量【hào liàng】🎁
void down(struct semaphore *sem);
int down_interruptible(struct semaphore*sem);
int down_trylock(struct semahpore *sem);
void up(struct semaphore *sem);
锁定和🥣解锁信号量【xìn hào liàng】⛎。如果必【rú guǒ bì】要,down会将调用【yòng】进程置于不【zhì yú bú】可中断的【de】休眠状态【zhuàng tài】;相反【xiàng fǎn】,down_interruptible可被信号【hào】中断😰。down_trylock不会休🗣眠,并且会在信号量【xìn hào liàng】⛎不可用【bú kě yòng】时立😖即返回。锁定信😯号量【hào liàng】🎁的代码【de dài mǎ】最后必【zuì hòu bì】须使用【xū shǐ yòng】📃up解锁该信号量【xìn hào liàng】⛎。
2)自旋锁【zì xuán suǒ】🎋
spionlock_t lock = SPIN_LOCK_UNLOCKED;
spin_lock_init(spinlock_t *lock);
初始化【chū shǐ huà】自旋锁【zì xuán suǒ】🎋的两种【de liǎng zhǒng】方式。
voidspin_lock(spinlock_t *lock);
锁定自旋锁【zì xuán suǒ】🎋
voidspin_unlock(spinlock_t *lock);
解锁自旋锁【zì xuán suǒ】🎋
二【èr】、驱动【qū dòng】♐代码【dài mǎ】✈
view plaincopy to clipboardprint?#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#define MEMDEV_MAJOR 251
#define MEMDEV_NUM 2
#define MEMDEV_SIZE 1024
struct mem_dev
{
unsignedint size;
char*data;
structsemaphore sem;
};
static int mem_major = MEMDEV_MAJOR;
struct cdev mem_cdev;
struct mem_dev *mem_devp;
static int mem_open(struct inode *inode,struct file *filp)
{
structmem_dev *dev;
unsignedint num;
printk("mem_open.\n");
num= MINOR(inode->i_rdev);//获得次设备号【shè bèi hào】😊
if(num> (MEMDEV_NUM -1)) //检查次【jiǎn chá cì】设备号【shè bèi hào】😊有效性
return-ENODEV;
dev= &mem_devp[num];
filp->private_data= dev; //将设备【jiāng shè bèi】结构🕞保存为私有数据🗾
return0;
}
static int mem_release(struct inode *inode,struct file *filp)
{
printk("mem_release.\n");
return0;
}
static ssize_t mem_read(struct file *filp,char __user *buf, size_t size, loff_t *ppos)
{
intret = 0;
structmem_dev *dev;
unsignedlong p;
unsignedlong count;
printk("mem_read.\n");
dev= filp->private_data;//获得设备结构🕞
count= size;
p= *ppos;
//检查偏🔂移量【yí liàng】🕣和数据【hé shù jù】大小的有效性
if(p> MEMDEV_SIZE)
return0;
if(count> (MEMDEV_SIZE-p))
count= MEMDEV_SIZE - p;
if(down_interruptible(&dev->sem))//锁定互【suǒ dìng hù】斥信号🥩量【liàng】🕣
return -ERESTARTSYS;
//读取数据到用🌾户空间【hù kōng jiān】
if(copy_to_user(buf,dev->data+p, count)){
ret= -EFAULT;
printk("copyfrom user failed\n");
}
else{
*ppos+= count;
ret= count;
printk("read%d bytes from dev\n", count);
}
up(&dev->sem);//解锁互😤斥信号🥩量【liàng】🕣
returnret;
}
static ssize_t mem_write(struct file *filp,const char __user *buf, size_t size, loff_t *ppos)//注意:第二个【dì èr gè】💇参数和🌸read方法不【fāng fǎ bú】🚝同
{
intret = 0;
structmem_dev *dev;
unsignedlong p;
unsignedlong count;
printk("mem_write.\n");
dev= filp->private_data;
count= size;
p= *ppos;
if(p> MEMDEV_SIZE)
return0;
if(count> (MEMDEV_SIZE-p))
count= MEMDEV_SIZE - p;
if(down_interruptible(&dev->sem))//锁定互【suǒ dìng hù】斥信号🥩量【liàng】🕣
return-ERESTARTSYS;
if(copy_from_user(dev->data+p,buf, count)){
ret= -EFAULT;
printk("copyfrom user failed\n");
}
else{
*ppos+= count;
ret= count;
printk("write%d bytes to dev\n", count);
}
up(&dev->sem);//解锁互😤斥信号🥩量【liàng】🕣
returnret;
}
static loff_t mem_llseek(struct file *filp,loff_t offset, int whence)
{
intnewpos;
printk("mem_llseek.\n");
switch(whence)
{
case0:
newpos= offset;
break;
case1:
newpos= filp->f_pos + offset;
break;
case2:
newpos= MEMDEV_SIZE - 1 + offset;
break;
default:
return-EINVAL;
}
if((newpos<0)|| (newpos>(MEMDEV_SIZE - 1)))
return-EINVAL;
filp->f_pos= newpos;
returnnewpos;
}
static const struct file_operationsmem_fops = {
.owner= THIS_MODULE,
.open= mem_open,
.write= mem_write,
.read= mem_read,
.release= mem_release,
.llseek= mem_llseek,
};
static int __init memdev_init(void)
{
intresult;
interr;
inti;
//申请设备号【shè bèi hào】😊
dev_tdevno = MKDEV(mem_major, 0);
if(mem_major)
result= register_chrdev_region(devno, MEMDEV_NUM, "memdev");//注意静态申请♿的dev_t参数和🌸动【dòng】态💬dev_t参数的【cān shù de】区别 <
关键词【guān jiàn cí】:Linux,设备驱动【qū dòng】♐
阅读本文后您有什么感想? 已有 人给出评价!
- 1
- 1
- 1
- 1
- 1
- 1