内核版本:Linux-4.19.5
开发板:SAMSUNG JZ2440
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev_id)
irq:中断编号,在\arch\arm\mach-s3c24xx\include\mach\irqs.h头文件中定义了各个中断编号的宏定义
handler:中断执行函数,就是发生中断的时候会自动跳转执行的函数
flags:中断类型,在include\linux\interrupt.h头文件中定义了各个中断类型的宏定义
name:中断的名称
dev_id:传参,中断执行函数有两个传入参数一个是中断号irq,另一个就是dev_id指针
注册一个中断,并设置对应的引脚
void *free_irq(unsigned int irq, void *dev_id)
irq:中断编号,free_irq函数通过传入的irq,dev_id来释放中断,填写和request_irq中相同的参数,就可以释放对应的中断。
dev_id:同上。
释放一个中断
irqreturn_t (*irq_handler_t)(int irq, void *dev_id)
irq:中断编号,触发该中断的中断编号
dev_id:注册中断时候request_irq,设置的dev_id指针的值
中断执行函数,每次中断触发都会执行该函数
/* 驱动程序 */
#include
#include
#include
#include
#include
#include
#include
#include
#include
int major; //主设备号
static struct class *buttons_class;
volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;
volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
static unsigned char key_val; //返回给用户的键值
static DECLARE_WAIT_QUEUE_HEAD(button_waitq); //休眠队列
static volatile int ev_press = 0; //条件变量
const int t_s3c2440_devid[4] = {1, 2, 3, 4}; //键值数组
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
int i_pinselect = *((int *)dev_id);
int i_pinval = 0;
unsigned long ul_regval;
switch(i_pinselect)
{
case 1:
case 2:
ul_regval = *gpfdat; //读寄存器gpfdat的值
if (i_pinselect == 1)
i_pinval = (ul_regval & (1<<0)) ? 1 : 0;
else
i_pinval = (ul_regval & (1<<2)) ? 1 : 0;
break;
case 3:
case 4:
ul_regval = *gpgdat; //读寄存器gpgdat的值
if (i_pinselect == 3)
i_pinval = (ul_regval & (1<<3)) ? 1 : 0;
else
i_pinval = (ul_regval & (1<<11)) ? 1 : 0;
break;
}
if (i_pinval) //按下读回来的值为0,松开读回来的值为1
{
/* 松开 */
key_val = 0x80 | i_pinselect;
}
else
{
/* 按下 */
key_val = i_pinselect;
}
ev_press = 1; /* 表示中断发生了 */
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
return IRQ_RETVAL(IRQ_HANDLED);
}
static int buttons_open(struct inode *inode, struct file *file)
{
int i_ret;
/* 注册一个名为S2的外部中断,上升沿和下降沿触发,中断执行函数为buttons_irq */
i_ret = request_irq(IRQ_EINT0, buttons_irq, IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING, "S2", (void *)&t_s3c2440_devid[0]);
i_ret = request_irq(IRQ_EINT2, buttons_irq, IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING, "S3", (void *)&t_s3c2440_devid[1]);
i_ret = request_irq(IRQ_EINT11, buttons_irq, IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING, "S4", (void *)&t_s3c2440_devid[2]);
i_ret = request_irq(IRQ_EINT19, buttons_irq, IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING, "S5", (void *)&t_s3c2440_devid[3]);
return 0;
}
ssize_t buttons_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
int i_ret;
if (size != 1)
return -EINVAL;
/* 如果没有按键动作, 休眠 */
wait_event_interruptible(button_waitq, ev_press);
/* 如果有按键动作, 返回键值 */
i_ret = copy_to_user(buf, &key_val, 1);
ev_press = 0;
return 1;
}
int buttons_drv_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT0, (void *)&t_s3c2440_devid[0]); //释放中断
free_irq(IRQ_EINT2, (void *)&t_s3c2440_devid[1]);
free_irq(IRQ_EINT11, (void *)&t_s3c2440_devid[2]);
free_irq(IRQ_EINT19, (void *)&t_s3c2440_devid[3]);
return 0;
}
static struct file_operations buttons_fops=
{
.owner = THIS_MODULE,
.open = buttons_open,
.read = buttons_read,
.release = buttons_drv_close,
};
static int buttons_init(void)
{
major = register_chrdev(0, "buttons", &buttons_fops); //注册一个字符设备
buttons_class = class_create(THIS_MODULE, "buttons"); //创建一个类
device_create(buttons_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 buttons_exit(void)
{
device_destroy(buttons_class, MKDEV(major,0));
class_destroy(buttons_class);
unregister_chrdev(major, "buttons");
iounmap(gpfcon);
iounmap(gpgcon);
}
module_init(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE("GPL");
/* 测试程序 */
#include
#include
#include
#include
/* seconddrvtest
*/
int main(int argc, char **argv)
{
int fd;
unsigned char key_val;
fd = open("/dev/buttons", O_RDWR);
if (fd < 0)
{
printf("can't open!\n");
}
while (1)
{
read(fd, &key_val, 1);
printf("key_val = 0x%x\n", key_val);
}
return 0;
}