日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

linux驱动文件操作简单介绍

發(fā)布時(shí)間:2023/12/20 linux 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux驱动文件操作简单介绍 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1、設(shè)備號(hào)

主設(shè)備號(hào)標(biāo)識(shí)設(shè)備對(duì)應(yīng)的驅(qū)動(dòng)程序,次設(shè)備號(hào)由內(nèi)核使用,用于確定設(shè)備文件所指的設(shè)備。

通過(guò)次設(shè)備號(hào)獲得一個(gè)指向內(nèi)核設(shè)備的直接指針,也可將此設(shè)備號(hào)當(dāng)作設(shè)備本地?cái)?shù)組的索引。

設(shè)備編號(hào)用dev_t表示(Linux/types.h? 32位,其中12位表示主設(shè)備號(hào),20位表示次設(shè)備號(hào))。

dev_t獲得主設(shè)備號(hào)或次設(shè)備號(hào):MAJOR(dev_t dev); MINOR(dev_t dev)

已知主設(shè)備號(hào)和次設(shè)備號(hào)來(lái)獲取dev_t類型:MKDEV(int? major,? int? minor)

獲取一個(gè)或多個(gè)設(shè)備編號(hào)int? register_chrdev_region(dev_t first,? unsigned int? count,? char? *name);(靜態(tài)分配,事先已知道設(shè)備號(hào))

動(dòng)態(tài)分配設(shè)備編號(hào)int? alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);調(diào)用成功后dev會(huì)保存已分配的第一個(gè)編號(hào)。

釋放設(shè)備編號(hào):void unregister_chrdev_region(dev_t first, unsigned int count);

接下來(lái),驅(qū)動(dòng)程序需要將設(shè)備編號(hào)和內(nèi)部函數(shù)連接起來(lái)。

注:(下一步可嘗試采用動(dòng)態(tài)分配設(shè)備號(hào)

?

動(dòng)態(tài)分配設(shè)備號(hào)缺點(diǎn):不能預(yù)先創(chuàng)建設(shè)備節(jié)點(diǎn)(因?yàn)榉峙涞脑O(shè)備號(hào)不能保證始終一致)。

2、文件操作file_operations:

這些操作將與設(shè)備編號(hào)連接起來(lái)。

__user:用于文檔,表明該指針是一個(gè)用戶空間地址。

主要成員:open, ?ioctl,? read,? write,? llseek

3、struct file結(jié)構(gòu)? linux/fs.h文件描述符

每打開(kāi)一個(gè)文件,內(nèi)核就會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的file結(jié)構(gòu),在open()時(shí)創(chuàng)建,同時(shí)會(huì)傳遞給在該文件上進(jìn)行操作的所有函數(shù)(因?yàn)?span style="font-family:Calibri">file結(jié)構(gòu)中包含file_operations結(jié)構(gòu),而該結(jié)構(gòu)包含了所有驅(qū)動(dòng)操作的函數(shù))。

內(nèi)核中用filp作為執(zhí)行file結(jié)構(gòu)的指針。

主要成員:

Mode_t? f_mode;? loff_t? f_pos;? ?struct file_operations *f_pos;? void? private_data;?

4inode結(jié)構(gòu)

對(duì)單個(gè)文件只有一個(gè)inode,而可能有多個(gè)file(由于forkdup操作)。

主要成員:

dev_t? i_rdev; 對(duì)表示設(shè)備文件的inode結(jié)構(gòu),該字段包含真正的設(shè)備編號(hào)。

struct cdev?*i_cdev;? ?該結(jié)構(gòu)表示字符設(shè)備的內(nèi)核的內(nèi)部結(jié)構(gòu),當(dāng)inode指向一個(gè)字符設(shè)備文件時(shí),該字段包含指向struct cdev結(jié)構(gòu)的指針。

inode中獲取設(shè)備號(hào): iminor(struct inode *inode);? imajor(inode);

5、字符設(shè)備注冊(cè)? /linux/cdev.h

