LINUX字符設(shè)備驅(qū)動(dòng)編寫(xiě)基本流程_第1頁(yè)
LINUX字符設(shè)備驅(qū)動(dòng)編寫(xiě)基本流程_第2頁(yè)
LINUX字符設(shè)備驅(qū)動(dòng)編寫(xiě)基本流程_第3頁(yè)
LINUX字符設(shè)備驅(qū)動(dòng)編寫(xiě)基本流程_第4頁(yè)
LINUX字符設(shè)備驅(qū)動(dòng)編寫(xiě)基本流程_第5頁(yè)
已閱讀5頁(yè),還剩5頁(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、- 簡(jiǎn)介L(zhǎng)inux 下的 MISC 簡(jiǎn)單字符設(shè)備驅(qū)動(dòng)雖然使用簡(jiǎn)單,但卻不靈活。只能建立主設(shè)備號(hào)為 10 的設(shè)備文件。 字符設(shè)備比較容易理解, 同時(shí)也能夠滿足大多數(shù)簡(jiǎn) 單的硬件設(shè)備 , 字符設(shè)備通過(guò)文件系 統(tǒng)中的名字來(lái)讀取。這些名字就是文件系統(tǒng)中的特 殊文件或者稱為設(shè)備文件、 文件系統(tǒng)的簡(jiǎn)單結(jié)點(diǎn), 一般位于 /dev/ 目錄下 使用 ls 進(jìn)行查 看會(huì)顯示以 C 開(kāi)頭證明這是字符設(shè)備文件crw-w 1 root tty 4, 0 4 月 14 11:05 tty0 。第一個(gè)數(shù)字是主設(shè)備 號(hào),第二個(gè)數(shù)字是次設(shè)備號(hào)。- 分配和釋放設(shè)備編號(hào)1) 在 建 立 字 符 設(shè) 備 驅(qū) 動(dòng) 時(shí) 首 先 要 獲

2、取 設(shè) 備 號(hào) , 為 此 目 的 的 必 要 的 函 數(shù) 是 register_chrdev_region, 在 linux/fs.h 中 聲 明 : int register_chrdev_region(dev_t first, unsigned int count, char *name);first 是你想 要分配的起始設(shè)備編號(hào), first 的次編號(hào)通 常是 0,count 是你請(qǐng)求的連續(xù)設(shè)備編號(hào)的 總數(shù)。 count 如果太大會(huì)溢出到下一個(gè)主設(shè)備號(hào)中。 name 是設(shè)備的名字,他會(huì)出 現(xiàn)在 /proc/devices 和 sysfs 中。操作成功返回 0,如果失敗會(huì)返回一個(gè)負(fù)的錯(cuò)誤

3、碼。2) 如果明確知道設(shè)備號(hào)可用那么上一個(gè)方法可行,否則我們可以使用內(nèi)核動(dòng)態(tài)分配的設(shè) 備號(hào) int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name);dev 是個(gè)只輸出的參數(shù), firstminor 請(qǐng)求的第一個(gè)要用的次 編號(hào), count和name的作用如上1)對(duì)于新驅(qū)動(dòng),最好的方法是進(jìn)行動(dòng)態(tài)分配3) 釋放設(shè)備號(hào), void unregister_chrdev_region(dev_t first unsigned int count);- 文件操作 file_ope

4、rations 結(jié)構(gòu)體, 內(nèi)部連接了多個(gè)設(shè)備具體操作函數(shù)。 該變量?jī)?nèi)部 的函數(shù)指針指向驅(qū)動(dòng)程序中的具體操作,沒(méi)有對(duì)應(yīng)動(dòng)作的指針設(shè)置為NULL。1) fops的第一個(gè)成員是 struct module *owner 通常都是設(shè)置成 THIS_MODULElinux/module.h 中定義的宏。用來(lái)在他的操作還在被使用時(shí)阻止模塊被卸載。2) loff_t (*llseek) (struct file *, loff_t, int);該方法用以改變文件中的當(dāng)前讀 /寫(xiě)位置該函數(shù)用返回新位置。3) ssize_t (*read) (struct file *, char _user *, size_

5、t, loff_t *);以從設(shè)備文件中讀取數(shù)據(jù),讀取成功返回讀取的字節(jié)數(shù)。4) ssize_t (*write) (struct file *, const char _user *,size_t , loff_t *); 該函數(shù)用以向設(shè)備寫(xiě)入數(shù)據(jù),如果成功返回寫(xiě)入的字節(jié)數(shù)。5) int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);ioctl 系統(tǒng)調(diào)用提供發(fā)出設(shè)備特定命令的方法。6) int (*open) (struct inode *, struct file *);設(shè)備文件進(jìn)行的第一個(gè)操作,

