key.c 利用内核中断实现按键
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
struct tiny4412_key {
int keynum; //按键编号
int irqnum; //记录内核的中断号
int cnt; //条件标记
}keys[4] = {
{0, IRQ_EINT(26), 0},
{1, IRQ_EINT(27), 0},
{2, IRQ_EINT(28), 0},
{3, IRQ_EINT(29), 0},
};
extern void print_info(char *str);//doem中的打印函数,实现临界资源访问的部分
extern spinlock_t spin; //从doem申请的自旋锁
/*当按键中断发生后,内核自动调用到注册的这个处理函数,并将
注册中断时的第五个参数传给此处理函数的第二形参*/
static irqreturn_t do_key(int irqnum, void *data) //中断处理函数
{
struct tiny4412_key *k = data;
char kbuf[SZ_64];
unsigned long flag;
k->cnt ^= 1;
sprintf(kbuf, "key %d is %s.", k->keynum, (k->cnt)?"down":"up");
spin_lock_irqsave(&spin, flag); //加锁 避免死锁 用_irqsave函数
print_info(kbuf);
spin_unlock_irqrestore(&spin, flag);//解锁
return IRQ_HANDLED; //IRQ_NONE;
}
int register_key_irq(void)
{
int i;
int ret;
for (i = 0; i < 4; i++) {
ret = request_irq(keys[i].irqnum, do_key,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"keys", keys+i); //注册中断 通过内核中断的编号,设置双边沿触发
if (ret < 0) {
goto error0;
}
}
return 0;
error0:
while (i--) {
free_irq(keys[i].irqnum, keys+i);
}
return ret;
}
void unregister_key_irq(void)
{
int i = 4;
while (i--) {
free_irq(keys[i].irqnum, keys+i); //出口时,需要释放注册的中断
}
}
demo.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/delay.h>
#define DEVNAME "spin"
#define LOOPCNT 3
extern void unregister_key_irq(void);
extern int register_key_irq(void);
static int glb_cnt = 0;
spinlock_t spin;
void print_info(char *str)
{
int i;
for (i = 0; i < LOOPCNT; i++) {
printk("%d -> : %s\n", glb_cnt, str);
glb_cnt++;
mdelay(50);
}
}
static long
demo_ioctl (struct file *filp, unsigned int request, unsigned long arg)
{
unsigned long flag;
// spin_lock(&spin);//使用 这个函数会导致只要进程逻辑不结束,永远不会进中断
spin_lock_irqsave(&spin, flag);
print_info((char *)arg);
spin_unlock_irqrestore(&spin, flag);
// spin_unlock(&spin);
return 0;
}
/*
为上层用户提供了ioctl的函数接口
*/
static struct file_operations fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = demo_ioctl,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVNAME,
.fops = &fops,
};
static int demo_init(void) //驱动模块的入口
{
int ret;
spin_lock_init(&spin); //初始化自旋锁
ret = misc_register(&misc); //注册混杂设备驱动
if (ret < 0) {
return ret;
}
ret = register_key_irq(); .//调用key.c中实现的注册中断函数
if (ret < 0) {
goto error0;
}
return 0;
error0:
misc_deregister(&misc);
return ret;
}
module_init(demo_init);
static void demo_exit(void) //驱动的出口
{
misc_deregister(&misc);
unregister_key_irq(); //需要释放注册的中断和混杂设备驱动
printk("goodbye...\n");
}
module_exit(demo_exit);
MODULE_LICENSE("GPL");
MODULE_VERSION("2018-09-30");
MODULE_AUTHOR("Hebowen");
MODULE_DESCRIPTION("a simple demo for module");
app.c 开启512个进程,使之打印每3个一致,即使发生中断,不会发生资源
的抢占,然后进入中断
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#define N 98
#define SZ 512
/*
./a.out /dev/semaphore r/w
*/
int main(int argc, char **argv)
{
int fd;
int ret;
int i;
pid_t pid[N];
char buf[SZ];
if (argc != 2) {
fprintf(stderr, "Usage: %s devicefile\n", argv[0]);
exit(1);
}
fd = open(argv[1], O_RDWR | O_NDELAY);
assert(fd > 0);
for (i = 0; i < N; i++) {
if ((pid[i] = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid[i] == 0) {
sprintf(buf, "hello, %d.", getpid());
ret = ioctl(fd, 0, buf);
assert(ret == 0);
return;
}
}
for (i = 0; i < N; i++) {
waitpid(pid[i], NULL, 0);
}
close(fd);
return 0;
}