国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Linux驅(qū)動(dòng)開發(fā)庖丁解牛之三——揭開字符設(shè)備驅(qū)動(dòng)程序的面紗
Linux驅(qū)動(dòng)開發(fā)庖丁解牛之三
——揭開字符設(shè)備驅(qū)動(dòng)程序的面紗
By:dreamice 2008-11-23
dreamice.jiang@gmail.com
1.寫在前面的話
我們知道,在Linux設(shè)備驅(qū)動(dòng)開發(fā)中,包括三大設(shè)備類:字符設(shè)備,塊設(shè)備和網(wǎng)絡(luò)設(shè)備。而字符設(shè)備,作為最簡(jiǎn)單的設(shè)備類,為此,我們將從最簡(jiǎn)單的字符設(shè)備開始,走進(jìn)Linux驅(qū)動(dòng)程序設(shè)計(jì)的神秘殿堂。
——我們已經(jīng)踏上了真正的設(shè)備驅(qū)動(dòng)開發(fā)的道路了!
有志者,事竟成。付出越多,而上蒼定會(huì)以同等的收獲回饋于你,當(dāng)然,最重要的一點(diǎn)是:我們必須走上正確的道路,做正確的付出。開始吧……
參考書目:
《Linux Device Driver》第三版
《Understanding the linux kernel》第三版
《Linux設(shè)備驅(qū)動(dòng)開發(fā)詳解》

2.必備之“磚”
蓋大樓,得預(yù)先準(zhǔn)備好磚頭。同樣的道理,要寫好驅(qū)動(dòng)程序,我們也必須準(zhǔn)備好自己的“磚頭”,拿好這些磚頭,便會(huì)真正如庖丁解牛般,游刃于Linux驅(qū)動(dòng)程序設(shè)計(jì)的神奇藝術(shù)之中。
在Linux的設(shè)計(jì)之初,曾提出:一切皆文件,如果一個(gè)東西不是文件,那就是進(jìn)程。由此可見,文件的概念在Linux系統(tǒng)中可謂是根深蒂固,以至于它深入到對(duì)驅(qū)動(dòng)程序的控制,這也是情理之中的事。
下圖描述了Linux系統(tǒng)中虛擬文件系統(tǒng)和進(jìn)程之間的關(guān)系:

fs.JPG (25.04 KB)

 

fs

__________________________________
Nothing is impossible!



 

圖表 1進(jìn)程和文件系統(tǒng)的關(guān)系
在上圖中,我們看到了Process,F(xiàn)ile object,dentry object,inode object以及Sperblock object等概念。Process就是指一個(gè)特定的進(jìn)程,而File obeject對(duì)應(yīng)于進(jìn)程打開的一個(gè)文件;dentry object描述了一個(gè)目錄項(xiàng);inode object則對(duì)應(yīng)于磁盤上一個(gè)特定的文件;Sperblock object描述了文件系統(tǒng)的相關(guān)信息。從這個(gè)圖中,可以看到進(jìn)程到磁盤上一個(gè)文件實(shí)體的路徑及對(duì)應(yīng)關(guān)系。下面,我們一次看看這些實(shí)體結(jié)構(gòu)在內(nèi)核中的定義。
2.1 File object
File結(jié)構(gòu)代表一個(gè)打開的文件,系統(tǒng)中每個(gè)打開的文件,在內(nèi)核空間都對(duì)應(yīng)一個(gè)file結(jié)構(gòu)。它由內(nèi)核在調(diào)用open時(shí)創(chuàng)建,并傳遞給在該文件上操作的所有函數(shù),直到最后的close函數(shù)。在文件的所有實(shí)例都被關(guān)閉以后,內(nèi)核才會(huì)釋放這個(gè)結(jié)構(gòu)。
在內(nèi)核中,通常以filp來代表指向file結(jié)構(gòu)的指針。File結(jié)構(gòu)的詳細(xì)定義如下:
//linux/fs.h
779 struct file {
780         /*
781          * fu_list becomes invalid after file_free is called and queued via
782          * fu_rcuhead for RCU freeing
783          */
784         union {
785                 struct list_head        fu_list;
786                 struct rcu_head         fu_rcuhead;
787         } f_u;
788         struct path             f_path;
789 #define f_dentry        f_path.dentry
790 #define f_vfsmnt        f_path.mnt
791         const struct file_operations    *f_op; //與文件操作相關(guān)的函數(shù)指針結(jié)構(gòu)
792         atomic_t                f_count;
793         unsigned int            f_flags;
794         mode_t                  f_mode;
795         loff_t                  f_pos;
796         struct fown_struct      f_owner;
797         unsigned int            f_uid, f_gid;
798         struct file_ra_state    f_ra;
799
800         u64                     f_version;
801 #ifdef CONFIG_SECURITY
802         void                    *f_security;
803 #endif
804         /* needed for tty driver, and maybe others */
805         void                    *private_data;
806
807 #ifdef CONFIG_EPOLL
808         /* Used by fs/eventpoll.c to link all the hooks to this file */
809         struct list_head        f_ep_links;
810         spinlock_t              f_ep_lock;
811 #endif /* #ifdef CONFIG_EPOLL */
812         struct address_space    *f_mapping;
813 };

