免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 55667 | 回复: 61

Linux驱动开发庖丁解牛之三——揭开字符设备驱动程序的面纱 [复制链接]

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2008-11-23 22:36 |显示全部楼层
Linux驱动开发庖丁解牛之三
——揭开字符设备驱动程序的面纱
By:dreamice 2008-11-23
dreamice.jiang@gmail.com
1.写在前面的话
我们知道,在Linux设备驱动开发中,包括三大设备类:字符设备,块设备和网络设备。而字符设备,作为最简单的设备类,为此,我们将从最简单的字符设备开始,走进Linux驱动程序设计的神秘殿堂。
——我们已经踏上了真正的设备驱动开发的道路了!
有志者,事竟成。付出越多,而上苍定会以同等的收获回馈于你,当然,最重要的一点是:我们必须走上正确的道路,做正确的付出。开始吧……
参考书目:
《Linux Device Driver》第三版
《Understanding the linux kernel》第三版
《Linux设备驱动开发详解》

2.必备之“砖”
盖大楼,得预先准备好砖头。同样的道理,要写好驱动程序,我们也必须准备好自己的“砖头”,拿好这些砖头,便会真正如庖丁解牛般,游刃于Linux驱动程序设计的神奇艺术之中。
在Linux的设计之初,曾提出:一切皆文件,如果一个东西不是文件,那就是进程。由此可见,文件的概念在Linux系统中可谓是根深蒂固,以至于它深入到对驱动程序的控制,这也是情理之中的事。
下图描述了Linux系统中虚拟文件系统和进程之间的关系:
fs.JPG

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2008-11-23 22:37 |显示全部楼层
图表 1进程和文件系统的关系
在上图中,我们看到了Process,File object,dentry object,inode object以及Sperblock object等概念。Process就是指一个特定的进程,而File obeject对应于进程打开的一个文件;dentry object描述了一个目录项;inode object则对应于磁盘上一个特定的文件;Sperblock object描述了文件系统的相关信息。从这个图中,可以看到进程到磁盘上一个文件实体的路径及对应关系。下面,我们一次看看这些实体结构在内核中的定义。
2.1 File object
File结构代表一个打开的文件,系统中每个打开的文件,在内核空间都对应一个file结构。它由内核在调用open时创建,并传递给在该文件上操作的所有函数,直到最后的close函数。在文件的所有实例都被关闭以后,内核才会释放这个结构。
在内核中,通常以filp来代表指向file结构的指针。File结构的详细定义如下:
//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; //与文件操作相关的函数指针结构
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 };
其中,蓝色字体标出部分,为与驱动程序最为密切的部分。由于很多书中都对这些结构体做了详细的阐述,这里就不再赘述了。

2.2 inode object
内核用inode结构在内部表示文件,它和file结构的不同之处在于:file表示打开的文件描述符,对单个文件,可能有多个表示打开的文件描述符的file结构,但他们都指向同一个inode结构。
Inode结构的详细定义如下:
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操作函数集合
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对应于一个特定的文件系统,通常对应于存放在磁盘扇区中的文件系统超级块或文件系统控制块,而对于非基于文件系统的文件,他们会在使用现场创建超级块,并将其保存到内存中。
一下是结构体的详细描述:
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中把目录也当作文件,为了方便查找操作,虚拟文件系统(VFS)引入了目录项的概念。每个dentry代表路径中一个特定部分。由于驱动程序很少涉及到dentry,所以在这里就不做描述了。

3. 实例剖析Linux字符设备驱动程序
Linux的变化真的是太快了。当我们还在研读最新版的LDD3(基于内核2.6.11)时,而实际上,它的驱动程序框架结构已经发生了很大的变化。当我还在投入的学习scull示例驱动程序的时候,我发现,对于编写一个字符设备驱动程序,已经有了新的变化。原本打算剖析scull程序,来达到融会贯通的目的,然而,面对变化,我不得不去学习一种全新的字符设备驱动程序的编写。
我想这是一种挑战,学习,是一个终身的过程。
3.1 描述字符设备体结构(cdev)
在新版的linux内核中,使用cdev结构体描述一个字符设备,其定义如下:
//include/linux/cdev.h
13 struct cdev {
14         struct kobject kobj;//kobject对象
15         struct module *owner;
16         const struct file_operations *ops;//文件操作结构体
17         struct list_head list;
18         dev_t dev;//定设备的主次设备号
19         unsigned int count;
20 };
(关于kobject还正在研究中……)
结构中的ops定义了操作File 的函数指针集,dev存储了主次设备号。注意,在很多著作中谈到Linux2.6内核中,dev_t是一个32位的类型,其中高12位存储主设备号,低20位存储次设备号。但我们最好不要这样去引用,内核版本的变化可谓是瞬息万变,很可能有一天这个约定就变化了,因此就将导致旧的驱动程序将不再兼容新的内核。最好的方式是使用下面两个宏定义获取主次设备号:
MAJOR(dev_t dev)
MINOR(dev_t dev)
使用下面的宏则可以将主次设备号生成一个dev_t:
MKDEV(int major, int minor)
一下是操作cdev结构体的相关内核函数:
22 void cdev_init(struct cdev *, const struct file_operations *); //初始化cdev结构,并建立//cdev结构和file_operations之间的连接
23
24 struct cdev *cdev_alloc(void);//动态申请cdev内存
25
26 void cdev_put(struct cdev *p);//解除读一个cdev的引用,相应的cdev_get函数增加
//对cdev的引用计数
27
28 int cdev_add(struct cdev *, dev_t, unsigned);//向系统添加一个cdev
29
30 void cdev_del(struct cdev *);//删除系统中一个cdev
31
32 void cd_forget(struct inode *);//
3.2 分配和释放设备号
int register_chrdev_region(dev_t from, unsigned count, const char *name)
该函数用于已知起始设备的设备号的情况。
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
                        const char *name)
