chap6-1 嵌入式Linux驅(qū)動(dòng)程序開發(fā)_第1頁(yè)
chap6-1 嵌入式Linux驅(qū)動(dòng)程序開發(fā)_第2頁(yè)
chap6-1 嵌入式Linux驅(qū)動(dòng)程序開發(fā)_第3頁(yè)
chap6-1 嵌入式Linux驅(qū)動(dòng)程序開發(fā)_第4頁(yè)
chap6-1 嵌入式Linux驅(qū)動(dòng)程序開發(fā)_第5頁(yè)
已閱讀5頁(yè),還剩60頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、第6章 嵌入式Linux驅(qū)動(dòng)程序開發(fā)6.1 嵌入式Linux的設(shè)備管理Linux設(shè)備概述:塊設(shè)備:類似磁盤以記錄塊或扇區(qū)為單位,成塊進(jìn)行輸入/輸出的設(shè)備;字符設(shè)備:類似鍵盤以字符為單位,逐個(gè)進(jìn)行輸入/輸出的設(shè)備。網(wǎng)路設(shè)備:介于塊設(shè)備和字符設(shè)備之間的一種特殊設(shè)備。塊設(shè)備/字符設(shè)備n塊設(shè)備:僅支持面向塊的I/O操作,所有I/O操作都通過在內(nèi)核地址空間中的I/O緩沖區(qū)進(jìn)行,可以支持隨機(jī)存取的功能。文件系統(tǒng)通常都建立在塊設(shè)備上。n字符設(shè)備:支持面向字符的I/O操作,不經(jīng)過系統(tǒng)的快速緩存,要負(fù)責(zé)管理自己的緩沖區(qū)結(jié)構(gòu)。字符設(shè)備接口只支持順序存取的功能,一般不能進(jìn)行任意長(zhǎng)度的I/O請(qǐng)求,而是限制I/O請(qǐng)求的

2、長(zhǎng)度必須是設(shè)備要求的基本塊長(zhǎng)的倍數(shù)。n處理器與設(shè)備間數(shù)據(jù)交換方式查詢方式、 中斷方式 直接內(nèi)存存取(DMA)方式。1查詢方式 設(shè)備驅(qū)動(dòng)程序通過設(shè)備的I/O端口空間,以及存儲(chǔ)器空間完成數(shù)據(jù)的交換。n利用這些地址空間,驅(qū)動(dòng)程序可以向外設(shè)發(fā)送指定的操作指令。n驅(qū)動(dòng)程序在提交命令之后,開始查詢?cè)O(shè)備的狀態(tài)寄存器,當(dāng)狀態(tài)寄存器表明操作完成時(shí),驅(qū)動(dòng)程序可繼續(xù)后續(xù)處理。n優(yōu)點(diǎn):硬件開銷小,使用起來(lái)比較簡(jiǎn)單。 缺點(diǎn):CPU要不斷地查詢外設(shè)的狀態(tài),當(dāng)外設(shè)未準(zhǔn)備好時(shí),就只能循環(huán)等待,不能執(zhí)行其他程序,這樣就浪費(fèi)了CPU的大量時(shí)間,降低了處理器的利用率。中斷方式的原理當(dāng)CPU進(jìn)行主程序操作時(shí),外設(shè)的數(shù)據(jù)已存入端口的數(shù)

3、據(jù)輸入寄存器,或端口的數(shù)據(jù)輸出寄存器已空,此時(shí)由外設(shè)通過接口電路向CPU發(fā)出中斷請(qǐng)求信號(hào)。 CPU在滿足一定條件下,暫停執(zhí)行當(dāng)前正在執(zhí)行的主程序,轉(zhuǎn)入執(zhí)行相應(yīng)能夠進(jìn)行輸入/輸出操作的子程序,待輸入/輸出操作執(zhí)行完畢之后,CPU再返回并繼續(xù)執(zhí)行原來(lái)被中斷的主程序。 CPU就避免了把大量時(shí)間耗費(fèi)在等待、查詢外設(shè)狀態(tài)的操作上,使其工作效率得以大大提高。2中斷方式中斷響應(yīng)n能夠向CPU發(fā)出中斷請(qǐng)求的設(shè)備或事件稱為中斷源。中斷源向CPU發(fā)出中斷請(qǐng)求,若優(yōu)先級(jí)別最高,則CPU在滿足一定的條件時(shí),可中斷當(dāng)前程序的運(yùn)行,保護(hù)好被中斷的主程序的斷點(diǎn)及現(xiàn)場(chǎng)信息,然后根據(jù)中斷源提供的信息,找到中斷服務(wù)子程序的入口地

4、址,轉(zhuǎn)去執(zhí)行新的程序段,這就是中斷響應(yīng)。nCPU響應(yīng)中斷是有條件的,如內(nèi)部允許中斷、中斷未被屏蔽、當(dāng)前指令執(zhí)行完等。nCPU響應(yīng)中斷以后,就會(huì)中止當(dāng)前的程序,轉(zhuǎn)去執(zhí)行一個(gè)中斷服務(wù)子程序,以完成為相應(yīng)設(shè)備的服務(wù)。DMA可允許設(shè)備和系統(tǒng)內(nèi)存間在沒有處理器參與的情況下傳輸大量數(shù)據(jù)。 設(shè)備驅(qū)動(dòng)程序在利用DMA之前,需要選擇DMA通道并定義相關(guān)寄存器,以及數(shù)據(jù)的傳輸方向,即讀取或?qū)懭耄缓髮⒃O(shè)備設(shè)定為利用該DMA通道傳輸數(shù)據(jù)。 設(shè)備完成設(shè)置之后,可以立即利用該DMA通道在設(shè)備和系統(tǒng)的內(nèi)存之間傳輸數(shù)據(jù),傳輸完畢后產(chǎn)生中斷以便通知驅(qū)動(dòng)程序進(jìn)行后續(xù)處理。 在利用DMA進(jìn)行數(shù)據(jù)傳輸?shù)耐瑫r(shí),處理器仍然可以繼續(xù)執(zhí)行