內(nèi)核使用struct cdev結(jié)構(gòu)表示字符設(shè)備,所以在內(nèi)核調(diào)用該設(shè)備操作之前,需要分配并注冊(cè)一個(gè)或者多個(gè)該結(jié)構(gòu)。

注冊(cè)有兩種方式:

新方法:

1)定義字節(jié)的結(jié)構(gòu):

struct my_dev {

???????? struct? cdev? cdev; //此處如果定義的是指針類型,則需要申請(qǐng)分配內(nèi)存

}my_dev;

//my_dev ->cdev = cdev_alloc();? //如果cdev是指針則需要這一步

my_dev->cdev.ops = &my_fops;

my_dev->cdev.owner = THIS_MODULE;

2)再調(diào)用cdev_init(struct cdev *cdev,? struct file_operations *fops);

3)調(diào)用cdev_add(struct cdev *dev,? dev_t num,? unsigned int count);

上面每一步都要判斷函數(shù)調(diào)用是否出錯(cuò)。

舊辦法(老接口):

注冊(cè):int register_chrdev();移除:int unregister_chrdev()

?

6、各操作函數(shù)實(shí)現(xiàn)

1open?? int (*open) (struct? inode? *inode,? struct? file? *filp)

完成以下工作:傳入一個(gè)inode,創(chuàng)建一個(gè)file結(jié)構(gòu)

n? 檢查設(shè)備特定錯(cuò)誤(如未就緒);

n? 如果設(shè)備首次打開(kāi),則進(jìn)行初始化;

n? 必要時(shí)更新f_op指針;

n? 分配并填寫filp->private_data

注:inode結(jié)構(gòu)是傳入的參數(shù),對(duì)應(yīng)一個(gè)特定的設(shè)備(這就是為什么要在/devmknodde原因),而file結(jié)構(gòu)的filp是要修改的參數(shù)(傳出),對(duì)應(yīng)該設(shè)備的一個(gè)文件描述符,也就是一個(gè)inode可能有多個(gè)file描述符,而每個(gè)描述符需要保存inode的信息,即存放在filp->private_data中。

2release? int (*release) (struct inode *inode,? struct file *filp)

完成工作:傳入一個(gè)inode,釋放這個(gè)file結(jié)構(gòu)

n? 釋放由open分配的、保存在filp->private_data中的內(nèi)容;

n? 在最后一次close時(shí)關(guān)閉設(shè)備

dup fork都會(huì)在不調(diào)用open時(shí)創(chuàng)建新的file結(jié)構(gòu)(對(duì)應(yīng)同一個(gè)inode)。

注:并不是每個(gè)close調(diào)用都會(huì)調(diào)用release;只有真正釋放設(shè)備數(shù)據(jù)結(jié)構(gòu)的close調(diào)用才會(huì)調(diào)用release。內(nèi)核對(duì)每個(gè)file結(jié)構(gòu)維護(hù)其被使用次數(shù)的計(jì)數(shù)器,無(wú)論是fork還是dup,都不會(huì)創(chuàng)建新的數(shù)據(jù)結(jié)構(gòu)(只會(huì)有open創(chuàng)建),它們只是增加已有結(jié)構(gòu)中的計(jì)數(shù)器而已。只有在file結(jié)構(gòu)的計(jì)數(shù)為0時(shí),close才會(huì)調(diào)用release。

3read? ssize_t ?read(struct ?file? *filp,? char __user *buf, ?count,? loff_t *offp)

完成工作:傳入file,將count個(gè)字節(jié)數(shù)據(jù)寫入用戶地址buf,修改loff_t

copy_to_user()實(shí)現(xiàn)
返回值說(shuō)明:

n? 等于count:所請(qǐng)求的字節(jié)數(shù)讀取成功;

n? 返回值為正,但小于count:只讀取了部分?jǐn)?shù)據(jù);

n? 0:已經(jīng)達(dá)到文件尾;

