linux驱动怎样通知应用程序

linux驱动怎样通知应用程序,第1张

驱动程序一般是通过模块注入内核,用字符驱动程序举个例子:

1.编写字符驱动程序需要在内核中注册设备和中断程序,还有file_ops里面的open,read,release等函数

2.注册成功后在/proc/device文件里面可以看到你注册的设备名称和主设备号,/proc/interrupt文件中可以看到注册的中断

3.为设备创建文件节点,mknod /dev/char_dev_test c 主设备号 次设备号,于是就在/dev/里面生成一个char_dev_test 设备文件

4,应用程序通过文件 *** 作函数,比如open,read等 *** 作char_dev_test 文件

eg: FILE* p=open("/dev/char_dev_test","rb")

if(p==NULL) { printf("error,can't open dev file!")return -1}

char buf[1024]

read(p,buf,size_t)

//其中open是调用的注册进入内核的file_ops的open函数,read是调用的file_ops的read函数,里面一般有copy_to_user,将内核数据复制到用户空间,也就是复制到了buf中。

姓名:王芷若    学号:19020100180

学院:电子工程学院

【嵌牛导读】:本篇文章整理Linux知识点—Linux字符型设备驱动初步。

【嵌牛鼻子】:Linux设备类型,结构体,驱动模块

【嵌牛提问】:Linux设备有什么类型?关键函数有哪些?

【嵌牛内容】–linux字符型设备驱动初步

一、Linux字符设备驱动初步

1、Linux设备类型

(1)字符设备:只能一个字节一个字节的读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后顺序进行。字符设备是面向流的设备,常见的字符设备如鼠标、键盘、串口、控制台、LED等。

(2)块设备:是指可以从设备的任意位置读取一定长度的数据设备。块设备如硬盘、磁盘、U盘和SD卡等存储设备。

(3)网络设备:网络设备比较特殊,不在是对文件进行 *** 作,而是由专门的网络接口来实现。应用程序不能直接访问网络设备驱动程序。在/dev目录下也没有文件来表示网络设备。

2、开发流程

在这里插入图片描述

3、关键函数讲解(以2.6以下版本内核为例)

(1)驱动模块注册register_chrdev()函数

原型:register_chrdev(unsigned int major, const char *name,const struct file_operations *fops);

major:主设备号,该值为 0 时,自动运行分配。而实际值不是 0 ;

name:设备名称;

fops: *** 作函数,实现驱动定义的open、read、write、close等内核函数与应用程序调用的open、read、write、close间的映射;

返回值:

major 值为 0 ,正常注册后,返回分配的主设备号。如果分配失败,返回 EBUSY 的负值 ( -EBUSY ) 。major 值若大于 linux/major.h (2.4内核)中声明的最大值 (#define MAX_CHRDEV 255) ,则返回EINVAL 的负值 (-EINVAL) 。指定 major 值后,若有注册的设备,返回 EBUSY 的负值 (-EBUSY)。若正常注册,则返回 0 值

(2)驱动注销unregister_chrdev()函数

原型:

#include <linux.fs.h>

int unregister_chrdev (unsigned int major, const char *name)

变量:

major 主设备号

name 设备文件

返回值:

major 值若大于 linux/major.h (2.4 内核)中声明的最大值 (#define MAX_CHRDEV 255),返回 EINVAL的负值 (-EINVAL)。指定了 major的值后,若将要注销的 major 值并不是注册的设备驱动程序,返回 EINVAL的负值 ( -EINVAL )。正常注销则返回 0值。

(3)File_operation结构体

file_operations结构是建立驱动程序和设备编号的连接,内部是一组函数指针,每个打开的文件,也就是file结构,和一组函数关联,这些 *** 作主要用来实现系统调用的

struct file_operations {

struct module *owner//拥有该结构的模块的指针,一般为THIS_MODULES

loff_t (*llseek) (struct file *, loff_t, int)//用来修改文件当前的读写位置

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *)//从设备中同步读取数据

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *)//向设备发送数据

ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t)//初始化一个异步的读取 *** 作

ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t)//初始化一个异步的写入 *** 作