5、指令。3直接訪問內(nèi)存(DMA)方式設(shè)備驅(qū)動(dòng)程序的概念 設(shè)備驅(qū)動(dòng)程序:處理和操作硬件控制器的軟件,本質(zhì)上,是內(nèi)核中具有最高特權(quán)級(jí)的、駐留內(nèi)存的、可共享的底層硬件處理例程。驅(qū)動(dòng)程序是內(nèi)核的一部分,是操作系統(tǒng)內(nèi)核與硬件設(shè)備的直接接口。驅(qū)動(dòng)程序屏蔽了硬件的細(xì)節(jié),完成以下功能: 對(duì)設(shè)備初始化和釋放; 對(duì)設(shè)備進(jìn)行管理,包括實(shí)時(shí)參數(shù)設(shè)置,以及提供對(duì)設(shè)備的操作接口; 讀取應(yīng)用程序傳送給設(shè)備文件的數(shù)據(jù)或者回送應(yīng)用程序請(qǐng)求的數(shù)據(jù); 檢測(cè)和處理設(shè)備出現(xiàn)的錯(cuò)誤。Linux設(shè)備驅(qū)動(dòng)程序Linux操作系統(tǒng)將所有的設(shè)備全部看成文件,并通過文件的操作界面進(jìn)行操作。對(duì)用戶程序而言,設(shè)備驅(qū)動(dòng)程序隱藏了設(shè)備的具體細(xì)節(jié),對(duì)各種不同設(shè)

6、備提供了一致的接口,一般來(lái)說(shuō),是把設(shè)備映射為一個(gè)特殊的設(shè)備文件。設(shè)備文件的屬性由三部分信息組成:第一部分是文件的類型,第二部分是一個(gè)主設(shè)備號(hào),第三部分是一個(gè)次設(shè)備號(hào)。 其中類型和主設(shè)備號(hào)結(jié)合在一起惟一地確定了設(shè)備文件驅(qū)動(dòng)程序及其界面,而次設(shè)備號(hào)則說(shuō)明目標(biāo)設(shè)備是同類設(shè)備中的第幾個(gè)。Linux設(shè)備驅(qū)動(dòng)程序Linux 中將設(shè)備當(dāng)做文件處理,對(duì)設(shè)備進(jìn)行操作的系統(tǒng)調(diào)用格式與對(duì)文件的操作類似,主要包括open()、read()、write()、ioctl()、close()等。應(yīng)用程序發(fā)出系統(tǒng)調(diào)用命令后,從用戶態(tài)轉(zhuǎn)到核心態(tài),通過內(nèi)核將系統(tǒng)調(diào)用轉(zhuǎn)換成對(duì)物理設(shè)備的操作。這意味著: 由于每一個(gè)設(shè)備至少由文件系統(tǒng)

7、的一個(gè)文件代表,因而都有一個(gè)“文件名”。 應(yīng)用程序通??梢酝ㄟ^系統(tǒng)調(diào)用open()打開設(shè)備文件,建立起與目標(biāo)設(shè)備的連接。 打開了代表著目標(biāo)設(shè)備的文件,即建立起與設(shè)備的連接后,可以通過read()、write()、ioctl()等常規(guī)的文件操作對(duì)目標(biāo)設(shè)備進(jìn)行操作。 驅(qū)動(dòng)程序結(jié)構(gòu) 1自動(dòng)配置和初始化子程序,用來(lái)檢測(cè)所需驅(qū)動(dòng)的硬件設(shè)備是否工作正常、對(duì)正常工作的設(shè)備及其相關(guān)驅(qū)動(dòng)程序所需要的軟件狀態(tài)進(jìn)行初始化。2服務(wù)于I/O請(qǐng)求的子程序,該子程序稱為驅(qū)動(dòng)程序的上半部。這部分程序在執(zhí)行時(shí),系統(tǒng)仍認(rèn)為與進(jìn)行調(diào)用的進(jìn)程屬于同一個(gè)進(jìn)程,只是由用戶態(tài)變成了核心態(tài),可在其中調(diào)用sleep()等與進(jìn)程運(yùn)行環(huán)境有關(guān)的函

8、數(shù)。3中斷服務(wù)程序,又稱為驅(qū)動(dòng)程序的下半部,由Linux系統(tǒng)來(lái)接收硬件中斷,再由系統(tǒng)調(diào)用中斷服務(wù)子程序。在系統(tǒng)內(nèi)部,I/O設(shè)備的存取通過一組固定的入口點(diǎn)來(lái)進(jìn)行,入口點(diǎn)也可以理解為設(shè)備的句柄,就是對(duì)設(shè)備進(jìn)行操作的基本函數(shù)。 驅(qū)動(dòng)程序結(jié)構(gòu) 字符型設(shè)備驅(qū)動(dòng)程序入口點(diǎn): open入口點(diǎn)。打開設(shè)備準(zhǔn)備I/O操作。open子程序必須對(duì)將要進(jìn)行的I/O操作做好必要的準(zhǔn)備工作,如清除緩沖區(qū)等。如果設(shè)備是獨(dú)占的,即同一時(shí)刻只能有一個(gè)程序訪問此設(shè)備,則open子程序必須設(shè)置一些標(biāo)志以表示設(shè)備處于忙狀態(tài)。 close入口點(diǎn)。關(guān)閉一個(gè)設(shè)備。當(dāng)最后一次使用設(shè)備完成后,調(diào)用close子程序。獨(dú)占設(shè)備必須標(biāo)記設(shè)備方可再次使

9、用。字符型設(shè)備驅(qū)動(dòng)程序入口點(diǎn):nioctl入口點(diǎn)。執(zhí)行讀、寫之外的操作。n select入口點(diǎn)。檢查設(shè)備,看數(shù)據(jù)是否可讀或設(shè)備是否可用于寫數(shù)據(jù)。select系統(tǒng)調(diào)用在檢查與設(shè)備文件相關(guān)的文件描述符時(shí)使用select入口點(diǎn)。 阻塞struct struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char *, size_t, loff_t *);ssize_t (*write) (struct file *, const char *, size_t,

10、 loff_t *);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int

11、 (*flush) (struct file *);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, struct dentry *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct *);ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);ssiz

12、e_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *,unsigned long, unsigned long, unsigned long, unsigned long); lseek,移動(dòng)文件指針的位置,只能用于可以隨機(jī)存取的設(shè)備。 rea

