一、重要知识点
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参数的区别