n? 負(fù)值:出錯(cuò)

4write? ssize_t? write(struct ?file? *filp,? char? __user *buf,? count,? offp);

copy_from_user()實(shí)現(xiàn)

返回值同上。

?

[cpp] view plaincopy
  • 1)驅(qū)動(dòng)代碼??
  • Demo.h??
  • #ifndef?_DEMO_H_??
  • #define?_DEMO_H_??
  • #include?<linux/ioctl.h>??
  • /*Macros?to?help?debuging*/??
  • #undef?PDEBUG??
  • #ifdef?DEMO_DEBUG??
  • ????#ifdef?__KERNEL__??
  • ????????#define?PDEBUG(fmt,?args...)?printk(KERN_DEBUG?"DEMO:"?fmt,##?args)???
  • ????#else??
  • ????????#define?PDEBUG(fmt,?args...)?fprintf(stderr,?fmt,?##?args)??
  • ????#endif??
  • #else??
  • #define?PDEBUG(fmt,?args...)???
  • #endif??
  • ??
  • #define?DEMO_MAJOR?224??
  • #define?DEMO_MINOR?0??
  • #define?COMMAND1?1??
  • #define?COMMAND2?2??
  • ??
  • struct?demo_dev?{??
  • ????struct?cdev?cdev;??
  • };??
  • ??
  • ssize_t?demo_read(struct?file?*filp,?char?__user?*buf,?size_t?count,?loff_t?*f_pos);??
  • ssize_t?demo_write(struct?file?*filp,?const?char?__user?*buf,?size_t?count,?loff_t?*f_pos);??
  • loff_t?demo_llseek(struct?file?*filp,?loff_t?off,?int?whence);??
  • int?demo_ioctl(struct?inode?*inode,?struct?file?*filp,?unsigned?int?cmd,?unsigned?long?arg);??
  • ??
  • #endif??
  • demo.c??
  • #include?<linux/module.h>??
  • #include?<linux/kernel.h>??
  • #include?<linux/fs.h>??
  • #include?<linux/errno.h>??
  • #include?<linux/types.h>??
  • #include?<linux/fcntl.h>??
  • #include?<linux/cdev.h>??
  • #include?<linux/version.h>??
  • #include?<linux/vmalloc.h>??
  • #include?<linux/ctype.h>??
  • #include?<linux/pagemap.h>??
  • #include?"demo.h"??
  • ??
  • MODULE_AUTHOR("Yangjin");??
  • MODULE_LICENSE("Dual?BSD/GPL");??
  • ??
  • struct?demo_dev?*demo_devices;??
  • ??
  • static?unsigned?char?demo_inc?=?0;//全局變量,每次只能打開(kāi)一個(gè)設(shè)備??
  • ??
  • static?u8?demo_buffer[256];??
  • ??
  • int?demo_open(struct?inode?*inode,?struct?file?*filp)??
  • {??
  • ????struct?demo_dev?*dev;??
  • ??????
  • ????if?(demo_inc?>?0)?return?-ERESTARTSYS;??
  • ????demo_inc++;??
  • ????dev?=?container_of(inode->i_cdev,?struct?demo_dev,?cdev);??
  • ????filp->private_data?=?dev;??
  • ??
  • ????return?0;??
  • }??
  • ??
  • int?demo_release(struct?inode?*inode,?struct?file?*filp)??
  • {?????
  • ????demo_inc--;??
  • ????return?0;??
  • }??
  • ??
  • ssize_t?demo_read(struct?file?*filp,?char?__user?*buf,?size_t?count,?loff_t?*f_pos)??
  • {??
  • ????int?result;??
  • ????loff_t?pos?=?*f_pos;?//pos:?offset??
  • ??
  • ????if?(pos?>=?256)?{??
  • ????????result?=?0;??
  • ????????goto?out;????????????????????????????????????????????????????????????????????????????????????????????????
  • ????}??
  • ????if?(count?>?(256?-?pos))??
  • ????????count?=?256?-?pos;??
  • ????pos?+=?count;??
  • ??
  • ????if?(copy_to_user(buf,?demo_buffer+*f_pos,?count))?{??
  • ????????count?=?-EFAULT;??
  • ????????goto?out;?????
  • ????}??
  • ??????
  • ????*f_pos?=?pos;??
  • out:??
  • ????return?count;??
  • }??
  • ??
  • ssize_t??demo_write(struct?file?*filp,?const?char?__user?*buf,?size_t?count,?loff_t?*f_pos)??
  • {??
  • ????ssize_t?retval?=?-ENOMEM;??
  • ????loff_t?pos?=?*f_pos;??
  • ??
  • ????if?(pos?>?256)??
  • ????????goto?out;??
  • ????if?(count?>?(256?-?pos))???
  • ????????count?=?256?-?pos;????
  • ????pos?+=?count;??
  • ????if?(copy_from_user(demo_buffer+*f_pos,?buf,?count))?{??
  • ????????retval?=?-EFAULT;??
  • ????????goto?out;?????
  • ????}??
  • ??????
  • ????*f_pos?=?pos;??
  • ????retval?=?count;??
  • out:??
  • ????return?retval;??
  • }??
  • ??
  • int??demo_ioctl(struct?inode?*inode,?struct?file?*filp,?unsigned?int?cmd,?unsigned?long?arg)??
  • {??
  • ????if?(cmd?==?COMMAND1)?{??
  • ????????printk("ioctl?command?1?successfully\n");??
  • ????????return?0;?????
  • ????}??
  • ????if?(cmd?==?COMMAND2)?{??
  • ????????printk("ioctl?command?2?successfully\n");??
  • ????????return?0;?????
  • ????}??
  • ????printk("ioctl?error\n");??
  • ????return?-EFAULT;??
  • }??
  • ??
  • loff_t?demo_llseek(struct?file?*filp,?loff_t?off,?int?whence)??
  • {??
  • ????loff_t?pos;??
  • ??????
  • ????pos?=?filp->f_pos;??
  • ????switch?(whence)?{??
  • ????case?0:??
  • ????????pos?=?off;??
  • ????????break;??
  • ????case?1:??
  • ????????pos?+=?off;??
  • ????????break;??
  • ????case?2:??
  • ????default:??
  • ????????return?-EINVAL;???
  • ????}??
  • ??????
  • ????if?((pos?>?256)?||?(pos?<?0))??
  • ????????return?-EINVAL;??
  • ??????
  • ????return?filp->f_pos?=?pos;??
  • }??
  • ??
  • struct?file_operations?demo_fops?=?{??
  • ????.owner?=?THIS_MODULE,??
  • ????.llseek?=?demo_llseek,??
  • ????.read?=?demo_read,??
  • ????.write?=?demo_write,??
  • ????.ioctl?=?demo_ioctl,??
  • ????.open?=?demo_open,??
  • ????.release?=?demo_release,??
  • };??
  • ??
  • void?demo_cleanup_module(void)??
  • {??
  • ????dev_t?devno?=?MKDEV(DEMO_MAJOR,?DEMO_MINOR);??
  • ??????
  • ????if?(demo_devices)?{??
  • ????????cdev_del(&demo_devices->cdev);??
  • ????????kfree(demo_devices);??
  • ????}??
  • ????unregister_chrdev_region(devno,?1);??
  • }??
  • ??
  • Init?module流程:??
  • 1)注冊(cè)設(shè)備號(hào)MKDEV;??
  • 2)注冊(cè)設(shè)備驅(qū)動(dòng)程序,即初始化cdev結(jié)構(gòu)(嵌入到demo_devices結(jié)構(gòu)中)??
  • int?demo_init_module(void)??
  • {??
  • ????int?result;??
  • ????dev_t?dev?=?0;??
  • ??????
  • ????dev?=?MKDEV(DEMO_MAJOR,?DEMO_MINOR);??
  • ????result?=?register_chrdev_region(dev,?1,?"DEMO");??
  • ????if?(result?<?0)?{??
  • ????????printk(KERN_WARNING?"DEMO:?can't?get?major?%d\n",?DEMO_MAJOR);??
  • ????????return?result;??
  • ????}??
  • ????demo_devices?=?kmalloc(sizeof(struct?demo_dev),?GFP_KERNEL);??
  • ????if?(!demo_devices)?{??
  • ????????result?=?-ENOMEM;??
  • ????????goto?fail;??
  • ????}??
  • ????memset(demo_devices,?0,?sizeof(struct?demo_dev));??
  • ????cdev_init(&demo_devices->cdev,?&demo_fops);????
  • demo_devices->cdev.owner?=?THIS_MODULE;??
  • ????demo_devices->cdev.ops?=?&demo_fops;?//將創(chuàng)建的字符設(shè)備與file_operations中各函數(shù)操作連接起來(lái)??
  • ??
  • ????result?=?cdev_add(&demo_devices->cdev,?dev,?1);??
  • ????if?(result)?{??
  • ????????printk(KERN_NOTICE?"error?%d?adding?demo\n",?result);??
  • ????????goto?fail;??
  • ????}??
  • ????return?0;??
  • fail:??
  • ????demo_cleanup_module();??
  • ????return?result;??
  • }??
  • ??
  • module_init(demo_init_module);??
  • module_exit(demo_cleanup_module);??

  • ?

    2)加載驅(qū)動(dòng)insmod demo.ko,再使用lsmodcat /proc/modules查看驅(qū)動(dòng)是否安裝;

    3)創(chuàng)建設(shè)備節(jié)點(diǎn):mknod? /dev/yangjin c 224 0;注意:此處的節(jié)點(diǎn)設(shè)備號(hào)要與驅(qū)動(dòng)程序中的注冊(cè)的設(shè)備號(hào)相同。

    4)再編寫應(yīng)用程序測(cè)試代碼:

    用戶測(cè)試代碼:

    [cpp] view plaincopy
  • #include?<sys/types.h>??
  • #include?<unistd.h>??
  • #include?<fcntl.h>??
  • #include?<linux/rtc.h>??
  • #include?<linux/ioctl.h>??
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • ??
  • #define?COMMAND1?1??
  • #define?COMMAND2?2??
  • ??
  • int?main()??
  • {??
  • ????int?fd;??
  • ????int?i;??
  • ????char?data[256]?=?{0};??
  • ????int?retval;??
  • ??????
  • ????fd?=?open("/dev/yangjin",?O_RDWR);??
  • ????if?(fd?==?1)?{??
  • ????????perror("open?error\n");??
  • ????????exit(-1);??
  • ????}??
  • ????printf("open?/dev/yangjin?successfully\n");??
  • ????retval?=?ioctl(fd,?COMMAND1,?0);??
  • ????if?(retval?==?-1)?{??
  • ????????perror("ioctl?error\n");??
  • ????????exit(-1);??
  • ????}??
  • ????printf("ioctl?command?1?successfully\n");??
  • ????retval?=?write(fd,?"yangjin",?7);??
  • ????if?(retval?==?-1)?{??
  • ????????perror("write?error\n");??
  • ????????exit(-1);??
  • ????}??
  • ????retval?=?lseek(fd,?0,?0);??
  • ????if?(retval?==?-1)?{??
  • ????????perror("lseek?error\n");??
  • ????????exit(-1);??
  • ????}??
  • ????retval?=?read(fd,?data,?10);??
  • ????if?(retval?==?-1)?{??
  • ????????perror("read?error\n");??
  • ????????exit(-1);??
  • ????}??
  • ????printf("read?successfully:?%s\n",?data);??
  • ????close(fd);??
  • ????return?0;??
  • }??


  • 總結(jié)

    以上是生活随笔為你收集整理的linux驱动文件操作简单介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。