13、d,進(jìn)行讀操作,buf為存放讀取結(jié)果的緩沖區(qū),count為所要讀取的數(shù)據(jù)長(zhǎng)度。 write,進(jìn)行寫操作,與read類似。 select,進(jìn)行選擇操作。 ioctl,進(jìn)行讀、寫以外的其他操作。 mmap,用于把設(shè)備的內(nèi)容映射到地址空間,一般只有塊設(shè)備驅(qū)動(dòng)程序使用。 open,打開設(shè)備進(jìn)行I/O操作。返回0表示成功,返回負(fù)數(shù)表示失敗。 release,即close 操作。 struct inode稱做索引節(jié)點(diǎn)數(shù)據(jù)結(jié)構(gòu),定義如下:struct inode struct list_head i_hash;struct list_head i_list;struct list_head i_dentry

14、;struct list_head i_dirty_buffers;struct list_head i_dirty_data_buffers;unsigned longi_ino;atomic_ti_count;kdev_ti_dev;umode_ti_mode;nlink_ti_nlink;uid_ti_uid;gid_ti_gid;kdev_ti_rdev;loff_ti_size;time_ti_atime;time_ti_mtime;time_ti_ctime;unsigned inti_blkbits;unsigned longi_blksize;unsigned longi_bl

15、ocks;unsigned longi_version;struct semaphorei_sem;struct semaphorei_zombie;struct inode_operations*i_op;struct *i_fop;struct super_block*i_sb;wait_queue_head_ti_wait;struct *i_flock;struct address_space*i_mapping;struct address_spacei_data;struct dquot*i_dquotMAXQUOTAS;struct list_head i_devices;str

16、uct pipe_inode_info*i_pipe;struct block_device*i_bdev;struct char_device*i_cdev;unsigned longi_dnotify_mask; struct dnotify_struct*i_dnotify; unsigned longi_state;unsigned inti_flags;unsigned chari_sock;atomic_ti_writecount;unsigned inti_attr_flags;_u32i_generation;union struct minix_inode_infominix

17、_i; struct ext2_inode_infoext2_i; struct ext3_inode_infoext3_i; struct hpfs_inode_infohpfs_i; struct ntfs_inode_infontfs_i; struct msdos_inode_infomsdos_i; struct umsdos_inode_infoumsdos_i; struct iso_inode_infoisofs_i; struct nfs_inode_infonfs_i; struct sysv_inode_infosysv_i; struct affs_inode_info

18、affs_i; struct ufs_inode_infoufs_i; struct efs_inode_infoefs_i; struct romfs_inode_inforomfs_i; struct shmem_inode_infoshmem_i; struct coda_inode_infocoda_i; struct smb_inode_infosmbfs_i; struct hfs_inode_infohfs_i; struct adfs_inode_infoadfs_i; struct qnx4_inode_infoqnx4_i; struct reiserfs_inode_in

19、foreiserfs_i; struct bfs_inode_infobfs_i; struct udf_inode_infoudf_i; struct ncp_inode_infoncpfs_i; struct proc_inode_infoproc_i; struct socketsocket_i; struct usbdev_inode_info usbdev_i; struct jffs2_inode_infojffs2_i; void*generic_ip; u; struct file主要用于與文件系統(tǒng)相關(guān)的設(shè)備驅(qū)動(dòng)程序,可提供關(guān)于被打開的文件的信息,定義如下:struct fil

20、e struct list_headf_list;struct dentry*f_dentry;struct vfsmount *f_vfsmnt;struct *f_op;atomic_tf_count;unsigned int f_flags;mode_tf_mode;loff_tf_pos;unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;struct fown_structf_owner;unsigned intf_uid, f_gid;intf_error;unsigned longf_version;/* neede

21、d for tty driver, and maybe others */void*private_data;/* preallocated helper kiobuf to speedup O_DIRECT */struct kiobuf*f_iobuf;longf_iobuf_lock;struct file struct *f_op;.;在用戶自己的驅(qū)動(dòng)程序中,首先要根據(jù)驅(qū)動(dòng)程序的功能,完成結(jié)構(gòu)中函數(shù)的實(shí)現(xiàn)。不需要的函數(shù)接口可以直接在結(jié)構(gòu)中初始化為NULL。中的變量會(huì)在驅(qū)動(dòng)程序初始化時(shí),注冊(cè)到系統(tǒng)內(nèi)部。每個(gè)進(jìn)程對(duì)設(shè)備的操作,都會(huì)根據(jù)主次設(shè)備號(hào),轉(zhuǎn)換成對(duì)結(jié)構(gòu)的訪問。 6.2 設(shè)備驅(qū)動(dòng)程序的

22、開發(fā)過程進(jìn)行嵌入式Linux系統(tǒng)的開發(fā),很大的工作量是為各種設(shè)備編寫驅(qū)動(dòng)程序。除非系統(tǒng)不使用操作系統(tǒng),程序直接操縱硬件。 嵌入式Linux系統(tǒng)驅(qū)動(dòng)程序開發(fā)與普通Linux開發(fā)沒有區(qū)別。可以在硬件生產(chǎn)廠家或者Internet上尋找驅(qū)動(dòng)程序,也可以根據(jù)相近的硬件驅(qū)動(dòng)程序來(lái)改寫,可以加快開發(fā)速度。6.2嵌入式Linux設(shè)備驅(qū)動(dòng)的開發(fā)流程:(1)查看原理圖,理解設(shè)備的工作原理。一般嵌入式處理器的生產(chǎn)商提供參考電路,也可以根據(jù)需要自行設(shè)計(jì)。(2)定義設(shè)備號(hào)。設(shè)備由一主設(shè)備號(hào)和一次設(shè)備號(hào)標(biāo)識(shí)。主設(shè)備號(hào)惟一標(biāo)識(shí)了設(shè)備類型,即設(shè)備驅(qū)動(dòng)程序類型,它是塊設(shè)備表或字符設(shè)備表中設(shè)備表項(xiàng)的索引。次設(shè)備號(hào)僅由設(shè)備驅(qū)動(dòng)程序