6、打開(kāi)設(shè)備文件。7) int (*release) (struct inode * , struct file *); 釋放文件結(jié)構(gòu)函數(shù)指針。 一般初始化該結(jié)構(gòu)體如下:struct file_operations fops = .owner = THIS_MODULE, .llseek= xxx_llseek, .read = xxx_read, .writexxx_write,.ioctl = xxx_ioctl, .open = xxx_open, .release = xxx_release ;PS:以上的文件操作函數(shù)指針并不是全部,只是介紹了幾個(gè)常用的操作。- 文件結(jié)構(gòu)struct fi

7、le 定義在 linux/fs.h 中,是設(shè)備驅(qū)動(dòng)中第二個(gè)最重要的數(shù)據(jù)結(jié)構(gòu), 此處的 file 和用戶空間程序中的 FILE 指針沒(méi)有關(guān)系。前者位于內(nèi)核空間,后者位于用戶控件。 文件結(jié)構(gòu)代表一個(gè)打開(kāi)的文件。 (他不特定給設(shè)備驅(qū)動(dòng) ; 系統(tǒng)中每個(gè)打開(kāi)的文件 有一個(gè)關(guān)聯(lián)的 struct file 在內(nèi)核空間 )。它由內(nèi)核在 open 時(shí)創(chuàng)建,并可以傳遞給文件 件操作函數(shù),文件關(guān)閉之后,內(nèi)核釋放數(shù)據(jù)結(jié)構(gòu)。1)mode_t f_mode 。確定文件讀寫(xiě)模式2)loff_t f_ops 。當(dāng)前讀寫(xiě)位置3)unsigned int f_flags。文件標(biāo)志, O_RDONL、Y O_NONBLOC,K4)

8、 struct file_operations *f_op 。關(guān)聯(lián)文件相關(guān)操作5) void *private_data。 open系統(tǒng)調(diào)用設(shè)置該指針NULL指向分配的數(shù)據(jù)。6) struct dentry *f_dentry。關(guān)聯(lián)到文件的目錄入口 dentry 結(jié)構(gòu)。-inode 結(jié)構(gòu)inode 結(jié)構(gòu)由內(nèi)核在內(nèi)部用來(lái)表示文件。它和代表打開(kāi)文件描述符的文件結(jié)構(gòu)是不同的。 inode 結(jié)構(gòu)包含大量關(guān)于文件的信息。作為通用規(guī)則,這個(gè)結(jié)構(gòu)只有兩個(gè)成 員對(duì)驅(qū)動(dòng)代碼有作用。dev_t i_rdev 。對(duì)于代表設(shè)備文件的節(jié)點(diǎn),這個(gè)成員包含實(shí)際的設(shè)備編號(hào)。struct cdev *i_cdev 。內(nèi)核內(nèi)部結(jié)

9、構(gòu),代表字符設(shè)備。- 字符設(shè)備注冊(cè)在內(nèi)核調(diào)用你的設(shè)備操作前,你編寫(xiě)分配并注冊(cè)一個(gè)或幾個(gè)struct cdev.struct cdev *my_cdev = cdev_alloc(); my_cdev-;ops = &my_fops;或者定義成 static 均可。對(duì)定義的 cdev 變量進(jìn)行初始化,可以使用專門(mén)的函數(shù),或者使用如上的方法。cdev_init( my_cdev, &my_fops); 其實(shí)上邊的兩行代碼就是做了這個(gè)函數(shù)的工作。最后告訴內(nèi)核該 cdev。cdev_add(struct cdev *dev, dev_t num, unsigned in

10、t count);/* 上述總結(jié),到此關(guān)于設(shè)備文件相關(guān)的結(jié)構(gòu)數(shù)據(jù)以及如何注冊(cè)銷毀等操作相關(guān)的 函數(shù)基本上都已經(jīng)介紹完畢。主要的還是要設(shè)計(jì)具體操作的函數(shù)來(lái)實(shí)現(xiàn)具體的 邏輯操作 */以下代碼整理、摘錄自 An droid深度探索HAL與驅(qū)動(dòng)開(kāi)發(fā)-李寧LED驅(qū)動(dòng)篇#include#include#include#include#include#include#include#deifne DEVICE_NAME s3c6410_leds#define DEVICE_COUNT 1#define S3C6410_LEDS_MAJOR 0#define S3C6410_LEDS_MINOR 234#de

