Android架构分析之Android驱动程序开发

 Android版本:2.3.7_r1

Linux内核版本:android-goldfish-2.6.29

 

本文介绍如何开发Android驱动程序并进行测试。

 

一、Android驱动程序开发

Android是基于Linux的,所以Android驱动程序的开发方法与Linux驱动程序开发方法相同。

下面我们通过一个例子程序来熟悉一下Android驱动程序的开发,这里只是一个简单的说明,如果你对Linux驱动开发也不熟悉,可以学习《Linux Device Driver》或参考的我博客的《LDD3源码分析》系列文章。

首先我们在Android内核源码的drivers目录下创建一个新的目录example,我们的驱动程序源码就放在这个目录下:

# mkdir drivers/example

# cd drivers/example

 

创建example.h文件,其内容如下: 

[cpp] view plain copy print ?
  1.  1#ifndef _EXAMPLE_H_  
  2.  2#define _EXAMPLE_H_  
  3.  3  
  4.  4#include <linux/cdev.h>  
  5.  5#include <linux/semaphore.h>  
  6.  6  
  7.  7#define EXAMPLE_DEVICE_NODE_NAME  "example"  
  8.  8#define EXAMPLE_DEVICE_FILE_NAME  "example"  
  9.  9#define EXAMPLE_DEVICE_PROC_NAME  "example"  
  10. 10#define EXAMPLE_DEVICE_CLASS_NAME "example"  
  11. 11#define EXAMPLE_MAJOR 0  
  12. 12  
  13. 13struct example_dev {  
  14. 14    struct semaphore sem;  
  15. 15    struct cdev cdev;  
  16. 16    int val;  
  17. 17};  
  18. 18  
  19. 19#endif  
 1#ifndef _EXAMPLE_H_
 2#define _EXAMPLE_H_
 3
 4#include <linux/cdev.h>
 5#include <linux/semaphore.h>
 6
 7#define EXAMPLE_DEVICE_NODE_NAME  "example"
 8#define EXAMPLE_DEVICE_FILE_NAME  "example"
 9#define EXAMPLE_DEVICE_PROC_NAME  "example"
10#define EXAMPLE_DEVICE_CLASS_NAME "example"
11#define EXAMPLE_MAJOR 0
12
13struct example_dev {
14    struct semaphore sem;
15    struct cdev cdev;
16    int val;
17};
18
19#endif

该头文件中定义了驱动程序中将用到的一些宏,并定义了设备结构体example_dev,该结构体的成员sem用于保证对设备的同步访问,cdev表示该设备是Linux设备驱动中的字符设备,val则代表该设备中的一个寄存器,我们这个驱动程序的作用就是给用户层应用程序提供读写这个val寄存器的方法。

 

创建example.c文件,其内容如下:

 

