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. 1)驅動代碼??
  2. Demo.h??
  3. #ifndef?_DEMO_H_??
  4. #define?_DEMO_H_??
  5. #include?<linux/ioctl.h>??
  6. /*Macros?to?help?debuging*/??
  7. #undef?PDEBUG??
  8. #ifdef?DEMO_DEBUG??
  9. ????#ifdef?__KERNEL__??
  10. ????????#define?PDEBUG(fmt,?args...)?printk(KERN_DEBUG?"DEMO:"?fmt,##?args)???
  11. ????#else??
  12. ????????#define?PDEBUG(fmt,?args...)?fprintf(stderr,?fmt,?##?args)??
  13. ????#endif??
  14. #else??
  15. #define?PDEBUG(fmt,?args...)???
  16. #endif??
  17. ??
  18. #define?DEMO_MAJOR?224??
  19. #define?DEMO_MINOR?0??
  20. #define?COMMAND1?1??
  21. #define?COMMAND2?2??
  22. ??
  23. struct?demo_dev?{??
  24. ????struct?cdev?cdev;??
  25. };??
  26. ??
  27. ssize_t?demo_read(struct?file?*filp,?char?__user?*buf,?size_t?count,?loff_t?*f_pos);??
  28. ssize_t?demo_write(struct?file?*filp,?const?char?__user?*buf,?size_t?count,?loff_t?*f_pos);??
  29. loff_t?demo_llseek(struct?file?*filp,?loff_t?off,?int?whence);??
  30. int?demo_ioctl(struct?inode?*inode,?struct?file?*filp,?unsigned?int?cmd,?unsigned?long?arg);??
  31. ??
  32. #endif??
  33. demo.c??
  34. #include?<linux/module.h>??
  35. #include?<linux/kernel.h>??
  36. #include?<linux/fs.h>??
  37. #include?<linux/errno.h>??
  38. #include?<linux/types.h>??
  39. #include?<linux/fcntl.h>??
  40. #include?<linux/cdev.h>??
  41. #include?<linux/version.h>??
  42. #include?<linux/vmalloc.h>??
  43. #include?<linux/ctype.h>??
  44. #include?<linux/pagemap.h>??
  45. #include?"demo.h"??
  46. ??
  47. MODULE_AUTHOR("Yangjin");??
  48. MODULE_LICENSE("Dual?BSD/GPL");??
  49. ??
  50. struct?demo_dev?*demo_devices;??
  51. ??
  52. static?unsigned?char?demo_inc?=?0;//全局變量,每次只能打開一個設備??
  53. ??
  54. static?u8?demo_buffer[256];??
  55. ??
  56. int?demo_open(struct?inode?*inode,?struct?file?*filp)??
  57. {??
  58. ????struct?demo_dev?*dev;??
  59. ??????
  60. ????if?(demo_inc?>?0)?return?-ERESTARTSYS;??
  61. ????demo_inc++;??
  62. ????dev?=?container_of(inode->i_cdev,?struct?demo_dev,?cdev);??
  63. ????filp->private_data?=?dev;??
  64. ??
  65. ????return?0;??
  66. }??
  67. ??
  68. int?demo_release(struct?inode?*inode,?struct?file?*filp)??
  69. {?????
  70. ????demo_inc--;??
  71. ????return?0;??
  72. }??
  73. ??
  74. ssize_t?demo_read(struct?file?*filp,?char?__user?*buf,?size_t?count,?loff_t?*f_pos)??
  75. {??
  76. ????int?result;??
  77. ????loff_t?pos?=?*f_pos;?//pos:?offset??
  78. ??
  79. ????if?(pos?>=?256)?{??
  80. ????????result?=?0;??
  81. ????????goto?out;????????????????????????????????????????????????????????????????????????????????????????????????
  82. ????}??
  83. ????if?(count?>?(256?-?pos))??
  84. ????????count?=?256?-?pos;??
  85. ????pos?+=?count;??
  86. ??
  87. ????if?(copy_to_user(buf,?demo_buffer+*f_pos,?count))?{??
  88. ????????count?=?-EFAULT;??
  89. ????????goto?out;?????
  90. ????}??
  91. ??????
  92. ????*f_pos?=?pos;??
  93. out:??
  94. ????return?count;??
  95. }??
  96. ??
  97. ssize_t??demo_write(struct?file?*filp,?const?char?__user?*buf,?size_t?count,?loff_t?*f_pos)??
  98. {??
  99. ????ssize_t?retval?=?-ENOMEM;??
  100. ????loff_t?pos?=?*f_pos;??
  101. ??
  102. ????if?(pos?>?256)??
  103. ????????goto?out;??
  104. ????if?(count?>?(256?-?pos))???
  105. ????????count?=?256?-?pos;????
  106. ????pos?+=?count;??
  107. ????if?(copy_from_user(demo_buffer+*f_pos,?buf,?count))?{??
  108. ????????retval?=?-EFAULT;??
  109. ????????goto?out;?????
  110. ????}??
  111. ??????
  112. ????*f_pos?=?pos;??
  113. ????retval?=?count;??
  114. out:??
  115. ????return?retval;??
  116. }??
  117. ??
  118. int??demo_ioctl(struct?inode?*inode,?struct?file?*filp,?unsigned?int?cmd,?unsigned?long?arg)??
  119. {??
  120. ????if?(cmd?==?COMMAND1)?{??
  121. ????????printk("ioctl?command?1?successfully\n");??
  122. ????????return?0;?????
  123. ????}??
  124. ????if?(cmd?==?COMMAND2)?{??
  125. ????????printk("ioctl?command?2?successfully\n");??
  126. ????????return?0;?????
  127. ????}??
  128. ????printk("ioctl?error\n");??
  129. ????return?-EFAULT;??
  130. }??
  131. ??
  132. loff_t?demo_llseek(struct?file?*filp,?loff_t?off,?int?whence)??
  133. {??
  134. ????loff_t?pos;??
  135. ??????
  136. ????pos?=?filp->f_pos;??
  137. ????switch?(whence)?{??
  138. ????case?0:??
  139. ????????pos?=?off;??
  140. ????????break;??
  141. ????case?1:??
  142. ????????pos?+=?off;??
  143. ????????break;??
  144. ????case?2:??
  145. ????default:??
  146. ????????return?-EINVAL;???
  147. ????}??
  148. ??????
  149. ????if?((pos?>?256)?||?(pos?<?0))??
  150. ????????return?-EINVAL;??
  151. ??????
  152. ????return?filp->f_pos?=?pos;??
  153. }??
  154. ??
  155. struct?file_operations?demo_fops?=?{??
  156. ????.owner?=?THIS_MODULE,??
  157. ????.llseek?=?demo_llseek,??
  158. ????.read?=?demo_read,??
  159. ????.write?=?demo_write,??
  160. ????.ioctl?=?demo_ioctl,??
  161. ????.open?=?demo_open,??
  162. ????.release?=?demo_release,??
  163. };??
  164. ??
  165. void?demo_cleanup_module(void)??
  166. {??
  167. ????dev_t?devno?=?MKDEV(DEMO_MAJOR,?DEMO_MINOR);??
  168. ??????
  169. ????if?(demo_devices)?{??
  170. ????????cdev_del(&demo_devices->cdev);??
  171. ????????kfree(demo_devices);??
  172. ????}??
  173. ????unregister_chrdev_region(devno,?1);??
  174. }??
  175. ??
  176. Init?module流程:??
  177. 1)注冊設備號MKDEV;??
  178. 2)注冊設備驅動程序,即初始化cdev結構(嵌入到demo_devices結構中)??
  179. int?demo_init_module(void)??
  180. {??
  181. ????int?result;??
  182. ????dev_t?dev?=?0;??
  183. ??????
  184. ????dev?=?MKDEV(DEMO_MAJOR,?DEMO_MINOR);??
  185. ????result?=?register_chrdev_region(dev,?1,?"DEMO");??
  186. ????if?(result?<?0)?{??
  187. ????????printk(KERN_WARNING?"DEMO:?can't?get?major?%d\n",?DEMO_MAJOR);??
  188. ????????return?result;??
  189. ????}??
  190. ????demo_devices?=?kmalloc(sizeof(struct?demo_dev),?GFP_KERNEL);??
  191. ????if?(!demo_devices)?{??
  192. ????????result?=?-ENOMEM;??
  193. ????????goto?fail;??
  194. ????}??
  195. ????memset(demo_devices,?0,?sizeof(struct?demo_dev));??
  196. ????cdev_init(&demo_devices->cdev,?&demo_fops);????
  197. demo_devices->cdev.owner?=?THIS_MODULE;??
  198. ????demo_devices->cdev.ops?=?&demo_fops;?//將創建的字符設備與file_operations中各函數操作連接起來??
  199. ??
  200. ????result?=?cdev_add(&demo_devices->cdev,?dev,?1);??
  201. ????if?(result)?{??
  202. ????????printk(KERN_NOTICE?"error?%d?adding?demo\n",?result);??
  203. ????????goto?fail;??
  204. ????}??
  205. ????return?0;??
  206. fail:??
  207. ????demo_cleanup_module();??
  208. ????return?result;??
  209. }??
  210. ??
  211. module_init(demo_init_module);??
  212. module_exit(demo_cleanup_module);??


