字符设备驱动--globalmem+mult_globalmem

1,设备描述符globalmem的代码如下所示:

  1 /*
  2  * a simple char device driver: globalmem without mutex
  3  *
  4  * Copyright (C) 2014 Barry Song  (baohua@kernel.org)
  5  *
  6  * Licensed under GPLv2 or later.
  7  */
  8 
  9 #include <linux/module.h>
 10 #include <linux/fs.h>
 11 #include <linux/init.h>
 12 #include <linux/cdev.h>
 13 #include <linux/slab.h>
 14 #include <linux/uaccess.h>
 15 
 16 #define GLOBALMEM_SIZE    0x1000
 17 #define MEM_CLEAR 0x1
 18 #define GLOBALMEM_MAJOR 230
 19 
 20 static int globalmem_major = GLOBALMEM_MAJOR;
 21 module_param(globalmem_major, int, S_IRUGO);
 22 
 23 struct globalmem_dev {
 24     struct cdev cdev;
 25     unsigned char mem[GLOBALMEM_SIZE];
 26 };
 27 
 28 struct globalmem_dev *globalmem_devp;
 29 
 30 static int globalmem_open(struct inode *inode, struct file *filp)
 31 {
 32     filp->private_data = globalmem_devp;
 33     return 0;
 34 }
 35 
 36 static int globalmem_release(struct inode *inode, struct file *filp)
 37 {
 38     return 0;
 39 }
 40 
 41 static long globalmem_ioctl(struct file *filp, unsigned int cmd,
 42                 unsigned long arg)
 43 {
 44     struct globalmem_dev *dev = filp->private_data;
 45 
 46     switch (cmd) {
 47     case MEM_CLEAR:
 48         memset(dev->mem, 0, GLOBALMEM_SIZE);
 49         printk(KERN_INFO "globalmem is set to zero\n");
 50         break;
 51 
 52     default:
 53         return -EINVAL;
 54     }
 55 
 56     return 0;
 57 }
 58 
 59 static ssize_t globalmem_read(struct file *filp, char __user * buf, size_t size,
 60                   loff_t * ppos)
 61 {
 62     unsigned long p = *ppos;
 63     unsigned int count = size;
 64     int ret = 0;
 65     struct globalmem_dev *dev = filp->private_data;
 66 
 67     if (p >= GLOBALMEM_SIZE)
 68         return 0;
 69     if (count > GLOBALMEM_SIZE - p)
 70         count = GLOBALMEM_SIZE - p;
 71 
 72     if (copy_to_user(buf, dev->mem + p, count)) {
 73         ret = -EFAULT;
 74     } else {
 75         *ppos += count;
 76         ret = count;
 77 
 78         printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);
 79     }
 80 
 81     return ret;
 82 }
 83 
 84 static ssize_t globalmem_write(struct file *filp, const char __user * buf,
 85                    size_t size, loff_t * ppos)
 86 {
 87     unsigned long p = *ppos;
 88     unsigned int count = size;
 89     int ret = 0;
 90     struct globalmem_dev *dev = filp->private_data;
 91 
 92     if (p >= GLOBALMEM_SIZE)
 93         return 0;
 94     if (count > GLOBALMEM_SIZE - p)
 95         count = GLOBALMEM_SIZE - p;
 96 
 97     if (copy_from_user(dev->mem + p, buf, count))
 98         ret = -EFAULT;
 99     else {
100         *ppos += count;
101         ret = count;
102 
103         printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p);
104     }
105 
106     return ret;
107 }
108 
109 static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
110 {
111     loff_t ret = 0;
112     switch (orig) {
113     case 0:
114         if (offset < 0) {
115             ret = -EINVAL;
116             break;
117         }
118         if ((unsigned int)offset > GLOBALMEM_SIZE) {
119             ret = -EINVAL;
120             break;
121         }
122         filp->f_pos = (unsigned int)offset;
123         ret = filp->f_pos;
124         break;
125     case 1:
126         if ((filp->f_pos + offset) > GLOBALMEM_SIZE) {
127             ret = -EINVAL;
128             break;
129         }
130         if ((filp->f_pos + offset) < 0) {
131             ret = -EINVAL;
132             break;
133         }
134         filp->f_pos += offset;
135         ret = filp->f_pos;
136         break;
137     default:
138         ret = -EINVAL;
139         break;
140     }
141     return ret;
142 }
143 
144 static const struct file_operations globalmem_fops = {
145     .owner = THIS_MODULE,
146     .llseek = globalmem_llseek,
147     .read = globalmem_read,
148     .write = globalmem_write,
149     .unlocked_ioctl = globalmem_ioctl,
150     .open = globalmem_open,
151     .release = globalmem_release,
152 };
153 
154 static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
155 {
156     int err, devno = MKDEV(globalmem_major, index);
157 
158     cdev_init(&dev->cdev, &globalmem_fops);
159     dev->cdev.owner = THIS_MODULE;
160     err = cdev_add(&dev->cdev, devno, 1);
161     if (err)
162         printk(KERN_NOTICE "Error %d adding globalmem%d", err, index);
163 }
164 
165 static int __init globalmem_init(void)
166 {
167     int ret;
168     dev_t devno = MKDEV(globalmem_major, 0);
169 
170     if (globalmem_major)
171         ret = register_chrdev_region(devno, 1, "globalmem");
172     else {
173         ret = alloc_chrdev_region(&devno, 0, 1, "globalmem");
174         globalmem_major = MAJOR(devno);
175     }
176     if (ret < 0)
177         return ret;
178 
179     globalmem_devp = kzalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
180     if (!globalmem_devp) {
181         ret = -ENOMEM;
182         goto fail_malloc;
183     }
184 
185     globalmem_setup_cdev(globalmem_devp, 0);
186     return 0;
187 
188  fail_malloc:
189     unregister_chrdev_region(devno, 1);
190     return ret;
191 }
192 module_init(globalmem_init);
193 
194 static void __exit globalmem_exit(void)
195 {
196     cdev_del(&globalmem_devp->cdev);
197     kfree(globalmem_devp);
198     unregister_chrdev_region(MKDEV(globalmem_major, 0), 1);
199 }
200 module_exit(globalmem_exit);
201 
202 MODULE_AUTHOR("Barry Song <baohua@kernel.org>");
203 MODULE_LICENSE("GPL v2");