1166 /*
1167  * NOTE:
1168  * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl
1169  * can be called without the big kernel lock held in all filesystems.
1170  */
1171 struct file_operations {
1172         struct module *owner;
1173         loff_t (*llseek) (struct file *, loff_t, int);
1174         ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
1175         ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
1176         ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
1177         ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
1178         int (*readdir) (struct file *, void *, filldir_t);
1179         unsigned int (*poll) (struct file *, struct poll_table_struct *);
1180         int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
1181         long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
1182         long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
1183         int (*mmap) (struct file *, struct vm_area_struct *);
1184         int (*open) (struct inode *, struct file *);
1185         int (*flush) (struct file *, fl_owner_t id);
1186         int (*release) (struct inode *, struct file *);
1187         int (*fsync) (struct file *, struct dentry *, int datasync);
1188         int (*aio_fsync) (struct kiocb *, int datasync);
1189         int (*fasync) (int, struct file *, int);
1190         int (*lock) (struct file *, int, struct file_lock *);
1191         ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
1192         unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
1193         int (*check_flags)(int);
1194         int (*dir_notify)(struct file *filp, unsigned long arg);
1195         int (*flock) (struct file *, int, struct file_lock *);
1196         ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
1197         ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
1198         int (*setlease)(struct file *, long, struct file_lock **);
1199 };
其中,藍(lán)色字體標(biāo)出部分,為與驅(qū)動(dòng)程序最為密切的部分。由于很多書中都對(duì)這些結(jié)構(gòu)體做了詳細(xì)的闡述,這里就不再贅述了。

