#include <linux/module.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.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/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <asm/current.h>
/* 主设备号 */
static int major = 0;
static struct class *gpio_button_class;
static struct gpio_desc *button_handle;
static int gpio_num;
static int button_irq;
static int g_button_value = 0;
static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);
struct fasync_struct *button_fasync;
/* 实现对应的open/read/write等函数,填入file_operations结构体 */
static ssize_t gpio_button_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
int err;
wait_event_interruptible(gpio_key_wait, g_button_value);
err = copy_to_user(buf, &g_button_value, 4);
g_button_value = 0;
return 4;
}
static unsigned int gpio_button_drv_poll(struct file *fp, poll_table * wait)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
poll_wait(fp, &gpio_key_wait, wait);
if(g_button_value)
return POLLIN | POLLRDNORM;
else
return 0;
}
static int gpio_button_drv_fasync(int fd, struct file *file, int on)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
if (fasync_helper(fd, file, on, &button_fasync) >= 0)
return 0;
else
return -EIO;
}
/* 定义自己的file_operations结构体 */
static struct file_operations gpio_button_drv = {
.owner = THIS_MODULE,
.read = gpio_button_drv_read,
.poll = gpio_button_drv_poll,
.fasync = gpio_button_drv_fasync,
};
static irqreturn_t gpio_button_isr(int irq, void *dev_id)
{
int val;
val = gpiod_get_value(button_handle);
printk("key value %d\n", val);
if(val)
{
g_button_value = val;
wake_up_interruptible(&gpio_key_wait);
kill_fasync(&button_fasync, SIGIO, POLL_IN);
}
return IRQ_HANDLED;
}
/* 1. 从platform_device获得GPIO
* 2. gpio=>irq
* 3. request_irq
*/
static int gpio_button_probe(struct platform_device *pdev)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
button_handle = gpiod_get(&pdev->dev, NULL, 0);
gpiod_direction_input(button_handle);
#if 0
struct device_node *node = pdev->dev.of_node;
enum of_gpio_flags flag;
gpio_num = of_get_gpio_flags(node, 0, &flag);
button_irq = gpio_to_irq(gpio_num);
#else
button_irq = gpiod_to_irq(button_handle);
#endif
request_irq(button_irq, gpio_button_isr, IRQF_TRIGGER_RISING, "pgg_button_irq", NULL);//IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
/* 注册file_operations */
major = register_chrdev(0, "pgg_button", &gpio_button_drv); /* /dev/gpio_key */
gpio_button_class = class_create(THIS_MODULE, "gpio_button_class");
if (IS_ERR(gpio_button_class))
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "pgg_button");
return PTR_ERR(gpio_button_class);
}
device_create(gpio_button_class, NULL, MKDEV(major, 0), NULL, "pgg_button"); /* /dev/100ask_gpio_key */
return 0;
}
static int gpio_button_remove(struct platform_device *pdev)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
device_destroy(gpio_button_class, MKDEV(major, 0));
class_destroy(gpio_button_class);
unregister_chrdev(major, "pgg_button");
gpiod_put(button_handle);
free_irq(button_irq,NULL);
return 0;
}
static const struct of_device_id pgg_button[] = {
{ .compatible = "pgg,button" },
{ },
};
/* 1. 定义platform_driver */
static struct platform_driver gpio_button_driver = {
.probe = gpio_button_probe,
.remove = gpio_button_remove,
.driver = {
.name = "pgg_gpio_button",
.of_match_table = pgg_button,
},
};
/* 2. 在入口函数注册platform_driver */
static int __init gpio_button_init(void)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = platform_driver_register(&gpio_button_driver);
return err;
}
/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
* 卸载platform_driver
*/
static void __exit gpio_button_exit(void)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
platform_driver_unregister(&gpio_button_driver);
}
/* 7. 其他完善:提供设备信息,自动创建设备节点 */
module_init(gpio_button_init);
module_exit(gpio_button_exit);
MODULE_LICENSE("GPL");
评论0