1. 姝g偣鍘熷瓙宓屽叆寮弆inux椹卞姩寮鍙戔斺擫inux IIO椹卞姩
鍦ㄥ伐涓氱墿鑱旂綉鐨勬氮娼涓錛孡inux IIO椹卞姩寮鍙戝逛簬綆$悊ADC鍜孌AC綾諱紶鎰熷櫒鑷沖叧閲嶈併侷IO瀛愮郴緇燂紙Instrial I/O錛夋槸鍐呮牳璁捐$殑綺懼欑粍浠訛紝涓撲負榪欑被璁懼囨彁渚涢珮鏁堝拰鐏墊椿鐨勭$悊銆傞氳繃iio_dev緇撴瀯浣擄紝椹卞姩寮鍙戣呰兘澶熸搷鎺ц懼囨ā寮忋佺紦鍐插尯鍜屽氶氶亾淇℃伅錛岀『淇濇暟鎹閲囬泦鐨勭簿鍑嗗拰瀹炴椂鎬с
瑕佸紑濮婭IO椹卞姩鐨勫紑鍙戱紝棣栧厛錛岄┍鍔ㄥ紑鍙戣呴渶瑕侀氳繃iio_device_alloc鍑芥暟鐢寵穒io_dev緇撴瀯錛屽苟鍒╃敤iio_priv灞炴ц幏鍙栬嚜瀹氫箟璁懼囩殑璇︾粏淇℃伅銆傛垚鍔熻幏鍙杋io_dev鍚庯紝瀹冭繑鍥炶懼囩殑棣栧湴鍧錛屽惁鍒欒繑鍥濶ULL銆傛帴涓嬫潵鐨勬ラゅ寘鎷鍒濆嬪寲銆佹敞鍐屽拰娉ㄩ攢iio_dev錛岀『淇濊懼囩殑鐢熷懡鍛ㄦ湡綆$悊銆
紺轟緥浠g爜涓錛岄氳繃iio_device_alloc涓巌io_priv鐨勯厤鍚堬紝寮鍙戣呭彲浠ヨ交鏉劇敵璇峰苟鎻愬彇icm20608_dev緇撴瀯浣擄紝鐢ㄤ簬澶勭悊ICM20608榪欑被浼犳劅鍣ㄣ俰io_device_free鑷鍔ㄥ勭悊閲婃斁iio_dev錛屾棤闇鎵嬪姩鎿嶄綔銆傚湪椹卞姩涓錛屽叧閿鐨剗io_device_register鐢ㄤ簬璁懼囨敞鍐岋紝鑰宨io_device_unregister鍒欑敤浜庢敞閿璁懼囷紝紜淇濊祫婧愮殑姝g『娓呯悊銆
娣卞叆鐞嗚Вiio_dev鐨剗nfo緇撴瀯浣撹嚦鍏抽噸瑕侊紝瀹冨畾涔夊湪iio.h涓錛屽寘鍚閫氱敤灞炴у拰璇誨啓鏁版嵁鎿嶄綔鎺ュ彛銆俽ead_raw鍜寃rite_raw鍑芥暟鏄鐢ㄦ埛絀洪棿涓庤懼囦氦浜掔殑鏍稿績錛屽厑璁哥洿鎺ヨ誨啓浼犳劅鍣ㄦ暟鎹錛屽弬鏁板寘鎷璁懼囥侀氶亾鍜屾暟鎹鍊箋傚悓鏃訛紝mask鐢ㄤ簬鎸囧畾璇誨彇鍐呭癸紝渚嬪傞檧鋙轟華鍜屽姞閫熷害璁$殑鍘熷嬪箋佽寖鍥村拰鍒嗚鯨鐜囥
渚嬪傦紝ICM20608鎷ユ湁7涓閫氶亾錛屾瘡涓閫氶亾瀵瑰簲涓涓浼犳劅鍣ㄧ淮搴︼紝濡傚姞閫熷害璁$殑X銆乊銆乑杞淬傞氶亾鎻忚堪鐢眎io_chan_spec緇撴瀯浣撴壙杞斤紝鍖呮嫭綾誨瀷銆佺儲寮曘佷慨楗扮︼紙濡侷IO_MOD_X錛夊拰鍦板潃絳夎︾粏淇℃伅銆傞氶亾閰嶇疆鏃訛紝濡傚湴鍧鐨勯夋嫨鍜屾壂鎻忕儲寮曠殑璁劇疆錛屽睍紺轟簡IIO妗嗘灦瀵逛簬涓嶅悓綾誨瀷浼犳劅鍣ㄧ殑騫挎硾鏀鎸併
鍦ㄥ紑鍙戣繃紼嬩腑錛屽備笌SPI鎴朓IC閫氫俊錛屽彲鑳借繕闇緇撳悎regmap鎴杙latform椹卞姩銆備互SPI椹卞姩涓轟緥錛屽紑鍙戣呴渶瑕佺紪鍐檖robe鍜宺emove鍑芥暟錛屼互鍙婅繘琛岃懼囧尮閰嶅拰椹卞姩緇撴瀯浣撶殑閰嶇疆銆傚湪瀹為檯紺轟緥涓錛屼唬鐮56.2.1.1灞曠ず浜嗗備綍灝咺IO妗嗘灦涓嶴PI椹卞姩鏁村悎錛屽寘鎷璁懼囩殑鍒濆嬪寲銆佹敞鍐屽拰璧勬簮閲婃斁銆
鐢ㄦ埛鑷瀹氫箟璁懼囩粨鏋勪綋涓鍖呭惈indio_dev銆乧han鍜宮ask鍙傛暟錛屾寚瀵兼搷浣滅殑鎵ц屻侷IO閫氶亾鏁扮粍鍒欏畾涔変簡鏁版嵁璇誨啓鐨勯昏緫璺寰勩俰io_info緇撴瀯浣撲腑錛宺ead_raw銆亀rite_raw鍜寃rite_raw_get_fmt鎴愬憳鎻愪緵浜嗘暟鎹璇誨彇銆佸啓鍏ュ拰鏍煎紡鑾峰彇鐨勬帴鍙c
鍦⊿PI椹卞姩鐨刾robe鍑芥暟涓錛屽紑鍙戣呴渶閫氳繃devm_iio_device_alloc鑾峰彇iio_dev錛岄厤緗鐩稿叧紜浠舵帴鍙o紝濡俿pi_device鍜宺egmap錛屽垵濮嬪寲騫舵敞鍐孖IO璁懼囥傚悓鏃訛紝鑺鐗囩殑鍒濆嬪寲涔熸槸鍏抽敭姝ラゃ俽emove鍑芥暟鍒欏湪璁懼囩Щ闄ゆ椂璐熻矗娉ㄩ攢璁懼囧苟閲婃斁璧勬簮銆
閽堝笽CM20608 IIO椹卞姩寮鍙戱紝閫氳繃SPI鍜宺egmap錛屽畾涔変簡閫氶亾瀹忓拰鏋氫婦綾誨瀷錛屽寘鎷闄鋙轟華銆佸姞閫熷害璁°佹俯搴﹀拰鏃墮棿鎴抽氶亾銆傛瀯寤篿cm20608_dev緇撴瀯浣撴椂錛屽寘鍚蹇呰佺殑閫氫俊鎺ュ彛鍜岄厤緗鍙傛暟銆傛牳蹇冮氶亾鐨勬弿榪伴氳繃iio_chan_spec鏁扮粍錛屽寘鍚7涓閫氶亾鐨勯厤緗錛屼互鍙婅誨啓瀵勫瓨鍣ㄥ拰鍒濆嬪寲閰嶇疆鐨勫嚱鏁般
椹卞姩鐨勫疄鐜頒腑錛宨cm20608_probe鍑芥暟璐熻矗璁懼囨敞鍐岋紝鍖呮嫭鍐呭瓨鍒嗛厤銆乮cm20608_dev緇撴瀯鐨勮劇疆銆丼PI鎺ュ彛鍜宺egmap閰嶇疆錛屼互鍙奍CM20608鐨勫垵濮嬪寲銆俰cm20608_remove鍒欏湪鍗歌澆鏃舵敞閿璁懼囧苟閲婃斁璧勬簮銆
鍦╯ysfs涓錛孖IO璁懼囨枃浠跺懡鍚嶈勫垯涓ヨ皚錛屽俰n_accel_x_raw錛屾寚紺哄姞閫熷害璁X杞達紝鍖呭惈浜嗛氶亾綾誨瀷鍜岀壒瀹氬睘鎬с傜敤鎴風┖闂撮氳繃icm20608_read_raw絳夊嚱鏁拌誨彇鏁版嵁錛岄氳繃iio_info鎺ュ彛鎿嶄綔錛屽傝劇疆浼犳劅鍣ㄨ寖鍥村拰璇誨彇鏁版嵁鏍煎紡銆
緙栧啓icm20608_read_raw鍑芥暟鏃訛紝瑕佽冭檻鍒頒笉鍚屼紶鎰熷櫒綾誨瀷鍜岄氶亾灞炴э紝渚嬪傞噺紼嬨佹牎鍑嗗肩瓑銆傝屽啓鍏ユ搷浣滃垯娑夊強icm20608_write_raw錛屾牴鎹鐢ㄦ埛杈撳叆鐨勬暟鎹榪涜岄厤緗銆
姝ゅ栵紝瑙﹀彂鍣ㄦ満鍒舵槸IIO椹卞姩涓鐨勯噸瑕佺粍鎴愰儴鍒嗭紝鐢ㄤ簬鏁版嵁閲囬泦鍜岀紦鍐插尯綆$悊銆傞氳繃iio_trigger鍜宨io_triggered_buffer_setup錛屽紑鍙戣呭彲浠ュ壋寤鴻嚜瀹氫箟瑙﹀彂鍣錛岄厤緗涓鏂澶勭悊錛屼互鍙婂湪涓鏂鍙戠敓鏃惰誨彇鏁版嵁銆
鎬葷粨鏉ヨ達紝linux IIO椹卞姩寮鍙戞秹鍙婅懼囩殑鍒濆嬪寲銆侀氫俊鎺ュ彛閰嶇疆銆侀氶亾綆$悊銆乻ysfs鎺ュ彛璁捐°佹暟鎹璇誨啓浠ュ強瑙﹀彂鍣ㄥ拰緙撳啿鍖虹殑璁劇疆銆傞氳繃榪欎簺姝ラわ紝椹卞姩寮鍙戣呭彲浠ュ疄鐜板瑰伐涓氱幆澧冧腑鍚勭嶄紶鎰熷櫒鐨勯珮鏁堢$悊鍜屾暟鎹閲囬泦錛屼負鐗╄仈緗戣懼囨彁渚涘己澶х殑鍔熻兘鏀鎸併
2. 如何系統的學習Linux驅動開發
在學習之前一直對驅動開發非常的陌生,感覺有點神秘。不知道驅動開發和普通的程序開發究竟有什麼不同;它的基本框架又是什麼樣的;他的開發環境有什麼特殊的地方;以及怎麼寫編寫一個簡單的字元設備驅動前編譯載入,下面我就對這些問題一個一個的介紹。
一、驅動的基本框架
1.那麼究竟什麼是驅動程序,它有什麼用呢:
l驅動是硬體設備與應用程序之間的一個中間軟體層
l它使得某個特定硬體能夠響應一個定義良好的內部編程介面,同時完全隱蔽了設備的工作細節
l用戶通過一組與具體設備無關的標准化的調用來完成相應的操作
l驅動程序的任務就是把這些標准化的系統調用映射到具體設備對於實際硬體的特定操作上
l驅動程序是內核的一部分,可以使用中斷、DMA等操作
l驅動程序在用戶態和內核態之間傳遞數據
2.Linux驅動的基本框架
3.Linux下設備驅動程序的一般可以分為以下三類
1)字元設備
a)所有能夠象位元組流一樣訪問的設備都通過字元設備來實現
b)它們被映射為文件系統中的節點,通常在/dev/目錄下面
c)一般要包含open read write close等系統調用的實現
2)塊設備
d)通常是指諸如磁碟、內存、Flash等可以容納文件系統的存儲設備。
e)塊設備也是通過文件系統來訪問,與字元設備的區別是:內核管理數據的方式不同
f)它允許象字元設備一樣以位元組流的方式來訪問,也可一次傳遞任意多的位元組。
3)網路介面設備
g)通常它指的是硬體設備,但有時也可能是一個軟體設備(如回環介面loopback),它們由內核中網路子系統驅動,負責發送和接收數據包。
h)它們的數據傳送往往不是面向流的,因此很難將它們映射到一個文件系統的節點上。
二、怎麼搭建一個驅動的開發環境
因為驅動是要編譯進內核,在啟動內核時就會驅動此硬體設備;或者編譯生成一個.o文件,當應用程序需要時再動態載入進內核空間運行。因此編譯任何一個驅動程序都要鏈接到內核的源碼樹。所以搭建環境的第一步當然是建內核源碼樹
1.怎麼建內核源碼樹
a)首先看你的系統有沒有源碼樹,在你的/lib/ moles目錄下會有內核信息,比如我當前的系統里有兩個版本:
#ls /lib/ moles
2.6.15-rc72.6.21-1.3194.fc7
查看其源碼位置:
## ll /lib/moles/2.6.15-rc7/build
lrwxrwxrwx 1 root root 27 2008-04-28 19:19 /lib/moles/2.6.15-rc7/build -> /root/xkli/linux-2.6.15-rc7
發現build是一個鏈接文件,其所對應的目錄就是源碼樹的目錄。但現在這里目標目錄已經是無效的了。所以得自己重新下載
b)下載並編譯源碼樹
有很多網站上可以下載,但官方網址是:
http://www.kernel.org/pub/linux/kernel/v2.6/
下載完後當然就是解壓編譯了
# tar –xzvf linux-2.6.16.54.tar.gz
#cd linux-2.6.16.54
## make menuconfig (配置內核各選項,如果沒有配置就無法下一步編譯,這里可以不要改任何東西)
#make
…
如果編譯沒有出錯。那麼恭喜你。你的開發環境已經搭建好了
三、了解驅動的基本知識
1.設備號
1)什麼是設備號呢?我們進系統根據現有的設備來講解就清楚了:
#ls -l /dev/
crwxrwxrwx 1 root root1,3 2009-05-11 16:36 null
crw------- 1 root root4,0 2009-05-11 16:35 systty
crw-rw-rw- 1 root tty5,0 2009-05-11 16:36 tty
crw-rw---- 1 root tty4,0 2009-05-11 16:35 tty0
在日期前面的兩個數(如第一列就是1,3)就是表示的設備號,第一個是主設備號,第二個是從設備號
2)設備號有什麼用呢?
l傳統上,主編號標識設備相連的驅動.例如, /dev/null和/dev/zero都由驅動1來管理,而虛擬控制台和串口終端都由驅動4管理
l次編號被內核用來決定引用哪個設備.依據你的驅動是如何編寫的自己區別
3)設備號結構類型以及申請方式
l在內核中, dev_t類型(在中定義)用來持有設備編號,對於2.6.0內核, dev_t是32位的量, 12位用作主編號, 20位用作次編號.
l能獲得一個dev_t的主或者次編號方式:
MAJOR(dev_t dev); //主要
MINOR(dev_t dev);//次要
l但是如果你有主次編號,需要將其轉換為一個dev_t,使用: MKDEV(int major, int minor);
4)怎麼在程序中分配和釋放設備號
在建立一個字元驅動時需要做的第一件事是獲取一個或多個設備編號來使用.可以達到此功能的函數有兩個:
l一個是你自己事先知道設備號的
register_chrdev_region,在中聲明:
int register_chrdev_region(dev_t first, unsigned int count, char *name);
first是你要分配的起始設備編號. first的次編號部分常常是0,count是你請求的連續設備編號的總數. name是應當連接到這個編號范圍的設備的名子;它會出現在/proc/devices和sysfs中.
l第二個是動態動態分配設備編號
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
使用這個函數, dev是一個只輸出的參數,它在函數成功完成時持有你的分配范圍的第一個數. fisetminor應當是請求的第一個要用的次編號;它常常是0. count和name參數如同給request_chrdev_region的一樣.
5)設備編號的釋放使用
不管你是採用哪些方式分配的設備號。使用之後肯定是要釋放的,其方式如下:
void unregister_chrdev_region(dev_t first, unsigned int count);
6)
2.驅動程序的二個最重要數據結構
1)file_operation
倒如字元設備scull的一般定義如下:
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
.ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};
file_operation也稱為設備驅動程序介面
定義在,是一個函數指針的集合.每個打開文件(內部用一個file結構來代表)與它自身的函數集合相關連(通過包含一個稱為f_op的成員,它指向一個file_operations結構).這些操作大部分負責實現系統調用,因此,命名為open, read,等等
2)File
定義位於include/fs.h
struct file結構與驅動相關的成員
lmode_t f_mode標識文件的讀寫許可權
lloff_t f_pos當前讀寫位置
lunsigned int_f_flag文件標志,主要進行阻塞/非阻塞型操作時檢查
lstruct file_operation * f_op文件操作的結構指針
lvoid * private_data驅動程序一般將它指向已經分配的數據
lstruct dentry* f_dentry文件對應的目錄項結構
3.字元設備注冊
1)內核在內部使用類型struct cdev的結構來代表字元設備.在內核調用你的設備操作前,必須編寫分配並注冊一個或幾個這些結構.有2種方法來分配和初始化一個這些結構.
l如果你想在運行時獲得一個獨立的cdev結構,可以這樣使用:
struct cdev *my_cdev = cdev_alloc();
my_cdev->ops = &my_fops;
l如果想將cdev結構嵌入一個你自己的設備特定的結構;你應當初始化你已經分配的結構,使用:
void cdev_init(struct cdev *cdev, struct file_operations *fops);
2)一旦cdev結構建立,最後的步驟是把它告訴內核,調用:
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
說明:dev是cdev結構, num是這個設備響應的第一個設備號, count是應當關聯到設備的設備號的數目.常常count是1,但是有多個設備號對應於一個特定的設備的情形.
3)為從系統去除一個字元設備,調用:
void cdev_del(struct cdev *dev);
4.open和release