23、解釋,區(qū)分被一設(shè)備驅(qū)動(dòng)控制下的某個(gè)獨(dú)立設(shè)備。(3)實(shí)現(xiàn)初始化函數(shù)。在驅(qū)動(dòng)程序中實(shí)現(xiàn)驅(qū)動(dòng)的注冊(cè)和卸載。(4)設(shè)計(jì)所要實(shí)現(xiàn)的文件操作,定義結(jié)構(gòu)。(5)實(shí)現(xiàn)所需的系統(tǒng)調(diào)用,如read、write等。(6)實(shí)現(xiàn)中斷服務(wù),并用request_irq向內(nèi)核注冊(cè),并不是每個(gè)設(shè)備驅(qū)動(dòng)所必需的。(7)編譯該驅(qū)動(dòng)程序到內(nèi)核中,或者用insmod命令加載模塊。(8)測(cè)試該設(shè)備,編寫應(yīng)用程序,對(duì)驅(qū)動(dòng)程序進(jìn)行測(cè)試。 模塊化驅(qū)動(dòng)程序設(shè)計(jì) 內(nèi)核模塊與應(yīng)用程序之間的區(qū)別。一個(gè)應(yīng)用從頭到尾完成一個(gè)任務(wù),而模塊則是為以后處理某些請(qǐng)求而注冊(cè)自己,完成這個(gè)任務(wù)后,它的“主”函數(shù)就立即中止了。內(nèi)核源碼僅能連接編譯到內(nèi)核模塊中,不像應(yīng)用

24、那樣有眾多的支持庫(kù),內(nèi)核能調(diào)用的僅是由內(nèi)核開放出來(lái)的那些函數(shù)。由于沒有庫(kù)連接到模塊中,所以源碼文件不應(yīng)該模塊化任何常規(guī)頭文件。與內(nèi)核有關(guān)的所有內(nèi)容都定義在目錄/usr/include/linux和/usr/include/asm下的頭文件中。模塊化驅(qū)動(dòng)程序設(shè)計(jì) 1內(nèi)核空間和用戶空間到軟件稱執(zhí)行態(tài)分為“內(nèi)核空間”和“用戶空間”。在Linux系統(tǒng)中,內(nèi)核在最高級(jí)執(zhí)行,也稱為“管理員態(tài)”,在這一級(jí)任何操作都可以執(zhí)行。而應(yīng)用程序則執(zhí)行在最低級(jí),所謂的“用戶態(tài)”,在這一級(jí)處理器禁止對(duì)硬件的直接訪問和對(duì)內(nèi)存的未授權(quán)訪問。模塊是在所謂的“內(nèi)核空間”中運(yùn)行的,而應(yīng)用程序則是在“用戶空間”中運(yùn)行的。它們分別引用

25、不同的內(nèi)存映射,也就是程序代碼使用不同的“地址空間”。Linux通過系統(tǒng)調(diào)用和硬件中斷完成從用戶空間到內(nèi)核空間的控制轉(zhuǎn)移。執(zhí)行系統(tǒng)調(diào)用的內(nèi)核代碼在進(jìn)程的上下文中執(zhí)行,它執(zhí)行調(diào)用進(jìn)程的操作而且可以訪問進(jìn)程地址空間的數(shù)據(jù)。各個(gè)模塊被分別編譯并鏈接成一組目標(biāo)文件,這些文件能被載入正在運(yùn)行的內(nèi)核,或從正在運(yùn)行的內(nèi)核中卸載。必要時(shí)內(nèi)核能請(qǐng)求內(nèi)核守護(hù)進(jìn)程Kerneld對(duì)模塊進(jìn)行加載或卸載。內(nèi)核模塊一部分保存在Kernel中,另一部分在Modules包中。內(nèi)核提供一個(gè)插槽,它就像一個(gè)插件,在需要時(shí),插入內(nèi)核中使用,不需要時(shí)從內(nèi)核中拔出。這一切都由一個(gè)稱為Kerneld的守護(hù)進(jìn)程自動(dòng)處理。根據(jù)需要?jiǎng)討B(tài)載入模塊

26、可以保證內(nèi)核達(dá)到最小,并且具有很大的靈活性。2模塊化的優(yōu)缺點(diǎn)優(yōu)點(diǎn):將內(nèi)核映像的尺寸保持在最小,并具有最大的靈活性。這便于檢驗(yàn)新的內(nèi)核代碼,而不需要重新編譯內(nèi)核并重新引導(dǎo)。對(duì)系統(tǒng)性能和內(nèi)存的利用有負(fù)面影響。裝入的內(nèi)核模塊與其他內(nèi)核部分一樣,具有相同的訪問權(quán)限,由此可見,差的內(nèi)核模塊會(huì)導(dǎo)致系統(tǒng)崩潰。為了使內(nèi)核模塊能訪問所有內(nèi)核資源,內(nèi)核必須維護(hù)符號(hào)表,并在加載和卸載模塊時(shí)修改這些符號(hào)表。由于有些模塊要求利用其他模塊的功能,故內(nèi)核要維護(hù)模塊之間的依賴性。內(nèi)核必須能夠在卸載模塊時(shí)通知模塊,并且要釋放分配給模塊的內(nèi)存和中斷等資源。內(nèi)核版本和模塊版本的不兼容也可能導(dǎo)致系統(tǒng)崩潰,因此,嚴(yán)格的版本檢查是必需的

27、。模塊機(jī)制確實(shí)是擴(kuò)充內(nèi)核功能的一種行之有效的方法,也是在內(nèi)核級(jí)進(jìn)行編程的有效途徑。 設(shè)備注冊(cè)和初始化 設(shè)備的驅(qū)動(dòng)程序在加載的時(shí)候首先需要調(diào)用入口函數(shù)init_module(),該函數(shù)最重要的一個(gè)工作就是向內(nèi)核注冊(cè)該設(shè)備。 對(duì)于字符設(shè)備調(diào)用register_chrdev()完成注冊(cè)。 int register_chrdev(unsigned int major, const char *name, struct file_ operations *fops);major向系統(tǒng)申請(qǐng)的主設(shè)備號(hào),為0,系統(tǒng)動(dòng)態(tài)分配一主設(shè)備號(hào)。name是設(shè)備名,fops是對(duì)各個(gè)調(diào)用的入口點(diǎn)說(shuō)明。函數(shù)返回值 0時(shí)表示成功

