字元裝置驅動——申請、建立、應用.
1、申請裝置號
// 1、註冊獲取裝置號// 2、初始化裝置// 3、操作裝置 file_operations – open release read write ioctl…// 4、兩個宏定義 module_init module_exit // 5、註冊裝置號 register_chrdev_region// 6、cdev_init 初始化字元裝置// 7、cdev_add 新增字元裝置到系統
1)向系統申請主裝置號
int register_chrdev(unsigned int major, const char * name, const struct file_operations * fops)
//引數://1、major:主裝置號// 裝置號(32bit–dev_t)==主裝置號(高12bit) + 次裝置號(低20bit)// 主裝置號:表示一類裝置—(如:camera)// 次裝置號: 表示一類裝置中某一個—(如:前置camera/後置camera)// 0 -->動態分配 ; 250 --> 給定整數,靜態指定//2、name: 描述裝置資訊,可自定義// 在目錄/proc/devices列舉出了所有的已經註冊的裝置//3、fops: 檔案操作物件// 提供open, read,write//返回值:成功-0,失敗-負數
2)釋放裝置號
void unregister_chrdev(unsigned int major, const char * name)
3)例:主裝置號的申請
chr_drv.c
載入驅動前:
載入驅動後:
2、建立裝置節點
1)手動建立
·· 缺點/dev/目錄中檔案都是在記憶體中,斷電後/dev/檔案就會消失
mknod /dev/裝置名 型別 主裝置號 次裝置號
(主裝置號要和驅動中申請的主裝置號保持一致)
比如:
mknod /dev/chr0 c 250 0
eg:
[root
drv_module]# ls /dev/chr0 -l
crw-r--r-- 1 0 0 250, 0 Jan 1 00:33 /dev/chr0
2)自動建立
透過udev/mdev機制
struct class *class_create(owner, name)//建立一個類
//引數://1、owner:THIS_MODULE//2、name :字串名字,自定義//返回:// 返回一個class指標
建立一個裝置檔案:
//建立一個裝置檔案struct device *device_create(struct class * class, struct device * parent, dev_t devt, void * drvdata, const char * fmt,...)
//引數://1、class結構體,class_create呼叫之後的返回值//2、表示父親,一般直接填NULL//3、裝置號型別 dev_t//4、私有資料,一般直接填NULL//5/6、表示可變引數,字串,表示裝置節點名字
裝置號型別:dev_t devt
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) //獲取主裝置號
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) //獲取次裝置號
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) //生成裝置號
銷燬裝置檔案:
void device_destroy(devcls, MKDEV(dev_major, 0));//引數://1、class結構體,class_create呼叫之後到返回值//2、裝置號型別 dev_t
void class_destroy(devcls);//引數:class結構體,class_create呼叫之後到返回值
3)示例:
chr_drv.c
3、實現檔案IO介面--fops
1)驅動中實現檔案io操作介面:struct file_operations
1 struct file_operations { 2 struct module *owner; 3 loff_t (*llseek) (struct file *, loff_t, int); 4 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 5 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 6 ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); 7 ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); 8 int (*iterate) (struct file *, struct dir_context *); 9 unsigned int (*poll) (struct file *, struct poll_table_struct *);10 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);11 long (*compat_ioctl) (struct file *, unsigned int, unsigned long);12 int (*mmap) (struct file *, struct vm_area_struct *);13 int (*open) (struct inode *, struct file *);14 ....16 long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len);17 int (*show_fdinfo)(struct seq_file *m, struct file *f);18 }; //函式指標的集合,其實就是介面,我們寫驅動到時候需要去實現19 20 const struct file_operations my_fops = {21 .open = chr_drv_open,22 .read = chr_drv_read,23 .write = chr_drv_write,24 .release = chr_drv_close,25 };
示例:
chr_drv1.c
實現了底層的fops成員函式,再實現應用程式的呼叫
2)應用程式呼叫檔案IO控制驅動 :open、read...
chr_drv1.c
chr_test.c
Makefile
測試結果;
4、應用程式控制驅動
應用程式要控制驅動,就涉及使用者空間與核心空間的資料互動,如何實現?透過以下函式:
1)copy_to_user
1 //將資料從核心空間複製到使用者空間,一般是在驅動中chr_drv_read()用2 int copy_to_user(void __user * to, const void * from, unsigned long n)3 //引數:4 //1:應用驅動中的一個buffer5 //2:核心空間到一個buffer6 //3:個數7 //返回值:大於0,表示出錯,剩下多少個沒有複製成功等於0,表示正確
2)copy_from_user
1 //將資料從使用者空間複製到核心空間,一般是在驅動中chr_drv_write()用2 int copy_from_user(void * to, const void __user * from, unsigned long n)3 //引數:4 //1:核心驅動中的一個buffer5 //2:應用空間到一個buffer6 //3:個數
示例:
chr_drv1.c
chr_test.c
測試:
5、驅動程式控制外設
之前我們瞭解了應用程式如何與核心空間進行資料互動,那麼核心驅動與外設間的控制是怎麼樣的?
寫過裸機程式的都知道,可以透過修改外設對應的控制暫存器來控制外設,即向暫存器的地址寫入資料,這個地址就是實體地址,且實體地址是已知的,有硬體設計決定。
在核心中,同樣也是操作地址控制外設,但是核心中的地址,是經過MMU對映後的虛擬地址,而且CPU通常並沒有為這些已知的外設I/O記憶體資源的實體地址預定義虛擬地址範圍,驅動程式並不能直接透過實體地址訪問I/O記憶體資源,而必須將它們對映到核心虛地址空間內,然後才能根據對映所得到的核心虛地址範圍,透過訪內指令訪問這些I/O記憶體資源。Linux在io.h標頭檔案中宣告瞭函式ioremap(),用來將I/O記憶體資源的實體地址對映到核心虛地址空間中
ioremap的函式如下:
1 //對映虛擬地址2 void *ioremap(cookie, size)3 //引數:4 //1、cookie:實體地址5 //2、size:長度(連續對映一定長度的地址空間)6 //返回值:虛擬地址
解除對映:
1 //去對映--解除對映2 void iounmap(void __iomem *addr)3 //引數:對映後的虛擬地址
例項:透過驅動控制LED燈
LED —— GPX2_7 —— GPX2CON —— 0x11000C40
GPX2DAT—— 0x11000C44
將0x11000c40對映為虛擬地址
chr_drv1.c
chr_test.c
測試:
執行app後,可以看到LED等以一秒的間隔亮滅
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946382/viewspace-2838192/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 字元裝置驅動 —— 字元裝置驅動框架字元框架
- LED字元裝置驅動字元
- 字元驅動裝置踩坑字元
- liunx驅動之字元裝置的註冊字元
- Linux驅動實踐:你知道【字元裝置驅動程式】的兩種寫法嗎?Linux字元
- ArmSoM系列板卡 嵌入式Linux驅動開發實戰指南 之 字元裝置驅動Linux字元
- 字元裝置驅動學習之cdev_init和cdev_alloc字元dev
- Linux裝置驅動程式學習----1.裝置驅動程式簡介Linux
- 驅動Driver-MISC雜項驅動裝置
- 【linux】驅動-7-平臺裝置驅動Linux
- Linux驅動開發筆記(四):裝置驅動介紹、熟悉雜項裝置驅動和ubuntu開發雜項裝置DemoLinux筆記Ubuntu
- platform 裝置驅動實驗Platform
- 【linux】驅動-6-匯流排-裝置-驅動Linux
- 在Linux中,什麼是裝置驅動程式?如何安裝和解除安裝裝置驅動程式?Linux
- 免費申請萬用字元證書字元
- 字元驅動框架字元框架
- 新字元驅動框架驅動LED字元框架
- 05_雜項裝置驅動
- mtd裝置驅動(待學習)
- linux 裝置驅動基本概念Linux
- win10驅動未知裝置怎麼辦_win10裝置管理器驅動未知裝置處理方法Win10
- pci匯流排驅動及pci裝置驅動註冊
- 裝置驅動程式包可以刪除嗎 win10裝置驅動程式包能刪嗎Win10
- 非同步通知和MISC裝置驅動非同步
- iOS 裝置驅動 for windows 32&64iOSWindows
- linux裝置驅動編寫入門Linux
- 無作業系統時的裝置驅動和有作業系統時的裝置驅動作業系統
- platform_driver驅動及裝置驅動匹配識別符號Platform符號
- Linux驅動實踐:如何編寫【 GPIO 】裝置的驅動程式?Linux
- Google 應用內購 (1): 申請身份證明Go
- 申請Let's Encrypt萬用字元SSL證書字元
- 裝置樹下的 LED 驅動實驗
- 【Linux SPI】RFID RC522 裝置驅動Linux
- 【linux】驅動-9-裝置樹外掛Linux
- Linux驅動之I2C匯流排裝置以及驅動Linux
- 如何編寫一個簡單的Linux驅動(三)——完善裝置驅動Linux
- linux核心原始碼閱讀-塊裝置驅動Linux原始碼
- linux驅動之獲取裝置樹資訊Linux