2.2 inode object
內(nèi)核用inode結(jié)構(gòu)在內(nèi)部表示文件,它和file結(jié)構(gòu)的不同之處在于:file表示打開的文件描述符,對(duì)單個(gè)文件,可能有多個(gè)表示打開的文件描述符的file結(jié)構(gòu),但他們都指向同一個(gè)inode結(jié)構(gòu)。
Inode結(jié)構(gòu)的詳細(xì)定義如下:
593 struct inode {
594         struct hlist_node       i_hash;
595         struct list_head        i_list;
596         struct list_head        i_sb_list;
597         struct list_head        i_dentry;
598         unsigned long           i_ino;
599         atomic_t                i_count;
600         unsigned int            i_nlink;
601         uid_t                   i_uid;
602         gid_t                   i_gid;
603         dev_t                   i_rdev;
604         u64                     i_version;
605         loff_t                  i_size;
606 #ifdef __NEED_I_SIZE_ORDERED
607         seqcount_t              i_size_seqcount;
608 #endif
609         struct timespec         i_atime;
610         struct timespec         i_mtime;
611         struct timespec         i_ctime;
612         unsigned int            i_blkbits;
613         blkcnt_t                i_blocks;
614         unsigned short          i_bytes;
615         umode_t                 i_mode;
616         spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
617         struct mutex            i_mutex;
618         struct rw_semaphore     i_alloc_sem;
619         const struct inode_operations   *i_op;//inode操作函數(shù)集合
620         const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */
621         struct super_block      *i_sb;
622         struct file_lock        *i_flock;
623         struct address_space    *i_mapping;
624         struct address_space    i_data;
625 #ifdef CONFIG_QUOTA
626         struct dquot            *i_dquot[MAXQUOTAS];
627 #endif
628         struct list_head        i_devices;
629         union {
630                 struct pipe_inode_info  *i_pipe;
631                 struct block_device     *i_bdev;
632                 struct cdev             *i_cdev;
633         };
634         int                     i_cindex;
635
636         __u32                   i_generation;
637
638 #ifdef CONFIG_DNOTIFY
639         unsigned long           i_dnotify_mask; /* Directory notify events */
640         struct dnotify_struct   *i_dnotify; /* for directory notifications */
641 #endif
642
643 #ifdef CONFIG_INOTIFY
644         struct list_head        inotify_watches; /* watches on this inode */
645         struct mutex            inotify_mutex;  /* protects the watches list */
646 #endif
647
648         unsigned long           i_state;
649         unsigned long           dirtied_when;   /* jiffies of first dirtying */
650
651         unsigned int            i_flags;
652
653         atomic_t                i_writecount;
654 #ifdef CONFIG_SECURITY
655         void                    *i_security;
656 #endif
657         void                    *i_private; /* fs or device private pointer */
658 };
2.3 Super block object
Super block object對(duì)應(yīng)于一個(gè)特定的文件系統(tǒng),通常對(duì)應(yīng)于存放在磁盤扇區(qū)中的文件系統(tǒng)超級(jí)塊或文件系統(tǒng)控制塊,而對(duì)于非基于文件系統(tǒng)的文件,他們會(huì)在使用現(xiàn)場(chǎng)創(chuàng)建超級(jí)塊,并將其保存到內(nèi)存中。
一下是結(jié)構(gòu)體的詳細(xì)描述:
981 struct super_block {
982         struct list_head        s_list;         /* Keep this first */
983         dev_t                   s_dev;          /* search index; _not_ kdev_t */
984         unsigned long           s_blocksize;
985         unsigned char           s_blocksize_bits;
986         unsigned char           s_dirt;
987         unsigned long long      s_maxbytes;     /* Max file size */
988         struct file_system_type *s_type;
989         const struct super_operations   *s_op;
990         struct dquot_operations *dq_op;
991         struct quotactl_ops     *s_qcop;
992         const struct export_operations *s_export_op;
993         unsigned long           s_flags;
994         unsigned long           s_magic;
995         struct dentry           *s_root;
996         struct rw_semaphore     s_umount;
997         struct mutex            s_lock;
998         int                     s_count;
999         int                     s_syncing;
1000         int                     s_need_sync_fs;
1001         atomic_t                s_active;
1002 #ifdef CONFIG_SECURITY
1003         void                    *s_security;
1004 #endif
1005         struct xattr_handler    **s_xattr;
1006
1007         struct list_head        s_inodes;       /* all inodes */
1008         struct list_head        s_dirty;        /* dirty inodes */
1009         struct list_head        s_io;           /* parked for writeback */
1010         struct list_head        s_more_io;      /* parked for more writeback */
1011         struct hlist_head       s_anon;         /* anonymous dentries for (nfs) exporting */
1012         struct list_head        s_files;
1013
1014         struct block_device     *s_bdev;
1015         struct mtd_info         *s_mtd;
1016         struct list_head        s_instances;
1017         struct quota_info       s_dquot;        /* Diskquota specific options */
1018
1019         int                     s_frozen;
1020         wait_queue_head_t       s_wait_unfrozen;
1021
1022         char s_id[32];                          /* Informational name */
1023
1024         void                    *s_fs_info;     /* Filesystem private info */
1025
1026         /*
1027          * The next field is for VFS *only*. No filesystems have any business
1028          * even looking at it. You had been warned.
1029          */
1030         struct mutex s_vfs_rename_mutex;        /* Kludge */
1031
1032         /* Granularity of c/m/atime in ns.
1033            Cannot be worse than a second */
1034         u32                s_time_gran;
1035
1036         /*
1037          * Filesystem subtype.  If non-empty the filesystem type field
1038          * in /proc/mounts will be "type.subtype"
1039          */
1040         char *s_subtype;
1041
1042         /*
1043          * Saved mount options for lazy filesystems using
1044          * generic_show_options()
1045          */
1046         char *s_options;
1047 };