28、;-EINVAL,表示申請(qǐng)的主設(shè)備號(hào)非法,主設(shè)備號(hào)大于系統(tǒng)所允許的最大設(shè)備號(hào);-EBUSY,所申請(qǐng)的主設(shè)備號(hào)正在被其他設(shè)備程序使用。如果動(dòng)態(tài)分配主設(shè)備號(hào)成功,此函數(shù)將返回所分配的主設(shè)備號(hào)。如果register_chrdev()操作成功,設(shè)備名就會(huì)出現(xiàn)在/proc/dvices文件中。用mknod命令來(lái)把設(shè)備映射為一特別文件,其它程序使用這個(gè)設(shè)備的時(shí)候,只要對(duì)此特別文件進(jìn)行操作 設(shè)備注冊(cè)和初始化 Linux在/dev目錄中為每個(gè)設(shè)備建立一個(gè)文件,用ls l命令列出。注冊(cè)以后,Linux將設(shè)備名與主、次設(shè)備號(hào)聯(lián)系起來(lái)。當(dāng)有對(duì)此設(shè)備名的訪問時(shí),Linux通過請(qǐng)求訪問的設(shè)備名得到主、次設(shè)備號(hào),然后把此

29、訪問分發(fā)到對(duì)應(yīng)的設(shè)備驅(qū)動(dòng),設(shè)備驅(qū)動(dòng)再根據(jù)次設(shè)備號(hào)調(diào)用不同的函數(shù)。當(dāng)設(shè)備驅(qū)動(dòng)模塊從Linux內(nèi)核中卸載,對(duì)應(yīng)的主設(shè)備號(hào)必須被釋放。字符設(shè)備在cleanup_ module()函數(shù)中調(diào)用unregister_chrdev()來(lái)完成設(shè)備的注銷。int unregister_chrdev(unsigned int major, const char *name);Linux內(nèi)核把name和major在內(nèi)核注冊(cè)的名稱對(duì)比,如果不相等,卸載失敗,并返回EINVAL;如果major大于最大的設(shè)備號(hào),也返回EINVAL。 設(shè)備驅(qū)動(dòng)的初始化函數(shù)主要完成功能(1)對(duì)驅(qū)動(dòng)程序管理的硬件進(jìn)行必要的初始化。對(duì)硬件寄存器

30、進(jìn)行設(shè)置。比如,設(shè)置中斷掩碼,設(shè)置串口的工作方式、并口的數(shù)據(jù)方向等。(2)初始化設(shè)備驅(qū)動(dòng)相關(guān)的參數(shù)。一般說(shuō)來(lái),每個(gè)設(shè)備都要定義一個(gè)設(shè)備變量,用以保存設(shè)備相關(guān)的參數(shù)。在這一步驟里對(duì)設(shè)備變量中的項(xiàng)進(jìn)行初始化。(3)在內(nèi)核注冊(cè)設(shè)備。調(diào)用register_chrdev()函數(shù)來(lái)注冊(cè)設(shè)備。(4)注冊(cè)中斷。如果設(shè)備需要IRQ支持,則要使用request_irq()函數(shù)注冊(cè)中斷。設(shè)備驅(qū)動(dòng)的初始化函數(shù)主要完成功能(5)其他初始化工作。初始化部分一般還負(fù)責(zé)給設(shè)備驅(qū)動(dòng)程序申請(qǐng)包括內(nèi)存、時(shí)鐘、I/O端口等在內(nèi)的系統(tǒng)資源,這些資源也可以在open子程序或者其他地方申請(qǐng)。這些資源不用時(shí),應(yīng)該釋放,以利于資源的共享。若驅(qū)

31、動(dòng)程序是內(nèi)核的一部分,初始化函數(shù)則要按如下方式聲明:int _init chr_driver_init(void);其中_init是必不可少的,在系統(tǒng)啟動(dòng)時(shí)會(huì)由內(nèi)核調(diào)用chr_driver_init,完成驅(qū)動(dòng)程序的初始化。當(dāng)驅(qū)動(dòng)程序是以模塊的形式編寫時(shí),則要按照如下方式聲明:int init_module(void)當(dāng)運(yùn)行后面介紹的insmod命令插入模塊時(shí),會(huì)調(diào)用init_module函數(shù)完成初始化工作。 中斷管理 設(shè)備驅(qū)動(dòng)程序通過調(diào)用request_irq函數(shù)來(lái)申請(qǐng)中斷,通過free_irq來(lái)釋放中斷。它們?cè)趌inux/sched.h中的定義如下:int request_irq(unsig

32、ned int irq,void (*handler)(int irq,void dev_id,struct pt_regs *regs),unsigned long flags,const char *device,void *dev_id);void free_irq(unsigned int irq, void *dev_id);通常從request_irq函數(shù)返回的值為0時(shí),表示申請(qǐng)成功;負(fù)值表示出現(xiàn)錯(cuò)誤。 irq表示所要申請(qǐng)的硬件中斷號(hào)。 handler為向系統(tǒng)登記的中斷處理子程序,中斷產(chǎn)生時(shí)由系統(tǒng)來(lái)調(diào)用,調(diào)用時(shí)所帶參數(shù)irq為中斷號(hào),dev_id為申請(qǐng)時(shí)告訴系統(tǒng)的設(shè)備標(biāo)識(shí),regs

33、為中斷發(fā)生時(shí)寄存器內(nèi)容。 device為設(shè)備名,將會(huì)出現(xiàn)在/proc/interrupts文件里。 flag是申請(qǐng)時(shí)的選項(xiàng),它決定中斷處理程序的一些特性,其中最重要的是決定中斷處理程序是快速處理程序(flag里設(shè)置了SA_INTERRUPT)還是慢速處理程序(不設(shè)置SA_INTERRUPT)。下面的代碼將在SBC-2410X的Linux中注冊(cè)外部中斷2。eint_irq = IRQ_EINT2;set_external_irq (eint_irq, EXT_FALLING_EDGE,GPIO_PULLUP_DIS);ret_val = request_irq(eint_irq,eint2_ha

34、ndler, “S3C2410X eint2”,0);if(ret_val 0)return ret_val;用來(lái)打開和關(guān)閉中斷的函數(shù)如下:#define cli() _asm_ _volatile_ (cli:)#define sli() _asm_ _volatile_ (sli:) 中斷管理 設(shè)備驅(qū)動(dòng)程序通過調(diào)用request_irq函數(shù)來(lái)申請(qǐng)中斷,通過free_irq來(lái)釋放中斷。在linux/sched.h中定義:int request_irq(unsigned int irq, /*所要申請(qǐng)的硬件中斷號(hào)*/void (*handler)(int irq,void dev_id,str