对设备号未知的情况,使用该函数向内核动态申请未被占用的设备号。
对于一个驱动程序员来说,如果不确定设备号,最好不要妄自定义一个设备号进行注册,这样的后果是:如果该设备号已用,将注册不成功;如果该设备号在后来将被引用,那么将导致其他设备无法注册。所以,在这种情况下,最好使用动态注册的方式。
void unregister_chrdev_region(dev_t from, unsigned count)
该函数释放先前注册的设备。

3.3 一个简单的字符设备驱动程序
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  /* 虚拟字符设备内存缓冲区大小 */
  20. 20 #define MEM_CLEAR 0x1  /*  ioctl操作指令 (这里只是简单起见,不建议这么定义)*/
  21. 21 //#define GLOBALMEM_MAJOR 254    /*  静态定义主设备号 */
  22. 22 #define GLOBALMEM_MAJOR 0 /*定义动态申请主设备号*/
  23. 23
  24. 24 static int globalmem_major = GLOBALMEM_MAJOR;
  25. 25 /*globalmem 虚拟字符设备结构体 */
  26. 26 struct globalmem_dev
  27. 27 {
  28. 28   struct cdev cdev; /*cdev结构体 */
  29. 29   unsigned char mem[GLOBALMEM_SIZE]; /*虚拟设备内存区大小*/
  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   /*将设备结构体指针赋给文件私有数据 */
  36. 37   filp->private_data = globalmem_devp;
  37. 38   return 0;
  38. 39 }
  39. 40 /*释放函数*/
  40. 41 int globalmem_release(struct inode *inode, struct file *filp)
  41. 42 {
  42. 43   return 0;
  43. 44 }
  44. 45
  45. 46 /* ioct操作函数*/
  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函数*/
  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:   /*当前位置*/
  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 /*操作函数结构体*/
  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 /*初始化并注册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 /*设备驱动模块加载*/
  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   /*静态指定设备编号*/
  197. 198   if (globalmem_major)
  198. 199     result = register_chrdev_region(devno, 1, "globalmem");
  199. 200   else  /*动态申请*/
  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   /* 动态申请设备结构体内存*/
  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 /*模块卸载函数*/
  225. 226 void globalmem_exit(void)
  226. 227 {
  227. 228   cdev_del(&globalmem_devp->cdev);   /*注销cdev*/
  228. 229   kfree(globalmem_devp);     /*释放结构体内存*/
  229. 230   unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*释放设备号*/
  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);
复制代码


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
复制代码

测试:
# 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

当然,我们也可以写c程序来测试该程序。
4.总结:
    在编写字符设备驱动程序中,最重要的是file_operations这个结构,我们通常只需要实现read,write,ioctl等函数的操作。
对于一个特定的字符设备驱动的编写,必须把该设备同一个cdev结构关联起来。我们必须完成设备号的指定或者动态申请,这是设备在系统中的唯一标识。然后,完成设备驱动程序的模块初始化,以及模块注销的相关实现。
注意,file_operations与cdev结构的关联,这与老版本的驱动程序编写有很大差异。
5.后续工作
(1)研究总结kobject以及sysfs;
(2)深入学习,通过改进该实例驱动程序,使之包含更多模块及设备驱动程序编写涉及的知识点,如多个子设备,内核同步相关知识点等,来达到更深入领会字符设备驱动程序的目的。
(3)深入剖析内核文件系统。

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2008-11-23 22:39 |显示全部楼层
由于文档待完善,所以暂时没有贴出pdf文档,请谅解

论坛徽章:
0
发表于 2008-11-24 05:35 |显示全部楼层
好文章,dreamice兄辛苦了
我一直对kobject的部分存在很多的不解,刚好借此机会,稍后整理一下组织组织问题的表述向dreamice和各位请教一下,哈哈,机会难得啊

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2008-11-24 09:15 |显示全部楼层
原帖由 蓝豆 于 2008-11-24 05:35 发表
好文章,dreamice兄辛苦了
我一直对kobject的部分存在很多的不解,刚好借此机会,稍后整理一下组织组织问题的表述向dreamice和各位请教一下,哈哈,机会难得啊


kobject和sysfs我现在搞得还不是很清楚,正在研究中呢。

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
发表于 2008-11-24 13:00 |显示全部楼层
好文章,顶一下

论坛徽章:
0
发表于 2008-11-26 16:12 |显示全部楼层
# cd /sys/module/globalmem/parameters 这个目录是怎么产生的?
globalmem_major这个文件是怎么产生的?

globalmem_setup_cdev函数里面devno定义为int,是否有误?

[ 本帖最后由 yangliu817 于 2008-11-26 16:23 编辑 ]

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2008-11-26 18:16 |显示全部楼层
原帖由 yangliu817 于 2008-11-26 16:12 发表
# cd /sys/module/globalmem/parameters 这个目录是怎么产生的?
globalmem_major这个文件是怎么产生的?

globalmem_setup_cdev函数里面devno定义为int,是否有误?


这个就是系统的sysfs生成的。
程序没有问题,我都測試了的。

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
发表于 2008-11-26 18:52 |显示全部楼层
最近在dreamice兄的带动下,很多网友包括我,开始对内核中一个一个小的方面进行研究了。感觉确实学到了好多东西啊。

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2008-11-26 20:42 |显示全部楼层
原帖由 Godbach 于 2008-11-26 18:52 发表
最近在dreamice兄的带动下,很多网友包括我,开始对内核中一个一个小的方面进行研究了。感觉确实学到了好多东西啊。


Godbach,你实在是太抬举了哈,呵呵,在跟你的交流中学到了很多东西,呵呵。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP