Chinaunix首页 | 论坛 | 博客
  • 博客访问: 304570
  • 博文数量: 53
  • 博客积分: 1266
  • 博客等级: 少尉
  • 技术积分: 572
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-16 16:45
文章分类

全部博文(53)

文章存档

2012年(37)

2011年(16)

分类: 嵌入式

2012-10-05 11:01:45

    接上篇内核编译继续编一个简单的随内核加载的驱动。
1、进入内核代码所在路径
2、cd goldfish/drivers
3、mkdir hello
4、cd hello
5、创建hello.h

点击(此处)折叠或打开

  1. #ifndef _HELLO_ANDROID_H_
  2. #define _HELLO_ANDROID_H_

  3. #include <linux/cdev.h>
  4. #include <linux/semaphore.h>

  5. #define HELLO_DEVICE_NODE_NAME "hello"
  6. #define HELLO_DEVICE_FILE_NAME "hello"
  7. #define HELLO_DEVICE_PROC_NAME "hello"
  8. #define HELLO_DEVICE_CLASS_NAME "hello"

  9. struct hello_android_dev {
  10.     int val;
  11.     struct semaphore sem;
  12.     struct cdev dev;
  13. };

  14. #endif
6、创建hello.c

点击(此处)折叠或打开

  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. #include "hello.h"

  9. /*主设备和从设备号变量*/
  10. static int hello_major = 0;
  11. static int hello_minor = 0;

  12. /*设备类别和设备变量*/
  13. static struct class* hello_class = NULL;
  14. static struct hello_android_dev* hello_dev = NULL;

  15. /*传统的设备文件操作方法*/
  16. static int hello_open(struct inode* inode, struct file* filp);
  17. static int hello_release(struct inode* inode, struct file* filp);
  18. static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);
  19. static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);

  20. /*设备文件操作方法表*/
  21. static struct file_operations hello_fops = {
  22.     .owner = THIS_MODULE,
  23.     .open = hello_open,
  24.     .release = hello_release,
  25.     .read = hello_read,
  26.     .write = hello_write,
  27. };

  28. /*访问设置属性方法*/
  29. static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf);
  30. static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);

  31. /*定义设备属性*/
  32. static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store);

  33. /*打开设备方法*/
  34. static int hello_open(struct inode* inode, struct file* filp) {
  35.     struct hello_android_dev* dev;
  36.     
  37.     /*将自定义设备结构体保存在文件指针的私有数据域中,以便访问设备时拿来用*/
  38.     dev = container_of(inode->i_cdev, struct hello_android_dev, dev);
  39.     filp->private_data = dev;
  40.     
  41.     return 0;
  42. }

  43. /*设备文件释放时调用,空实现*/
  44. static int hello_release(struct inode* inode, struct file* filp) {
  45.     return 0;
  46. }

  47. /*读取设备的寄存器val的值*/
  48. static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {
  49.     ssize_t err = 0;
  50.     struct hello_android_dev* dev = filp->private_data;

  51.     /*同步访问*/
  52.     if(down_interruptible(&(dev->sem))) {
  53.         return -ERESTARTSYS;
  54.     }

  55.     if(count < sizeof(dev->val)) {
  56.         goto out;
  57.     }

  58.     /*将寄存器val的值拷贝到用户提供的缓冲区*/
  59.     if(copy_to_user(buf, &(dev->val), sizeof(dev->val))) {
  60.         err = -EFAULT;
  61.         goto out;
  62.     }

  63.     err = sizeof(dev->val);

  64. out:
  65.     up(&(dev->sem));
  66.     return err;
  67. }

  68. /*写设备的寄存器值val*/
  69. static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {
  70.     struct hello_android_dev* dev = filp->private_data;
  71.     ssize_t err = 0;

  72.     /*同步访问*/
  73.     if(down_interruptible(&(dev->sem))) {
  74.         return -ERESTARTSYS;
  75.     }

  76.     if(count != sizeof(dev->val)) {
  77.         goto out;
  78.     }

  79.     /*将用户提供的缓冲区的值写到设备寄存器去*/
  80.     if(copy_from_user(&(dev->val), buf, count)) {
  81.         err = -EFAULT;
  82.         goto out;
  83.     }

  84.     err = sizeof(dev->val);

  85. out:
  86.     up(&(dev->sem));
  87.     return err;
  88. }

  89. /*读取寄存器val的值到缓冲区buf中,内部使用*/
  90. static ssize_t __hello_get_val(struct hello_android_dev* dev, char* buf) {
  91.     int val = 0;

  92.     /*同步访问*/
  93.     if(down_interruptible(&(dev->sem))) {
  94.         return -ERESTARTSYS;
  95.     }

  96.     val = dev->val;
  97.     up(&(dev->sem));

  98.     return snprintf(buf, PAGE_SIZE, "%d\n", val);
  99. }

  100. /*把缓冲区buf的值写到设备寄存器val中去,内部使用*/
  101. static ssize_t __hello_set_val(struct hello_android_dev* dev, const char* buf, size_t count) {
  102.     int val = 0;

  103.     /*将字符串转换成数字*/
  104.     val = simple_strtol(buf, NULL, 10);

  105.     /*同步访问*/
  106.     if(down_interruptible(&(dev->sem))) {
  107.         return -ERESTARTSYS;
  108.     }

  109.     dev->val = val;
  110.     up(&(dev->sem));

  111.     return count;
  112. }

  113. /*读取设备属性val*/
  114. static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {
  115.     struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);

  116.     return __hello_get_val(hdev, buf);
  117. }

  118. /*写设备属性val*/
  119. static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {
  120.     struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);
  121.     
  122.     return __hello_set_val(hdev, buf, count);
  123. }

  124. /*读取设备寄存器val的值,保存在page缓冲区中*/
  125. static ssize_t hello_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) {
  126.     if(off > 0) {
  127.         *eof = 1;
  128.         return 0;
  129.     }

  130.     return __hello_get_val(hello_dev, page);
  131. }

  132. /*把缓冲区的值buff保存到设备寄存器val中去*/
  133. static ssize_t hello_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) {
  134.     int err = 0;
  135.     char* page = NULL;

  136.     if(len > PAGE_SIZE) {
  137.         printk(KERN_ALERT"The buff is too large: %lu.\n", len);
  138.         return -EFAULT;
  139.     }

  140.     page = (char*)__get_free_page(GFP_KERNEL);
  141.     if(!page) {
  142.         printk(KERN_ALERT"Failed to alloc page.\n");
  143.         return -ENOMEM;
  144.     }

  145.     /*先把用户提供的缓冲区值拷贝到内核缓冲区中去*/
  146.     if(copy_from_user(page, buff, len)) {
  147.         printk(KERN_ALERT"Failed to copy buff from user.\n");
  148.         err = -EFAULT;
  149.         goto out;
  150.     }

  151.     err = __hello_set_val(hello_dev, page, len);

  152. out:
  153.     free_page((unsigned long)page);
  154.     return err;
  155. }

  156. /*创建/proc/hello文件*/
  157. static void hello_create_proc(void) {
  158.     struct proc_dir_entry* entry;
  159.     
  160.     entry = create_proc_entry(HELLO_DEVICE_PROC_NAME, 0, NULL);
  161.     if(entry) {
  162.         entry->owner = THIS_MODULE;
  163.         entry->read_proc = hello_proc_read;
  164.         entry->write_proc = hello_proc_write;
  165.     }
  166. }

  167. /*删除/proc/hello文件*/
  168. static void hello_remove_proc(void) {
  169.     remove_proc_entry(HELLO_DEVICE_PROC_NAME, NULL);
  170. }

  171. /*初始化设备*/
  172. static int __hello_setup_dev(struct hello_android_dev* dev) {
  173.     int err;
  174.     dev_t devno = MKDEV(hello_major, hello_minor);

  175.     memset(dev, 0, sizeof(struct hello_android_dev));

  176.     cdev_init(&(dev->dev), &hello_fops);
  177.     dev->dev.owner = THIS_MODULE;
  178.     dev->dev.ops = &hello_fops;

  179.     /*注册字符设备*/
  180.     err = cdev_add(&(dev->dev),devno, 1);
  181.     if(err) {
  182.         return err;
  183.     }

  184.     /*初始化信号量和寄存器val的值*/
  185.     init_MUTEX(&(dev->sem));
  186.     dev->val = 0;

  187.     return 0;
  188. }

  189. /*模块加载方法*/
  190. static int __init hello_init(void){
  191.     int err = -1;
  192.     dev_t dev = 0;
  193.     struct device* temp = NULL;

  194.     printk(KERN_ALERT"Initializing hello device.\n");

  195.     /*动态分配主设备和从设备号*/
  196.     err = alloc_chrdev_region(&dev, 0, 1, HELLO_DEVICE_NODE_NAME);
  197.     if(err < 0) {
  198.         printk(KERN_ALERT"Failed to alloc char dev region.\n");
  199.         goto fail;
  200.     }

  201.     hello_major = MAJOR(dev);
  202.     hello_minor = MINOR(dev);

  203.     /*分配helo设备结构体变量*/
  204.     hello_dev = kmalloc(sizeof(struct hello_android_dev), GFP_KERNEL);
  205.     if(!hello_dev) {
  206.         err = -ENOMEM;
  207.         printk(KERN_ALERT"Failed to alloc hello_dev.\n");
  208.         goto unregister;
  209.     }

  210.     /*初始化设备*/
  211.     err = __hello_setup_dev(hello_dev);
  212.     if(err) {
  213.         printk(KERN_ALERT"Failed to setup dev: %d.\n", err);
  214.         goto cleanup;
  215.     }

  216.     /*/sys/class/目录下创建设备类别目录hello*/
  217.     hello_class = class_create(THIS_MODULE, HELLO_DEVICE_CLASS_NAME);
  218.     if(IS_ERR(hello_class)) {
  219.         err = PTR_ERR(hello_class);
  220.         printk(KERN_ALERT"Failed to create hello class.\n");
  221.         goto destroy_cdev;
  222.     }

  223.     /*/dev/目录和/sys/class/hello目录下分别创建设备文件hello*/
  224.     temp = device_create(hello_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME);
  225.     if(IS_ERR(temp)) {
  226.         err = PTR_ERR(temp);
  227.         printk(KERN_ALERT"Failed to create hello device.");
  228.         goto destroy_class;
  229.     }

  230.     /*/sys/class/hello/hello目录下创建属性文件val*/
  231.     err = device_create_file(temp, &dev_attr_val);
  232.     if(err < 0) {
  233.         printk(KERN_ALERT"Failed to create attribute val.");
  234.         goto destroy_device;
  235.     }

  236.     dev_set_drvdata(temp, hello_dev);

  237.     /*创建/proc/hello文件*/
  238.     hello_create_proc();

  239.     printk(KERN_ALERT"Succedded to initialize hello device.\n");
  240.     return 0;

  241. destroy_device:
  242.     device_destroy(hello_class, dev);

  243. destroy_class:
  244.     class_destroy(hello_class);

  245. destroy_cdev:
  246.     cdev_del(&(hello_dev->dev));

  247. cleanup:
  248.     kfree(hello_dev);

  249. unregister:
  250.     unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1);

  251. fail:
  252.     return err;
  253. }

  254. /*模块卸载方法*/
  255. static void __exit hello_exit(void) {
  256.     dev_t devno = MKDEV(hello_major, hello_minor);

  257.     printk(KERN_ALERT"Destroy hello device.\n");

  258.     /*删除/proc/hello文件*/
  259.     hello_remove_proc();

  260.     /*销毁设备类别和设备*/
  261.     if(hello_class) {
  262.         device_destroy(hello_class, MKDEV(hello_major, hello_minor));
  263.         class_destroy(hello_class);
  264.     }

  265.     /*删除字符设备和释放设备内存*/
  266.     if(hello_dev) {
  267.         cdev_del(&(hello_dev->dev));
  268.         kfree(hello_dev);
  269.     }

  270.     /*释放设备号*/
  271.     unregister_chrdev_region(devno, 1);
  272. }

  273. MODULE_LICENSE("GPL");
  274. MODULE_DESCRIPTION("First Android Driver");

  275. module_init(hello_init);
  276. module_exit(hello_exit);