35、uct pt_regs *regs),unsigned long flags, /*申請(qǐng)時(shí)的選項(xiàng) SA_INTERRUPT快速處理程序*/const char *device, /*設(shè)備名,出現(xiàn)在/proc/interrupts文件*/void *dev_id );void free_irq(unsigned int irq, void *dev_id);通常從request_irq函數(shù)返回的值為0時(shí),表示申請(qǐng)成功;負(fù)值表示出現(xiàn)錯(cuò)誤。 handler為向系統(tǒng)登記的中斷處理子程序,中斷產(chǎn)生時(shí)由系統(tǒng)來(lái)調(diào)用,調(diào)用時(shí)所帶參數(shù)irq為中斷號(hào),dev_id為申請(qǐng)時(shí)告訴系統(tǒng)的設(shè)備標(biāo)識(shí),regs為中斷發(fā)生時(shí)寄

36、存器內(nèi)容。 設(shè)備驅(qū)動(dòng)開發(fā)的基本函數(shù) 1I/O口函數(shù)無(wú)論驅(qū)動(dòng)程序多么復(fù)雜,歸根結(jié)底,無(wú)非還是向某個(gè)端口或者某個(gè)寄存器位賦值,這個(gè)值只能是0或1。接收值的就是I/O口。與中斷和內(nèi)存不同,使用一個(gè)沒有申請(qǐng)的I/O端口不會(huì)使處理器產(chǎn)生異常,也就不會(huì)導(dǎo)致諸如“segmentation fault”一類的錯(cuò)誤發(fā)生。 由于任何進(jìn)程都可以訪問任何一個(gè)I/O端口,此時(shí)系統(tǒng)無(wú)法保證對(duì)I/O端口的操作不會(huì)發(fā)生沖突,甚至因此而使系統(tǒng)崩潰。因此,在使用I/O端口前,也應(yīng)該檢查此I/O端口是否已有別的程序在使用,若沒有,再把此端口標(biāo)記為正在使用,在使用完以后釋放它。 設(shè)備驅(qū)動(dòng)開發(fā)的基本函數(shù) 1I/O口函數(shù)需要用到如下幾個(gè)

37、函數(shù):int check_region(unsigned int from, unsigned int extent);void request_region(unsigned int from, unsigned int extent,const char *name);void release_region(unsigned int from, unsigned int extent); from表示所申請(qǐng)的I/O端口的起始地址; extent為所要申請(qǐng)的從from開始的端口數(shù); name為設(shè)備名,將會(huì)出現(xiàn)在/proc/ioports文件里; check_region返回0表示I/O端口空

38、閑,否則為正在被使用。在申請(qǐng)了I/O端口之后,可以借助asm/io.h中的如下幾個(gè)函數(shù)來(lái)訪問I/O端口:inline unsigned int inb(unsigned short port);inline unsigned int inb_p(unsigned short port);inline void outb(char value, unsigned short port);inline void outb_p(char value, unsigned short port);其中inb_p和outb_p插入一定延時(shí)適應(yīng)低速的I/O端口。 2時(shí)鐘函數(shù)在設(shè)備驅(qū)動(dòng)程序中,一般都需要用到計(jì)

39、時(shí)機(jī)制。在Linux系統(tǒng)中,時(shí)鐘是由系統(tǒng)接管的,設(shè)備驅(qū)動(dòng)程序可以向系統(tǒng)申請(qǐng)時(shí)鐘。與時(shí)鐘有關(guān)的系統(tǒng)調(diào)用有:#include #include void add_timer(struct timer_list * timer);int del_timer(struct timer_list * timer);inline void init_timer(struct timer_list * timer);struct timer_list的定義為:struct timer_list struct timer_list *next;struct timer_list *prev;unsigned

40、long expires;unsigned long data;void (*function)(unsigned long d);其中,expires是要執(zhí)行function的時(shí)間。系統(tǒng)計(jì)時(shí)到預(yù)定時(shí)間就調(diào)用function,并把此子程序從定時(shí)隊(duì)列里刪除,可見,如果想要每隔一定時(shí)間間隔執(zhí)行一次的話,就必須在function里再一次調(diào)用add_timer。function的參數(shù)d即為timer里面的data項(xiàng)。 n定時(shí)機(jī)制系統(tǒng)核心有一個(gè)全局變量jiffies表示當(dāng)前時(shí)間,一般在調(diào)用add_timer時(shí)jiffies=JIFFIES+num,表示在num個(gè)系統(tǒng)最小時(shí)間間隔后執(zhí)行function函數(shù)

41、。系統(tǒng)最小時(shí)間間隔與所用的硬件平臺(tái)有關(guān),在核心里定義了常數(shù)HZ表示一秒內(nèi)最小時(shí)間間隔的數(shù)目,則num*HZ表示num秒。3內(nèi)存操作函數(shù)作為系統(tǒng)核心的一部分,設(shè)備驅(qū)動(dòng)程序在申請(qǐng)和釋放內(nèi)存時(shí)不是調(diào)用malloc和free,而代之以調(diào)用kmalloc和kfree,它們?cè)趌inux/kernel.h中被定義為:void * kmalloc(unsigned int len, int priority);void kfree(void * obj);參數(shù)len為希望申請(qǐng)的字節(jié)數(shù),obj為要釋放的內(nèi)存指針。priority為分配內(nèi)存操作的優(yōu)先級(jí),即在沒有足夠空閑內(nèi)存時(shí)如何操作,一般由取值GFP_KERNE

42、L解決即可。4復(fù)制函數(shù)在用戶程序調(diào)用read、write時(shí),因?yàn)檫M(jìn)程的運(yùn)行狀態(tài)由用戶態(tài)變?yōu)楹诵膽B(tài),地址空間也變?yōu)楹诵牡刂房臻g。由于read、write中參數(shù)buf是指向用戶程序的私有地址空間的,所以不能直接訪問,必須通過下面兩個(gè)系統(tǒng)函數(shù)來(lái)訪問用戶程序的私有地址空間。#include void memcpy_fromfs(void * to,const void * from,unsigned long n);由用戶程序地址空間往核心地址空間復(fù)制void memcpy_tofs(void * to,const void * from,unsigned long n);由核心地址空間往用戶程序地址

