当前位置: 首页 > news >正文

是做网站好还是做游戏好/网络黄页平台网址有哪些

是做网站好还是做游戏好,网络黄页平台网址有哪些,如何做html网站,安装wordpress提示建立数据库连接时出错本文主要参考韦东山老师视频及文档 Linux中断处理流程 中断系统中相关数据结构 ​ 每一个irq_desc数组项中都有一个函数:handle_irq,还有一个action链表。要理解它们,需要先看中断结构图: ​ 外部设备1、外部设备n共享一个GPI…

本文主要参考韦东山老师视频及文档

  1. Linux中断处理流程
    在这里插入图片描述

  2. 中断系统中相关数据结构
    在这里插入图片描述

    ​ 每一个irq_desc数组项中都有一个函数:handle_irq,还有一个action链表。要理解它们,需要先看中断结构图: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GEIBRiW6-1647057964616)(E:/Glen/Linux/Linux%E9%A9%B1%E5%8A%A8%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/Linux%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E4%B9%8B%E4%B8%AD%E6%96%AD%E7%BA%BF%E7%A8%8B%E5%8C%96%E5%A4%84%E7%90%86.assets/image-20220312100124272.png)]

    ​ 外部设备1、外部设备n共享一个GPIO中断B,多个GPIO中断汇聚到GIC(通用中断控制器)的A号中断,GIC再去中断CPU。那么软件处理时就是反过来,先读取GIC获得中断号A,再细分出GPIO中断B,最后判断是哪一个外部芯片发生了中断。

    ​ 所以,中断的处理函数来源有三:

    ① GIC的处理函数:

    ​ 假设irq_desc[A].handle_irqXXX_gpio_irq_handler,这个函数需要读取芯片的GPIO控制器,细分发生的是哪一个GPIO中断(假设是B),再去调用irq_desc[B]. handle_irq

    注意irq_desc[A].handle_irq细分出中断后B,调用对应的irq_desc[B].handle_irq

    显然中断A是CPU接收到的顶层中断,GIC中断CPU时,CPU读取GIC状态得到中断A。

    ② 模块的中断处理函数:

    ​ 比如对于GPIO模块向GIC发出的中断B,它的处理函数是irq_desc[B].handle_irq

    BSP开发人员会设置对应的处理函数,一般是handle_level_irqhandle_edge_irq,是用来处理电平触发的中断、边沿触发的中断。

    注意:导致GPIO中断B发生的原因很多,可能是外部设备1,可能是外部设备n,可能只是某一个设备,也可能是多个设备。所以irq_desc[B].handle_irq会调用某个链表里的函数,这些函数由外部设备提供。这些函数自行判断该中断是否自己产生,若是则处理。

    ③ 外部设备提供的处理函数:

    ​ 这里说的“外部设备”可能是芯片,也可能总是简单的按键。它们的处理函数由自己驱动程序提供,这是最熟悉这个设备的“人”:它知道如何判断设备是否发生了中断,如何处理中断。

    ​ 对于共享中断,比如GPIO中断B,它的中断来源可能有多个,每个中断源对应一个中断处理函数。所以irq_desc[B]中应该有一个链表,存放着多个中断源的处理函数。一旦程序确定发生了GPIO中断B,那么就会从链表里把那些函数取出来一一执行。这个链表就是action链表。

    • struct irq_desc结构体

      /*** struct irq_desc - interrupt descriptor* @irq_data:		per irq and chip data passed down to chip functions* @preflow_handler:	handler called before the flow handler (currently used by sparc)* @action:		the irq action chain* @name:		flow handler name for /proc/interrupts output*/
      struct irq_desc {struct irq_data		irq_data;irq_flow_handler_t	handle_irq;struct irqaction	*action;	/* IRQ action list */int			threads_handled_last;const char		*name;......
      };
      
    • struct irqaction结构体

      struct irqaction {irq_handler_t		handler;void			*dev_id;void __percpu		*percpu_dev_id;struct irqaction	*next;irq_handler_t		thread_fn;struct task_struct	*thread;unsigned int		irq;unsigned int		flags;unsigned long		thread_flags;unsigned long		thread_mask;const char		*name;struct proc_dir_entry	*dir;
      };
      

      ​ 当调用request_irqrequest_threaded_irq注册中断处理函数时,内核就会构造一个irqaction结构体。在里面保存namedev_id等,最重要的是handlerthread_fnthread

      handler是中断处理的上半部函数,用来处理紧急的事情。

      thread_fn对应一个内核线程thread,当handler执行完毕,Linux内核会唤醒对应的内核线程。在内核线程里,会调用thread_fn函数。

      ​ 可以提供handler而不提供thread_fn,就退化为一般的request_irq函数。

      ​ 可以不提供handler只提供thread_fn,完全由内核线程来处理中断。

      ​ 也可以既提供handler也提供thread_fn,这就是中断上半部、下半部。

      reqeust_irq时可以传入dev_id,其作用有以下两点:

      ① 中断处理函数执行时,可以使用dev_id

      ② 卸载中断时要传入dev_id,这样才能在action链表中根据dev_id找到对应项

      所以在共享中断中必须提供dev_id,非共享中断可以不提供。

    • struct irq_data结构体

      struct irq_data {u32			mask;unsigned int		irq;unsigned long		hwirq;unsigned int		node;unsigned int		state_use_accessors;struct irq_chip		*chip;struct irq_domain	*domain;
      #ifdef	CONFIG_IRQ_DOMAIN_HIERARCHYstruct irq_data		*parent_data;
      #endifvoid			*handler_data;void			*chip_data;struct msi_desc		*msi_desc;cpumask_var_t		affinity;
      };
      

      ​ 它就是个中转站,里面有irq_chip指针 irq_domain指针,都是指向别的结构体。

      irqhwirqirq是软件中断号,hwirq是硬件中断号。上面的例子,在GPIO中断B是软件中断号,可以找到irq_desc[B]这个数组项;GPIO里的第x号中断,这就是hwirq

      ​ 谁来建立irqhwirq之间的联系呢?由irq_domain来建立。irq_domain会把本地的hwirq映射为全局的irq,什么意思?比如GPIO控制器里有第1号中断,UART模块里也有第1号中断,这两个“第1号中断”是不一样的,它们属于不同的“域”──irq_domain。

    • struct irq_chip结构体

      struct irq_chip {void		(*irq_enable)(struct irq_data *data);void		(*irq_disable)(struct irq_data *data);void		(*irq_ack)(struct irq_data *data);void		(*irq_mask)(struct irq_data *data);void		(*irq_mask_ack)(struct irq_data *data);......
      };
      

      ​ 这个结构体跟“chip”即芯片相关,里面各成员的作用在头文件中也列得很清楚,摘录部分如下:

      * @irq_startup:	start up the interrupt (defaults to ->enable if NULL)
      * @irq_shutdown:	shut down the interrupt (defaults to ->disable if NULL)
      * @irq_enable:		enable the interrupt (defaults to chip->unmask if NULL)
      * @irq_disable:	disable the interrupt
      * @irq_ack:		start of a new interrupt
      * @irq_mask:		mask an interrupt source
      * @irq_mask_ack:	ack and mask an interrupt source
      * @irq_unmask:		unmask an interrupt source
      * @irq_eoi:		end of interrupt
      

      ​ 在request_irq后,并不需要手动去使能中断,原因就是系统调用对应的irq_chip里的函数已使能了中断。

      ​ 我们提供的中断处理函数中,也不需要执行主芯片相关的清中断操作,也是系统帮我们调用irq_chip中的相关函数。

      ​ 但是对于外部设备相关的清中断操作,还是需要我们自己做的。

      ​ 就像上面图里的“外部设备1“、“外部设备n”,外设备千变万化,内核里可没有对应的清除中断操作。

    • struct irq_domain结构体

      struct irq_domain {const struct irq_domain_ops *ops;irq_hw_number_t hwirq_max;unsigned int revmap_size;unsigned int linear_revmap[];
      };
      

      ​ 在驱动中会使用request_irq(irq, handler)这样的函数来注册中断,irq是什么?它是软件中断号,它可以从设备树中interrupt-parent = <&www>interrupts = <n xxx>转换得来。

      ​ 谁把hwirq转换为irq?由www的相关数据结构,就是www对应的irq_domain结构体。

      irq_domain结构体中有一个irq_domain_ops结构体,里面有各种操作函数,主要是:

      xlate 用来解析设备树的中断属性,提取出hwirqtype等信息。

      maphwirq转换为irq

    • struct irq_domain_ops结构体

      struct irq_domain_ops {int (*match)(struct irq_domain *d, struct device_node *node);int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);void (*unmap)(struct irq_domain *d, unsigned int virq);int (*xlate)(struct irq_domain *d, struct device_node *node,const u32 *intspec, unsigned int intsize,unsigned long *out_hwirq, unsigned int *out_type);......
      };
      
  3. 中断的线程化处理

    ​ 中断线程化主要是考虑到实时性的要求。如果实时任务不能抢占ISR,那么其执行的延迟(latency)时间将不确定,这不符合实时性的要求。如果内核在编译的时候配置了CONFIG_PREEMPT选项,那么将支持线程抢占,借此就可以实现中断线程化,线程化的中断处理部分被称为threaded interrupt handler在这里插入图片描述

    __do_softirq()执行次数/时间超过限制后触发ksoftirqd只是中断线程化的一种情况,更通用的是使用request_threaded_irq(),只要没有在flag参数中指定"IRQF_NO_THREAD",那么就将按中断线程化的方式处理。

    ​ 当使用ps命令查看的时候,格式为"irq/%d-%s"就是这些threaded interrupt handler,其中"d"为irq号,"s"为名称:

    /drv_module # ps -ef | grep "\[irq"46 0         0:00 [irq/40-edt-ft54]47 0         0:00 [irq/225-mmc0]48 0         0:00 [irq/50-2190000.]49 0         0:00 [irq/226-mmc1]59 0         0:00 [irq/205-imx_the]83 0         0:00 grep \[irq

    这些线程是在__setup_irq()中创建的:

    __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
    {.../** Create a handler thread when a thread function is supplied* and the interrupt does not nest into another interrupt* thread.*/if (new->thread_fn && !nested) {struct task_struct *t;static const struct sched_param param = {.sched_priority = MAX_USER_RT_PRIO/2,};t = kthread_create(irq_thread, new, "irq/%d-%s", irq,new->name);...sched_setscheduler_nocheck(t, SCHED_FIFO, &param);/** We keep the reference to the task struct even if* the thread dies to avoid that the interrupt code* references an already freed task_struct.*/get_task_struct(t);new->thread = t;/** Tell the thread to set its affinity. This is* important for shared interrupt handlers as we do* not invoke setup_affinity() for the secondary* handlers as everything is already set up. Even for* interrupts marked with IRQF_NO_BALANCE this is* correct as we want the thread to move to the cpu(s)* on which the requesting code placed the interrupt.*/set_bit(IRQTF_AFFINITY, &new->thread_flags);}...
    }
    

    ​ 线程的入口函数存放在new->thread_fn中,而这个thread_fn就是request_threaded_irq()相较于传统的request_irq()新增的那个参数。

    ​ 实际上,threaded irq,为每一个中断创建一个内核线程;多个中断的内核线程可以分配到多个CPU上执行,这提高了效率。

  4. 以按键进行编程实践

    5.1 按键设备驱动文件
    button_drv.c文件中,

    • 加载模块时,btn_hw_drv_probe函数中调用request_threaded_irq将按键工作中断上半部处理函数gpio_btn_isrbutton_threaded_isr_fun赋给struct irq_desc数组的action指针;

    • gpio_btn_isr按键中断服务程序(中断上半部)处理完毕,返回IRQ_WAKE_THREAD,用以后续调用button_threaded_isr_fun处理比较耗时的事情;

    • button_threaded_isr_fun为内核线程所调用,进一步执行。