2.4 Identry object
Linux中把目錄也當(dāng)作文件,為了方便查找操作,虛擬文件系統(tǒng)(VFS)引入了目錄項(xiàng)的概念。每個(gè)dentry代表路徑中一個(gè)特定部分。由于驅(qū)動(dòng)程序很少涉及到dentry,所以在這里就不做描述了。

3. 實(shí)例剖析Linux字符設(shè)備驅(qū)動(dòng)程序
Linux的變化真的是太快了。當(dāng)我們還在研讀最新版的LDD3(基于內(nèi)核2.6.11)時(shí),而實(shí)際上,它的驅(qū)動(dòng)程序框架結(jié)構(gòu)已經(jīng)發(fā)生了很大的變化。當(dāng)我還在投入的學(xué)習(xí)scull示例驅(qū)動(dòng)程序的時(shí)候,我發(fā)現(xiàn),對(duì)于編寫一個(gè)字符設(shè)備驅(qū)動(dòng)程序,已經(jīng)有了新的變化。原本打算剖析scull程序,來達(dá)到融會(huì)貫通的目的,然而,面對(duì)變化,我不得不去學(xué)習(xí)一種全新的字符設(shè)備驅(qū)動(dòng)程序的編寫。
我想這是一種挑戰(zhàn),學(xué)習(xí),是一個(gè)終身的過程。
3.1 描述字符設(shè)備體結(jié)構(gòu)(cdev)
在新版的linux內(nèi)核中,使用cdev結(jié)構(gòu)體描述一個(gè)字符設(shè)備,其定義如下:
//include/linux/cdev.h
13 struct cdev {
14         struct kobject kobj;//kobject對(duì)象
15         struct module *owner;
16         const struct file_operations *ops;//文件操作結(jié)構(gòu)體
17         struct list_head list;
18         dev_t dev;//定設(shè)備的主次設(shè)備號(hào)
19         unsigned int count;
20 };
(關(guān)于kobject還正在研究中……)
結(jié)構(gòu)中的ops定義了操作File 的函數(shù)指針集,dev存儲(chǔ)了主次設(shè)備號(hào)。注意,在很多著作中談到Linux2.6內(nèi)核中,dev_t是一個(gè)32位的類型,其中高12位存儲(chǔ)主設(shè)備號(hào),低20位存儲(chǔ)次設(shè)備號(hào)。但我們最好不要這樣去引用,內(nèi)核版本的變化可謂是瞬息萬變,很可能有一天這個(gè)約定就變化了,因此就將導(dǎo)致舊的驅(qū)動(dòng)程序?qū)⒉辉偌嫒菪碌膬?nèi)核。最好的方式是使用下面兩個(gè)宏定義獲取主次設(shè)備號(hào):
MAJOR(dev_t dev)
MINOR(dev_t dev)
使用下面的宏則可以將主次設(shè)備號(hào)生成一個(gè)dev_t:
MKDEV(int major, int minor)
一下是操作cdev結(jié)構(gòu)體的相關(guān)內(nèi)核函數(shù):
22 void cdev_init(struct cdev *, const struct file_operations *); //初始化cdev結(jié)構(gòu),并建立//cdev結(jié)構(gòu)和file_operations之間的連接
23
24 struct cdev *cdev_alloc(void);//動(dòng)態(tài)申請(qǐng)cdev內(nèi)存
25
26 void cdev_put(struct cdev *p);//解除讀一個(gè)cdev的引用,相應(yīng)的cdev_get函數(shù)增加
//對(duì)cdev的引用計(jì)數(shù)
27
28 int cdev_add(struct cdev *, dev_t, unsigned);//向系統(tǒng)添加一個(gè)cdev
29
30 void cdev_del(struct cdev *);//刪除系統(tǒng)中一個(gè)cdev
31
32 void cd_forget(struct inode *);//
3.2 分配和釋放設(shè)備號(hào)
int register_chrdev_region(dev_t from, unsigned count, const char *name)
該函數(shù)用于已知起始設(shè)備的設(shè)備號(hào)的情況。
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
                        const char *name)