43、空間復(fù)制參數(shù)to為復(fù)制的目的指針,from為源指針,n為要復(fù)制的字節(jié)數(shù)。在設(shè)備驅(qū)動(dòng)程序里,可以調(diào)用printk來(lái)打印一些調(diào)試信息,printk的用法與printf類似。printk打印的信息不僅出現(xiàn)在屏幕上,同時(shí)還記錄在文件syslog里。 加載和卸載驅(qū)動(dòng)程序 1入口函數(shù)在編寫模塊程序時(shí),必須提供兩個(gè)函數(shù),int init_module(),在加載此模塊時(shí)自動(dòng)調(diào)用,負(fù)責(zé)進(jìn)行設(shè)備驅(qū)動(dòng)程序的初始化工作。init_module()返回0,表示初始化成功,返回負(fù)數(shù)表示失敗,它在內(nèi)核中注冊(cè)一定的功能函數(shù)。在注冊(cè)之后,如果有程序訪問內(nèi)核模塊的某個(gè)功能,內(nèi)核將查表獲得該功能的位置,然后調(diào)用功能函數(shù)。init

44、_module()的任務(wù)就是為以后調(diào)用模塊的函數(shù)做準(zhǔn)備。void cleanup_module(),在模塊被卸載時(shí)調(diào)用,負(fù)責(zé)進(jìn)行設(shè)備驅(qū)動(dòng)程序的清除工作。這個(gè)函數(shù)的功能是取消init_module()所做的事情,把init_module()函數(shù)在內(nèi)核中注冊(cè)的功能函數(shù)完全卸載,如果沒有完全卸載,在此模塊下次調(diào)用時(shí),將會(huì)因?yàn)橛兄孛暮瘮?shù)而導(dǎo)致調(diào)入失敗。加載和卸載驅(qū)動(dòng)程序 1入口函數(shù)在2.3版本以上的Linux內(nèi)核中,提供了一種新的方法來(lái)命名這兩個(gè)函數(shù)。例如,可以定義init_my()代替init_module()函數(shù),定義exit_my()代替cleanup_module()函數(shù),然后在源代碼文件末

45、尾使用下面的語(yǔ)句:module_init(init_my);module_exit(exit_my);這樣做的好處是,每個(gè)模塊都可以有自己的初始化和卸載函數(shù)的函數(shù)名,多個(gè)模塊在調(diào)試時(shí)不會(huì)有重名的問題。 2模塊加載與卸載雖然模塊作為內(nèi)核的一部分,但并未被編譯到內(nèi)核中,它們被分別編譯和鏈接成目標(biāo)文件。Linux中模塊可以用C語(yǔ)言編寫,用gcc命令編譯成模塊*.o,在命令行里加上-c的參數(shù)和“-D_KERNEL_-DMODULE”參數(shù)。然后用depmod -a 使此模塊成為可加載模塊。模塊用insmod命令加載,用rmmod命令來(lái)卸載,這兩個(gè)命令分別調(diào)用init_module()和cleanup_

46、module()函數(shù),還可以用lsmod命令來(lái)查看所有已加載的模塊的狀態(tài)。insmod命令可將編譯好的模塊調(diào)入內(nèi)存。內(nèi)核模塊與系統(tǒng)中其他程序一樣是已鏈接的目標(biāo)文件,但不同的是它們被鏈接成可重定位映像。insmod將執(zhí)行一個(gè)特權(quán)級(jí)系統(tǒng)調(diào)用get_kernel_sysms()函數(shù)以找到內(nèi)核的輸出內(nèi)容,insmod修改模塊對(duì)內(nèi)核符號(hào)的引用后,將再次使用特權(quán)級(jí)系統(tǒng)調(diào)用create_module()函數(shù)來(lái)申請(qǐng)足夠的物理內(nèi)存空間,以保存新的模塊。內(nèi)核將為其分配一個(gè)新的module結(jié)構(gòu),以及足夠的內(nèi)核內(nèi)存,并將新模塊添加在內(nèi)核模塊鏈表的尾部,然后將新模塊標(biāo)記為uninitialized。利用rmmod命令可

47、以卸載模塊。如果內(nèi)核中還在使用此模塊,這個(gè)模塊就不能被卸載。原因是如果設(shè)備文件正被一個(gè)進(jìn)程打開就卸載還在使用的內(nèi)核模塊,并導(dǎo)致對(duì)內(nèi)核模塊的讀/寫函數(shù)所在內(nèi)存區(qū)域的調(diào)用。如果幸運(yùn),沒有其他代碼被加載到那個(gè)內(nèi)存區(qū)域,將得到一個(gè)錯(cuò)誤提示;否則,另一個(gè)內(nèi)核模塊被加載到同一區(qū)域,這就意味著程序跳到內(nèi)核中另一個(gè)函數(shù)的中間,結(jié)果是不可預(yù)見的。 2模塊加載與卸載6.3 LED驅(qū)動(dòng)程序設(shè)計(jì)LED接口設(shè)計(jì) S3C2410X提供了多達(dá)117個(gè)可編程的通用I/O端口,可以方便地輸入輸出各種信號(hào)。SBC-2410X目標(biāo)板選用S3C2410X微處理器,帶有4個(gè)用戶可編程I/O方式的LED,硬件原理圖如圖6.2所示,表6.

48、1為L(zhǎng)ED對(duì)應(yīng)的I/O口。LED控制采用低電平有效方式,當(dāng)端口電平為低時(shí)點(diǎn)亮LED指示燈,輸出高電平時(shí)LED熄滅。與LED相連的通用I/O端口由表6.3所示的控制寄存器配置。.#define GPIO_CTL_BASE0 x56000000 /*IO口控制寄存器及地址*/#define bGPIO(p) _REG(GPIO_CTL_BASE + (p) /*寄存器地址0X50000000p*/#define GPBCON bGPIO(0 x10) /*寄存器地址0X56000010*/#define GPBDAT bGPIO(0 x14) /*寄存器地址0X56000014*/#define

49、GPBUP bGPIO(0 x18) /*寄存器地址0X56000018*/.#define MAKE_GPIO_NUM(p, o)(p GPIO_PORT_SHIFTT) | (o GPIO_OFS_SHIFT)#define PORTB_OFS1#define GPIO_B7MAKE_GPIO_NUM(PORTB_OFS, 7) /*端口GPB7*/#define GPIO_B8MAKE_GPIO_NUM(PORTB_OFS, 8) /*端口GPB8*/#define GPIO_B9MAKE_GPIO_NUM(PORTB_OFS, 9) /*端口GPB9*/#define GPIO_B10

