標籤:roi ack 分解 mac 自己 nmap arm架構 null log
上一篇講到android驅動開發中,應用是怎樣去操作底層硬體的整個流程,實現了按鍵控制led的亮滅。當然,這是一個非常easy的執行個體,只是略微演變一下,就能夠得到廣泛的應用。
如開發掃描磁頭,應用透過監聽上報的按鍵的鍵值,監聽到,則調用掃描磁頭的模組。成功,則點亮LED燈,並把掃描磁頭解碼後的條碼資訊。通過廣播的形式發出。又扯到其他地方,這裡主要說說中斷。
1. 中斷的一些概念
中斷,是什嗎?
中斷。能夠看成是cpu對特殊事件的一種處理的機制,這類特殊事件一般指緊急事件或者說例外狀況事件。非常easy的一個範例,你拿你手機正在看視頻,來了一個電話。你接完電話,還是停在視頻。本來你的cpu正在運行看視頻這一系列的指令處理。但當接收到電話,會產生一個中斷,cpu依據優先順序推斷。優先順序高於當前則停止當前工作。並儲存,然後運行中斷的處理函數,其中斷這一系列的事件處理完成以後。再運行儲存在暫停隊列中的工作。這是一個外部中斷的範例。
那麼中斷,是指 CPU 在運行程式的過程中,出現了某些突發事件時 CPU 必須暫停運行當前的程式,轉去處理突發事件,處理完成後 CPU 又返回原程式被中斷的位置並繼續運行。依據中斷的來源,中斷可分為內部中斷和外部中斷,內部中斷的中斷源來自 CPU內部(軟體中斷指令、溢出、除法錯誤等,比如,作業系統從使用者態切換到核心態需藉助 CPU 內部的軟體中斷),外部中斷的中斷源來自 CPU 外部,由外設提出請求。
中斷,實現它的機制?
中斷。當外設發出一個中斷訊號,cpu則依據中斷訊號,來進行分析處理,依據中斷訊號所對於的地址。去調用中斷處理函數。所以。中斷處理函數。是值該中斷產生後,cpu應該去緊急啟動並執行事件。
那麼,這裡主要解說一下中斷處理函數的機制。
s5pv210是arm架構的晶片,當中斷的資源很的豐富,這裡有32個外部中斷和其餘的gpio中斷。一般。實際開發中,中斷主要由外設發出。所以,這裡我們基本都是用的外部中斷。採用外部中斷的 CPU 通常為不同的中斷分配不同的中斷號,當檢測到某中斷號的中斷到來後,就自己主動跳轉到與該中斷號相應的地址運行。
不同中斷號的中斷有不同的入口地址。
中斷處理機制,,Linux 將中斷處理常式分解為兩個半部:頂半部(top half)和底半部(bottom half)。
在這兩者重要的差別,頂半部,不可被中斷,而底半部,能夠被新的中斷開啟。那麼,這兩者之前的差別,就認為了它們各自獨特的特性。頂半部,不可被打斷,所以註定它的已耗用時間要很很的高速,所以一般它僅僅是簡單的讀取寄存器的中斷狀態並清楚中斷標誌,然後就把底半部處理常式掛究竟半部運行隊列中。而這樣,中斷處理的大部分工作就落究竟半部了。由於可被打斷,相對來說,時間就比較充足。運行一些耗時的任務。
底半部的三種方式:非強制中斷、tasklet、工作隊列。
這裡有個博文連結。主要將三種機制以及之間的差異。http://blog.chinaunix.net/uid-20768928-id-5077401.html
中斷,當中關鍵的一些函數?
int request_threaded_irq(unsigned int irq, irq_handler_t handler,
irq_handler_t thread_fn, unsigned long irqflags,
const char *devname, void *dev_id)
irq:中斷號,這裡由gpio_to_irq()方法得到。
handler:發生中斷時首先要啟動並執行硬中斷處理函數,這個函數能夠通過返回 IRQ_WAKE_THREADED喚醒中斷線程,也可返回IRQ_HANDLE不運行中斷線程
thread_fn : 中斷線程,類似於中斷下半部,若傳參為null,則和request_irq()一樣
qflags:中斷標誌。備忘:IRQF_SHARED 共用中斷時,dev_id不可為空。由於釋放irq時要區分哪個共用中斷。
devname:中斷名
dev_id: 傳給中斷處理函數的參數。
2.簡單的執行個體:
#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/irq.h>#include <linux/input.h>#include <linux/platform_device.h>#include <linux/miscdevice.h>#include <mach/gpio.h>#include <linux/io.h>#include <mach/hardware.h>#include <linux/delay.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <linux/interrupt.h>#include <linux/gpio.h>#include <linux/wait.h>#include <linux/sched.h>#include <plat/gpio-core.h>#include <plat/gpio-cfg.h>#include <plat/gpio-cfg-helpers.h>static struct class *buttondrv_class;static struct device *buttondrv_class_dev;int major;volatile unsigned long *GPCCON;volatile unsigned long *GPCDAT;//static DECLARE_WAIT_QUEUE_HEAD(button_waitq);static unsigned char key_val;static volatile int ev_press = 0;struct pin_desc{unsigned int pin;unsigned int key_val;};struct pin_desc pins_desc[2] = {{S5PV210_GPH3(7), 0x01},};static irqreturn_t buttons_irq(int irq, void *dev_id){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>buttons_irq\n");struct pin_desc *pindesc = (struct pin_desc *)dev_id;unsigned int pinval;pinval = gpio_get_value(pindesc->pin);printk("irq >>>>>>>>>>>>>>>>>>>>>>>>>>>>pinval =%d \n",pinval);if (pinval){key_val = 0x80 | pindesc->key_val;printk("1111 >>>>>>>>>>>>>>>>>>>>>>>>>>>key_val =%d \n",key_val);}else{key_val = pindesc->key_val;printk("0000 >>>>>>>>>>>>>>>>>>>>>>>>>>>key_val =%d \n",key_val);} ev_press = 1; // wake_up_interruptible(&button_waitq); return IRQ_RETVAL(IRQ_HANDLED);}static int button_drv_open(struct inode *inode, struct file *file){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_open\n");int ret=-1;s3c_gpio_setpull(S5PV210_GPH3(7), S3C_GPIO_PULL_NONE);ret = request_threaded_irq(gpio_to_irq(S5PV210_GPH3(7)), NULL,buttons_irq,IRQF_TRIGGER_RISING,"s2", &pins_desc[0]);printk("ret=%d irq=%d >>>>>>>>>>>>>>>>>>>>>>>>>\n ",ret,gpio_to_irq(S5PV210_GPH3(7)));return 0;}int button_drv_close(struct inode *inode, struct file *file){free_irq(gpio_to_irq(S5PV210_GPH3(7)), &pins_desc[0]);return 0;}static int button_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *offp){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_read\n");if (count != 1)return -EINVAL;printk("read >>>>>>>>>>>>>>>>>>>>>>>>>>>key_val =%d \n",key_val);//wait_event_interruptible(button_waitq, ev_press);copy_to_user(buf, &key_val, 1);key_val=0;ev_press = 0;return 1;}static struct file_operations button_drv_fops = { .owner = THIS_MODULE, .open = button_drv_open, .read=button_drv_read, .release = button_drv_close,};static int button_drv_init(void){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_init\n"); GPCCON = (volatile unsigned long *)ioremap(0xE0200C60, 8);GPCDAT= GPCCON + 1;if (!GPCCON) {return -EIO;}major = register_chrdev(0, "button_drv", &button_drv_fops); buttondrv_class = class_create(THIS_MODULE, "buttondrv");buttondrv_class_dev = device_create(buttondrv_class, NULL, MKDEV(major, 0), NULL, "button"); return 0;}static void button_drv_exit(void){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_exit\n");unregister_chrdev(major, "button_drv"); device_unregister(buttondrv_class_dev);class_destroy(buttondrv_class);iounmap(GPCCON);}module_init(button_drv_init);module_exit(button_drv_exit);MODULE_LICENSE("GPL");
關於代碼一些簡單的說明:
static DECLARE_WAIT_QUEUE_HEAD(button_waitq)
wake_up_interruptible(&button_waitq)
wait_event_interruptible(button_waitq, ev_press)
這個是等待隊列的機制,當有中斷的時候。喚醒。把事件增加工作隊列中,處理完事件後。繼續休眠,直到下次中斷。
3.關於一些調試方法:
一般在編寫中斷的程式,最基本的是要看,gpio口的中斷號是否申請成功。這裡主要依據列印語句進行調試了。
若驅動程式不報錯誤了,則可進入android系統下,cat proc/interrupts ,可查看到你申請成功的中斷。
初入android驅動開發之字元裝置(四-中斷)