驅動之路三--------button驅動(input裝置)
阿新 • • 發佈:2019-02-09
開發板:smdk6410
系統:Linux
按鍵是經常要用的,通過按鍵產生中斷,可以處理不同的功能,鍵盤的輸入就是這麼一個原理,
鍵盤也可以作為一個字元裝置去寫,在 驅動之路二 中就詳細闡述過裝置分類的概念,也將LED驅動寫成了misc裝置的,在這要將button驅動基於input裝置去寫,現在開始寫了,
先是標頭檔案 s3c_button.h
#ifndef __BUTTON_H #define __BUTTON_H #include <linux/device.h> #include <linux/interrupt.h> #include <linux/input.h> struct button_info { char name[32]; int user; int status; void __iomem *v; struct input_dev *dev;//input裝置結構體 int irq;//中斷線 int code; irqreturn_t (*do_button)(int no, void *data);。。中斷處理函式 }; #define S3C_PA_BUTTON 0x7f008000 #define S3C_SZ_BUTTON SZ_4K #define GPNDAT 0x834 #define S3C_IRQ_BUTTON_S IRQ_EINT(0) #define S3C_IRQ_BUTTON_E IRQ_EINT(5) #define S3C_NUM_BUTTON 6 #endif
標頭檔案還是就一個button_info結構體,用於描述button這個裝置,再就是相關巨集定義,
裝置檔案的修改和之前的之前寫的LED驅動相比,改動不大,
#include <linux/init.h> #include <linux/module.h> #include <linux/device.h> #include <linux/platform_device.h> #include "s3c_button.h" void b_release(struct device *dev) { printk("Device is released\n"); } //寫button就需要兩種資源了,這個需要注意 struct resource b_res[] = { [0] = { .start = S3C_PA_BUTTON, .end = S3C_PA_BUTTON + S3C_SZ_BUTTON - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = S3C_IRQ_BUTTON_S, .end = S3C_IRQ_BUTTON_E, .flags = IORESOURCE_IRQ, } }; struct platform_device dev = { .name = "s3c-button", .id = -1, .num_resources = ARRAY_SIZE(b_res), .resource = b_res, .dev = { .release = b_release, } }; static __init int module_test_init(void) { return platform_device_register(&dev); } static __exit void module_test_exit(void) { platform_device_unregister(&dev); } module_init(module_test_init); module_exit(module_test_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Musesea"); MODULE_VERSION("1.0"); MODULE_DESCRIPTION("Test for module");
裝置檔案沒什麼好說的。
下面是驅動檔案
#include <linux/init.h> #include <linux/module.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/device.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/input.h> #include "s3c_button.h" int if_down(struct button_info *b) { //GPNDAT[5-0] return !(readl(b->v + GPNDAT) & (1 << (b->irq - S3C_IRQ_BUTTON_S))); } irqreturn_t button_handle(int no, void *data) { struct button_info *b = data; if(if_down(b)){ input_report_key(b->dev, b->code, 1);//上報事件,注意核心需要支援上報 input_sync(b->dev);//不同步是什麼事件都不能上報的 }else{ input_report_key(b->dev, b->code, 0); input_sync(b->dev); } return IRQ_HANDLED; } void s3c_button_exit(struct button_info *b) { } void s3c_button_init(struct button_info *b, int start) { int i; for(i = 0; i < S3C_NUM_BUTTON; i++){ sprintf(b[i].name, "button%d", i); b[i].user = 0; b[i].irq = start + i; b[i].dev = b[0].dev; b[i].v = b[0].v; b[i].do_button = button_handle; } //鍵碼,就是每個鍵代表的意思 b[0].code = KEY_UP; b[1].code = KEY_DOWN; b[2].code = KEY_LEFT; b[3].code = KEY_RIGHT; b[4].code = KEY_ESC; b[5].code = KEY_ENTER; } int b_probe(struct platform_device *pdev) { int ret; int i; struct resource *g_res, *irq_res; struct button_info *button; g_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//獲取資源 irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if(!g_res || !irq_res) return -EBUSY; button = kzalloc(sizeof(struct button_info) * S3C_NUM_BUTTON, GFP_KERNEL); if(!button) return -ENOMEM; button->v = ioremap(g_res->start, g_res->end - g_res->start + 1); if(!button->v){ ret = -ENOMEM; goto remap_error; } button->dev = input_allocate_device();//分配input裝置 if(!button->dev){ ret = -ENOMEM; goto alloc_dev_error; } button->dev->name = pdev->name; button->dev->uniq = "20131113"; button->dev->phys = "/dev/eventx"; button->dev->id.bustype = BUS_HOST; button->dev->id.vendor = 110; button->dev->id.product = 120; button->dev->id.version = 119; //evbit[0] |= 1 << EV_KEY; //設定該裝置要支援的事件型別 set_bit(EV_KEY, button->dev->evbit); set_bit(EV_SYN, button->dev->evbit); //設定該裝置要支援的key事件 set_bit(KEY_UP, button->dev->keybit); set_bit(KEY_DOWN, button->dev->keybit); set_bit(KEY_LEFT, button->dev->keybit); set_bit(KEY_RIGHT, button->dev->keybit); set_bit(KEY_ESC, button->dev->keybit); set_bit(KEY_ENTER, button->dev->keybit); ret = input_register_device(button->dev);//註冊input裝置 if(ret) goto register_error; platform_set_drvdata(pdev, button);//將button儲存到pdev中 s3c_button_init(button, irq_res->start); for(i = 0; i < S3C_NUM_BUTTON; i++) //申請中斷 ret = request_irq(button[i].irq, button[i].do_button, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, button[i].name, &button[i]); if(ret) goto request_irq_error; return 0; request_irq_error: while(i--) free_irq(button[i].irq, &button[i]); register_error: input_free_device(button->dev); alloc_dev_error: iounmap(button->v); remap_error: kfree(button); return ret; } int b_remove(struct platform_device *pdev) { int i = 6; struct button_info *button; button = platform_get_drvdata(pdev); while(i--) free_irq(button[i].irq, &button[i]); s3c_button_exit(button); input_unregister_device(button->dev); input_free_device(button->dev); iounmap(button->v); kfree(button); return 0; } struct platform_driver drv = { .driver = { .name = "s3c-button", }, .probe = b_probe, .remove = b_remove, }; static __init int module_test_init(void) { return platform_driver_register(&drv); } static __exit void module_test_exit(void) { platform_driver_unregister(&drv); } module_init(module_test_init); module_exit(module_test_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Musesea"); MODULE_VERSION("1.0"); MODULE_DESCRIPTION("Test for module");
OK了!又一個驅動算是完了。
還是那句話,大家若是發現什麼問題一定要告訴我,大家一起學習