int (*readdir) (struct file *, void *, filldir_t)//仅用于读取目录,对于设备文件,该字段为NULL

unsigned int (*poll) (struct file *, struct poll_table_struct *)//轮询函数,判断目前是否可以进行非阻塞的读写或写入

int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long)//执行设备I/O控制命令

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long)//不使用BLK文件系统,将使用此种函数指针代替ioctl

long (*compat_ioctl) (struct file *, unsigned int, unsigned long)//在64位系统上,32位的ioctl调用将使用此函数指针代替

int (*mmap) (struct file *, struct vm_area_struct *)//用于请求将设备内存映射到进程地址空间

int (*open) (struct inode *, struct file *)//打开

int (*flush) (struct file *, fl_owner_t id)

int (*release) (struct inode *, struct file *)//关闭

int (*fsync) (struct file *, struct dentry *, int datasync)//刷新待处理的数据

int (*aio_fsync) (struct kiocb *, int datasync)//异步刷新待处理的数据

int (*fasync) (int, struct file *, int)//通知设备FASYNC标志发生变化

int (*lock) (struct file *, int, struct file_lock *)

ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int)

unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long)

int (*check_flags)(int)

int (*flock) (struct file *, int, struct file_lock *)

ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int)

ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int)

int (*setlease)(struct file *, long, struct file_lock **)

}

#include<iostream>

#include<cstring>

using namespace std

class string

{

private:

char *str

public:

string(char *s)

~string(){delete str}

int getlen(){return strlen(str)+1}

char *get(){return str}

void print()

}

string::string(char *s)

{

str=new char[strlen(s)+1]

strcpy(str,s)

cout<<"constructing string"<<endl

}

void string::print()

{

cout<<"原数组为:"<<str<<endl

}

class editstring : public string

{

private:

char *str

unsigned int cursor

public:

editstring(char *s)

~editstring(){delete str}

void setcurright()

{

if(cursor<strlen(str)+1)

cursor++

cout<<"光标点右移为:"<<cursor<<endl

}

void setcurleft()

{

if(cursor>0)

cursor--

cout<<"光标点左移为:"<<cursor<<endl

}

void insert(char c)

void deletes()

char *get(){return str}

void replace(char c)

void print()

}

editstring::editstring(char *s):string(s)

{

str=new char[strlen(s)+1]

strcpy(str,s)

cursor=0

cout<<"constructing editstring"<<endl

}

void editstring::insert(char c)

{

cout<<"插入字母:"<<c<<""<<endl<<"目前光标点为"<<cursor<<""<<endl

int max=strlen(str)+1

max++

char *temp=new char[max]

strcpy(temp,str)

str=new char[max]

strcpy(str,temp)

unsigned int j

for(j=cursorj<max-1j++)

{

str[j+1]=temp[j]

}

str[cursor]=c

delete []temp//delete temp.一样吗?

}

void editstring::deletes()

{

cout<<"删除函数被调用。"<<endl<<"目前光标点为"<<cursor<<""<<endl

int max=strlen(str)+1

int i=0

for(i=cursori<maxi++)

{

str[i]=str[i+1]

}

i--

str[i]='\0'

}

void editstring::replace(char c)

{

cout<<"替换函数被调用。"<<endl<<"目前光标点为"<<cursor<<""<<endl

str[cursor]=c

}

void editstring::print()

{

cout<<"编辑后的数组为:"<<str<<endl

}

void main()

{

editstring p("china")

p.string::print()

p.setcurright()

p.setcurright()

p.setcurleft()

p.deletes()

p.editstring::print()

p.insert('a')

p.editstring::print()

p.deletes()

p.editstring::print()

p.replace('s')

p.editstring::print()

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/7110966.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-01
下一篇 2023-04-01

发表评论

登录后才能评论

评论列表(0条)

保存