linux内核中常用的功能实例

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;
}

猜你喜欢

转载自blog.csdn.net/QQ135102692/article/details/114707063