1.1 l68行的globalmem_init()中的 dev_t devno = MKDEV(globalmem_major, 0); 

1)其中dev_t的定义如下所示:

typedef __u32 __kernel_dev_t;

typedef __kernel_fd_set        fd_set;
typedef __kernel_dev_t        dev_t;

dev_t实际上是32bit的无符号类型;

2)MKDEV()原型如下所示:

#define MAJOR(dev)    ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev)    ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))

dev_t devno = MKDEV(globalmem_major, 0);----表示主设备号是globalmem_major,次设备号是0;通过MKDEV之后,得到的是32位的设备号

MAJOR是通过设备号获取主设备号;MINOR是通过设备号获取次设备号;12位为主设备号,20位为次设备号

1.2 第171行 ret = register_chrdev_region(devno, 1, "globalmem"); register_chrdev_region的原型如下所示:from表示设备号起始地址,count表示设备个数,*name表示设备名

 1 /**
 2  * register_chrdev_region() - register a range of device numbers
 3  * @from: the first in the desired range of device numbers; must include
 4  *        the major number.
 5  * @count: the number of consecutive device numbers required
 6  * @name: the name of the device or driver.
 7  *
 8  * Return value is zero on success, a negative error code on failure.
 9  */
10 int register_chrdev_region(dev_t from, unsigned count, const char *name)
11 {
12     struct char_device_struct *cd;
13     dev_t to = from + count;
14     dev_t n, next;
15 
16     for (n = from; n < to; n = next) {
17         next = MKDEV(MAJOR(n)+1, 0);
18         if (next > to)
19             next = to;
20         cd = __register_chrdev_region(MAJOR(n), MINOR(n),
21                    next - n, name);
22         if (IS_ERR(cd))
23             goto fail;
24     }
25     return 0;
26 fail:
27     to = n;
28     for (n = from; n < to; n = next) {
29         next = MKDEV(MAJOR(n)+1, 0);
30         kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
31     }
32     return PTR_ERR(cd);
33 }

1.3 第179行 globalmem_devp = kzalloc(sizeof(struct globalmem_dev), GFP_KERNEL); 

1)kzalloc的源码如下所示:

/**
 * kzalloc - allocate memory. The memory is set to zero.
 * @size: how many bytes of memory are required.
 * @flags: the type of memory to allocate (see kmalloc).
 */
static inline void *kzalloc(size_t size, gfp_t flags)
{
    return kmalloc(size, flags | __GFP_ZERO);
}

其中gfp_t定义为 typedef unsigned __bitwise__ gfp_t; 是bitwise类型的,个人理解类似独热码

2)GFP_KERNEL定义如下所示:

 #define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS) 

