按鍵驅動:platform架構
這篇文章接著上篇文章介紹按鍵驅動的第二種實現方法,就是應用驅動和裝置分離的思想。
話不多說,直接上程式:
整個程式的結構如下:
.
├── dev
│ ├── key_dev.c
│ └── Makefile
├── dri
│ ├── key_dri.c
│ └── Makefile
└── test
└── test.c
key_dev.c
#include <linux/module.h> #include <linux/kernel.h> #include <linux/platform_device.h> #include <mach/regs-gpio.h> #include <mach/hardware.h> #include <linux/irq.h> struct jz2440_key_t { const char *name; unsigned int pin; unsigned char key_val; unsigned int irq; /*按鍵的中斷號 */ unsigned int setting; /* 按鍵對應的功能的掩碼 */ unsigned int id; }; struct jz2440_key_platform { struct jz2440_key_t *buttonp; int button_num; }; /* * key s2 is GPF0 -- EINT0 * key s3 is GPF2 -- EINT2 * key s4 is GPG3 -- EINT11 * key s5 is GPG11-- EINT19 */ struct jz2440_key_t key_table[] = { {"Button S2", S3C2410_GPF(0), 0, IRQ_EINT(0), S3C2410_GPF0_EINT0, 0}, {"Button S3", S3C2410_GPF(2), 0, IRQ_EINT(2), S3C2410_GPF2_EINT2, 1}, {"Button S4", S3C2410_GPG(3), 0, IRQ_EINT(11), S3C2410_GPG3_EINT11, 2}, {"Button S5", S3C2410_GPG(11), 0, IRQ_EINT(19), S3C2410_GPG11_EINT19, 3}, }; struct jz2440_key_platform jz2440_key = { .buttonp = key_table, .button_num = ARRAY_SIZE(key_table), }; static void device_release(struct device *dev) { printk("platform: device release\n"); }; struct platform_device jz2440_key_dev = { .id = -1, .name = "jz2440_button", /* 用於匹配的名字 */ .dev = { .release = device_release, .platform_data = &jz2440_key, /* 是 void * 型別 */ } }; static int __init jz2440_button_dev_init(void) { printk("dev init\n"); platform_device_register(&jz2440_key_dev); return 0; } static void __exit jz2440_button_dev_exit(void) { printk("dev exit\n"); platform_device_unregister(&jz2440_key_dev); } module_init(jz2440_button_dev_init); module_exit(jz2440_button_dev_exit); MODULE_LICENSE("Dual BSD/GPL");
說明:
【1】要想將自己定義的結構體陣列傳遞給別的模組,需要首地址和陣列的元素個數,所以又定義了一個 jz2440_key 的結構體
Makefile
ifeq ($(KERNELRELEASE),) #KERNELDIR ?= /lib/modules/$(shell uname -r)/build KERNELDIR ?= ~/wor_lip/linux-3.4.112 PWD := $(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules* Module* .PHONY: modules modules_install clean else obj-m := key_dev.o endif
key_dri.c
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/irq.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <linux/poll.h> #include <linux/interrupt.h> #include <mach/regs-gpio.h> #include <mach/hardware.h> #include <linux/wait.h> #include <linux/device.h> #include <mach/gpio.h> #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/timer.h> #include <linux/platform_device.h> #define DEVICE_NAME "jz2440_button_drv" static unsigned char key_vals[4]; /* 儲存要傳遞給使用者空間的4個按鍵值 */ static struct timer_list key_timers[4]; #define KEYDOWN_DELAY (HZ/100) /* 按鍵按下時的去抖延時是10ms */ #define KEYUP_DELAY (HZ/200) /* 按鍵擡起時的去抖延時是5ms */ struct jz2440_key_t { const char *name; unsigned int pin; unsigned char key_val; unsigned int irq; /*按鍵的中斷號 */ unsigned int setting; /* 按鍵對應的功能的掩碼 */ unsigned int id; }; struct jz2440_key_platform { struct jz2440_key_t *buttonp; int button_num; }; struct jz2440_key_t *key_tablep; struct jz2440_key_platform *key_platformp; static struct class *button_drv_class; int major; unsigned int key_pressed; unsigned int key_pressed_middle_flag; static DECLARE_WAIT_QUEUE_HEAD(button_waitq); int jz2440_key_dri_probe(struct platform_device *dev) { key_platformp = (struct jz2440_key_platform *)dev->dev.platform_data; key_tablep = key_platformp->buttonp; printk("platform: match ok!\n"); return 0; } int jz2440_key_dri_remove(struct platform_device *dev) { printk("platform: driver remove\n"); return 0; } struct platform_driver jz2440_key_dri = { .probe = jz2440_key_dri_probe, .remove = jz2440_key_dri_remove, .driver = { .name = "jz2440_button" }, }; irqreturn_t irq_handler(int irq, void *dev_id) { int key_num = *((int *)dev_id); unsigned int pinval = s3c2410_gpio_getpin(key_tablep[key_num].pin); if (!pinval) { key_pressed_middle_flag = 1; mod_timer(&key_timers[key_num], jiffies + KEYDOWN_DELAY); }else { key_pressed_middle_flag = 0; mod_timer(&key_timers[key_num], jiffies + KEYUP_DELAY); } return IRQ_RETVAL(IRQ_HANDLED); } void fun_timer(unsigned long arg) { int pinval = s3c2410_gpio_getpin(key_tablep[arg].pin); if (!pinval) { if (key_pressed_middle_flag == 1) { /*printk("pree down\n");*/ key_pressed = 1; key_tablep[arg].key_val = 1; wake_up_interruptible(&button_waitq); /* 喚醒如果讀而引起的阻塞 */ } }else { if (key_pressed_middle_flag == 0) { /*printk("pree up\n");*/ key_pressed = 0; key_tablep[arg].key_val = 0; } } } static int jz2440_button_drv_open(struct inode *inode, struct file *filp) { int i; for (i = 0; i < key_platformp->button_num; i++) { s3c2410_gpio_cfgpin(key_tablep[i].pin, key_tablep[i].setting); /* 將晶片引腳設定成中斷 */ irq_set_irq_type(key_tablep[i].irq, IRQ_TYPE_EDGE_BOTH); /* 下降沿觸發 */ request_irq(key_tablep[i].irq, irq_handler, IRQF_DISABLED, key_tablep[i].name, &key_tablep[i].id); /* 向系統核心申請快速中斷 */ setup_timer(&key_timers[i], fun_timer, i); } printk("button_drv_open\n"); return 0; } static int jz2440_button_drv_close(struct inode *inode, struct file *filp) { int i; for (i = 0; i < key_platformp->button_num; i++) { del_timer(&key_timers[i]); disable_irq(key_tablep[i].irq); free_irq(key_tablep[i].irq, &key_tablep[i].id); } return 0; } /* 讀的時候按鍵的數量必須是 4 ,返回成功讀取的個數 */ ssize_t jz2440_button_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { int j; unsigned long ret; if (size != sizeof(key_vals)) return -EINVAL; /* 如果是非阻塞的讀 */ if (file->f_flags & O_NONBLOCK) { if (!key_pressed) /* 非阻塞的讀,按鍵沒有按下過 */ return -EAGAIN; } else if (!key_pressed) /* 阻塞的讀,按鍵沒有按下過 */ { wait_event_interruptible(button_waitq, key_pressed); } key_pressed = 0; for (j = 0; j < key_platformp->button_num; j++) { key_vals[j] = key_tablep[j].key_val; } ret = copy_to_user(buf, key_vals, size); /* 返回key_vals陣列資料到使用者空間 */ return ret ? -EFAULT : min(sizeof(key_vals), size); } unsigned int jz2440_button_drv_poll (struct file *filp, struct poll_table_struct *wait) { unsigned int mask = 0; poll_wait(filp, &button_waitq, wait);/* 加讀等待佇列頭 */ if (key_pressed) mask |= POLLIN | POLLRDNORM; /* 標示資料可獲得 */ return mask; } static struct file_operations button_drv_fops = { .owner = THIS_MODULE, .open = jz2440_button_drv_open, .release = jz2440_button_drv_close, .read = jz2440_button_drv_read, .poll = jz2440_button_drv_poll, }; int button_drv_init(void) { platform_driver_register(&jz2440_key_dri); /* auto choice major */ major = register_chrdev(0, DEVICE_NAME, &button_drv_fops); if (major < 0) { printk("jz2440 button driver can't register major number!\n"); return major; } button_drv_class = class_create(THIS_MODULE, DEVICE_NAME); if (IS_ERR(button_drv_class)) { printk("error, fail to init button_drv_class"); return -1; } device_create(button_drv_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); printk("BUTTON_DRV initialized! \n"); return 0; } void button_drv_exit(void) { platform_driver_unregister(&jz2440_key_dri); device_destroy(button_drv_class, MKDEV(major, 0)); //刪掉裝置節點 class_destroy(button_drv_class); //登出類 unregister_chrdev(major, DEVICE_NAME); //解除安裝驅動 printk("exit is finished.\n"); } module_init(button_drv_init); module_exit(button_drv_exit); MODULE_LICENSE("GPL");
說明:
【1】在 probe 函式中想要用到匹配好的裝置檔案中的元素,直接使用 platform_device 的指標
【2】在除錯過程中在申請了中斷後,可以用 cat /proc/interrupt 檢視申請的中斷,顯示如下
CPU0
16: 2 s3c-ext0 Button S2
18: 2 s3c-ext0 Button S3
24: 0 s3c s3c2410-rtc tick
30: 24994 s3c S3C2410 Timer Tick
32: 0 s3c s3c2410-lcd
37: 0 s3c s3c-mci
42: 0 s3c ohci_hcd:usb1
43: 8 s3c s3c2440-i2c
46: 0 s3c s3c2410-rtc alarm
51: 2805 s3c-ext eth0
55: 2 s3c-ext Button S4
60: 1 s3c-ext s3c-mci
63: 2 s3c-ext Button S5
第一列是中斷號,第二列是中斷髮生的次數,第三列是,第四列是中斷的名字
【3】這裡有個現象,也不知道是不是問題,當 free_irq 之後,發現中斷並沒有在列表中消失,只是名字消失了。
【4】這個函式的 init 和 exit 中對字元裝置的註冊和釋放以及裝置節點的建立還是有點麻煩,可以檢視 混雜裝置驅動 進行 混雜裝置驅動改寫,可以減少不少程式碼。
Makefile 中改一下目標檔案即可
test.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/select.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
int fd;
fd_set rds;
void stop(int signo)
{
close(fd);
FD_CLR(fd, &rds);
_exit(0);
}
int main(int argc, const char *argv[])
{
unsigned char data_buf[4];
signal(SIGINT, stop); /* 按下ctrl+c,呼叫stop函式 */
/* 阻塞的讀 */
if ((fd = open("/dev/jz2440_button_drv", O_RDONLY)) < 0)
{
perror("fail to open");
return -1;
}
while (1)
{
int ret, i;
FD_ZERO(&rds);
FD_SET(fd, &rds); /* 將fd檔案描述符新增到rds這個檔案描述符集中去 */
ret = select(fd + 1, &rds, NULL, NULL, NULL);
printf("doing\n");
if (ret < 0)
{
printf("read jz2440 button fail!\n");
continue;
}else if (ret == 0)
{
printf("read jz2440 button time out!\n");
continue;
}
if (FD_ISSET(fd, &rds))
{
ret = read(fd, data_buf, sizeof(data_buf));
if (ret < 4)
{
printf("read not complete.\n");
break;
}
for (i = 0 ; i < 4; i++)
{
printf("S%d:%d ", 2 + i, data_buf[i]);
}
printf("\n");
}
}
return 0;
}
這個檔案的編譯命令:
arm-none-linux-gnueabi-gcc test.c -o button -march=armv4t
實驗結果:
[[email protected] ~]# insmod key_dev.ko
dev init
[[email protected] ~]# insmod key_dri.ko
platform: match ok!
BUTTON_DRV initialized!
[[email protected] ~]# ./button
button_drv_open
doing
S2:1 S3:0 S4:0 S5:0
doing
S2:0 S3:1 S4:0 S5:0
doing
S2:0 S3:0 S4:1 S5:0
doing
S2:0 S3:0 S4:0 S5:1
相關推薦
按鍵驅動:platform架構
這篇文章接著上篇文章介紹按鍵驅動的第二種實現方法,就是應用驅動和裝置分離的思想。 話不多說,直接上程式: 整個程式的結構如下: . ├── dev │ ├── key_dev.c │ └── Makefile ├── dri │ ├── key_dri.c │
Linux ALSA音效卡驅動之八:ASoC架構中的Platform
1. Platform驅動在ASoC中的作用 前面幾章內容已經說過,ASoC被分為Machine,Platform和Codec三大部件,Platform驅動的主要作用是完成音訊資料的管理,最終通過CPU的數字音訊介面(DAI)把音訊資料傳送給Codec進行處理,最終由Co
Linux驅動開發10:【裝置樹】nanopi的按鍵驅動
介紹 這一節在nanopi上實現按鍵驅動,和LED驅動一樣,通用的按鍵驅動在linux核心中已經實現好,我們只需要按照要求寫好裝置樹即可,不用我們自己實現按鍵驅動。這一節中首先修改裝置樹並測試按鍵驅動,然後分析drivers/input/keyboard/gpio_keys.c檔案,
Linux ALSA音效卡驅動之六:ASoC架構中的Machine
前面一節的內容我們提到,ASoC被分為Machine、Platform和Codec三大部分,其中的Machine驅動負責Platform和Codec之間的耦合以及部分和裝置或板子特定的程式碼,再次引用上一節的內容:Machine驅動負責處理機器特有的一些控制元件和音訊
Linux ALSA 音效卡驅動之一:ALSA架構簡介
一. 概述 ALSA是Advanced Linux Sound Architecture 的縮寫,目前已經成為了linux的主流音訊體系結構,想了解更多的關於ALSA的這一開源專案的資訊和知識,請檢視以下網址:http://www.alsa-project.org/。 在核心裝置驅動層,
Linux ALSA音效卡驅動之七:ASoC架構中的Codec
1. Codec簡介 在移動裝置中,Codec的作用可以歸結為4種,分別是: 對PCM等訊號進行D/A轉換,把數字的音訊訊號轉換為模擬訊號對Mic、Linein或者其他輸入源的模擬訊號進行A/D轉換,把模擬的聲音訊號轉變CPU能夠處理的數字訊號對音訊通路進行控制,比如
Linux音訊驅動之ASoC架構中的Platform
1. Platform驅動在ASoC中的作用 前面幾章內容已經說過,ASoC被分為Machine,Platform和Codec三大部件,Platform驅動的主要作用是完成音訊資料的管理,最終通過CPU的數字音訊介面(DAI)把音訊資料傳送給Codec進行處理,最終由Codec輸出驅動耳機或者是喇叭的
Linux ALSA音效卡驅動之一:ALSA架構簡介
一. 概述 ALSA是Advanced Linux Sound Architecture 的縮寫,目前已經成為了linux的主流音訊體系結構,想了解更多的關於ALSA的這一開源專案的資訊和知識,請檢視以下網址:http://www.alsa-project.org/。 在核心裝置驅動層
fl2440 platform 按鍵驅動的製作和測試
在led驅動的基礎上,繼續學習按鍵驅動 Makefile 1 2 obj-m := s3c_button.o 3 KERNEL_DIR := ~/fl2440/kernel/linux-3.0.54/ 4 PWD := $(shell pwd) 5 a
【TINY4412】LINUX移植筆記:(22)裝置樹LCD按鍵驅動
【TINY4412】LINUX移植筆記:(22)裝置樹 LCD按鍵驅動 宿主機 : 虛擬機器 Ubuntu 16.04 LTS / X64 目標板[底板]: Tiny4412SDK - 1506 目標板[核心板]:
Linux裝置驅動工程師之路——platform型別按鍵驅動
Linux裝置驅動工程師之路——platform按鍵驅動 Y-Kee 轉載請註明來自於衡陽師範學院08電2 Y-Kee http://blog.csdn.net/ayangke,QQ:843308498 一 、重要知識點: 1.platform裝置模型
老查的ARM學習筆記:chapter-1(按鍵驅動程式設計)
前面的部落格中,有一篇通過按鍵玩中斷的文章,不過那裡的程式是裸機,也就是沒有加系統下設計的程式,也就和在微控制器中設計的程式一樣比較簡單。現在我們來看看按鍵的驅動程式在linux系統下是如何設計的。 1 混雜裝置驅動模型** 1 混雜裝置驅動描述 首先
嵌入式Linux裝置驅動開發之:按鍵驅動程式例項
11.6 按鍵驅動程式例項 11.6.1 按鍵工作原理 高電平和低電平相接怎麼會變成低電平呢 就像你把電源正極的負極相連一樣會把電壓拉低。大電流會從高電平引腳流向低電平引腳,把高電平引腳拉低。 LED和蜂鳴器是最簡單的GPIO的應用,都不需要任何外部
linux設備驅動之platform平臺總線工作原理(三)
linux設備和驅動設備為數據,驅動為加工著1、以led-s3c24xx.c為例來分析platform設備和驅動的註冊過程其中關於led的驅動數據結構為:static struct platform_driver s3c24xx_led_driver = { .probe = s3c24xx_led_pr
python每日一類(2):platform
獲得 min def glob model implement 匯總 uname 信息 根據官方文檔的解釋(https://docs.python.org/3.5/library/platform.html#module-platform): 學習其他人的代碼如下: #
【DDD】領域驅動設計實踐 —— 架構風格及架構實例
讀取 bili 邏輯 stat orcal ransac 應用服務 業務場景 解讀 概述 DDD為復雜軟件的設計提供了指導思想,其將易發生變化的業務核心域放置在限定上下文中,在確保核心域一致性和內聚性的基礎上,DDD可以被多種語言和多種技術框架實現,具體的框架實現需要根據
7.自己寫中斷方式按鍵驅動程序
ops tar open ask edge tpi 資源 logs 修改 request_irq()和free_irq()分析完畢後,接下來開始編寫上升沿中斷的按鍵驅動 如下圖,需要設置4個按鍵的EINT0, EINT2, EINT11, EINT19的模式為雙邊沿,且設置
原創:LNMP架構部署個人博客網站 禁止轉載復制
mcr sysv 返回 瀏覽器 you 首頁 gid 軟件程序 esp nginx編譯安裝步驟 ①. 檢查軟件安裝的系統環境 cat /etc/redhat-release uname -r
11.按鍵驅動之定時器防抖(詳解)
pri pos long 超時時間 device queue pen fun cti 本節目標: 通過定時器來防止按鍵抖動,測試程序是使用上節的:阻塞操作的測試程序 1.如下圖所示,在沒有定時器防抖情況下,按鍵沒有穩定之前會多次進入中斷,使得輸出多個相同信息出來
開源純C#工控網關+組態軟件(三)加入一個新驅動:西門子S7
space 流量 php cls clsid hub pro 第一個 問題 一、 引子 首先感謝博客園:第一篇文章、第一個開源項目,算是旗開得勝。可以看到,項目大部分流量來自於博客園,碼農樂園,名不虛傳^^。 園友給了我很多支持,並提出了很好的改進意見。現加入屏幕分辨率自適