對(duì)設(shè)備號(hào)未知的情況,使用該函數(shù)向內(nèi)核動(dòng)態(tài)申請(qǐng)未被占用的設(shè)備號(hào)。
對(duì)于一個(gè)驅(qū)動(dòng)程序員來說,如果不確定設(shè)備號(hào),最好不要妄自定義一個(gè)設(shè)備號(hào)進(jìn)行注冊(cè),這樣的后果是:如果該設(shè)備號(hào)已用,將注冊(cè)不成功;如果該設(shè)備號(hào)在后來將被引用,那么將導(dǎo)致其他設(shè)備無法注冊(cè)。所以,在這種情況下,最好使用動(dòng)態(tài)注冊(cè)的方式。
void unregister_chrdev_region(dev_t from, unsigned count)
該函數(shù)釋放先前注冊(cè)的設(shè)備。

3.3 一個(gè)簡(jiǎn)單的字符設(shè)備驅(qū)動(dòng)程序
global_mem.c
  1.   1 /*=============================================================
  2.   2     A simple example of char device drivers
  3.   3
  4.   4     
  5.   5     <[email]dreamice.jiang@gmail.com[/email]>
  6.   6  ============================================================*/
  7.   7 #include <linux/module.h>
  8.   8 #include <linux/types.h>
  9.   9 #include <linux/fs.h>
  10. 10 #include <linux/errno.h>
  11. 11 #include <linux/mm.h>
  12. 12 #include <linux/sched.h>
  13. 13 #include <linux/init.h>
  14. 14 #include <linux/cdev.h>
  15. 15 #include <asm/io.h>
  16. 16 #include <asm/system.h>
  17. 17 #include <asm/uaccess.h>
  18. 18
  19. 19 #define GLOBALMEM_SIZE  0x1000  /* 虛擬字符設(shè)備內(nèi)存緩沖區(qū)大小 */
  20. 20 #define MEM_CLEAR 0x1  /*  ioctl操作指令 (這里只是簡(jiǎn)單起見,不建議這么定義)*/
  21. 21 //#define GLOBALMEM_MAJOR 254    /*  靜態(tài)定義主設(shè)備號(hào) */
  22. 22 #define GLOBALMEM_MAJOR 0 /*定義動(dòng)態(tài)申請(qǐng)主設(shè)備號(hào)*/
  23. 23
  24. 24 static int globalmem_major = GLOBALMEM_MAJOR;
  25. 25 /*globalmem 虛擬字符設(shè)備結(jié)構(gòu)體 */
  26. 26 struct globalmem_dev
  27. 27 {
  28. 28   struct cdev cdev; /*cdev結(jié)構(gòu)體 */
  29. 29   unsigned char mem[GLOBALMEM_SIZE]; /*虛擬設(shè)備內(nèi)存區(qū)大小*/
  30. 30 };
  31. 31
  32. 32 struct globalmem_dev *globalmem_devp;
  33. 34 int globalmem_open(struct inode *inode, struct file *filp)
  34. 35 {
  35. 36   /*將設(shè)備結(jié)構(gòu)體指針賦給文件私有數(shù)據(jù) */
  36. 37   filp->private_data = globalmem_devp;
  37. 38   return 0;
  38. 39 }
  39. 40 /*釋放函數(shù)*/
  40. 41 int globalmem_release(struct inode *inode, struct file *filp)
  41. 42 {
  42. 43   return 0;
  43. 44 }
  44. 45
  45. 46 /* ioct操作函數(shù)*/
  46. 47 static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned
  47. 48   int cmd, unsigned long arg)
  48. 49 {
  49. 50   struct globalmem_dev *dev = filp->private_data;/*&raquo;&ntilde;&micro;&Atilde;&Eacute;è±&cedil;&frac12;á&sup1;&sup1;&Igrave;&aring;&Ouml;&cedil;&Otilde;&euml;*/
  50. 51
  51. 52   switch (cmd)
  52. 53   {
  53. 54     case MEM_CLEAR:
  54. 55       memset(dev->mem, 0, GLOBALMEM_SIZE);
  55. 56       printk(KERN_INFO "globalmem is set to zero\n");
  56. 57       break;
  57. 58
  58. 59     default:
  59. 60       return  - EINVAL;
  60. 61   }
  61. 62   return 0;
  62. 63 }
  63. 64
  64. 65 /*read函數(shù)*/
  65. 66 static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size,
  66. 67   loff_t *ppos)
  67. 68 {
  68. 69   unsigned long p =  *ppos;
  69. 70   unsigned int count = size;
  70. 71   int ret = 0;
  71. 72   struct globalmem_dev *dev = filp->private_data;
  72. 73
  73. 74   
  74. 75   if (p >= GLOBALMEM_SIZE)
  75. 76     return count ?  - ENXIO: 0;
  76. 77   if (count > GLOBALMEM_SIZE - p)
  77. 78     count = GLOBALMEM_SIZE - p;
  78. 79
  79. 80   
  80. 81   if (copy_to_user(buf, (void*)(dev->mem + p), count))
  81. 82   {
  82. 83     ret =  - EFAULT;
  83. 84   }
  84. 85   else
  85. 86   {
  86. 87     *ppos += count;
  87. 88     ret = count;
  88. 89
  89. 90     printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);
  90. 91   }
  91. 92
  92. 93   return ret;
  93. 94 }
  94. 95
  95. 96 /*&ETH;&acute;&ordm;&macr;&Ecirc;&yacute;*/
  96. 97 static ssize_t globalmem_write(struct file *filp, const char __user *buf,
  97. 98   size_t size, loff_t *ppos)
  98. 99 {
  99. 100   unsigned long p =  *ppos;
  100. 101   unsigned int count = size;
  101. 102   int ret = 0;
  102. 103   struct globalmem_dev *dev = filp->private_data;
  103. 104
  104. 105   
  105. 106   if (p >= GLOBALMEM_SIZE)
  106. 107     return count ?  - ENXIO: 0;
  107. 108   if (count > GLOBALMEM_SIZE - p)
  108. 109     count = GLOBALMEM_SIZE - p;
  109. 110
  110. 111   //
  111. 112   if (copy_from_user(dev->mem + p, buf, count))
  112. 113     ret =  - EFAULT;
  113. 114   else
  114. 115   {
  115. 116     *ppos += count;
  116. 117     ret = count;
  117. 118
  118. 119     printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p);
  119. 120   }
  120. 121
  121. 122   return ret;
  122. 123 }
  123. 124
  124. 125
  125. 126 static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
  126. 127 {
  127. 128   loff_t ret = 0;
  128. 129   switch (orig)
  129. 130   {
  130. 131     case 0:  //起始位置
  131. 132       if (offset < 0)
  132. 133       {
  133. 134         ret =  - EINVAL;
  134. 135         break;
  135. 136       }
  136. 137       if ((unsigned int)offset > GLOBALMEM_SIZE)
  137. 138       {
  138. 139         ret =  - EINVAL;
  139. 140         break;
  140. 141       }
  141. 142       filp->f_pos = (unsigned int)offset;
  142. 143       ret = filp->f_pos;
  143. 144       break;
  144. 145     case 1:   /*當(dāng)前位置*/
  145. 146       if ((filp->f_pos + offset) > GLOBALMEM_SIZE)
  146. 147       {
  147. 148         ret =  - EINVAL;
  148. 149         break;
  149. 150       }
  150. 151       if ((filp->f_pos + offset) < 0)
  151. 152       {
  152. 153         ret =  - EINVAL;
  153. 154         break;
  154. 155       }
  155. 156       filp->f_pos += offset;
  156. 157       ret = filp->f_pos;
  157. 158       break;
  158. 159     default:
  159. 160       ret =  - EINVAL;
  160. 161       break;
  161. 162   }
  162. 163   return ret;
  163. 164 }
  164. 165
  165. 166 /*操作函數(shù)結(jié)構(gòu)體*/
  166. 167 static const struct file_operations globalmem_fops =
  167. 168 {
  168. 169   .owner = THIS_MODULE,
  169. 170   .llseek = globalmem_llseek,
  170. 171   .read = globalmem_read,
  171. 172   .write = globalmem_write,
  172. 173   .ioctl = globalmem_ioctl,
  173. 174   .open = globalmem_open,
  174. 175   .release = globalmem_release,
  175. 176 };
  176. 177
  177. 178 /*初始化并注冊(cè)cdev */
  178. 179 static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
  179. 180 {
  180. 181   int err, devno = MKDEV(globalmem_major, index);
  181. 182
  182. 183   cdev_init(&dev->cdev, &globalmem_fops);
  183. 184   dev->cdev.owner = THIS_MODULE;
  184. 185   dev->cdev.ops = &globalmem_fops;
  185. 186   err = cdev_add(&dev->cdev, devno, 1);
  186. 187   if (err)
  187. 188     printk(KERN_NOTICE "Error %d adding LED%d", err, index);
  188. 189 }
  189. 190
  190. 191 /*設(shè)備驅(qū)動(dòng)模塊加載*/
  191. 192 int globalmem_init(void)
  192. 193 {
  193. 194   int result;
  194. 195   dev_t devno = MKDEV(globalmem_major, 0);
  195. 196
  196. 197   /*靜態(tài)指定設(shè)備編號(hào)*/
  197. 198   if (globalmem_major)
  198. 199     result = register_chrdev_region(devno, 1, "globalmem");
  199. 200   else  /*動(dòng)態(tài)申請(qǐng)*/
  200. 201   {
  201. 202     result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
  202. 203     globalmem_major = MAJOR(devno);
  203. 204   }
  204. 205   if (result < 0)
  205. 206     return result;
  206. 207
  207. 208   /* 動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備結(jié)構(gòu)體內(nèi)存*/
  208. 209   globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
  209. 210   if (!globalmem_devp)    /*&Eacute;ê&Ccedil;&euml;&Ecirc;§°&Uuml;*/
  210. 211   {
  211. 212     result =  - ENOMEM;
  212. 213     goto fail_malloc;
  213. 214   }
  214. 215   memset(globalmem_devp, 0, sizeof(struct globalmem_dev));
  215. 216
  216. 217   globalmem_setup_cdev(globalmem_devp, 0);
  217. 218   printk(KERN_INFO"Init global_mem success!\n");
  218. 219   return 0;
  219. 220
  220. 221   fail_malloc: unregister_chrdev_region(devno, 1);
  221. 222   return result;
  222. 223 }
  223. 224
  224. 225 /*模塊卸載函數(shù)*/
  225. 226 void globalmem_exit(void)
  226. 227 {
  227. 228   cdev_del(&globalmem_devp->cdev);   /*注銷cdev*/
  228. 229   kfree(globalmem_devp);     /*釋放結(jié)構(gòu)體內(nèi)存*/
  229. 230   unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*釋放設(shè)備號(hào)*/
  230. 231   printk(KERN_INFO"Bye-bye global_mem!\n");
  231. 232 }
  232. 233
  233. 234 MODULE_AUTHOR("Dreamice");
  234. 235 MODULE_LICENSE("Dual BSD/GPL");
  235. 236
  236. 237 module_param(globalmem_major, int, S_IRUGO);
  237. 238
  238. 239 module_init(globalmem_init);
  239. 240 module_exit(globalmem_exit);
