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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux驱动文件操作简单介绍

發布時間:2023/12/20 linux 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux驱动文件操作简单介绍 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、設備號

主設備號標識設備對應的驅動程序,次設備號由內核使用,用于確定設備文件所指的設備。

通過次設備號獲得一個指向內核設備的直接指針,也可將此設備號當作設備本地數組的索引。

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

dev_t獲得主設備號或次設備號:MAJOR(dev_t dev); MINOR(dev_t dev)

已知主設備號和次設備號來獲取dev_t類型:MKDEV(int? major,? int? minor)

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

動態分配設備編號int? alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);調用成功后dev會保存已分配的第一個編號。

釋放設備編號:void unregister_chrdev_region(dev_t first, unsigned int count);

接下來,驅動程序需要將設備編號和內部函數連接起來。

注:(下一步可嘗試采用動態分配設備號

?

動態分配設備號缺點:不能預先創建設備節點(因為分配的設備號不能保證始終一致)。

2、文件操作file_operations:

這些操作將與設備編號連接起來。

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

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

3struct file結構? linux/fs.h文件描述符

每打開一個文件,內核就會創建一個對應的file結構,在open()時創建,同時會傳遞給在該文件上進行操作的所有函數(因為file結構中包含file_operations結構,而該結構包含了所有驅動操作的函數)。

內核中用filp作為執行file結構的指針。

主要成員:

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

4inode結構

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

主要成員:

dev_t? i_rdev; 對表示設備文件的inode結構,該字段包含真正的設備編號。

struct cdev?*i_cdev;? ?該結構表示字符設備的內核的內部結構,當inode指向一個字符設備文件時,該字段包含指向struct cdev結構的指針。

inode中獲取設備號: iminor(struct inode *inode);? imajor(inode);

5、字符設備注冊? /linux/cdev.h

內核使用struct cdev結構表示字符設備,所以在內核調用該設備操作之前,需要分配并注冊一個或者多個該結構。

注冊有兩種方式:

新方法:

1)定義字節的結構:

struct my_dev {

???????? struct? cdev? cdev; //此處如果定義的是指針類型,則需要申請分配內存

}my_dev;

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

my_dev->cdev.ops = &my_fops;

my_dev->cdev.owner = THIS_MODULE;

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

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

上面每一步都要判斷函數調用是否出錯。

舊辦法(老接口):

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

?

6、各操作函數實現

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

完成以下工作:傳入一個inode,創建一個file結構

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

n? 如果設備首次打開,則進行初始化;

n? 必要時更新f_op指針;

n? 分配并填寫filp->private_data

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

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

完成工作:傳入一個inode,釋放這個file結構

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

n? 在最后一次close時關閉設備

dup fork都會在不調用open時創建新的file結構(對應同一個inode)。

注:并不是每個close調用都會調用release;只有真正釋放設備數據結構的close調用才會調用release。內核對每個file結構維護其被使用次數的計數器,無論是fork還是dup,都不會創建新的數據結構(只會有open創建),它們只是增加已有結構中的計數器而已。只有在file結構的計數為0時,close才會調用release

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

完成工作:傳入file,將count個字節數據寫入用戶地址buf,修改loff_t

copy_to_user()實現
返回值說明:

n? 等于count:所請求的字節數讀取成功;

n? 返回值為正,但小于count:只讀取了部分數據;

n? 0:已經達到文件尾;

n? 負值:出錯

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

copy_from_user()實現

返回值同上。

?

[cpp] view plaincopy
  • 1)驅動代碼??
  • 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;//全局變量,每次只能打開一個設備??
  • ??
  • 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)注冊設備號MKDEV;??
  • 2)注冊設備驅動程序,即初始化cdev結構(嵌入到demo_devices結構中)??
  • 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;?//將創建的字符設備與file_operations中各函數操作連接起來??
  • ??
  • ????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)加載驅動insmod demo.ko,再使用lsmodcat /proc/modules查看驅動是否安裝;

    3)創建設備節點:mknod? /dev/yangjin c 224 0;注意:此處的節點設備號要與驅動程序中的注冊的設備號相同。

    4)再編寫應用程序測試代碼:

    用戶測試代碼:

    [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;??
  • }??


  • 總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。