[cpp] view plain copy print ?
  1.   1#include <linux/init.h>  
  2.   2#include <linux/module.h>  
  3.   3#include <linux/types.h>  
  4.   4#include <linux/fs.h>  
  5.   5#include <linux/proc_fs.h>  
  6.   6#include <linux/device.h>  
  7.   7#include <asm/uaccess.h>  
  8.   8  
  9.   9#include "example.h"  
  10.  10  
  11.  11static int example_major = EXAMPLE_MAJOR;  
  12.  12static int example_minor = 0;  
  13.  13  
  14.  14static struct class* example_class = NULL;  
  15.  15static struct example_dev* example_dev = NULL;  
  16.  16  
  17.  17module_param(example_major, int, S_IRUGO);  
  18.  18module_param(example_minor, int, S_IRUGO);  
  19.  19  
  20.  20static int example_open(struct inode* inode, struct file* filp)  
  21.  21{  
  22.  22    struct example_dev* dev;  
  23.  23  
  24.  24    /* 
  25.  25     * 取得设备结构体example_dev,保存在filp私有数据区中,以方便其它函数使用。 
  26.  26     */  
  27.  27    dev = container_of(inode->i_cdev, struct example_dev, cdev);  
  28.  28    filp->private_data = dev;  
  29.  29  
  30.  30    return 0;  
  31.  31}  
  32.  32  
  33.  33static int example_release(struct inode* inode, struct file* filp)  
  34.  34{  
  35.  35    return 0;  
  36.  36}  
  37.  37  
  38.  38static ssize_t example_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos)  
  39.  39{  
  40.  40    struct example_dev* dev = filp->private_data;  
  41.  41    ssize_t retval = 0;  
  42.  42  
  43.  43    /* 
  44.  44     * 加锁 
  45.  45     */  
  46.  46    if(down_interruptible(&(dev->sem)))  
  47.  47        return -ERESTARTSYS;  
  48.  48  
  49.  49    if(count < sizeof(dev->val))  
  50.  50        goto out;  
  51.  51  
  52.  52    /* 
  53.  53     * 读寄存器的值到用户空间。 
  54.  54     */  
  55.  55    if(copy_to_user(buf, &(dev->val), sizeof(dev->val)))  
  56.  56    {  
  57.  57        retval = -EFAULT;  
  58.  58        goto out;  
  59.  59    }  
  60.  60  
  61.  61    retval = sizeof(dev->val);  
  62.  62  
  63.  63out:  
  64.  64    /* 
  65.  65     * 解锁 
  66.  66     */  
  67.  67    up(&(dev->sem));  
  68.  68    return retval;  
  69.  69}  
  70.  70  
  71.  71static ssize_t example_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos)  
  72.  72{  
  73.  73    struct example_dev* dev = filp->private_data;  
  74.  74    ssize_t retval = 0;  
  75.  75  
  76.  76    /* 
  77.  77     * 加锁 
  78.  78     */  
  79.  79    if(down_interruptible(&(dev->sem)))  
  80.  80        return -ERESTARTSYS;  
  81.  81  
  82.  82    if(count != sizeof(dev->val))  
  83.  83        goto out;  
  84.  84  
  85.  85    /* 
  86.  86     * 从用户空间读取并给寄存器赋值。 
  87.  87     */  
  88.  88    if(copy_from_user(&(dev->val), buf, count))  
  89.  89    {  
  90.  90        retval = -EFAULT;  
  91.  91        goto out;  
  92.  92    }  
  93.  93  
  94.  94    retval = sizeof(dev->val);  
  95.  95  
  96.  96out:  
  97.  97    /* 
  98.  98     * 解锁 
  99.  99     */  
  100. 100    up(&(dev->sem));  
  101. 101    return retval;  
  102. 102}  
  103. 103  
  104. 104/* 
  105. 105 * 设备操作函数集 
  106. 106 */  
  107. 107static struct file_operations example_fops =  
  108. 108{  
  109. 109    .owner = THIS_MODULE,  
  110. 110    .open = example_open,  
  111. 111    .release = example_release,  
  112. 112    .read = example_read,  
  113. 113    .write = example_write,  
  114. 114};  
  115. 115  
  116. 116  
  117. 117/* 
  118. 118 * 在同步状态下读取寄存器的值。 
  119. 119 */  
  120. 120static ssize_t __example_get_val(struct example_dev* dev, char* buf)  
  121. 121{  
  122. 122    int val = 0;  
  123. 123  
  124. 124    if(down_interruptible(&(dev->sem)))  
  125. 125        return -ERESTARTSYS;  
  126. 126  
  127. 127    val = dev->val;  
  128. 128    up(&(dev->sem));  
  129. 129  
  130. 130    return snprintf(buf, 30, "%d\n", val);  
  131. 131}  
  132. 132  
  133. 133/* 
  134. 134 * 在同步状态下设置寄存器的值。 
  135. 135 */  
  136. 136static ssize_t __example_set_val(struct example_dev* dev, const char* buf, size_t count)  
  137. 137{  
  138. 138    int val = 0;  
  139. 139  
  140. 140    val = (int)simple_strtol(buf, NULL, 10);  
  141. 141  
  142. 142    if(down_interruptible(&(dev->sem)))  
  143. 143        return -ERESTARTSYS;  
  144. 144  
  145. 145    dev->val = val;  
  146. 146    up(&(dev->sem));  
  147. 147  
  148. 148    return count;  
  149. 149}  
  150. 150  
  151. 151/* 
  152. 152 * 对属性文件的读取操作函数。 
  153. 153 */  
  154. 154static ssize_t example_val_show(struct device* dev, struct device_attribute* attr, char* buf)  
  155. 155{  
  156. 156    struct example_dev* hdev = (struct example_dev*)dev_get_drvdata(dev);  
  157. 157  
  158. 158    return __example_get_val(hdev, buf);  
  159. 159}  
  160. 160  
  161. 161/* 
  162. 162 * 对属性文件的写操作函数。 
  163. 163 */  
  164. 164static ssize_t example_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)  
  165. 165{  
  166. 166    struct example_dev* hdev = (struct example_dev*)dev_get_drvdata(dev);  
  167. 167  
  168. 168    return __example_set_val(hdev, buf, count);  
  169. 169}  
  170. 170  
  171. 171/* 
  172. 172 * DEVICE_ATTR宏展开后生成的是dev_attr_val。 
  173. 173 * 指定属性名为"val“,对应的读写函数分别是example_val_show和example_val_store。 
  174. 174 */  
  175. 175static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, example_val_show, example_val_store);  
  176. 176  
  177. 177/* 
  178. 178 * /proc节点的读操作函数。 
  179. 179 */  
  180. 180static ssize_t example_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data)  
  181. 181{  
  182. 182    if(off > 0)  
  183. 183    {  
  184. 184        *eof = 1;  
  185. 185        return 0;  
  186. 186    }  
  187. 187  
  188. 188    return __example_get_val(example_dev, page);  
  189. 189}  
  190. 190  
  191. 191/* 
  192. 192 * /proc节点的写操作函数。 
  193. 193 */  
  194. 194static ssize_t example_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data)  
  195. 195{  
  196. 196    int err = 0;  
  197. 197    char* page = NULL;  
  198. 198  
  199. 199    if(len > PAGE_SIZE)  
  200. 200    {  
  201. 201        printk(KERN_ALERT"The buff is too large: %lu.\n", len);  
  202. 202        return -EFAULT;  
  203. 203    }  
  204. 204  
  205. 205    page = (char*)__get_free_page(GFP_KERNEL);  
  206. 206    if(!page)  
  207. 207    {  
  208. 208        printk(KERN_ALERT"Failed to alloc page.\n");  
  209. 209        return -ENOMEM;  
  210. 210    }  
  211. 211  
  212. 212    if(copy_from_user(page, buff, len))  
  213. 213    {  
  214. 214        printk(KERN_ALERT"Failed to copy buff from user.\n");  
  215. 215        err = -EFAULT;  
  216. 216        goto out;  
  217. 217    }  
  218. 218  
  219. 219    err = __example_set_val(example_dev, page, len);  
  220. 220  
  221. 221out:  
  222. 222    free_page((unsigned long)page);  
  223. 223    return err;  
  224. 224}  
  225. 225  
  226. 226/* 
  227. 227 * 创建/proc节点 
  228. 228 */  
  229. 229static void example_create_proc(void)  
  230. 230{  
  231. 231    struct proc_dir_entry* entry;  
  232. 232  
  233. 233    entry = create_proc_entry(EXAMPLE_DEVICE_PROC_NAME, 0, NULL);  
  234. 234    if(entry)  
  235. 235    {  
  236. 236        entry->owner = THIS_MODULE;  
  237. 237        entry->read_proc = example_proc_read;  
  238. 238        entry->write_proc = example_proc_write;  
  239. 239    }  
  240. 240}  
  241. 241  
  242. 242/* 
  243. 243 * 删除/proc节点 
  244. 244 */  
  245. 245static void example_remove_proc(void)  
  246. 246{  
  247. 247    remove_proc_entry(EXAMPLE_DEVICE_PROC_NAME, NULL);  
  248. 248}  
  249. 249  
  250. 250/* 
  251. 251 * 初始化设备结构体example_dev。 
  252. 252 */  
  253. 253static int  __example_setup_dev(struct example_dev* dev)  
  254. 254{  
  255. 255    int retval;  
  256. 256  
  257. 257    /* 
  258. 258     * 取得设备编号 
  259. 259     */  
  260. 260    dev_t devno = MKDEV(example_major, example_minor);  
  261. 261  
  262. 262    /* 
  263. 263     * 将设备结构体内存空间初始化为0。 
  264. 264     */  
  265. 265    memset(dev, 0, sizeof(struct example_dev));  
  266. 266  
  267. 267    /* 
  268. 268     * 初始化设备结构体的cdev成员,指定owner和操作函数集。 
  269. 269     */  
  270. 270    cdev_init(&(dev->cdev), &example_fops);  
  271. 271    dev->cdev.owner = THIS_MODULE;  
  272. 272    dev->cdev.ops = &example_fops;  
  273. 273  
  274. 274    /* 
  275. 275     * 调用cdev_add,通知内核该字符设备的存在。 
  276. 276     */  
  277. 277    retval = cdev_add(&(dev->cdev),devno, 1);  
  278. 278    if(retval)  
  279. 279    {  
  280. 280        return retval;  
  281. 281    }  
  282. 282  
  283. 283    /* 
  284. 284     * 初始化信号量 
  285. 285     */  
  286. 286    init_MUTEX(&(dev->sem));  
  287. 287  
  288. 288    /* 
  289. 289     *将寄存器val值初始化为0 
  290. 290     */  
  291. 291    dev->val = 0;  
  292. 292  
  293. 293    return 0;  
  294. 294}  
  295. 295  
  296. 296/* 
  297. 297 * 模块初始化函数。 
  298. 298 */  
  299. 299static int __init example_init(void)  
  300. 300{  
  301. 301    int retval = -1;  
  302. 302    dev_t dev = 0;  
  303. 303    struct device* device = NULL;  
  304. 304  
  305. 305    printk(KERN_ALERT"Initializing example device.\n");  
  306. 306  
  307. 307    /* 
  308. 308     * 如果用户指定了主设备号,即example_major不为0,则调用 
  309. 309     * register_chrdev_region分配指定的设备编号。 
  310. 310     * 如果用户没有指定主设备号,即example_major为0,则调用 
  311. 311     * alloc_chrdev_region动态分配设备编号。 
  312. 312     */  
  313. 313    if (example_major) {  
  314. 314        dev = MKDEV(example_major, example_minor);  
  315. 315        retval = register_chrdev_region(dev, 1, EXAMPLE_DEVICE_NODE_NAME);  
  316. 316    } else {  
  317. 317        retval = alloc_chrdev_region(&dev, example_minor, 1, EXAMPLE_DEVICE_NODE_NAME);  
  318. 318    }  
  319. 319    if (retval < 0) {  
  320. 320        printk(KERN_WARNING "can't get example_major %d\n", example_major);  
  321. 321        goto fail;  
  322. 322    }  
  323. 323  
  324. 324    /* 
  325. 325     * 取得主设备号和次设备号 
  326. 326     */  
  327. 327    example_major = MAJOR(dev);  
  328. 328    example_minor = MINOR(dev);  
  329. 329  
  330. 330    /* 
  331. 331     * 为设备结构体example_dev动态分配内存空间。 
  332. 332     */  
  333. 333    example_dev = kmalloc(sizeof(struct example_dev), GFP_KERNEL);  
  334. 334    if(!example_dev)  
  335. 335    {  
  336. 336        retval = -ENOMEM;  
  337. 337        printk(KERN_ALERT"Failed to alloc example_dev.\n");  
  338. 338        goto unregister;  
  339. 339    }  
  340. 340  
  341. 341    /* 
  342. 342     * 调用__example_setup_dev函数对example_dev结构体进行初始化。 
  343. 343     */  
  344. 344    retval = __example_setup_dev(example_dev);  
  345. 345    if(retval)  
  346. 346    {  
  347. 347        printk(KERN_ALERT"Failed to setup dev: %d.\n", retval);  
  348. 348        goto cleanup;  
  349. 349    }  
  350. 350  
  351. 351    /* 
  352. 352     * 创建类example,class_create函数执行成功后,在/sys/class目录下 
  353. 353     * 就会出现一个名为example的目录。 
  354. 354     */  
  355. 355    example_class = class_create(THIS_MODULE, EXAMPLE_DEVICE_CLASS_NAME);  
  356. 356    if(IS_ERR(example_class))  
  357. 357    {  
  358. 358        retval = PTR_ERR(example_class);  
  359. 359        printk(KERN_ALERT"Failed to create example class.\n");  
  360. 360        goto destroy_cdev;  
  361. 361    }  
  362. 362  
  363. 363    /* 
  364. 364     * 创建设备,device_create函数执行成功后,会生成/dev/example文件 
  365. 365     * 和/sys/class/example/example目录及相关文件。 
  366. 366     * 注意device的类型是struct device,代表一个设备。 
  367. 367     */  
  368. 368    device = device_create(example_class, NULL, dev, "%s", EXAMPLE_DEVICE_FILE_NAME);  
  369. 369    if(IS_ERR(device))  
  370. 370    {  
  371. 371        retval = PTR_ERR(device);  
  372. 372        printk(KERN_ALERT"Failed to create example device.");  
  373. 373        goto destroy_class;  
  374. 374    }  
  375. 375  
  376. 376    /* 
  377. 377     * 创建属性文件,对应的属性操作函数由dev_attr_val指定。 
  378. 378     */  
  379. 379    retval = device_create_file(device, &dev_attr_val);  
  380. 380    if(retval < 0)  
  381. 381    {  
  382. 382        printk(KERN_ALERT"Failed to create attribute val.");  
  383. 383        goto destroy_device;  
  384. 384    }  
  385. 385  
  386. 386    /* 
  387. 387     * 将example_dev保存在设备私有数据区中。 
  388. 388     */  
  389. 389    dev_set_drvdata(device, example_dev);  
  390. 390  
  391. 391    /* 
  392. 392     * 创建proc节点。 
  393. 393     */  
  394. 394    example_create_proc();  
  395. 395  
  396. 396    printk(KERN_ALERT"Succedded to initialize example device.\n");  
  397. 397    return 0;  
  398. 398  
  399. 399destroy_device:  
  400. 400    device_destroy(example_class, dev);  
  401. 401  
  402. 402destroy_class:  
  403. 403    class_destroy(example_class);  
  404. 404  
  405. 405destroy_cdev:  
  406. 406    cdev_del(&(example_dev->cdev));  
  407. 407  
  408. 408cleanup:  
  409. 409    kfree(example_dev);  
  410. 410  
  411. 411unregister:  
  412. 412    unregister_chrdev_region(MKDEV(example_major, example_minor), 1);  
  413. 413  
  414. 414fail:  
  415. 415    return retval;  
  416. 416}  
  417. 417  
  418. 418/* 
  419. 419 * 模块清理函数。 
  420. 420 */  
  421. 421static void __exit example_exit(void)  
  422. 422{  
  423. 423    dev_t dev = MKDEV(example_major, example_minor);  
  424. 424  
  425. 425    printk(KERN_ALERT"Destroy example device.\n");  
  426. 426  
  427. 427    example_remove_proc();  
  428. 428  
  429. 429    if(example_class)  
  430. 430    {  
  431. 431        device_destroy(example_class, MKDEV(example_major, example_minor));  
  432. 432        class_destroy(example_class);  
  433. 433    }  
  434. 434  
  435. 435    if(example_dev)  
  436. 436    {  
  437. 437        cdev_del(&(example_dev->cdev));  
  438. 438        kfree(example_dev);  
  439. 439    }  
  440. 440  
  441. 441    unregister_chrdev_region(dev, 1);  
  442. 442}  
  443. 443  
  444. 444MODULE_LICENSE("GPL");  
  445. 445  
  446. 446module_init(example_init);  
  447. 447module_exit(example_exit);  
  448.    
  1#include <linux/init.h>
  2#include <linux/module.h>
  3#include <linux/types.h>
  4#include <linux/fs.h>
  5#include <linux/proc_fs.h>
  6#include <linux/device.h>
  7#include <asm/uaccess.h>
  8
  9#include "example.h"
 10
 11static int example_major = EXAMPLE_MAJOR;
 12static int example_minor = 0;
 13
 14static struct class* example_class = NULL;
 15static struct example_dev* example_dev = NULL;
 16
 17module_param(example_major, int, S_IRUGO);
 18module_param(example_minor, int, S_IRUGO);
 19
 20static int example_open(struct inode* inode, struct file* filp)
 21{
 22    struct example_dev* dev;
 23
 24    /*
 25     * 取得设备结构体example_dev,保存在filp私有数据区中,以方便其它函数使用。
 26     */
 27    dev = container_of(inode->i_cdev, struct example_dev, cdev);
 28    filp->private_data = dev;
 29
 30    return 0;
 31}
 32
 33static int example_release(struct inode* inode, struct file* filp)
 34{
 35    return 0;
 36}
 37
 38static ssize_t example_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos)
 39{
 40    struct example_dev* dev = filp->private_data;
 41    ssize_t retval = 0;
 42
 43    /*
 44     * 加锁
 45     */
 46    if(down_interruptible(&(dev->sem)))
 47        return -ERESTARTSYS;
 48
 49    if(count < sizeof(dev->val))
 50        goto out;
 51
 52    /*
 53     * 读寄存器的值到用户空间。
 54     */
 55    if(copy_to_user(buf, &(dev->val), sizeof(dev->val)))
 56    {
 57        retval = -EFAULT;
 58        goto out;
 59    }
 60
 61    retval = sizeof(dev->val);
 62
 63out:
 64    /*
 65     * 解锁
 66     */
 67    up(&(dev->sem));
 68    return retval;
 69}
 70
 71static ssize_t example_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos)
 72{
 73    struct example_dev* dev = filp->private_data;
 74    ssize_t retval = 0;
 75
 76    /*
 77     * 加锁
 78     */
 79    if(down_interruptible(&(dev->sem)))
 80        return -ERESTARTSYS;
 81
 82    if(count != sizeof(dev->val))
 83        goto out;
 84
 85    /*
 86     * 从用户空间读取并给寄存器赋值。
 87     */
 88    if(copy_from_user(&(dev->val), buf, count))
 89    {
 90        retval = -EFAULT;
 91        goto out;
 92    }
 93
 94    retval = sizeof(dev->val);
 95
 96out:
 97    /*
 98     * 解锁
 99     */
100    up(&(dev->sem));
101    return retval;
102}
103
104/*
105 * 设备操作函数集
106 */
107static struct file_operations example_fops =
108{
109    .owner = THIS_MODULE,
110    .open = example_open,
111    .release = example_release,
112    .read = example_read,
113    .write = example_write,
114};
115
116
117/*
118 * 在同步状态下读取寄存器的值。
119 */
120static ssize_t __example_get_val(struct example_dev* dev, char* buf)
121{
122    int val = 0;
123
124    if(down_interruptible(&(dev->sem)))
125        return -ERESTARTSYS;
126
127    val = dev->val;
128    up(&(dev->sem));
129
130    return snprintf(buf, 30, "%d\n", val);
131}
132
133/*
134 * 在同步状态下设置寄存器的值。
135 */
136static ssize_t __example_set_val(struct example_dev* dev, const char* buf, size_t count)
137{
138    int val = 0;
139
140    val = (int)simple_strtol(buf, NULL, 10);
141
142    if(down_interruptible(&(dev->sem)))
143        return -ERESTARTSYS;
144
145    dev->val = val;
146    up(&(dev->sem));
147
148    return count;
149}
150
151/*
152 * 对属性文件的读取操作函数。
153 */
154static ssize_t example_val_show(struct device* dev, struct device_attribute* attr, char* buf)
155{
156    struct example_dev* hdev = (struct example_dev*)dev_get_drvdata(dev);
157
158    return __example_get_val(hdev, buf);
159}
160
161/*
162 * 对属性文件的写操作函数。
163 */
164static ssize_t example_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
165{
166    struct example_dev* hdev = (struct example_dev*)dev_get_drvdata(dev);
167
168    return __example_set_val(hdev, buf, count);
169}
170
171/*
172 * DEVICE_ATTR宏展开后生成的是dev_attr_val。
173 * 指定属性名为"val“,对应的读写函数分别是example_val_show和example_val_store。
174 */
175static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, example_val_show, example_val_store);
176
177/*
178 * /proc节点的读操作函数。
179 */
180static ssize_t example_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data)
181{
182    if(off > 0)
183    {
184        *eof = 1;
185        return 0;
186    }
187
188    return __example_get_val(example_dev, page);
189}
190
191/*
192 * /proc节点的写操作函数。
193 */
194static ssize_t example_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data)
195{
196    int err = 0;
197    char* page = NULL;
198
199    if(len > PAGE_SIZE)
200    {
201        printk(KERN_ALERT"The buff is too large: %lu.\n", len);
202        return -EFAULT;
203    }
204
205    page = (char*)__get_free_page(GFP_KERNEL);
206    if(!page)
207    {
208        printk(KERN_ALERT"Failed to alloc page.\n");
209        return -ENOMEM;
210    }
211
212    if(copy_from_user(page, buff, len))
213    {
214        printk(KERN_ALERT"Failed to copy buff from user.\n");
215        err = -EFAULT;
216        goto out;
217    }
218
219    err = __example_set_val(example_dev, page, len);
220
221out:
222    free_page((unsigned long)page);
223    return err;
224}
225
226/*
227 * 创建/proc节点
228 */
229static void example_create_proc(void)
230{
231    struct proc_dir_entry* entry;
232
233    entry = create_proc_entry(EXAMPLE_DEVICE_PROC_NAME, 0, NULL);
234    if(entry)
235    {
236        entry->owner = THIS_MODULE;
237        entry->read_proc = example_proc_read;
238        entry->write_proc = example_proc_write;
239    }
240}
241
242/*
243 * 删除/proc节点
244 */
245static void example_remove_proc(void)
246{
247    remove_proc_entry(EXAMPLE_DEVICE_PROC_NAME, NULL);
248}
249
250/*
251 * 初始化设备结构体example_dev。
252 */
253static int  __example_setup_dev(struct example_dev* dev)
254{
255    int retval;
256
257    /*
258     * 取得设备编号
259     */
260    dev_t devno = MKDEV(example_major, example_minor);
261
262    /*
263     * 将设备结构体内存空间初始化为0。
264     */
265    memset(dev, 0, sizeof(struct example_dev));
266
267    /*
268     * 初始化设备结构体的cdev成员,指定owner和操作函数集。
269     */
270    cdev_init(&(dev->cdev), &example_fops);
271    dev->cdev.owner = THIS_MODULE;
272    dev->cdev.ops = &example_fops;
273
274    /*
275     * 调用cdev_add,通知内核该字符设备的存在。
276     */
277    retval = cdev_add(&(dev->cdev),devno, 1);
278    if(retval)
279    {
280        return retval;
281    }
282
283    /*
284     * 初始化信号量
285     */
286    init_MUTEX(&(dev->sem));
287
288    /*
289     *将寄存器val值初始化为0
290     */
291    dev->val = 0;
292
293    return 0;
294}
295
296/*
297 * 模块初始化函数。
298 */
299static int __init example_init(void)
300{
301    int retval = -1;
302    dev_t dev = 0;
303    struct device* device = NULL;
304
305    printk(KERN_ALERT"Initializing example device.\n");
306
307    /*
308     * 如果用户指定了主设备号,即example_major不为0,则调用
309     * register_chrdev_region分配指定的设备编号。
310     * 如果用户没有指定主设备号,即example_major为0,则调用
311     * alloc_chrdev_region动态分配设备编号。
312     */
313    if (example_major) {
314        dev = MKDEV(example_major, example_minor);
315        retval = register_chrdev_region(dev, 1, EXAMPLE_DEVICE_NODE_NAME);
316    } else {
317        retval = alloc_chrdev_region(&dev, example_minor, 1, EXAMPLE_DEVICE_NODE_NAME);
318    }
319    if (retval < 0) {
320        printk(KERN_WARNING "can't get example_major %d\n", example_major);
321        goto fail;
322    }
323
324    /*
325     * 取得主设备号和次设备号
326     */
327    example_major = MAJOR(dev);
328    example_minor = MINOR(dev);
329
330    /*
331     * 为设备结构体example_dev动态分配内存空间。
332     */
333    example_dev = kmalloc(sizeof(struct example_dev), GFP_KERNEL);
334    if(!example_dev)
335    {
336        retval = -ENOMEM;
337        printk(KERN_ALERT"Failed to alloc example_dev.\n");
338        goto unregister;
339    }
340
341    /*
342     * 调用__example_setup_dev函数对example_dev结构体进行初始化。
343     */
344    retval = __example_setup_dev(example_dev);
345    if(retval)
346    {
347        printk(KERN_ALERT"Failed to setup dev: %d.\n", retval);
348        goto cleanup;
349    }
350
351    /*
352     * 创建类example,class_create函数执行成功后,在/sys/class目录下
353     * 就会出现一个名为example的目录。
354     */
355    example_class = class_create(THIS_MODULE, EXAMPLE_DEVICE_CLASS_NAME);
356    if(IS_ERR(example_class))
357    {
358        retval = PTR_ERR(example_class);
359        printk(KERN_ALERT"Failed to create example class.\n");
360        goto destroy_cdev;
361    }
362
363    /*
364     * 创建设备,device_create函数执行成功后,会生成/dev/example文件
365     * 和/sys/class/example/example目录及相关文件。
366     * 注意device的类型是struct device,代表一个设备。
367     */
368    device = device_create(example_class, NULL, dev, "%s", EXAMPLE_DEVICE_FILE_NAME);
369    if(IS_ERR(device))
370    {
371        retval = PTR_ERR(device);
372        printk(KERN_ALERT"Failed to create example device.");
373        goto destroy_class;
374    }
375
376    /*
377     * 创建属性文件,对应的属性操作函数由dev_attr_val指定。
378     */
379    retval = device_create_file(device, &dev_attr_val);
380    if(retval < 0)
381    {
382        printk(KERN_ALERT"Failed to create attribute val.");
383        goto destroy_device;
384    }
385
386    /*
387     * 将example_dev保存在设备私有数据区中。
388     */
389    dev_set_drvdata(device, example_dev);
390
391    /*
392     * 创建proc节点。
393     */
394    example_create_proc();
395
396    printk(KERN_ALERT"Succedded to initialize example device.\n");
397    return 0;
398
399destroy_device:
400    device_destroy(example_class, dev);
401
402destroy_class:
403    class_destroy(example_class);
404
405destroy_cdev:
406    cdev_del(&(example_dev->cdev));
407
408cleanup:
409    kfree(example_dev);
410
411unregister:
412    unregister_chrdev_region(MKDEV(example_major, example_minor), 1);
413
414fail:
415    return retval;
416}
417
418/*
419 * 模块清理函数。
420 */
421static void __exit example_exit(void)
422{
423    dev_t dev = MKDEV(example_major, example_minor);
424
425    printk(KERN_ALERT"Destroy example device.\n");
426
427    example_remove_proc();
428
429    if(example_class)
430    {
431        device_destroy(example_class, MKDEV(example_major, example_minor));
432        class_destroy(example_class);
433    }
434
435    if(example_dev)
436    {
437        cdev_del(&(example_dev->cdev));
438        kfree(example_dev);
439    }
440
441    unregister_chrdev_region(dev, 1);
442}
443
444MODULE_LICENSE("GPL");
445
446module_init(example_init);
447module_exit(example_exit);
 