7、创建Kconfig

点击(此处)折叠或打开

  1. config HELLO
  2.     tristate "First Android Driver"
  3.     default n
  4.     help
  5.     This is the first android driver.
8、创建Makefile

点击(此处)折叠或打开

  1. obj-$(CONFIG_HELLO) += hello.o
9、进入内核源代码的goldfish/arch/arm路径
10、在Kconfig文件中的menu "Device Drivers"和endmenu之间添加:
source "drivers/hello/Kconfig"
11、进入内核源代码的goldfish/drivers路径
12、在Kconfig文件中的menu "Device Drivers"和endmenu之间添加:
source "drivers/hello/Kconfig"
13、在Makefile文件中添加:
obj-$(CONFIG_HELLO) += hello/
14、进入goldfish路径
15、make menuconfig
"Device Drivers" => "First Android Drivers"选项选中
16、make
17、emulator -kernel 内核源代码路径/goldfish/arch/arm/boot/zImage -avd a_avd&
18、adb shell
19、察看驱动是否随内核加载
ls /dev
ls /proc
20、验证驱动是否可用

点击(此处)折叠或打开

  1. cd proc
  2. cat hello
  3. echo '5' > hello
  4. cat hello
  5. cd /sys/class
  6. cd hello
  7. cd hello
  8. cat val
  9. echo '0' > val
  10. cat val



阅读(3859) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~