老男人百科 > 百科 > 正文

linux字符设备驱动程序开发实例(linux字符驱动)

2023-05-18 14:46:38 阅读( 5765)

一、重要知识点1.主次设备号dev_tdev_t是内核中用来表示设备编号的数据类型;intMAJOR(dev_tdev)intMINOR(dev_tdev)这两个宏抽取主次设备号。

一、重要知识点

1.一次和二次设备编号

dev_t

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

int MAJOR(dev_t dev)

int MINOR(dev_t dev)

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

开发_t市场开发(无符号int大调,无符号int minor)

这个宏从主/辅设备号构建一个dev_t结构。

2.分配和释放设备编号

int register_chardev_region(dev_t first,unsigned int count, char *name)

静态应用设备编号。

Int alloc_chardev_region(dev_t *dev,unsigned int firstminor, unsigned int count, char *name)

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

3.几种重要的数据结构

struct file

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

当跨系统调用时,文件结构private_data是保存状态信息的非常有用的资源。

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

struct inode

内核使用inode来表示磁盘上的文件,这与file structure不同,file structure表示打开的文件描述符。对于单个文件,可能有许多表示打开文件的文件描述符文件结构,但它们都指向单个inode结构。

inode的dev_t i_rdev成员包含实际设备号,struct cdev *i_cdev包含指向struct cdev结构的指针。

struct file_operations

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

4. 字符设备的注册和注销

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);

用来管理cdev结构的函数,内核中使用该结构表示字符设备。注意cdev_add函数的count参数为次设备的个数,要想拥有多个次设备,就必须将该参数设为次设备的个数。

5. 并发处理

信号量和自旋锁的区别,使用信号量时当调用进程试图获得一个锁定了的锁时会导致进程睡眠,而自旋锁则是一直循法的等待一直到该锁解锁了为止。

1)信号量

DECLARE_MUTEX(name);

DECLARE_MUTEX_LOCKED(name);

声明和初始化用在互斥模式中的信号量的两个宏

void init_MUTEX(struct semaphore *sem)

void init_MUTEX_LOCKER(struct semaphore*sem);

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

void down(struct semaphore *sem);

int down_interruptible(struct semaphore*sem);

int down_trylock(struct semahpore *sem);

void up(struct semaphore *sem);

锁定和解锁信号量。如果必要,down会将调用进程置于不可中断的休眠状态;相反,down_interruptible可被信号中断。down_trylock不会休眠,并且会在信号量不可用时立即返回。

锁定信号量的代码最后必须使用up解锁该信号量。

2)自旋锁

spionlock_t lock=SPIN_LOCK_UNLOCKED;

spin_lock_init(spinlock_t *lock);

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

voidspin_lock(spinlock_t *lock);

锁定自旋锁

voidspin_unlock(spinlock_t *lock);

解锁自旋锁

二、驱动代码

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);//获得次设备号

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

return-ENODEV;

dev=mem_devp[num];

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

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;

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

if(p MEMDEV_SIZE)

return0;

if(count (MEMDEV_SIZE-p))

count=MEMDEV_SIZE - p;

if(down_interruptible(dev-sem))//锁定互斥信号量

return -ERESTARTSYS;

//读取数据到用户空间

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);//解锁互斥信号量

returnret;

}

static ssize_t mem_write(struct file *filp,const char __user *buf, size_t size, loff_t *ppos)//注意:第二个参数和read方法不同

{

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))//锁定互斥信号量

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);//解锁互斥信号量

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((newpos0)|| (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;

//申请设备号

dev_tdevno=MKDEV(mem_major, 0);

if(mem_major)

result=register_chrdev_region(devno, MEMDEV_NUM, 'memdev');//注意静态申请的dev_t参数和动态dev_t参数的区别

专题页