標籤:style blog io color os 使用 sp for 檔案
由於項目上要用到,於是乎我要學習linux裝置驅動的編寫,開始的時候還比較清楚,能夠對簡單的GPIO控制操作實現出來,但是項目上要用到的是SPI和GPIO的輸入中斷來讀取AD的電壓值,然後就陷入到了一個龐大的裝置代碼閱讀中去了,尤其是platform device的學習,到現在都還沒有理清其中的關係,雖然搜尋了很多網上的文章,但慶幸的是我有一種比著框框買鴨蛋的精神,我想要比著這些源碼畫一個出來。以前沒有在LPC1768上使用過SPI,導致對SPI是一個完全陌生的狀態,不清楚他的傳輸方式,這也是學習中的一個問題,也是一開始我的盲目無方向感的原因,因為這裡的linux SPI裝置驅動和SPI協議就是兩個要學習的問題。
先來把“簡單”的中斷實現出來吧,其實中斷處理並不簡單,他是很多項目中必須要用到的東西,這裡使用的S5PV210的GPH3(2)這一個GPIO來實現,查看晶片手冊其對應的外部中斷號為EINT26,所以在驅動中定義一個結構體來描述他如下:
struct s5pv210_gpio_key{ int pin;//引腳號 int eint;//外部中斷號 int eintcfg;//外部中斷使能 int inputcfg;//輸入使能};struct s5pv210_gpio_key my_gpio_key={ .pin = S5PV210_GPH3(2), .eintcfg = 0X0f<<4, .inputcfg = 0<<4, .eint = IRQ_EINT(26), };
然後構建一個驅動的架構代碼:
static int __init gpio_interrupt_init(void){ int err=0; gpio_int_num = MKDEV(MY_MAJOR,MY_MINOR); err = register_chrdev_region(gpio_int_num, 1, "GPH3_2_interrupt"); if(err < 0) { printk("register error, num: %d have been used!\n", gpio_int_num); return err; } cdev_init(&my_cdev , &gpio_interrupt_ops); my_cdev.owner = THIS_MODULE; err = cdev_add(&my_cdev, gpio_int_num, 1); if(err < 0) { printk("add my_cdev error!\n"); return err; } printk("init ok\n"); return 0; }static void __exit gpio_interrupt_exit(void){ cdev_del(&my_cdev); unregister_chrdev_region(gpio_int_num, 1); printk("exit ok\n"); }module_init(gpio_interrupt_init);module_exit(gpio_interrupt_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("galuo");
在載入模組的函數中,register_chrdev_region註冊了一個裝置號,在載入了該模組後,使用mknod命令來建立裝置檔案節點;然後使用cdev_init來初始化字元裝置結構體變數cdev,將file_operations結構體gpio_interrupt_ops載入進來,就可以在使用者空間使用的時候明確調用的關係;使用cdev_add向核心註冊字元I/O裝置。字元模組的退出函數使用cdev_del函數來刪除核心中的字元裝置;使用unregister_chrdev_region來釋放裝置號。
定義file_operations結構體執行個體gpio_interrupt_ops,在使用者空間操作的時候實現調用對應的功能,其定義如下:
struct file_operations gpio_interrupt_ops={ .open=gpio_interrupt_open, .release=gpio_interrupt_close, };
.open實現中斷的請求,並且使能中斷
.release實現中斷的釋放
int gpio_interrupt_open(struct inode *inode,struct file *file){ int error; error = request_irq(my_gpio_key.eint, //中斷號 gpio_keys_isr,//中斷處理函數 IRQF_TRIGGER_FALLING ,//下降沿觸發 "interrupt_test", NULL); if(error){ printk("request irq failed!\n"); return -1; } printk("hello irq\n"); return 0; }int gpio_interrupt_close(struct inode *inode,struct file *file){ free_irq(my_gpio_key.eint, NULL); printk("good bye irq\n"); return 0;}
在中斷處理函數gpio_keys_isr中就可以實現中斷的需求:
static irqreturn_t gpio_keys_isr(int irq, void *dev_id){ printk("this is interrupt function\n"); return IRQ_HANDLED;}
這裡中斷處理函數的定義類型和傳回值固定不變。
linux裝置驅動的學習之一