三伏天說來就來了,比起去年,今年的夏天沒熱得那麼不可思議了。也許真正的炎熱還沒有到來。任時光匆匆而過,也沒得到自己想要的生活,覺得有點得過且過的樣子。需要換位思考,需要領悟人生的真諦,需要去追求自己想要的。覺得,孟非老師說的一句話很實在,工作再努力,提早完成了之後,能得到什麼呢?只會換來領導的一句話,恩,不錯,那個,那個這些事你也做一下吧。哈哈,的確如此,所以何不善待自己呢?做自己喜歡的事,而不是一味的工作,工作中雖然可以學到東西,但是,不可能只學一樣啊,那樣如果你想換換生活,換換工作,你又能做些什麼呢?努力是需要的,我有我的夢想,我的未來,我的一切,合理安排時間,而不是把生活全部都放在了工作中,那樣,豈不毀了一生,直待老去之後就只能慢慢懊悔,究竟得到了什麼。。。。。。。。
閑話講了太多了,接下來還是迴歸正題吧。話說剛開始接觸linux驅動時就是從char裝置開始的,然後接著又把那個char裝置改寫為input裝置了,從中也開始對於linux裝置驅動編程入了個小門了接著就把那個代碼貼一下,用以以後可以記起。
具體的代碼含義都加了注釋了:
#include <linux/slab.h>#include <linux/irq.h>#include <linux/interrupt.h>#include <linux/poll.h>#include <asm/io.h>#include <linux/delay.h>#include <linux/module.h>#include <linux/time.h>#include <linux/gpio.h>#include <linux/wait.h>#include <linux/input.h>#include <linux/init.h> static gpio_base = 96; //gpio的基址,看不同的平台而定的。static pow_btn = 18; //按鍵的中斷號,也是依賴於平台的 struct input_dev *btn_dev; //input裝置的結構體,這裡定義了btn_devstruct delayed_work btn_work; //這個是工作隊列,用於讓中斷處理常式在中斷後半部分 static irqreturn_t power_isr(int irq, void *dev_id); //中斷入口函數 static int __init button_init(void); static void __exit button_exit(void); static void power_work_fn(struct work_struct *work) //中斷下半部分處理,即工作隊列中處理{ struct timeval tm_p, tm_n; unsigned char flag = 1; unsigned int width = 0; if(gpio_get_value(power)) return; do_gettimeofday(&tm_p); //取當前的時間 while(!gpio_get_value(pow_btn)) //判斷按鍵是否彈起 { if(!flag) continue; do_gettimeofday(&tm_n); //再取間 width = 1000000 * (tm_n.tv_sec - tm_p.tv_sec) //計算兩次的時間差,就是按鍵一直沒彈起 + tm_n.tv_usec - tm_p.tv_usec; if(width >= 1500000) //自己定義的超過了1.5s就上報一次, { input_report_key(btn_dev, KEY_POWER, 0); //上報按索引值 input_report_key(btn_dev, KEY_POWER, 1); input_sync(btn_dev); flag =0; } } if(flag) { input_report_key(btn_dev, KEY_POWER, 1); input_report_key(btn_dev, KEY_POWER, 0); input_sync(btn_dev); }} static irqreturn_t power_isr(int irq, void *dev_id) //中斷處理函數{ schedule_delayed_work(&power_work, 0); //把中斷函數放在工作隊列裡去做了 return IRQ_HANDLED;} static int __init button_init(void){ int error; gpio_request(pow_btn, "power-gpio"); //初始化申請gpio gpio_direction_input(pow_btn); //設定gpio口為輸入 //申請中斷 if(reques_irq(gpio_base+pow_btn, power_isr, IRQ_DISABLED, "my_power", NULL) != 0) { printk(KERN_ERR "my_power: can't allocate irq %d\n", pow_btn); return (-EIO); } //分配input裝置 btn_dev = input_allocate_device(); if(!btn_dev) { printk(KERN_ERR "button: not enough memory\n"); error = -ENOMEM; goto err_free_irq; } //把相應的按鍵給置上 btn_dev->evbit[0] = BIT_MASK(EV_KEY); btn_dev->keybit[BIT_WORK(KEY_POWER)] |= BIT_MASK(KEY_POWER); //註冊input裝置 error = input_register_device(btn_dev); if(error) { printk(KERN_ERR "button: failed to register device\n"); goto err_free_dev; } //初始化工作隊列 INIT_DELAYED_WORK(&power_work, power_work_fn); printk("$$$$$$$my_power button register ok\n"); return 0; err_free_dev: input_free_device(btn_dev); err_free_irq: free_irq(gpio_base+pow_btn, power_isr); return error; } static void __exit button_exit(void){ input_free_device(btn_dev); free_irq(gpio_base+pow_btn, power_isr);} module_init(button_init);module_exit(button_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("eastmoon");
好了,這就是一個按鍵的裝置驅動了,其中用到了很多知識了,像中斷啊,input裝置啊,工作隊列啊,時間的擷取啊。GPIO的使用啊。分析好了這個驅動,下面貼個應用程式層的調用。總不能只有個驅動,而沒法測試吧。
#include <stdio.h>#include <sys/ioctl.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/select.h>#include <sys/time.h>#include <linux/input.h> #define DEVICE "/dev/event0" int main(int argc, char *argv[]){ struct input_event btn; int fd, rev; unsigned short type; unsigned short code; int value; fd = open(DEVICE, O_RDWR); if(fd < 0) { printf("Open file %s failed!\n", DEVICE); return -1; } while(1) { rev = read(fd, &btn, sizeof(struct input_event)); if(rev > 0) { type = btn.type; code = btn.code; value = btn.value; printf("type = %d, code = %d, value = %d\n", type, code ,value); } } close(fd); return 0;}
相比知道了上面的驅動程式,應用程式肯定顯得那麼簡單了。就不多做分析了。
這個就是最最簡單的input的基本模型了,相信以這個為基礎,其他的input裝置也是大同小異的了。