復(fù)制代碼


Makefile:
  1.   1 TARGET = global_mem
  2.   2 KDIR = /lib/modules/$(shell uname -r)/build
  3.   3 PWD = $(shell pwd)
  4.   4 obj-m := $(TARGET).o
  5.   5 default:
  6.   6         make -C $(KDIR) M=$(PWD) modules
  7.   7 clean:
  8.   8         $(RM) *.o *.ko *.mod.c Module.symvers modules.order
復(fù)制代碼

測(cè)試:
# cd /sys/module/globalmem/parameters
# cat globalmem_major
251
# mknod /dev/globalmem c 251 0
# echo ‘hello dreamice’ > /dev/gloablmem
# cat /dev/gloablmem
hello dreamice

當(dāng)然,我們也可以寫c程序來測(cè)試該程序。
4.總結(jié):
    在編寫字符設(shè)備驅(qū)動(dòng)程序中,最重要的是file_operations這個(gè)結(jié)構(gòu),我們通常只需要實(shí)現(xiàn)read,write,ioctl等函數(shù)的操作。
對(duì)于一個(gè)特定的字符設(shè)備驅(qū)動(dòng)的編寫,必須把該設(shè)備同一個(gè)cdev結(jié)構(gòu)關(guān)聯(lián)起來。我們必須完成設(shè)備號(hào)的指定或者動(dòng)態(tài)申請(qǐng),這是設(shè)備在系統(tǒng)中的唯一標(biāo)識(shí)。然后,完成設(shè)備驅(qū)動(dòng)程序的模塊初始化,以及模塊注銷的相關(guān)實(shí)現(xiàn)。
注意,file_operations與cdev結(jié)構(gòu)的關(guān)聯(lián),這與老版本的驅(qū)動(dòng)程序編寫有很大差異。
5.后續(xù)工作
(1)研究總結(jié)kobject以及sysfs;
(2)深入學(xué)習(xí),通過改進(jìn)該實(shí)例驅(qū)動(dòng)程序,使之包含更多模塊及設(shè)備驅(qū)動(dòng)程序編寫涉及的知識(shí)點(diǎn),如多個(gè)子設(shè)備,內(nèi)核同步相關(guān)知識(shí)點(diǎn)等,來達(dá)到更深入領(lǐng)會(huì)字符設(shè)備驅(qū)動(dòng)程序的目的。
(3)深入剖析內(nèi)核文件系統(tǒng)。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux內(nèi)核開發(fā)之簡(jiǎn)單字符設(shè)備驅(qū)動(dòng)(上)
十一、Linux驅(qū)動(dòng)程序開發(fā)(3) - 字符設(shè)備驅(qū)動(dòng)(2)-globalmem設(shè)備驅(qū)動(dòng)
[快速上手Linux設(shè)備驅(qū)動(dòng)]之我看字符設(shè)備驅(qū)動(dòng)
字符設(shè)備驅(qū)動(dòng)程序及數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)介
Linux設(shè)備驅(qū)動(dòng)開發(fā)詳解小結(jié)(一)之字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)
深入淺出:Linux設(shè)備驅(qū)動(dòng)之字符設(shè)備驅(qū)動(dòng) - 博客 - 伯樂在線
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服