11、fine PARAM_SIZE 3static int major = S3C6410_LEDS_MAJOR;static int minor = S3C6410_LEDS_MINOR;static dev_t dev_number;static int leds_state = 1;static char *params = string1,string2,string3;static iint param_size = PARAM_SIZE;static struct class *leds_class = NULL;static int s3c6410_leds_ioctl (struc

12、t file *file, unsigned int cmd, unsigned long arg)switch (cmd)unsigned tmp;case 0:case 1:if (arg ; 4)return -EINVAL;tmp = ioread32 (S3C64XX_GPMDAT);if (cmd = 1)tmp &= (1 << arg);elsetmp |= (1 << arg);iowrite32 (tmp, S3C64XX_GPMDAT);return 0;default : return -EINVA

13、L;static ssize_t s3c6410_leds_write (struct file *file, const char _user *buf, size_t count, loff_t *ppos)unsigned tmp = count;unsigned long i = 0;memset(mem, 0, 4);if (count ; 4)tmp = 4;if (copy_from_user (mem, buf, tmp) )return -EFAULT;elsefor( i=0; i<4; i+)tmp = ioread32(S3C64XX_GPMDAT);if

14、 (memi = '1')tmp &= (1 << i);elsetmp |= (1 << i);iowrite32(tmp, S3C64XX_GPMDAT);return count;static struct file_operations dev_fops =.write.owner = THIS_MODULE, .unlocked_ioctl = s3c6410_leds_ioctl, s3c6410_leds_write;static struct cdev leds_cdev;static in

15、t leds_create_device(void)int ret = 0;int err = 0;cdev_init (&leds_cdev, &dev_fops);leds_cdev.owner = THIS_MODULE;if (major ; 0)dev_number = MKDEV(major,minor);err = register_chrdev_region(dev_number, DEVICE_COUNT, DEVICE_NAME);if (err < 0)printk(KERN_WANRING register_chrdev_r

16、egion errorn);return errelseerr = alloc_chrdev_region(&leds_cdev.dev, 10, DEVICE_COUNT, DEVICE_NAME); if(err < 0)printk (KERN_WARNING alloc_chrdev_region errorn);return err;major = MAJOR(leds_cdev.dev);major = MINOR(leds_cdev.dev);dev_number = leds_cdev.dev;ret = cdev_add(&led

17、s_cdev,dev_number, DEVICE_COUNT);leds_class = class_create (THIS_MODULE, DEVICE_NAME); device_create (leds_class, NULL, dev_number, NULL, DEVICE_NAME); return ret;static void leds_init_gpm(int leds_default)int tmp = 0;tmp = ioread32(S3C64XX_GPMCON);tmp &= (0xffff);tmp |= 0x1111;iowrite32(tmp

18、,S3C64XX_GPMCON);tmp = ioread32(S3C64XX_GPMPUD);tmp &= (0XFF);tmp |= 0xaa;iowrite32(tmp,S3C64XX_GPMPUD);tmp = ioread32(S3C64XX_GPMDAT);tmp &= (0xf);tmp |= leds_default;iowrite32(tmp, S3C64XX_GPMDAT);static leds_init( void)int ret;ret = leds_create_device();leds_init_gpm (leds_state);printk(DEVICE_NAMEtinitializedn);return ret;static void leds_destroy_device(void)device_destroy(leds_class, dev_number);if(leds_class)class_destroy(leds_class);unregister_chrdev_region(dev

溫馨提示

  • 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ù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 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)論