?

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

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

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

用戶測試代碼:

[cpp] view plaincopy
  1. #include?<sys/types.h>??
  2. #include?<unistd.h>??
  3. #include?<fcntl.h>??
  4. #include?<linux/rtc.h>??
  5. #include?<linux/ioctl.h>??
  6. #include?<stdio.h>??
  7. #include?<stdlib.h>??
  8. ??
  9. #define?COMMAND1?1??
  10. #define?COMMAND2?2??
  11. ??
  12. int?main()??
  13. {??
  14. ????int?fd;??
  15. ????int?i;??
  16. ????char?data[256]?=?{0};??
  17. ????int?retval;??
  18. ??????
  19. ????fd?=?open("/dev/yangjin",?O_RDWR);??
  20. ????if?(fd?==?1)?{??
  21. ????????perror("open?error\n");??
  22. ????????exit(-1);??
  23. ????}??
  24. ????printf("open?/dev/yangjin?successfully\n");??
  25. ????retval?=?ioctl(fd,?COMMAND1,?0);??
  26. ????if?(retval?==?-1)?{??
  27. ????????perror("ioctl?error\n");??
  28. ????????exit(-1);??
  29. ????}??
  30. ????printf("ioctl?command?1?successfully\n");??
  31. ????retval?=?write(fd,?"yangjin",?7);??
  32. ????if?(retval?==?-1)?{??
  33. ????????perror("write?error\n");??
  34. ????????exit(-1);??
  35. ????}??
  36. ????retval?=?lseek(fd,?0,?0);??
  37. ????if?(retval?==?-1)?{??
  38. ????????perror("lseek?error\n");??
  39. ????????exit(-1);??
  40. ????}??
  41. ????retval?=?read(fd,?data,?10);??
  42. ????if?(retval?==?-1)?{??
  43. ????????perror("read?error\n");??
  44. ????????exit(-1);??
  45. ????}??
  46. ????printf("read?successfully:?%s\n",?data);??
  47. ????close(fd);??
  48. ????return?0;??
  49. }??


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457901.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457901.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457901.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

