1
0
Files
MSE-CSEL/solutions/03_drivers/exercice07/drv/skeleton.c

127 lines
3.5 KiB
C

/* skeleton.c */
#include <linux/init.h> /* needed for macros */
#include <linux/kernel.h> /* needed for debugging */
#include <linux/module.h> /* needed by all modules */
#include <linux/cdev.h> /* needed for char device driver */
#include <linux/fs.h> /* needed for device drivers */
#include <linux/uaccess.h> /* needed to copy data to/from user */
#include <linux/poll.h> /* needed for polling handling */
#include <linux/sched.h> /* needed for scheduling constants */
#include <linux/wait.h> /* needed for wating */
#include <linux/gpio.h> /* needed for i/o handling */
#include <linux/interrupt.h> /* needed for interrupt handling */
#include <linux/io.h> /* needed for mmio handling */
#include <linux/ioport.h> /* needed for memory region handling */
#include <linux/miscdevice.h>
#define K1 0
#define K2 2
#define K3 3
static char* k1 = "gpio_a.0-k1";
static char* k2 = "gpio_a.2-k2";
static char* k3 = "gpio_a.3-k3";
static atomic_t nb_of_interrupts;
DECLARE_WAIT_QUEUE_HEAD(queue);
irqreturn_t gpio_isr(int irq, void* handle)
{
atomic_inc(&nb_of_interrupts);
wake_up_interruptible(&queue);
pr_info("interrupt %s raised...\n", (char*)handle);
return IRQ_HANDLED;
}
static ssize_t skeleton_read(struct file* f,
char __user* buf,
size_t sz,
loff_t* off)
{
return 0;
}
static unsigned int skeleton_poll(struct file* f, poll_table* wait)
{
unsigned mask = 0;
poll_wait(f, &queue, wait);
if (atomic_read(&nb_of_interrupts) != 0) {
mask |= POLLIN | POLLRDNORM; /* read operation */
/* mask |= POLLOUT | POLLWRNORM; write operation */
atomic_dec(&nb_of_interrupts);
pr_info("polling thread waked-up...\n");
}
return mask;
}
static struct file_operations skeleton_fops = {
.owner = THIS_MODULE,
.read = skeleton_read,
.poll = skeleton_poll,
};
struct miscdevice misc_device = {
.minor = MISC_DYNAMIC_MINOR,
.fops = &skeleton_fops,
.name = "mymodule",
.mode = 0777,
};
static int __init skeleton_init(void)
{
int status = 0;
atomic_set(&nb_of_interrupts, 0);
status = misc_register(&misc_device);
// install k1
if (status == 0)
status = devm_request_irq(misc_device.this_device,
gpio_to_irq(K1),
gpio_isr,
IRQF_TRIGGER_FALLING | IRQF_SHARED,
k1,
k1);
// install k2
if (status == 0)
status = devm_request_irq(misc_device.this_device,
gpio_to_irq(K2),
gpio_isr,
IRQF_TRIGGER_RISING | IRQF_SHARED,
k2,
k2);
// install k3
if (status == 0)
status = devm_request_irq(
misc_device.this_device,
gpio_to_irq(K3),
gpio_isr,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_SHARED,
k3,
k3);
pr_info("Linux module skeleton loaded(status=%d)\n", status);
return status;
}
static void __exit skeleton_exit(void)
{
misc_deregister(&misc_device);
pr_info("Linux module skeleton unloaded\n");
}
module_init(skeleton_init);
module_exit(skeleton_exit);
MODULE_AUTHOR("Daniel Gachet <daniel.gachet@hefr.ch>");
MODULE_DESCRIPTION("Module skeleton");
MODULE_LICENSE("GPL");