其中__GFP_WAIT等的定义如下所示:

 1 /* Plain integer GFP bitmasks. Do not use this directly. */
 2 #define ___GFP_DMA        0x01u
 3 #define ___GFP_HIGHMEM        0x02u
 4 #define ___GFP_DMA32        0x04u
 5 #define ___GFP_MOVABLE        0x08u
 6 #define ___GFP_WAIT        0x10u
 7 #define ___GFP_HIGH        0x20u
 8 #define ___GFP_IO        0x40u
 9 #define ___GFP_FS        0x80u
10 #define ___GFP_COLD        0x100u
11 #define ___GFP_NOWARN        0x200u
12 #define ___GFP_REPEAT        0x400u
13 #define ___GFP_NOFAIL        0x800u
14 #define ___GFP_NORETRY        0x1000u
15 #define ___GFP_MEMALLOC        0x2000u
16 #define ___GFP_COMP        0x4000u
17 #define ___GFP_ZERO        0x8000u
18 #define ___GFP_NOMEMALLOC    0x10000u
19 #define ___GFP_HARDWALL        0x20000u
20 #define ___GFP_THISNODE        0x40000u
21 #define ___GFP_RECLAIMABLE    0x80000u
22 #define ___GFP_NOTRACK        0x200000u
23 #define ___GFP_NO_KSWAPD    0x400000u
24 #define ___GFP_OTHER_NODE    0x800000u
25 #define ___GFP_WRITE        0x1000000

 

1.4 在globalmem_setup_cdev中进行了cdev_init和cdev_add操作,其中cdev_init的globalmem_fops是144行的file_operations函数,file_operations中的open等函数又单独实现,这里不再详细注解;

1.5在globalmem_exit函数中,先调用cdev_del删除已经add的globalmem字符设备,然后调用kfree释放globalmem_devp的空间;之后unregiter_chrdev_region解除注册

 

2,mult_globalmem