50、MAKE_GPIO_NUM(PORTB_OFS, 10) /*端口GBP10*/.#define GPCON(x)_REG2(0 x56000000, (x) * 0 x10) /*功能選擇寄存器地址*/#define GPDAT(x)_REG2(0 x56000004, (x) * 0 x10) /*數(shù)據(jù)寄存器地址*/#define GPUP(x)_REG2(0 x56000008, (x) * 0 x10) /*上拉電阻設(shè)置寄存器地址*/.#define GPIO_OFS_SHIFT0#define GPIO_PORT_SHIFTT 8#define GPIO_PULLUP_SHIFT 1

51、6 #define GPIO_MODE_SHIFT 24#define GPIO_OFS_MASK 0 x000000ff#define GPIO_PORT_MASK0 x0000ff00#define GPIO_PULLUP_MASK0 x00ff0000#define GPIO_MODE_MASK0 xff000000#define GPIO_MODE_IN(0 GPIO_MODE_SHIFT)#define GPIO_MODE_OUT(1 GPIO_MODE_SHIFT)#define GPIO_MODE_ALT0(2 GPIO_MODE_SHIFT)#define GPIO_MODE_

52、ALT1(3 GPIO_MODE_SHIFT)#define GPIO_PULLUP_EN(0 GPIO_PULLUP_SHIFT)#define GPIO_PULLUP_DIS(1 GPIO_MODE_SHIFT)#define GRAB_PULLUP(x)(x) & GPIO_PULLUP_MASK) GPIO_PULLUP_SHIFT)#define GRAB_PORT(x)(x) & GPIO_PORT_MASK) GPIO_PORT_SHIFTT)#define GRAB_OFS(x)(x) & GPIO_OFS_MASK) GPIO_OFS_SHIFT)./

53、*端口參數(shù)設(shè)置宏*/#define set_gpio_ctrl(x) ( GPCON(GRAB_PORT(x) &= (0 x3 (GRAB_OFS(x)*2); GPCON(GRAB_PORT(x) |= (GRAB_MODE(x) (GRAB_OFS(x)*2); GPUP(GRAB_PORT(x) &= (1 GRAB_OFS(x); GPUP(GRAB_PORT(x) |= (GRAB_PULLUP(x) GRAB_OFS(x); )#define set_gpio_pullup(x) ( GPUP(GRAB_PORT(x) &= (1 GRAB_OFS(x);

54、 GPUP(GRAB_PORT(x) |= (GRAB_PULLUP(x) GRAB_OFS(x); )#define set_gpio_pullup_user(x, v) ( GPUP(GRAB_PORT(x) &= (1 GRAB_OFS(x); GPUP(GRAB_PORT(x) |= (v) GRAB_OFS(x); )#define set_gpio_mode(x) ( GPCON(GRAB_PORT(x) &= (0 x3 (GRAB_OFS(x)*2); GPCON(GRAB_PORT(x) |= (GRAB_MODE(x) (GRAB_OFS(x)*2); )#

55、define set_gpio_mode_user(x, v) ( GPCON(GRAB_PORT(x) & = (0 x3 (GRAB_OFS(x)*2); GPCON(GRAB_PORT(x) |= (v) (GRAB_OFS(x)*2); )#define set_gpioA_mode(x) ( GPCON(GRAB_PORT(x) &= (0 x1 GRAB_OFS(x); GPCON(GRAB_PORT(x) |= (GRAB_MODE(x) GRAB_OFS(x); )#define read_gpio_bit(x)(GPDAT(GRAB_PORT(x) &

56、 (1 GRAB_OFS(x)#define read_gpio_reg(x)(GPDAT(GRAB_PORT(x)#define write_gpio_bit(x, v) ( GPDAT(GRAB_PORT(x) &= (0 x1 GRAB_OFS(x); GPDAT(GRAB_PORT(x) |= (v) GRAB_OFS(x); )#define write_gpio_reg(x, v)(GPDAT(GRAB_PORT(x) = (v)LED驅(qū)動(dòng)程序代碼分析 1系統(tǒng)資源和宏定義#define DEVICE_NAME leds /*定義led 設(shè)備的名字*/#define LED_

57、MAJOR 231 /*定義led 設(shè)備的主設(shè)備號(hào)*/static unsigned long led_table = /*I/O 方式led 設(shè)備對(duì)應(yīng)的硬件資源*/GPIO_B7,GPIO_B8,GPIO_B9,GPIO_B10,;2入口函數(shù)模塊的入口函數(shù)leds_init(),所做的工作是點(diǎn)亮I/O端口對(duì)應(yīng)的LED,這些二極管可以作為狀態(tài)指示之用。register_chrdev()完成字符設(shè)備在系統(tǒng)中的注冊(cè),并建立與文件系統(tǒng)的并聯(lián)。static int _init leds_init (void)int ret;int i;/*在內(nèi)核中注冊(cè)設(shè)備*/ret = register_chrdev

58、(LED_MAJOR, DEVICE_NAME, &leds_fops);if (ret 0) printk(DEVICE_NAME cant register major numbern);return ret;devfs_handle = devfs_register(NULL, DEVICE_NAME, DEVFS_FL_DEFAULT,LED_ MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, &matrix4_leds_fops,NULL);/*使用宏進(jìn)行端口初始化,set_gpio_ctrl 和write_gpio_bit 均為宏定義*/

59、for (i = 0; i 4) return -EINVAL;write_gpio_bit(led_tablearg, !cmd);default:return -EINVAL;5文件系統(tǒng)接口定義static struct leds_fops = owner: THIS_MODULE,ioctl: leds_ioctl,;6模塊化module_init(leds_init);module_exit(leds_exit);用insmod命令加載模塊時(shí),調(diào)用module_init();用rmmod命令來(lái)卸載模塊時(shí),調(diào)用module_exit()函數(shù)。 加載運(yùn)行LED驅(qū)動(dòng)程序 1應(yīng)用程序設(shè)計(jì)#in

60、clude #include #include #include int main(int argc, char *argv)int on;int led_no;int fd;if (argc != 3 | sscanf(argv1, %d, &led_no) != 1 | sscanf(argv2,%d, &on) != 1 |on 1 | led_no 3) fprintf(stderr, Usage: ledtest led_no 0|1n);exit(1);if (fd 0) perror(open device leds);exit(1);ioctl(fd,on,led_no);close(fd);return 0;該程序首先讀取命令行的參數(shù)輸入,其中參數(shù)argv1賦值給led_n

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論