1、switch上报功能:通过switch类上报内核状态值
相关的文件放在:/drivers/switch/switch_gpio.c /drivers/switch/switch_class.c
下面的代码展示了功能实现流程:
#include <linux/switch.h>
static int switch_test_init(void)
{
printk("switch_test_init\n");
struct switch_dev *sdev;
sdev=kzalloc(sizeof(struct switch_dev), GFP_KERNEL);
sdev->name = "switch_status";
switch_dev_register(sdev);
int state = 1;
switch_set_state(&sdev,state);
return 0;
}
static void switch_test_exit(void)
{
printk("switch_test_exit\n");
}
module_init(switch_test_init);
module_exit(switch_test_exit);
结果:
cat /sys/class/switch/switch_status/state
1
2、schedule_work 工作队列
工作队列一般可以用来做需要延时的工作,比如中断中有大量的事情需要做,但是显然中断又不能耗费太长的时间,因此我们可以把一些耗时长,但不要求实时性的工作放在工作队列来完成
①第一种工作队列的创建方式:非延时工作队列
#include <linux/workqueue.h>
struct work_struct test_work;
static void schedule_work_function(struct work_struct *work)
{
printk("LPF:----into %s successful!!!!------------- \n",__func__);
}
static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
{
schedule_work(&test_work);
return IRQ_HANDLED;
}
static int __init irq_switch_init(void)
{
......
request_irq(switch_data->irq, gpio_irq_handler,
IRQF_TRIGGER_FALLING , pdev->name, switch_data); //中断函数申请
INIT_WORK(&test_work, schedule_work_function, &data)
......
}
......
②第二种工作队列的创建方式:延时工作队列
#include <linux/workqueue.h>
strcut delayed_work test_work;
static void schedule_work_function(struct work_struct *work)
{
printk("LPF:----into %s successful!!!!------------- \n",__func__);
}
static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
{
schedule_delayed_work(&test_work,20); //延迟20个节拍
return IRQ_HANDLED;
}
static int __init irq_switch_init(void)
{
......
request_irq(switch_data->irq, gpio_irq_handler,
IRQF_TRIGGER_FALLING , pdev->name, switch_data); //中断函数申请
INIT_DELAYED_WORK(&test_work, schedule_work_function)
......
}
......
③第三种工作队列的创建方式:延时工作队列
#include <linux/workqueue.h>
static struct workqueue_struct *test_queue;
static struct delayed_work test_work;
static void schedule_work_function(struct work_struct *work)
{
printk("LPF:----into %s successful!!!!------------- \n",__func__);
}
static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
{
queue_delayed_work(test_queue,&test_work, 20); //延迟20个节拍
return IRQ_HANDLED;
}
static int __init irq_switch_init(void)
{
......
request_irq(switch_data->irq, gpio_irq_handler,
IRQF_TRIGGER_FALLING , pdev->name, switch_data); //中断函数申请
/*创建一个单线程的工作队列*/
test_queue=create_singlethread_workqueue("test_work");
INIT_DELAYED_WORK(&test_work,schedule_work_function);
......
}
......
3、应用层响应内核中断的异步通信机制
阻塞型和非阻塞型操作的组合以及select方法\poll可以有效地查询设备中断是否发生,但这种技术处理的效率不高;想实现应用层响应内核中断,可以采用异步通知机制,一旦内核中断响应,则主动通知应用程序,发送信号,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”的概念,比较准确的称谓是“信号驱动的异步I/O”。
内核实现
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/switch_to.h>
#include <asm/uaccess.h>
#define INTERRUPT_GPIO 42
struct test_interrupt {
struct class *class;
int major;
struct fasync_struct *fasync_queue; //异步通知队列
unsigned int irq_num;
struct device * dev;
};
struct test_interrupt *test;
int test_irq_open(struct inode *inode,struct file *filp){
printk("---------LPF-%s:test iterrupt device open!----------\n",__func__);
return 0;
}
int test_irq_release(struct inode *inode,struct file *filp){
printk("---------LPF-%s:test iterrupt device release!----------\n",__func__);
return 0;
}
/*fasync方法的实现*/
static int test_fasync(int fd, struct file * filp, int on)
{
int retval;
/*将对应设备登记到fasync_queue队列中去*/
retval=fasync_helper(fd,filp,on,&test->fasync_queue);
if(retval<0)
return retval;
return 0;
}
static const struct file_operations test_fops={
.owner=THIS_MODULE,
.open=test_irq_open,
.release=test_irq_release,
.fasync=test_fasync,
};
/* 在中断服务函数中向应用层发送消息-异步通知! */
irqreturn_t irq_callback(int irqno, void *dev_id)
{
printk("---------LPF-%s:driver irq work !!!------------\n",__func__);
if (test->fasync_queue) {
kill_fasync(&test->fasync_queue, SIGIO, POLL_IN); //中断触发时,向对应进程发送SIGIO信号
}
return IRQ_HANDLED;
}
static int __init test_init_module(void){
int rtn;
/*空间申请*/
test = kzalloc(sizeof(struct test_interrupt),GFP_KERNEL);
if(IS_ERR(test)){
printk("-------LPF-%s:kzalloc test failed!--------\n",__func__);
rtn = PTR_ERR(test);
return rtn;
}
/* 注册相应的设备驱动 */
test->major = register_chrdev(0,"test",&test_fops);
if(test->major < 0){
printk("-------LPF-%s:register_chrdev error test.major:%d-------\n",__func__,test->major);
rtn = -EINVAL;
goto err_kzalloc;
}
/* 创建设备的类 */
test->class = class_create(THIS_MODULE, "test_class");
if(IS_ERR(test->class)){
printk("-------LPF-%s:class_create---------\n",__func__);
rtn = PTR_ERR(test->class);
goto err_register;
}
/*创建设备节点*/
test->dev=device_create(test->class, NULL, MKDEV(test->major, 0), NULL,"test_device");
if(IS_ERR(test->dev)){
printk("---------LPF-%s:device_create failed!---------\n",__func__);
rtn = PTR_ERR(test->dev);
goto err_device_create;
}
/*gpio申请*/
rtn = gpio_request(SPI_INTERRUPT_GPIO, "irq_gpio");
if(rtn!=0){
printk("-------LPF-%s:my_irq irq pin request io failed--------\n",__func__);
goto err_gpio_request;
}
/*获取gpio中断号*/
test->irq_num = gpio_to_irq(SPI_INTERRUPT_GPIO);
/*GPIO中断服务函数注册,*/ /*上升沿触发*/
rtn = request_irq(test->irq_num, irq_callback,IRQF_TRIGGER_FALLING,"irq", NULL);
if (rtn<0) {
printk("--------LPF-%s:my_irq request irq false-------\n",__func__);
goto err_irq;
} else {
printk("--------LPF-%s:my_irq request irq success: %d---------\n",__func__,test->irq_num);
}
printk("-------LPF-%s:module_init sucessful!!!----------\n",__func__);
return 0;
//错误处理
err_irq:
gpio_free(INTERRUPT_GPIO);
err_gpio_request:
device_destroy(test->class,MKDEV(test->major, 0));
err_device_create:
class_destroy(test->class);
err_register:
unregister_chrdev(test->major,"test");
err_kzalloc:
kfree(test);
return rtn;
}
static void __exit test_release_module(void)
{
/* 卸载相应的设备驱动 */
gpio_free(INTERRUPT_GPIO);
device_destroy(test->class,MKDEV(test->major, 0));
class_destroy(test->class);
unregister_chrdev(test->major,"test");
kfree(test);
printk("-----LPF-%s:module_exit sucessful!!!-----------\n",__func__);
}
module_init(test_init_module);
module_exit(test_release_module);
MODULE_LICENSE("Dual BSD/GPL");
应用层实现
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <signal.h>
#define INTERRUPT_DEVICE "/dev/test_device"
void response_handler(int signo)
{
printf("------LPF:sigterm_handler----------\n");
}
int main(int argc, char *argv[])
{
int oflags;
int fd;
fd = open(INTERRUPT_DEVICE, O_RDWR);
if (fd < 0)
pabort("can't open device");
signal(SIGIO, response_handler); //将触发信号与触发函数绑定在一起
fcntl(fd, F_SETOWN, getpid()); //指定进程作为文件的“属主(owner)”
/*调用内核的test_fasync函数*/
oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, oflags | FASYNC);
while(1){
}
close(fd);
return ret;
}