/*** 文件    : button_drv.c* 作者    : glen  * 描述    : button driver文件*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/workqueue.h>#define KEY_BUF_LEN 16
#define NEXT_POS(x) ((x+1) % KEY_BUF_LEN)struct gbtn_irq {int gpio;struct gpio_desc *gpiod;int flag;int irq;int idx;char kval[KEY_BUF_LEN];int r, w;struct fasync_struct *fp;struct timer_list key_timer;struct tasklet_struct tasklet;struct work_struct wq;
};struct button_drv {struct class *class;struct gbtn_irq *gbtn_irq;char  *name;int count;int major;
};static struct button_drv *btn_drv;static int is_key_buf_empty(void *arg)
{struct gbtn_irq *p = (struct gbtn_irq *)arg;return (p->r == p->w);
}static int is_key_buf_full(void *arg)
{struct gbtn_irq *p = (struct gbtn_irq *)arg;return (p->r == NEXT_POS(p->w));
}static void put_key(char key, void *arg)
{struct gbtn_irq *p = (struct gbtn_irq *)arg;if (!is_key_buf_full(arg)) {p->kval[p->w] = key;p->w = NEXT_POS(p->w);}
}static char get_key(void *arg)
{char key = 'N';struct gbtn_irq *p = (struct gbtn_irq *)arg;if (!is_key_buf_full(arg)) {key = p->kval[p->r];p->r = NEXT_POS(p->r);}return key;
}/* 等待队列头的静态初始化 */
static DECLARE_WAIT_QUEUE_HEAD(gpio_button_wait);static void key_timer_expire(unsigned long data)
{int val;char key;struct gbtn_irq *ops = (struct gbtn_irq *)data;/* 读取按键的值 */val = gpiod_get_value(ops->gpiod);printk("button%d %d %d\n", ops->idx, ops->gpio, val);key = (ops->gpio << 4) | val;put_key(key, ops);/* 唤醒等待队列 */wake_up_interruptible(&gpio_button_wait);kill_fasync(&ops->fp, SIGIO, POLL_IN);/* enable btn*/enable_irq(ops->irq);
}/* 实现file_operations结构体成员 read 函数 */
ssize_t button_drv_read (struct file *filp, char __user *buf, size_t size, loff_t *pos)
{int minor = iminor(filp->f_inode);struct gbtn_irq *ops = (struct gbtn_irq *)filp->private_data;char kval;size = (size >= 1) ? 1 : 0;if (ops == NULL) {printk("Please register button instance %s %s, %d\n", __FILE__, __FUNCTION__, __LINE__);return -EIO;}if (is_key_buf_empty(ops) && (filp->f_flags & O_NONBLOCK))return -EAGAIN;wait_event_interruptible(gpio_button_wait, !is_key_buf_empty(ops));kval = get_key(ops);if (copy_to_user(buf, &kval, size))return -EFAULT;printk("Read button%d value successfully:", minor);return size;
}/* 实现file_operations结构体成员 open 函数 */
int button_drv_open(struct inode *nd, struct file *filp)
{int ret;int minor = iminor(nd);struct gbtn_irq *ops; if (btn_drv == NULL) {printk("Please register button instance %s %s, %d\n", __FILE__, __FUNCTION__, __LINE__);return -EIO;}ops = &btn_drv->gbtn_irq[minor];ret = gpiod_direction_input(ops->gpiod);if (ret) printk("Set the button pin as input error %s %s, %d\n", __FILE__, __FUNCTION__, __LINE__);else printk("Set the button%d pin as input successfully!\n", minor);filp->private_data = ops;return 0;
}/* 实现file_operations结构体成员 release 函数 */
int button_drv_release (struct inode *nd, struct file *filp)
{struct gbtn_irq *ops = (struct gbtn_irq *)filp->private_data;if (ops == NULL) {printk("Please register button instance %s %s, %d\n", __FILE__, __FUNCTION__, __LINE__);return -EIO;}filp->private_data = NULL;return 0;
}/* 实现file_operations结构体成员 poll 函数 */
unsigned int button_drv_poll (struct file *filp, struct poll_table_struct * wait)
{int minor = iminor(filp->f_inode);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);poll_wait(filp, &gpio_button_wait, wait);return (is_key_buf_empty(&btn_drv->gbtn_irq[minor]) ? 0 : POLLIN | POLLRDNORM);
}static int button_drv_fasync(int fd, struct file *filp, int on)
{struct gbtn_irq *ops = (struct gbtn_irq *)filp->private_data;if (fasync_helper(fd, filp, on, &ops->fp) >= 0)return 0;elsereturn -EIO;
}/*** 1. 构造file_operations结构体 */
static struct file_operations button_drv_ops = {.owner   = THIS_MODULE,.read    = button_drv_read,.open    = button_drv_open,.release = button_drv_release,.poll    = button_drv_poll,.fasync  = button_drv_fasync,
};/* 中断服务函数 */
static irqreturn_t gpio_btn_isr (int irq, void *dev_id)
{struct gbtn_irq *ops = dev_id;// printk("gpio_btn_isr key %d irq happened\n", ops->gpio);tasklet_schedule(&ops->tasklet);mod_timer(&ops->key_timer, jiffies + HZ / 50);schedule_work(&ops->wq);disable_irq_nosync(irq);return IRQ_WAKE_THREAD;
}/* tasklet action function */
static void button_tasklet_func (unsigned long data)
{int val;struct gbtn_irq *ops = (struct gbtn_irq *)data;/* 读取按键的值 */val = gpiod_get_value(ops->gpiod);printk("button_tasklet_func key%d %d %d\n", ops->idx, ops->gpio, val);}static void button_work_func (struct work_struct *work)
{int val;struct gbtn_irq *ops = container_of(work, struct gbtn_irq, wq);/* 读取按键的值 */val = gpiod_get_value(ops->gpiod);printk("button_work_func: the process is %s pid %d\n", current->comm, current->pid);printk("button_work_func key%d %d %d\n", ops->idx, ops->gpio, val);
}static irqreturn_t button_threaded_isr_fun (int irq, void *dev)
{int val;struct gbtn_irq *ops = dev;/* 读取按键的值 */val = gpiod_get_value(ops->gpiod);printk("button_threaded_isr_fun: the process is %s pid %d\n", current->comm, current->pid);printk("button_threaded_isr_fun key%d %d %d\n", ops->idx, ops->gpio, val);return IRQ_HANDLED;
}/* platform_driver结构体的 probe成员函数实现 */
int btn_hw_drv_probe (struct platform_device *pdev)
{int i;int ret;int count;// enum of_gpio_flags flag;struct device_node *node = pdev->dev.of_node;/* 从设备节点获取gpio数量 */count = of_gpio_count(node);if (!count) {printk("%s %s line %d, there isn't any gpio available!\n", __FILE__, __FUNCTION__, __LINE__);return -EIO;}btn_drv = kzalloc(sizeof(struct button_drv), GFP_KERNEL);if (btn_drv == NULL) return -ENOMEM;btn_drv->gbtn_irq = kzalloc(sizeof(struct gbtn_irq) * count, GFP_KERNEL);if (btn_drv->gbtn_irq == NULL)return -ENOMEM;for (i = 0; i < count; i++) {btn_drv->gbtn_irq[i].gpiod = gpiod_get_index_optional(&pdev->dev, NULL, i, GPIOD_ASIS);if (btn_drv->gbtn_irq[i].gpiod == NULL) {printk("%s %s line %d, gpiod_get_index_optional failed!\n", __FILE__, __FUNCTION__, __LINE__);return -EIO;}btn_drv->gbtn_irq[i].irq = gpiod_to_irq(btn_drv->gbtn_irq[i].gpiod);btn_drv->gbtn_irq[i].gpio = desc_to_gpio(btn_drv->gbtn_irq[i].gpiod);setup_timer(&btn_drv->gbtn_irq[i].key_timer, key_timer_expire, &btn_drv->gbtn_irq[i]);btn_drv->gbtn_irq[i].key_timer.expires = ~0;add_timer(&btn_drv->gbtn_irq[i].key_timer);tasklet_init(&btn_drv->gbtn_irq[i].tasklet, button_tasklet_func, &btn_drv->gbtn_irq[i]);INIT_WORK(&btn_drv->gbtn_irq[i].wq, button_work_func);btn_drv->gbtn_irq[i].idx = i;}for (i = 0; i < count; i++) /* 申请irq中断, 将中断服务程序注册到上半部 */// ret = request_irq(btn_drv->gbtn_irq[i].irq, gpio_btn_isr, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, //                  "gpio_btn", &btn_drv->gbtn_irq[i]);request_threaded_irq(btn_drv->gbtn_irq[i].irq, gpio_btn_isr, button_threaded_isr_fun, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "gpio_btn", &btn_drv->gbtn_irq[i]);/* 注册file_operationss结构体对象 -- button_drv_ops  */btn_drv->major = register_chrdev(btn_drv->major, "gbtn", &button_drv_ops);btn_drv->class = class_create(THIS_MODULE, "gbtn");if (IS_ERR(btn_drv->class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(btn_drv->major, "gbtn");return PTR_ERR(btn_drv->class);}for (i = 0; i < count; i++)device_create(btn_drv->class, NULL, MKDEV(btn_drv->major, i), NULL, "gbtn%d", i);btn_drv->count = count;return 0;
}/* platform_driver结构体的 remove成员函数实现 */
int btn_hw_drv_remove(struct platform_device *pdev)
{int i;struct device_node *node = pdev->dev.of_node;int count = of_gpio_count(node);for (i = 0; i < count; i++) {device_destroy(btn_drv->class, MKDEV(btn_drv->major, i));free_irq(btn_drv->gbtn_irq[i].irq, &btn_drv->gbtn_irq[i]);del_timer(&btn_drv->gbtn_irq[i].key_timer);tasklet_kill(&btn_drv->gbtn_irq[i].tasklet);}class_destroy(btn_drv->class);unregister_chrdev(btn_drv->major, "gbtn");kfree(btn_drv);return 0;
}/* 构造用于配置的设备属性 */
static const struct of_device_id gbtns_id[] = {{.compatible = "glen,gbtn"},{ },
};/* 构造(初始化)file_operations结构体 */
static struct platform_driver btn_hw_drv = {.driver = {.name = "gbtn",.of_match_table = gbtns_id,},.probe = btn_hw_drv_probe,.remove = btn_hw_drv_remove,
};/* 初始化 */
static int __init button_drv_init(void)
{int ret;ret = platform_driver_register(&btn_hw_drv);if (ret)pr_err("Unable to initialize button driver\n");elsepr_info("The button driver is registered.\n");return 0;
}
module_init(button_drv_init);static void __exit button_drv_exit(void)
{platform_driver_unregister(&btn_hw_drv);printk(" %s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
}
module_exit(button_drv_exit);/* insert author information for module */
MODULE_AUTHOR("glen");
/* insert license for module */
MODULE_LICENSE("GPL");

probe函数采用了先获取按键节点数量,然后分别读取gpio描述符并通过其获取为gpio和irq号,并申请注册中断服务程序。

3.2 设备树文件(不作更改)

 		pinctrl_btn0:btn0 {fsl,pins = <MX6UL_PAD_UART1_CTS_B__GPIO1_IO18	0xF080	/* KEY0 */ >;};pinctrl_btn1:btn1 {fsl,pins = <MX6UL_PAD_GPIO1_IO03__GPIO1_IO03    0xF080	/* KEY1  此按键不存在 */>;};/* 在根节点下添加基于pinctrl的gbtns设备节点 */gbtns {compatible = "glen,gbtn";#address-cells = <1>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_btn0 &pinctrl_btn1>;gpio-controller;#gpio-cells = <2>;gpios = <&gpio1 18 GPIO_ACTIVE_LOW /* button0 */&gpio1 3 GPIO_ACTIVE_LOW>;   /* button1 */};
  • 取消了gpios前缀“xxx-",相应地,在驱动程序用gpiod_get_index_optional函数获取gpio描述符时,第2个形参 ”const char *con_id“ 传递NULL即可;

  • 将pinctrl-0、gpios属性值由 “<>,<>;” 改为 “<>;",效果是一样的

3.3 应用程序

应用程序文件button_drv_test.c提供:

  • 定义sig_fun信号处理函数并注册信号,以后APP收到SIGIO信号时,这个函数会被自动调用;
  • fcntl(fd, F_SETOWN, getpid()); 把APP的PID(进程ID)告诉驱动程序,这个调用不涉及驱动程序,在内核的文件系统层次记录PID;
  • oflags = fcntl(fd, F_GETFL); 读取驱动程序文件oflags
  • fcntl(fd, F_SETFL, oflags | FASYNC); 设置oflags里面的FASYNC位为1:当FASYNC位发生变化时,会导致驱动程序的fasync被调用
 /** 文件名   :  button_drv_test.c* 作者     :  glen* 描述     :  button_drv应用程序*/#include "stdio.h"#include "sys/types.h"#include "sys/stat.h"#include "stdlib.h"#include "string.h"#include "poll.h"#include <signal.h>#include <unistd.h>#include <fcntl.h>int fd;static void sig_fun(int sig){char kval;read(fd, &kval, 1);printf("The glen button value is: %d!\n", kval);}/*** @brief   : main函数* @par     : argc  argv数组元素的个数*            argv  参数数组* @retval  : 0 成功    其它 失败*/int main(int argc, char *argv[]){int ret;int oflags;char *filename;if (argc != 2) {printf("Error Usage!\r\n");return -1;}signal(SIGIO, sig_fun);filename = argv[1];/* 打开驱动文件 */fd = open(filename, O_RDWR);if (fd < 0) {printf("Can't open file %s\r\n", filename);return -1;}fcntl(fd, F_SETOWN, getpid());oflags = fcntl(fd, F_GETFL);fcntl(fd, F_SETFL, oflags | FASYNC);while (1) {sleep(2);printf("Read the glen button in sleepping!\n");}/* 关闭文件 */ret = close(fd);if (ret < 0) {printf("file %s close failed!\r\n", argv[1]);return -1;}return 0;}

3.4 在alientek_linux_alpha开发板实测验证如下

/drv_module # insmod button_drv.ko
The button driver is registered.
/drv_module # ./btn_drv_test /dev/gbtn0
/drv_module # button_tasklet_func key0 18 1
button_threaded_isr_fun: the process is irq/49-gpio_btn pid 83
button_threaded_isr_fun key0 18 1
button_work_func: the process is kworker/0:2 pid 45
button_work_func key0 18 1
button0 18 1
button_tasklet_func key0 18 0
button_threaded_isr_fun: the process is irq/49-gpio_btn pid 83
button_threaded_isr_fun key0 18 0
button_work_func: the process is kworker/0:2 pid 45
button_work_func key0 18 0
button0 18 0
button_tasklet_func key0 18 1
button_threaded_isr_fun: the process is irq/49-gpio_btn pid 83
button_threaded_isr_fun key0 18 1
button_work_func: the process is kworker/0:2 pid 45
button_work_func key0 18 1
button0 18 1
button_tasklet_func key0 18 0
button_threaded_isr_fun: the process is irq/49-gpio_btn pid 83
button_threaded_isr_fun key0 18 0
button_work_func: the process is kworker/0:2 pid 45
button_work_func key0 18 0
button0 18 0
http://www.jmfq.cn/news/5267017.html

相关文章:

  • 用java可以做网站吗/重庆森林粤语完整版在线观看免费
  • 网站建设培训龙岗/百度网盘怎么找片
  • 网站设计流程是/小程序开发哪家好
  • 开个淘宝店做网站设计好吗/网站不收录怎么办
  • 17网站一起做网店 新塘/深圳百度seo怎么做
  • 营销网站开发渠道有哪些/深圳seo云哥
  • wordpress win10/百度seo原理
  • 网站管理助手数据库/app推广之家
  • 企业网站建设实验报告/百度搜索什么关键词排名
  • wordpress目录迁移/浙江关键词优化
  • 网站制作经费预算/发布软文平台
  • 上海工业网站建设/市场监督管理局上班时间
  • 新疆维吾尔建设厅网站官网/5000人朋友圈推广多少钱
  • 有网站源程序怎么做网站后台/seo赚钱吗
  • 岳阳公司做网站/bt蚂蚁磁力搜索天堂
  • 律师行业网站模板/seo工作流程
  • 网站建设外包工作/模板之家
  • 网站建设的测试/危机舆情公关公司
  • 做网站有没有免费空间/虎门今日头条新闻
  • 佛山网站建设首选/关键词的优化方案
  • 驻马店网站建设维护/网站推广的意义和方法
  • 专业建站/国家提供的免费网课平台
  • 同样也是做严选的网站/亚马逊关键词排名提升
  • 网站建设网站推广优化/百度快照优化培训班
  • 在线直播教学网站是怎么做的/app开发费用一般多少钱
  • 杭州城乡建设委网站/百度网页版登录入口官网
  • 企业邮箱后缀/seo关键词排名优化技巧
  • qt网站开发/营销培训内容有哪些
  • 给个手机网站就这么难吗/丹东seo推广优化报价
  • 怎么用2级目录做网站/seo网站优化怎么做