skywang12345

导航

 

Android中字符设备驱动和应用实例(一)——驱动部分

 

下面介绍创建Android设备对应的字符设备驱动

1 字符驱动

在此示例中,我们将字符驱动添加到drivers/char目录下。

(1)字符驱动的路径如下:

drivers/char/class_reg_unreg.c

 

(2)字符驱动的内容如下:

  1 #include <linux/module.h>
  2 #include <linux/init.h>
  3 #include <linux/kernel.h>
  4 #include <linux/slab.h>
  5 #include <linux/vmalloc.h>
  6 #include <linux/fs.h>
  7 #include <linux/cdev.h>
  8 #include <asm/uaccess.h>
  9 #include <linux/types.h>
 10 #include <linux/moduleparam.h>
 11 #include <linux/pci.h>
 12 #include <asm/unistd.h>
 13 #include <linux/device.h>
 14 
 15 
 16 #define    MEM_MALLOC_SIZE    4096
 17 #define    MEM_MAJOR        246
 18 #define    MEM_MINOR        0
 19 
 20 static char *mem_spvm;
 21 static struct class *mem_class;
 22 static struct cdev *mem_cdev;
 23 static int devno; 
 24 
 25 static int __init class_reg_unreg_init(void);
 26 static void __exit class_reg_unreg_exit(void);
 27 static int mem_open (struct inode *inode, struct file *filp);
 28 static int mem_release (struct inode *inode, struct file *filp);
 29 static ssize_t mem_read (struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
 30 static ssize_t mem_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
 31 
 32 static void class_create_release (struct class *cls);
 33 
 34 static void class_create_release (struct class *cls)
 35 {
 36     printk("%s\n", __func__ );
 37     kfree(cls);
 38 }
 39 
 40 struct file_operations mem_fops = 
 41 {
 42     .open = mem_open,
 43     .release = mem_release,
 44     .read = mem_read,
 45     .write = mem_write,
 46 };
 47 
 48 
 49 int mem_open (struct inode *inode, struct file *filp)
 50 {
 51     printk("mem open\n" );
 52     // 模块引用计数器子加
 53     try_module_get(THIS_MODULE);
 54     return 0;
 55 }
 56 
 57 int mem_release (struct inode *inode, struct file *filp)
 58 {
 59     printk("%s\n", __func__);
 60     // 模块引用计数器子加
 61     module_put(THIS_MODULE);
 62     return 0;
 63 }
 64 
 65 ssize_t mem_read (struct file *filp, char __user *buf, size_t count,
 66                         loff_t *f_pos)
 67 {
 68     int res = -1;
 69     char *tmp;
 70 
 71     printk("%s\n", __func__);
 72     
 73     tmp = mem_spvm;
 74     if (tmp == NULL) 
 75     {
 76         return 0;
 77         printk("%s error: empty pointer!\n", __func__);
 78     }
 79 
 80     if (count > MEM_MALLOC_SIZE)
 81     {
 82         count = MEM_MALLOC_SIZE;
 83         printk("%s size too large, resize to max size\n", __func__);
 84     }
 85     
 86     res = copy_to_user(buf, tmp, count);
 87     if (res == 0)
 88     {
 89         printk("<0> copy to user data success\n");
 90         return count;
 91     }
 92     printk("<0> copy to user data failed: res=%d\n", res);
 93 
 94     return 0;
 95 }
 96 
 97 ssize_t mem_write (struct file *filp, const char __user *buf, size_t count,
 98                         loff_t *f_pos)
 99 {
100     int res = -1;
101     char *tmp;
102 
103     printk("%s\n", __func__);
104 
105     tmp = mem_spvm;
106     if (tmp == NULL) 
107     {
108         return 0;
109         printk("%s error: empty pointer!\n", __func__);
110     }
111 
112     if (count > MEM_MALLOC_SIZE)
113     {
114         count = MEM_MALLOC_SIZE;
115         printk("%s size too large, resize to max size\n", __func__);
116     }
117 
118     res = copy_from_user(tmp, buf, count);
119     if (res == 0)
120     {
121         printk("<0> copy from user data success\n");
122         return count;
123     }
124     printk("<0> copy from user data fail: res=%d\n", res);
125 
126     return 0;
127 }
128 
129 
130 static int __init class_reg_unreg_init(void)
131 {
132     int ret = 0;
133 
134     printk("%s\n", __func__);
135 
136     // 创建设备号
137     devno = MKDEV(MEM_MAJOR, MEM_MINOR);
138 
139     // 申请字符设备号,并创建字符设备节点
140     if (MEM_MAJOR)
141     {
142         // 静态申请设备号
143         ret = register_chrdev_region(devno, 1, "my_char_dev");
144     }
145     else
146        {
147            // 动态分配设备号
148         ret = alloc_chrdev_region(&devno, 0, 1, "my_char_dev");
149     }  
150     if (ret) 
151     {
152         printk("<0> register chrdev failed!\n");
153         goto fail_register;    
154     }
155     printk("<0>register chrdev success, major, minor= (%d, %d)\n", MAJOR(devno), MINOR(devno));
156 
157     // 分配缓冲区
158     mem_spvm = (char *)vmalloc(MEM_MALLOC_SIZE);
159     if (mem_spvm == NULL)
160     {
161         ret = 1;
162         printk("<0>vmalloc failed!\n");
163         goto fail_vmalloc;
164     }
165     printk("<0>vmalloc success, addr=0x%x\n", (unsigned int)mem_spvm);
166 
167     // 动态分配一个字符设备对象
168     mem_cdev = cdev_alloc();
169     if (mem_cdev == NULL) 
170     {
171         printk("<0> cdev_alloc failed!\n");
172         ret = 1;
173         goto fail_cdev_alloc;
174     } 
175     printk("<0> cdev_alloc success, addr=0x%x\n", (unsigned int)mem_cdev);
176 
177     // 初始化字符设备对象
178     cdev_init(mem_cdev, &mem_fops);
179     // 初始化字符设备持有者
180     mem_cdev->owner = THIS_MODULE;
181     // 将字符设备添加到内核系统中
182     ret = cdev_add(mem_cdev, devno, 1);
183     if (ret) 
184     {
185         printk("<0> cdev_add failed!\n");
186         goto fail_cdev_add;    
187     }
188 
189     // 申请class结构体内存
190     mem_class = kzalloc(sizeof(*mem_class), GFP_KERNEL);
191     if (mem_class == NULL) 
192     {
193         printk("<0> create mem class failed!\n");
194         ret = 1;
195         goto fail_mem_class;
196     }
197     printk("<0> create mem class success\n");
198 
199     mem_class->name = "my_char_dev";
200     mem_class->owner = THIS_MODULE;
201     // 注销时class时的回调函数,在此回调函数中释放之前所分配的class结构体内存
202     mem_class->class_release = class_create_release;
203 
204     // 将class注册到内核中,同时会在/sys/class/下创建class对应的节点
205     int retval = class_register(mem_class);
206     if (ret) 
207     {
208         printk("<0> class_register failed!\n");
209         goto fail_class_reg;    
210     }
211     printk("<0> class_register success\n");
212 
213     // 在/dev/下创建与class对应的设备节点
214     device_create(mem_class, NULL, devno, NULL, "my_char_dev");
215 
216     return 0;
217 
218 fail_class_reg:
219 
220 fail_mem_class:
221     if (mem_class)
222     {
223         kfree(mem_class);
224         mem_class = NULL;
225     }
226 
227 fail_cdev_add:
228 fail_cdev_alloc:
229     if (mem_cdev)
230     {
231         kfree(mem_cdev);
232         mem_cdev = NULL;
233     }
234 
235 fail_vmalloc:
236     if (mem_spvm)
237     {
238         vfree(mem_spvm);
239         mem_spvm = NULL;
240     }
241 
242 fail_register:
243     unregister_chrdev_region(devno, 1);
244 
245     return ret;
246 }
247 
248 static void __exit class_reg_unreg_exit(void)
249 {
250     printk("%s\n", __func__);
251     device_destroy(mem_class, devno);
252     if (mem_class)
253     {
254         class_unregister(mem_class);
255         //kfree(mem_class);
256         mem_class = NULL;
257     }
258 
259     if (mem_spvm)
260     {
261         vfree(mem_spvm);
262         mem_spvm = NULL;
263     }
264 
265     if (mem_cdev)
266     {
267         // 从内核中将设备删除
268         cdev_del(mem_cdev);
269         kfree(mem_cdev);
270         mem_cdev = NULL;
271     }
272 
273     // 注销字符设备
274     unregister_chrdev_region(devno, 1);
275 }
276 
277 module_init(class_reg_unreg_init);
278 module_exit(class_reg_unreg_exit);
279 
280 MODULE_AUTHOR("skywang <wangkuiwu@gmail.com>");
281 MODULE_DESCRIPTION("class register unregister driver");
282 MODULE_LICENSE("GPL");
View Code

  

2 修改配置

(1)修改drivers/char/Kconfig,添加以下内容:

config SKYWANG_CLASS_REG_UNREG
     tristate "skywang class register and unregister driver"
     help
     add this to support skywang class register and unregister driver 

(2)修改drivers/char/Makefile,添加以下内容:

+obj-$(CONFIG_SKYWANG_CLASS_REG_UNREG) += class_reg_unreg.o 

 

3 编译

(1)执行make menuconfig生产字符设备模块文件,如下图:

(2)执行make编译生成模块文件,模块文件路径如下:

drivers/char/ class_reg_unreg.ko

 

4 装载/卸载到手机中

(1)将class_reg_unreg.ko导入到Android系统中,执行以下命令:

# adb push class_reg_unreg.ko /system/class_reg_unreg.ko

 

(2)装载模块文件,执行以下命令:

# cd /system/
# insmod class_reg_unreg.ko

执行insmod之后,坚持是否生成文件节点“/sys/class/my_char_dev”和“/dev/my_char_dev”。若生成文件节点,则代表装载驱动成功!

 

(3)若需要卸载模块文件,可以通过以下命令:

#rmmod class_reg_unreg.ko

 

关于该驱动的测试程序,请参考“Android中字符设备驱动和应用实例(二) 应用部分

 

 

posted on 2013-05-15 23:38  如果天空不死  阅读(2967)  评论(0编辑  收藏  举报