24.01.10 최초 작성
예제
threaded IRQ

등록 | 해제 | 인터럽트 핸들러 | bottom half |
---|
k_module_init() | k_module_exit() | k_top_half_gpio_irq_signal_handler() | k_bottom_half_gpio_irq_signal_handler() |
k_module_init()
: GPIO 16번에 신호가 들어오면 인터럽트 핸들러 실행되도록 설정
static int __init k_module_init(void)
{
...
button_irq = gpio_to_irq(16);
if (request_threaded_irq(button_irq, (void *)k_top_half_gpio_irq_signal_handler,
(void *)k_bottom_half_gpio_irq_signal_handler, IRQF_TRIGGER_RISING, "k_gpio_irq_signal", NULL) != 0) {
pr_err("Error!\n Can not request interrupt nr: %d\n", button_irq);
gpio_free(17);
return -1;
}
...
}
k_top_half_gpio_irq_signal_handler()
: 메시지를 출력하는 인터럽트 핸들러
static irq_handler_t k_top_half_gpio_irq_signal_handler(unsigned int irq, void *dev_id)
{
unsigned long diff = jiffies - pre_jiffie;
if (in_interrupt()) {
pr_info("k_top_half_gpio_irq_signal_handler: interrupt conext 입니다.!!!\n");
} else {
pr_info("k_top_half_gpio_irq_signal_handler: thread conext 입니다.!!!\n");
}
if (diff < msecs_to_jiffies(200)) {
return (irq_handler_t) IRQ_HANDLED;
}
pre_jiffie = jiffies;
return (irq_handler_t)IRQ_WAKE_THREAD;
}
k_bottom_half_gpio_irq_signal_handler()
: 메시지를 출력하고 LED를 조작하는 bottom half 핸들러
static irq_handler_t k_bottom_half_gpio_irq_signal_handler(unsigned int irq, void *dev_id)
{
if (in_interrupt()) {
pr_info("k_top_half_gpio_irq_signal_handler: interrupt conext 입니다.!!!\n");
} else {
pr_info("k_top_half_gpio_irq_signal_handler: thread conext 입니다.!!!\n");
}
pr_info("k_gpio_irq_signal_handler: interrupt triggered!!!\n");
led = (0x01 ^ led);
gpio_set_value(K_GPIO_OUTPUT, led);
pr_info("Interrupt(Threaded Handler) : K_GPIO_OUTPUT : %d ",gpio_get_value(K_GPIO_OUTPUT));
return (irq_handler_t) IRQ_HANDLED;
}
workqueue

등록 | 해제 | read | 인터럽트 핸들러 | bottom half |
---|
k_module_init() | k_module_exit() | k_driver_read() | k_top_half_gpio_irq_signal_handler() | workqueue_fn() |
k_module_init()
: 인터럽트 핸들러 등록 및 워크큐 생성
static int __init k_module_init(void)
{
...
button_irq = gpio_to_irq(16);
if (request_threaded_irq(button_irq, (void *)k_top_half_gpio_irq_signal_handler,
(void *)k_bottom_half_gpio_irq_signal_handler, IRQF_TRIGGER_RISING, "k_gpio_irq_signal", NULL) != 0) {
pr_err("Error!\n Can not request interrupt nr: %d\n", button_irq);
gpio_free(17);
return -1;
}
k_workqueue = create_workqueue("k_wq");
...
}
workqueue_fn()
: k_top_half_gpio_irq_signal_handler()
의 bottom half로 워크큐에 GPIO 입력을 저장
static DECLARE_WORK(work, workqueue_fn);
struct k_list {
struct list_head list;
int data;
};
static DEFINE_RWLOCK(k_rwlock);
LIST_HEAD(k_list_head);
volatile int k_value = 0;
static void workqueue_fn(struct work_struct *work)
{
struct k_list *new_node = NULL;
if (in_interrupt()) {
pr_info("workqueue_fn: interrupt conext 입니다.!!!\n");
} else {
pr_info("workqueue_fn: thread conext 입니다.!!!\n");
}
new_node = kmalloc(sizeof(struct k_list), GFP_KERNEL);
new_node->data = k_value++;
INIT_LIST_HEAD(&new_node->list);
write_lock(&k_rwlock);
list_add_tail(&new_node->list, &k_list_head);
write_unlock(&k_rwlock);
}
k_top_half_gpio_irq_signal_handler()
: 인터럽트 핸들러
static irq_handler_t k_top_half_gpio_irq_signal_handler(unsigned int irq, void *dev_id)
{
unsigned long diff = jiffies - pre_jiffie;
if (in_interrupt()) {
pr_info("k_top_half_gpio_irq_signal_handler: interrupt conext 입니다.!!!\n");
} else {
pr_info("k_top_half_gpio_irq_signal_handler: thread conext 입니다.!!!\n");
}
if (diff < msecs_to_jiffies(200)) {
return (irq_handler_t) IRQ_HANDLED;
}
pre_jiffie = jiffies;
queue_work(k_workqueue, &work);
return (irq_handler_t)IRQ_WAKE_THREAD;
}
k_driver_read()
: 워크큐에 저장된 모든 내용을 출력하고 워크큐에서 삭제
static ssize_t k_driver_read(struct file *filp, char __user *buf, size_t count, loff_t *offset)
{
struct k_list *temp;
int list_count = 0;
read_lock(&k_rwlock);
list_for_each_entry(temp, &k_list_head, list) {
pr_info("list_count : %d, data : %d\n", list_count++, temp->data);
}
read_unlock(&k_rwlock);
pr_info("Node count: %d\n", list_count);
return BUF_SIZE;
}
static void __exit k_module_exit(void)
{
...
destroy_workqueue(k_workqueue);
...
}