中国投资网 百科 关于Linux的简单字符设备驱动程序

关于Linux的简单字符设备驱动程序

一、重要知识点

1.一次和二次设备编号

开发_t

Dev_t是用来表示内核中设备号的数据类型;

内部专业(开发_t开发)

int MINOR(开发_t开发)

这两个宏提取主要和次要设备号。

dev _t MKDEV(无符号int major,无符号int minor)

这个宏通过主要/次要设备号构建一个dev_t结构。

2.分配并发布设备编号

int register _ char dev _ region(dev _ t first,unsigned int count,char *name)

静态应用设备编号。

int alloc _ char dev _ region(dev _ t * dev,unsigned int firstminor,unsigned int count,char *name)

申请动态设备号时,注意第一个参数是传输地址,静态参数是传输值。

3.几种重要的数据结构

结构文件

文件结构表示一个打开的文件,它是由内核在打开时创建的,并被传递给所有对该文件进行操作的函数,直到最后一个关闭函数。

当跨系统调用时,FilePrivate _ data结构对于保存状态信息是一个非常有用的资源。

文件结构的f_ops保存文件的当前读写位置。

结构信息节点

内核inode代表磁盘上的一个文件,与文件结构不同,后者代表打开的文件描述符。对于单个文件,可能有许多表示打开文件的文件描述符文件结构,但它们都指向单个inode结构。inode的dev_t i_rdev成员包含实际设备号,struct cdev *i_cdev包含指向struct cdev结构的指针。

结构文件_操作

file_operations结构保存了字符设备驱动程序的方法。

4.字符设备的注册和取消

struct cdev * cdev _ alloc(void);

void cdev_init(struct cdev *dev,struct file _ operations * fops);

int cdev_add(struct cdev *dev,dev_t num,无符号int count);

void cdev _ del(struct cdev * dev);

用于管理cdev结构的函数,cdev结构在内核中用于表示字符设备。注意,cdev_add函数的count参数是辅助设备的数量。如果您想要多个辅助设备,您必须将此参数设置为辅助设备的数量。

5.并行处理

信号量和自旋锁的区别在于,当使用信号量时,调用进程在试图获取锁定的锁时会休眠,而自旋锁会等到锁被解锁。

1)旗语

DECLARE _ MUTEX(name);

DECLARE _ MUTEX _ LOCKED(name);

和声明两个宏,这两个宏初始化互斥模式下使用的信号量。

void init_MUTEX(结构信号量*sem)

void init _ MUTEX _ LOCKER(struct semaphore * SEM);

这两个函数可以在运行时初始化信号量。

void down(结构信号量* SEM);

int down _ interruptible(struct semaphore * SEM);

int down _ try lock(struct sema hpore * SEM);

void up(结构信号量* SEM);

以及锁定和解锁信号量。如有必要,down会将呼叫过程置于不间断睡眠状态;相反,down_interruptible可以被一个信号中断。Down_trylock不会休眠,当信号量不可用时会立即返回。锁定信号量的代码最终必须用尽才能解锁信号量。

2)旋转锁

spion LOCK _ t LOCK=SPIN _ LOCK _ UNLOCKED;

spin _ lock _ init(spin lock _ t * lock);

初始化自旋锁的两种方法。

void spin _ lock(spin lock _ t * lock);

锁定旋转锁

void spin _ unlock(spin lock _ t * lock);

打开旋转锁

第二,驱动代码

查看剪贴板打印文本?#包含linux/module.h

#包含linux/types.h

#包含linux/fs.h

#包含linux/errno.h

#包含linux/mm.h

#包含linux/sched.h

#包含linux/init.h

#包含linux/cdev.h

#包含asm/io.h

#包含asm/system.h

#包含asm/uaccess.h

#定义内存开发_专业251

#定义内存开发数量2

#定义MEMDEV_SIZE 1024

结构内存_开发

{

未指定大小;

char * data

结构信号sem

};

static int mem _ MAJOR=mem dev _ MAJOR;