php學習筆記細節部分。

<?phpclass Car{public function Car()//構造函數 {//codeing 當實例化類的時候會調用這里面的方法}public function _destruct()//析構函數 {//codeing 對象的所有引用被刪除&#xff0c;或者對象被顯式的銷毀時會執行的函數。 }} l轉載于:https://www.cnblogs.com/OnlyL…

ctypes python_[python學習之路]ctypes,Python

ctypes 基本用法 ctypes 是一個方便 Python 調用本地已經編譯好的外部庫的模塊。 from ctypes import util, CDLL 標準 C 庫 使用 util 來找到標準 C 庫&#xff1a; libc_name util.find_library(c) # on WINDOWS print libc_name msvcr90.dll 使用 CDLL 來加載 C 庫&#xf…

oracle創建表空間和用戶授權

確定數據文件的存儲地址&#xff0c;有兩種情況&#xff0c;一個是明確存儲地址&#xff0c;一個是跟其他表空間存在一個地方&#xff0c;但是不知道地址&#xff0c;這時候可以根據如下SQL進行查找&#xff1a;select t.* from sys.dba_data_files t where t.tablespace_name…

linux驅動 cdev,inode結構體

前面我們學習了字符設備結構體cdev Linux 字符設備驅動開發 &#xff08;一&#xff09;—— 字符設備驅動結構&#xff08;上&#xff09; 下面繼續學習字符設備另外幾個重要的 數據結構。 先看下面這張圖&#xff0c;這是Linux 中虛擬文件系統、一般的設備文件與設備驅動程…

如何在VS和CB中配置MySQL環境

這里&#xff0c;由于我的MySQL安裝在D盤 MY SQL\MySQL Server 5.6該路徑下&#xff0c;所以后面的路徑均以D:\MY SQL\MySQL Server 5.6開頭 在VS中配置MySQL環境 包含目錄&#xff1a; D:\MY SQL\MySQL Server 5.6\include 庫目錄&#xff1a;D:\MY SQL\MySQL Server 5.…

點乘和叉乘的區別_關于延時和混響的區別與專用延時器與混響器的調控技巧

關于延時和混響的區別與專用延時器與混響器的調控技巧延時器與混響器是模擬室內聲場聲音信號特性的專用設備。在錄音節目制作中&#xff0c;延時器和混響器可以在模擬的藝術聲場中傳遞時間、空間、方位、距離等重要信息&#xff0c;并且可以制作某些特殊效果。延時器與混響器工…

zabbix監控工具

實驗環境網關 classroom 172.25.8.254workstation 172.25.8.9server a-jeth0 172.25.8.10-外網eth1 192.168.0.x內網eth2 192.168.1.x備用servera:webservere:server--------------------------------------------需求&#xff1a;監控設計&#xff1a;原理&#xff1a;硬件&…

linux驅動 自旋鎖

最近在內核頻繁使用了自旋鎖&#xff0c;自旋鎖如果使用不當&#xff0c;極易引起死鎖&#xff0c;在此總結一下。 自旋鎖是一個互斥設備&#xff0c;它只有兩個值&#xff1a;“鎖定”和“解鎖”。它通常實現為某個整數值中的某個位。希望獲得某個特定鎖得代碼測試相關的位。…

百度輸入法

[用戶界面]&#xff1a;界面美觀&#xff0c;有不同畫風的ui界面&#xff0c;適合不同消費群體的需求。 [記住用戶選擇]&#xff1a;會默認記住用戶以往的輸入習慣&#xff0c;只需輸入首拼音字母就會出現過去使用的高頻詞。 [短期刺激]&#xff1a;美化的用戶界面讓人眼前一新…

rs232讀取智能電表_三相電表怎么看度數 怎么計算總電量

現在的三相電表一般都是在屏幕上面直接看&#xff0c;屏幕上面是有文字提示顯示的&#xff0c;三相電表的總度數&#xff0c;上面的文字提醒一般是“正向有功總電量”&#xff0c;三相電表一般屏幕旁邊都會上翻鍵和下翻鍵&#xff0c;可以上下翻開電表里面的數據。如下圖所示&a…

android 學習隨筆十六(廣播 )

1、廣播接收者 BroadcastReceiver接收系統發出的廣播現實中的廣播&#xff1a;電臺為了傳達一些消息&#xff0c;而發送的廣播&#xff0c;通過廣播攜帶要傳達的消息&#xff0c;群眾只要買一個收音機&#xff0c;就可以收到廣播了 Android中的廣播&#xff1a;系統在運行過程中…

驅動面試題總結

1、字符型驅動設備你是怎么創建設備文件的&#xff0c;就是/dev/下面的設備文件&#xff0c;供上層應用程序打開使用的文件&#xff1f; 答&#xff1a;mknod命令結合設備的主設備號和次設備號&#xff0c;可創建一個設備文件。 評&#xff1a;這只是其中一種方式&#xff0…

python程序寫詩_將Python詩歌與D結合起來

在與docker一起使用poetry時&#xff0c;需要記住以下幾點。 安裝 安裝poetry的正式方法是通過&#xff1a;curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python 這種方式允許poetry及其依賴項與依賴項分離。但是&#xff0c;在我看來…

Azure運維系列 4:安裝和使用Azure PowerShell管理云

前面講到了很多的管理方式&#xff0c;包括Azure中國最近更新的預覽版管理門戶和Azure云助理&#xff0c;都是非常不錯的管理Azure的方式&#xff0c;今天我們再來介紹一種更加高效的管理方式Azure PowerShell。熟悉命令行的朋友都知道&#xff0c;Linux之所以那么好用是因為其…

[轉]char * 和字符數組

[轉]char * 和字符數組 原文地址&#xff1a;http://www.cnblogs.com/jeakon/archive/2012/05/27/2816809.html 代碼中的int * i就是我們關注的焦點。它是一個指向int指針。也就是說&#xff1a;i指向一個內存地址&#xff0c;從這個地址開始存儲了一個數據。int * i中的int標明…

設備模型1

作為開頭篇&#xff0c;我不想寫HELLLOWORLD驅動&#xff0c;甚至字符設備驅動的開發&#xff0c;這樣文章充斥在各大網站上的博客上&#xff0c;隨便搜搜&#xff0c;就可以找到幾百篇。這是最基本的東西&#xff0c;通過這些內容的學習&#xff0c;我們要掌握LINUX驅動的基本…

如何使用Android Studio把自己的Android library分享到jCenter和Maven Central

第一部分&#xff1a;在bintray上創建package首先&#xff0c;你需要在bintray上創建一個package。為此&#xff0c;你需要一個bintray賬號&#xff0c;并在網站上創建一個package。第一步&#xff1a;在bintray.com上注冊一個賬號。&#xff08;注冊過程很簡單&#xff0c;自己…

python2編碼_Python2字符編碼

我們通常見到的字符串編碼主要是三種GB2312/GBK、Unicode、UTF-8。GB2312/GBK是多字節(multibytes)編碼的一種&#xff0c;屬于“ASCII的加強版”&#xff0c;與之平行的由Big5、ShiftJIS之類的編碼各自為政&#xff0c;所有這些用兩個字節表示漢字的多字節編碼標準統稱為ANSI編…

angularJs關于指令的一些冷門屬性

我們使用ng的時候&#xff0c;經常會使用到指令&#xff0c;大家所熟知的屬性我在這里就不介紹了&#xff0c;講講大家沒怎么留意的屬性 1.multiElement 這是指定指令作用區間的功能&#xff0c;最常用的就是ng-repeat-start和ng-repeat-end了。 2.priority 指令優先級&#xf…

設備模型2

前言 在上一篇中&#xff0c;我們大致描述了LINUX設備模型&#xff0c;我們先來總結一下三要素的關系。 從圖中可以看出,Linux設備模型就是"總線、設備、驅動、類"這四個概念之前的相互關系;這也是Linux2.6內核抽象出來的用于管理系統中所有設備的模型圖; 簡單地描述…