ramlife

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  1. 编写实际的驱动函数类似于 led_open, led_write 等。
  2. 定义一个 file_operations 结构体,把 led_open 等实际的驱动函数填充进去。
  3. 调用 register_chrdev 函数,把 file_operations 结构体注册到内核里面去。
  4. 调用 register_chrdev 的这个函数,一般是 led_init ,也叫做驱动的入口函数。
  5. 使用 module_init(led_init); 这个宏来修饰 led_init 这个入口函数。内核会寻找 module_init 这个结构体,找到之后就会调用里面的函数指针 led_init 来调用驱动的入口函数了。
  6. 驱动注册之后,/dev/ 下面的设备一般是字符设备,就是属性是 c 开头的,还有相应的主设备号 major,和次设备号 minor。
  7. 在内核的 vfs 里面,有一个数组,这个数组每一位指向一个主设备号,register_chrdev 就是把 file_operations 挂接到这个数组的主设备号上面。内核需要调用相应的驱动函数,也是按照主设备号去这个数组里面去找相应的 file_operations 来进行操作。
  8. 出口函数 led_exit 里面调用 卸载函数 unregister_chrdev,然后用 module_exit 这个宏来修饰。
  9. 复制其他驱动下面的 makefile 到当前驱动的目录,简单的只需要修改 obj-m += 这一项为当前的驱动 即可。然后 make 即可生成驱动。
  10. 使用 cat /proc/devices 来查看内核目前支持的设备。
  11. 在 tq2440 里面编写的代码如下:
  1 #include <linux/module.h>
  2 #include <linux/kernel.h>
  3 #include <linux/fs.h>
  4 #include <linux/init.h>
  5 #include <linux/delay.h>
  6 #include <asm/uaccess.h>
  7 #include <asm/irq.h>
  8 //#include <asm.io.h>
  9 //#include <asm/arch/regs-gpio.h>
 10 //#include <asm/hardware.h>
 11 
 12 
 13 static int first_drv_open(struct inode *inode, struct file *file)
 14 {
 15         printk("first_drv_open\n");
 16         return 0;
 17 }
 18 
 19 static ssize_t first_drv_write(struct file *file, const char __user *buf, si    ze_t count, loff_t * ppos)
 20 {
 21         printk("first_drv_write\n");
 22         return 0;
 23 }
 24 
 25 static struct file_operations first_drv_fops = {
 26         .owner = THIS_MODULE,
 27         .open = first_drv_open,
 28         .write = first_drv_write,
 29 };
 30 
 31 int first_drv_init(void)
 32 {
 33         register_chrdev(111, "first_drv", &first_drv_fops);
 34         return 0;
 35 }
 36 
 37 void first_drv_exit(void)
 38 {
 39         unregister_chrdev(111, "first_drv");
 40         return;
 41 }
 42 
 43 module_init(first_drv_init);
 44 module_exit(first_drv_exit);

makefile

  1 KERN_DIR = /home/book/embed_sky/linux-2.6.30.4
  2 CC = arm-linux-gcc
  3 
  4 all:
  5         make -C $(KERN_DIR) M=`pwd` modules
  6 
  7 clean:
  8         make -C $(KERN_DIR) M=`pwd` modules clean
  9         rm -rf modules.order
 10 
 11 obj-m += first_drv.o
  1. make 编译出 ko 文件,然后复制到 nfs_root 目录。 切换到开发板上,使用 insmod xxx.ko 命令,加载驱动, 然后 cat /proc/devices,可以看到已经加载上驱动设备了。

  2. 编写驱动测试程序:

  1 #include <sys/types.h>
  2 #include <sys/stat.h>
  3 #include <fcntl.h>
  4 #include <stdio.h>
  5 
  6 int main(int argc, char **argv)
  7 {
  8         int fd;
  9         int val = 1;
 10         fd = open("/dev/xxx", O_RDWR);
 11         if (fd <0)
 12                 printf("can't open!\n");
 13         write(fd, &val, 4);
 14         return 0;
 15 }

然后 arm-linux-gcc -o first_test first_test.c
再把生成的文件复制到 nfs 里面去。

  1. 在开发板上执行 first_test, 提示 can't open! 因为没有 /dev/xxx 这个设备。
    所以我们先创建这个设备: mknod /dev/xxx c 111 0
    然后再次执行,就可以了。

  2. 在驱动程序里面可以不指定主设备号,让系统自动分配,这样程序就改为:

 31 int major;
 32 
 33 int first_drv_init(void)
 34 {
 35         major = register_chrdev(0, "first_drv", &first_drv_fops);
 36         return 0;
 37 }
 38 
 39 void first_drv_exit(void)
 40 {
 41         unregister_chrdev(major, "first_drv");
 42         return;
 43 }

然后重新编译并复制到 nfs 里面。
在开发板上,使用 rmmod first_drv 来卸载模块,然后 lsmod 确定模块卸载了, 然后使用 inmod 重新加载模块, cat /proc/devices 来看看分配到什么设备号了。
然后 rm /dev/xxx 删除原来的设备, mknod /dev/xxx c 252 0 按照新的设备号重新建立设备,这样就测试程序又可以正常工作了。

  1. 如果想要自动创建节点,那么就需要 udev,或者简化后的 mdev 来实现,mdev 根据 /sys/devices 目录下面的信息,自动创建节点。
posted on 2020-05-16 22:38  ramlife  阅读(117)  评论(0编辑  收藏  举报