代码中的注释已经很详细,这里再简单说一下:

20 - 114行,定义了example_open、example_release、example_read、example_write这4个函数,并将这4个函数赋值给file_operations结构体变量example_fops,应用程序通过/dev/example设备节点访问设备时,就会相应调用到这几个函数。

117 - 175行,定义了通过/sys/class/example/example/val对设备进行访问时,相应会调用的函数。

177 - 248行,定义了通过/proc/example对设备进行访问时,需要调用的函数。

 

有了源码,下面我们需要编写一个Makefile,对这些源码进行编译。

Makefile内容如下:

[cpp] view plain copy print ?
  1. obj-y += example.o  
obj-y += example.o

为什么Makefile能只有这一行,大家可以参考LDD3第29页的介绍,另外也可以参考我的博客文章LDD3源码分析之hello.c与Makefile模板

下面我们需要通知内核我们增加了一个新的驱动程序example,以便在编译内核时会对example进行编译。通知内核的方法是修改内核drivers目录下的Makefile,在该文件的最后增加一句:

 

[cpp] view plain copy print ?
  1. obj-y               += example/  
obj-y               += example/

为什么增加这一句就能通知内核呢?这个是Linux内核编译机制决定的,如果展开分析会包括很多内容,这里不再细述。大家先知道这么改就可以了。

以上工作完成后,我们就可以重新编译Linux内核了,回到内核根目录下,执行如下命令:

make

编译成功后得到的内核镜像就已经包括了我们加入的example驱动了。

下面我们来测试一下新加入的example驱动程序是否工作正常。

首先用我们新编译出来的Linux内核启动Android模拟器:

# source build/envsetup.sh

# lunch

# emulator -kernel kernel/goldfish/arch/arm/boot/zImage

# adb shell

进入系统后,可以看到example驱动程序创建的设备节点:/dev/example、/proc/example以及/sys/devices/virtual/example/example目录。

执行如下命令:

# cat /proc/example

0

# echo 5 > /proc/example

# cat /proc/example

5

可以看到,我们可以通过/proc/example节点访问设备寄存器。

# cat /sys/class/example/example/val

5

# echo 6 > /sys/class/example/example/val

# cat /sys/class/example/example/val

6

可以看到,我们可以通过/sys/class/example/example/val节点访问设备寄存器。

我们也可以通过/dev/example节点对设备寄存器进行访问,下一篇博客中我们将写一个C程序通过/dev/example节点访问设备寄存器,同时演示Android系统下开发C程序的步骤。

 

你可能感兴趣的:(android,Android驱动程序开发)