struct cdev mem _ cdev

struct mem _ dev * mem _ devp

static int mem_open(结构索引节点*索引节点,结构文件*filp)

{

structmem _ dev * dev

未签名的项目编号;

printk('mem_open。\ n’);

num=MINOR(inode-I _ rdev);//获取辅助设备号

If(num (MEMDEV_NUM -1)) //检查次要设备号的有效性

return-ENODEV;

dev=mem _ devp[num];

filp-private _ data=dev;//将设备结构保存为私有数据

return0

}

静态int mem_release(结构索引节点*索引节点,结构文件*filp)

{

printk('mem_release。\ n’);

return0

}

静态ssize _ t mem _ read(struct file * filp,char __user *buf,size_t size,loff_t *ppos)

{

intret=0;

结构内存_开发*开发

未签名的长p;

未签名的长计数;

printk('mem_read .\ n’);

dev=filp-private _ data;//获得设备结构

计数=大小;

p=* ppos

//检查偏移量和数据大小的有效性

if(p MEMDEV_SIZE)

返回0

if(count (MEMDEV_SIZE-p))

count=mem dev _ SIZE-p;

if(down _ interruptible(dev-SEM))//锁定互斥信号量

return-ERESTARTSYS;

//读取数据到用户空间

if(copy_to_user(buf,dev-data p,count)){

ret=-e故障;

printk('从用户复制失败\ n’);

}

否则{

*ppos=计数;

ret=计数;

printk('从偏差读取%d字节\n '计数);

}

up(dev-SEM);//解锁互斥信号量

返回ret

}

静态ssize _ t mem _ write(struct file * filp,const char __user *buf,size_t size,loff_t *ppos)//注意:第二个参数和阅读方法不同

{

intret=0;

结构内存_开发*开发

未签名的长p;

未签名的长计数;

printk('mem_write .\ n’);

dev=filp-private _ data;

计数=大小;

p=* ppos

if(p MEMDEV_SIZE)

返回0

if(count (MEMDEV_SIZE-p))

count=mem dev _ SIZE-p;

if(down _ interruptible(dev-SEM))//锁定互斥信号量

return-ERESTARTSYS;

if(copy_from_user(dev-data p,buf,count)){

ret=-e故障;

printk('从用户复制失败\ n’);

}

否则{

*ppos=计数;

ret=计数;

printk('将%d个字节写入dev\n 'count);

}

up(dev-SEM);//解锁互斥信号量

返回ret

}

静态loff_t mem_llseek(结构文件*filp,loff_t偏移量int whence)

{

intnewpos

printk('mem_llseek .\ n’);

开关(从哪里)

{

案例0:

newpos=offset

打破;

案例1:

new pos=filp-f _ pos offset;

打破;

案例2:

newpos=MEMDEV_SIZE - 1偏移量;

打破;

默认值:

return-EINVAL;

}

if((新位置0)| |(新位置(内存大小-1)))

return-EINVAL;

filp-f _ pos=新pos;

returnnewpos

}

静态构造结构file _ operationsmem _ fops={。所有者=本_模块。open=mem_open。写=内存_写。read=mem_read。释放=记忆_释放。llseek=mem_llseek,

};

静态int __init memdev_init(void)

{

结果

interr

英蒂

//申请设备号

dev_tdevno=MKDEV(mem_major,0);

如果(内存_专业)

result=register _ chrdev _ region(devno,MEMDEV_NUM,' MEMDEV ');//注意静态申请的开发_t参数和动态开发_t参数的区别

本文来自网络,不代表本站立场,转载请注明出处:https:

关于Linux的简单字符设备驱动程序

中国投资网后续将为您提供丰富、全面的关于关于Linux的简单字符设备驱动程序内容,让您第一时间了解到关于关于Linux的简单字符设备驱动程序的热门信息。小编将持续从百度新闻、搜狗百科、微博热搜、知乎热门问答以及部分合作站点渠道收集和补充完善信息。