当有多个同类型的字符设备globalmem的时候,字符设备驱动的修改点也比较少,具体代码如下所示:

  1 /*
  2  * a simple char device driver: globalmem without mutex
  3  *
  4  * Copyright (C) 2014 Barry Song  (baohua@kernel.org) 
  5  *
  6  * Licensed under GPLv2 or later.
  7  */
  8 
  9 #include <linux/module.h>
 10 #include <linux/fs.h>
 11 #include <linux/init.h>
 12 #include <linux/cdev.h>
 13 #include <linux/slab.h>
 14 #include <linux/uaccess.h>
 15 
 16 #define GLOBALMEM_SIZE    0x1000
 17 #define MEM_CLEAR 0x1
 18 #define GLOBALMEM_MAJOR 230
 19 #define DEVICE_NUM    10    #表示10个同样的字符设备
 20 
 21 static int globalmem_major = GLOBALMEM_MAJOR;
 22 module_param(globalmem_major, int, S_IRUGO);
 23 
 24 struct globalmem_dev {
 25     struct cdev cdev;
 26     unsigned char mem[GLOBALMEM_SIZE];
 27 };
 28 
 29 struct globalmem_dev *globalmem_devp;
 30 
 31 static int globalmem_open(struct inode *inode, struct file *filp)
 32 {
 33     struct globalmem_dev *dev = container_of(inode->i_cdev,
 34                 struct globalmem_dev, cdev);  
 35     filp->private_data = dev;
 36     return 0;
 37 }
 38 
 39 static int globalmem_release(struct inode *inode, struct file *filp)
 40 {
 41     return 0;
 42 }
 43 
 44 static long globalmem_ioctl(struct file *filp, unsigned int cmd,
 45                 unsigned long arg)
 46 {
 47     struct globalmem_dev *dev = filp->private_data;
 48 
 49     switch (cmd) {
 50     case MEM_CLEAR:
 51         memset(dev->mem, 0, GLOBALMEM_SIZE);
 52         printk(KERN_INFO "globalmem is set to zero\n");
 53         break;
 54 
 55     default:
 56         return -EINVAL;
 57     }
 58 
 59     return 0;
 60 }
 61 
 62 static ssize_t globalmem_read(struct file *filp, char __user * buf, size_t size,
 63                   loff_t * ppos)
 64 {
 65     unsigned long p = *ppos;
 66     unsigned int count = size;
 67     int ret = 0;
 68     struct globalmem_dev *dev = filp->private_data;
 69 
 70     if (p >= GLOBALMEM_SIZE)
 71         return 0;
 72     if (count > GLOBALMEM_SIZE - p)
 73         count = GLOBALMEM_SIZE - p;
 74 
 75     if (copy_to_user(buf, dev->mem + p, count)) {
 76         ret = -EFAULT;
 77     } else {
 78         *ppos += count;
 79         ret = count;
 80 
 81         printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);
 82     }
 83 
 84     return ret;
 85 }
 86 
 87 static ssize_t globalmem_write(struct file *filp, const char __user * buf,
 88                    size_t size, loff_t * ppos)
 89 {
 90     unsigned long p = *ppos;
 91     unsigned int count = size;
 92     int ret = 0;
 93     struct globalmem_dev *dev = filp->private_data;
 94 
 95     if (p >= GLOBALMEM_SIZE)
 96         return 0;
 97     if (count > GLOBALMEM_SIZE - p)
 98         count = GLOBALMEM_SIZE - p;
 99 
100     if (copy_from_user(dev->mem + p, buf, count))
101         ret = -EFAULT;
102     else {
103         *ppos += count;
104         ret = count;
105 
106         printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p);
107     }
108 
109     return ret;
110 }
111 
112 static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
113 {
114     loff_t ret = 0;
115     switch (orig) {
116     case 0:
117         if (offset < 0) {
118             ret = -EINVAL;
119             break;
120         }
121         if ((unsigned int)offset > GLOBALMEM_SIZE) {
122             ret = -EINVAL;
123             break;
124         }
125         filp->f_pos = (unsigned int)offset;
126         ret = filp->f_pos;
127         break;
128     case 1:
129         if ((filp->f_pos + offset) > GLOBALMEM_SIZE) {
130             ret = -EINVAL;
131             break;
132         }
133         if ((filp->f_pos + offset) < 0) {
134             ret = -EINVAL;
135             break;
136         }
137         filp->f_pos += offset;
138         ret = filp->f_pos;
139         break;
140     default:
141         ret = -EINVAL;
142         break;
143     }
144     return ret;
145 }
146 
147 static const struct file_operations globalmem_fops = {
148     .owner = THIS_MODULE,
149     .llseek = globalmem_llseek,
150     .read = globalmem_read,
151     .write = globalmem_write,
152     .unlocked_ioctl = globalmem_ioctl,
153     .open = globalmem_open,
154     .release = globalmem_release,
155 };
156 
157 static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
158 {
159     int err, devno = MKDEV(globalmem_major, index);
160 
161     cdev_init(&dev->cdev, &globalmem_fops);
162     dev->cdev.owner = THIS_MODULE;
163     err = cdev_add(&dev->cdev, devno, 1);
164     if (err)
165         printk(KERN_NOTICE "Error %d adding globalmem%d", err, index);
166 }
167 
168 static int __init globalmem_init(void)
169 {
170     int ret;
171     int i;
172     dev_t devno = MKDEV(globalmem_major, 0);
173 
174     if (globalmem_major)
175         ret = register_chrdev_region(devno, DEVICE_NUM, "globalmem");   #注册10个,设备号累加
176     else {
177         ret = alloc_chrdev_region(&devno, 0, DEVICE_NUM, "globalmem");
178         globalmem_major = MAJOR(devno);
179     }
180     if (ret < 0)
181         return ret;
182 
183     globalmem_devp = kzalloc(sizeof(struct globalmem_dev) * DEVICE_NUM, GFP_KERNEL);
184     if (!globalmem_devp) {
185         ret = -ENOMEM;
186         goto fail_malloc;
187     }
188 
189     for (i = 0; i < DEVICE_NUM; i++)
190         globalmem_setup_cdev(globalmem_devp + i, i);
191 
192     return 0;
193 
194 fail_malloc:
195     unregister_chrdev_region(devno, DEVICE_NUM);
196     return ret;
197 }
198 module_init(globalmem_init);
199 
200 static void __exit globalmem_exit(void)
201 {
202     int i;
203     for (i = 0; i < DEVICE_NUM; i++)
204         cdev_del(&(globalmem_devp + i)->cdev);
205     kfree(globalmem_devp);
206     unregister_chrdev_region(MKDEV(globalmem_major, 0), DEVICE_NUM);
207 }
208 module_exit(globalmem_exit);
209 
210 MODULE_AUTHOR("Barry Song <baohua@kernel.org>");
211 MODULE_LICENSE("GPL v2");

mult_globalmem和globalmem的主要区别是在register_chrdev_region的时候指定了个数;对每个字符设备单独进行globalmem_setup_cdev,进行add;

相应的在cdev_del时每个单独进行,unregister的时候,需要指定个数

globalmem_open函数中的container_of在下面的文章中进行分析。

 

posted @ 2023-07-22 15:31  burlingame  阅读(16)  评论(0编辑  收藏  举报