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