网站首页 > 技术文章 正文
小知识点:
/proc/devices文件
这个文件列出字符和块设备的主设备号,以及分配到这些设备号的设备名称
前言;
1,上几期(查询方式、中断方式、POLL机制)读取按键值都是应用程序主动读取按键值,那么有无被动读取呢?答:异步通知机制(核心:发送信号)
异步通知机制的作用是,可以让驱动通知应用去读取数据。
进程间发信号用:kill -信息 PID(进程号)
PID(进程号)可在终端用ps查询
2,简单发送信号的测试程序;
(1)程序源码 doubixiaohanhan.c
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
void signal_function(int signal)
{
static int time = 0;
time ++;
printf("Recieved a signal: %d,%d times\n",signal,time);
}
int main(int argc, char **argv)
{
signal(SIGUSR1,signal_function);
while (1)
{
sleep(5000);
}
return 0;
}
//signal函数原型:(可以使用man signal 命令查询)
(2)编译
arm-linux-gcc -o test doubixiaohanhan.c
(3)拷贝到网络文件系统,后台执行程序: ./test &
(4)使用ps命令查看进程:
可以看到./test进程处于休眠状态
(5)发送信号:
从上图也可以看出,信号SIGUSR1=10,验证;发送kill -10 771也可以得到同样的结果。
常见的信号类型:
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29
#define SIGPOLL SIGIO
/*
#define SIGLOST 29
*/
#define SIGPWR 30
#define SIGSYS 31
#define SIGUNUSED 31
/* These should not be considered constants from userland. */
#define SIGRTMIN 32
#define SIGRTMAX _NSIG
#define SIGSWI 32
从上述可以看出,之前使用的kill -9结束某个进程,这个信号是:#define SIGKILL 9
kill_fasync发送信号函数分析
1,void kill_fasync(struct fasync_struct **fp, int sig, int band)
2,void __kill_fasync(struct fasync_struct *fa, int sig, int band)
3,void send_sigio(struct fown_struct *fown, int fd, int band)
4,static void send_sigio_to_task(struct task_struct *p,
struct fown_struct *fown,
int fd,
int reason)
5, band_table[reason - POLL_IN];
6,/* Table to convert sigio signal codes into poll band bitmaps */
static const long band_table[NSIGPOLL] = {
POLLIN | POLLRDNORM, /* POLL_IN */
POLLOUT | POLLWRNORM | POLLWRBAND, /* POLL_OUT */
POLLIN | POLLRDNORM | POLLMSG, /* POLL_MSG */
POLLERR, /* POLL_ERR */
POLLPRI | POLLRDBAND, /* POLL_PRI */
POLLHUP | POLLERR /* POLL_HUP */
};
7,int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
8,int __group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
9,static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
struct sigpending *signals)
备注:#define POLL_IN(__SI_POLL|1) /* data input available */
驱动程序;
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h>
static struct class *button_class;
static struct class_device *button_class_dev;
volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;
volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;
struct pin_desc{
unsigned int pin;
unsigned int key_val;
};
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
struct pin_desc pins_desc[4] = {
{S3C2410_GPF0, 0x01},
{S3C2410_GPF2, 0x02},
{S3C2410_GPG3, 0x03},
{S3C2410_GPG11, 0x04},
};
//保存键值
static unsigned char key_val;
static DECLARE_WAIT_QUEUE_HEAD(button_interrupt_wait);//等待队列
static volatile int ev_press = 0;
static struct fasync_struct *button_async_queue;//定义一个信号相关的结构体
// 按键中断函数
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
struct pin_desc *pindesc = (struct pin_desc *)dev_id;
unsigned int val;
val = s3c2410_gpio_getpin(pindesc ->pin);
if(val)
{
//按键松开
key_val = 0x80 |pindesc->key_val;
}
else
{
key_val = pindesc->key_val;
}
ev_press = 1;
wake_up_interruptible(&button_interrupt_wait);//唤醒队列button_interrupt_wait
//发送信号通知signal 函数
kill_fasync(&button_async_queue, SIGIO, POLL_IN);
return 0;
}
static int button_drv_fasync(int fd, struct file *file, int on)
{
printk(" Driver: debug program ");
if (fasync_helper(fd, file, on, &button_async_queue) >= 0)
return 0;
else
return -EIO;
}
static int button_drv_open(struct inode *inode, struct file *file)
{
/* 配置GPF0,2为中断输入引脚 */
/* 配置GPG3,11为中断输入引脚 */
request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "button_1", &pins_desc[0]);//双边沿触发
request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "button_2", &pins_desc[1]);
request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "button_3", &pins_desc[2]);
request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "button_4", &pins_desc[3]);
return 0;
}
static ssize_t button_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
//no button press , button_interrupt_wait enters wait queue
wait_event_interruptible(button_interrupt_wait, ev_press);
copy_to_user(buf, &key_val, 1);
ev_press = 0;
return 0;
}
static int button_drv_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT0, &pins_desc[0]);
free_irq(IRQ_EINT2, &pins_desc[1]);
free_irq(IRQ_EINT11, &pins_desc[2]);
free_irq(IRQ_EINT19, &pins_desc[3]);
return 0;
}
static unsigned int button_drv_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
poll_wait(file, &button_interrupt_wait, wait);
if(ev_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}
static struct file_operations button_drv_fops = {
.owner = THIS_MODULE,
.open = button_drv_open,
.read = button_drv_read,
.release = button_drv_close,
.poll = button_drv_poll,
.fasync = button_drv_fasync,
};
int major;
static int button_drv_init(void)
{
major = register_chrdev(0, "button_drv", &button_drv_fops);//注册一个设备
button_class = class_create(THIS_MODULE, "button_drv");//创建一个类
//创建类设备/* /dev/buttons */
button_class_dev = class_device_create(button_class, NULL, MKDEV(major, 0), NULL, "buttons");
gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
gpfdat = gpfcon + 1;
gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
gpgdat = gpgcon + 1;
return 0;
}
static void button_drv_exit(void)
{
unregister_chrdev(major, "button_drv");
class_device_unregister(button_class_dev);
class_destroy(button_class);
iounmap(gpfcon);
iounmap(gpgcon);
}
module_init(button_drv_init);
module_exit(button_drv_exit);
MODULE_LICENSE("GPL");
测试程序;
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <sys/types.h>
#include <unistd.h>
int fd;
void signal_function(int signal_num)
{
static int timer = 0;
unsigned char button_val;
timer ++;
read(fd,&button_val,1);
printf("Recieved a signal: %d,%d times\n",signal_num,timer);
printf("Recieved a button: %d\n",button_val);
}
int main(int argc, char **argv)
{
int Oflags;
signal(SIGIO,signal_function);
fd = open("/dev/buttons", O_RDWR);
if (fd < 0)
{
printf("can't open /dev/buttons!\n");
return -1;
}
fcntl(fd, F_SETOWN, getpid()); //设置本进程为fd文件的拥有者,没有这一步,内核不会知道应该将信号发给哪个进程
Oflags = fcntl(fd, F_GETFL); //获取设备文件的f_flags
fcntl(fd, F_SETFL, oflags | FASYNC); //为了启用异步通知机制,还需对设备设置FASYNC标志
while (1)
{
sleep(5000);
}
return 0;
}
Makefile;
KERN_DIR = /work/system/linux-2.6.22.6
all:
make -C $(KERN_DIR) M=`pwd` modules
rm -rf modules.order Module.symvers button.mod.c
.PHONY:
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order Module.symvers button.mod.c
obj-m += signal_readButton.o
测试;
与上期测试一样;当有按键活动时,驱动程序发送信号给应用程序,应用程序然后使用read函数读取按键值
添加的主要代码:
1,驱动程序中使用的相关代码:
(1)static struct fasync_struct *button_async_queue;//定义一个信号相关的结构体
(2)kill_fasync(&button_async_queue, SIGIO, POLL_IN);//发送信号通知signal 函数
(3)static int button_drv_fasync(int fd, struct file *file, int on)
{
printk(" Driver: debug program ");
if (fasync_helper(fd, file, on, &button_async_queue) >= 0)
return 0;
else
return -EIO;
}
(4).fasync = button_drv_fasync,
2,应用程序中使用的相关代码:
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <sys/types.h>
#include <unistd.h>
int fd;
void signal_function(int signal_num)
{
static int timer = 0;
unsigned char button_val;
timer ++;
read(fd,&button_val,1);
printf("Recieved a signal: %d,%d times\n",signal_num,timer);
printf("Recieved a button: %d\n",button_val);
}
int Oflags;
signal(SIGIO,signal_function);
fcntl(fd,F_SETOWN,getpid());
Oflags = fcntl(fd,F_GETFL);
fcntl(fd,F_SETFL,Oflags | FASYNC);
补充:
fcntl是计算机中的一种函数,通过fcntl可以改变已打开的文件性质。fcntl针对描述符提供控制。参数fd是被参数cmd操作的描述符。针对cmd的值,fcntl能够接受第三个参数int arg。
fcntl的返回值与命令有关。如果出错,所有命令都返回-1,如果成功则返回某个其他值。
参数fd:
参数fd代表欲设置的文件描述符。
参数cmd:
参数cmd代表打算操作的指令。
有以下几种情况:
F_DUPFD用来查找大于或等于参数arg的最小且仍未使用的文件描述符,并且复制参数fd的文件描述符。执行成功则返回新复制的文件描述符。新描述符与fd共享同一文件表项,但是新描述符有它自己的一套文件描述符标志,其中FD_CLOEXEC文件描述符标志被清除。请参考dup2()。
F_GETFD取得close-on-exec旗标。若此旗标的FD_CLOEXEC位为0,代表在调用exec()相关函数时文件将不会关闭。
F_SETFD 设置close-on-exec 旗标。该旗标以参数arg 的FD_CLOEXEC位决定。
F_GETFL 取得文件描述符状态旗标,此旗标为open()的参数flags。
F_SETFL 设置文件描述符状态旗标,参数arg为新旗标,但只允许O_APPEND、O_NONBLOCK和O_ASYNC位的改变,其他位的改变将不受影响。
F_GETLK 取得文件锁定的状态。
F_SETLK 设置文件锁定的状态。此时flcok 结构的l_type 值必须是F_RDLCK、F_WRLCK或F_UNLCK。如果无法建立锁定,则返回-1,错误代码为EACCES 或EAGAIN。
F_SETLKW F_SETLK 作用相同,但是无法建立锁定时,此调用会一直等到锁定动作成功为止。若在等待锁定的过程中被信号中断时,会立即返回-1,错误代码为EINTR。
总结:
应用程序使用fcntl()设置当前进程的pid和FASYNC标志。
进而调用驱动程序的fasync(),即fasync_helper()。然后申请和设置fasync_struct结构,将此结构挂载到驱动程序的fasync_struct结构链表中。当设备可用时,驱动程序会使用kill_fasync(),从fasync_struct链表中,查找所有的等待进程,然后调用send_sigio发送相应的消息给进程。进程接收到消息,就会跳转到与消息绑定的消息处理函数中。
猜你喜欢
- 2024-10-15 微软推广XB1新招:拉朋友入伙奖一年EA Access会籍!
- 2024-10-15 EA Access很可能在年内登陆PS4(ea access hub)
- 2024-10-15 雅虎日本欲32亿美元收购eAccess(雅虎 收购)
- 2024-10-15 EA统一旗下订阅服务名称 "EA Play"更加专注玩家体验
- 2024-10-15 Windows 10 Microsfot Store新增订阅和Timeline功能
- 2024-10-15 EA Access登陆PS4平台 每月5美元 大作无限畅玩
- 2024-10-15 《FIFA15》正式登陆EA Access服务免费游戏库
- 2024-10-15 EA Access会员已可提前游玩《极品飞车 热度》
- 2024-10-15 手摸手带你 Docker 从入门到实践(dockerl)
- 2024-10-15 嵌入式学习总结5(嵌入式课程总结与体会)
- 11-26Win7\8\10下一条cmd命令可查得笔记本电脑连接过的Wifi密码
- 11-26一文搞懂MySQL行锁、表锁、间隙锁详解
- 11-26电脑的wifi密码忘记了?一招教你如何找回密码,简单明了,快收藏
- 11-26代码解决忘记密码问题 教你用CMD命令查看所有连接过的WIFI密码
- 11-26CMD命令提示符能干嘛?这些功能你都知道吗?
- 11-26性能测试之慢sql分析
- 11-26论渗透信息收集的重要性
- 11-26如何查看电脑连接过的所有WiFi密码
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)