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");
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中字符设备驱动和应用实例(二) 应用部分”