将自己开发的内核代码加入到Linux内核中,需要3个步骤:

1、确定把自己开发代码放入到内核合适的位置

将demo_chardev.c文件拷贝到.../drivers/char/目录下。

demo_chardev.c

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. /*结构体file_operations定义的头文件*/
  5. #include <linux/fs.h>
  6. /*声明copy_to/from_user函数的头文件*/
  7. #include <linux/uaccess.h>
  8. /*声明class_create 和device_create相关信息*/
  9. #include <linux/device.h>
  10. #define DEMO_DEBUG
  11. #ifdef  DEMO_DEBUG
  12. #define dem_dbg(fmt, arg...)  printk(KERN_WARNING fmt, ##arg)
  13. #else
  14. #define dem_dbg(fmt, arg...)  printk(KERN_DEBUG fmt, ##arg)
  15. #endif
  16. #define DEVICE_COUNT   2
  17. /*记录当前驱动所占用的主设备号*/
  18. static int major = 0;
  19. static int demo_open (struct inode *pnode, struct file *filp)
  20. {
  21. dem_dbg("[kern func]: %s  major: %d  minor: %d\n",
  22. __FUNCTION__, imajor(pnode), iminor(pnode));
  23. return 0;
  24. }
  25. static ssize_t demo_read (struct file *filp, char __user *buf, size_t count, loff_t *offp)
  26. {
  27. unsigned char ary[100] = "you are reading successfully!";
  28. unsigned long len = min(count, sizeof(ary)); //min是个宏,用来获取两个数中较小的值
  29. int retval;
  30. dem_dbg("[kern func]: %s  major: %d  minor: %d\n",
  31. __FUNCTION__, imajor(filp->f_dentry->d_inode),
  32. iminor(filp->f_dentry->d_inode));
  33. //file结构体的f_flags成员可用来判断是否阻塞读取,然后进行相应处理
  34. if(copy_to_user(buf, ary, len) != 0){
  35. retval = -EFAULT;
  36. goto cp_err;
  37. }
  38. return len; //成功返回实际传输的字节数
  39. cp_err:
  40. return retval;
  41. }
  42. static ssize_t demo_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp)
  43. {
  44. unsigned char ary[100] = "";
  45. unsigned long len = min(count, sizeof(ary)); //min是个宏,用来获取两个数中较小的值
  46. int retval;
  47. dem_dbg("[kern func]: %s  major: %d  minor: %d\n",
  48. __FUNCTION__, imajor(filp->f_dentry->d_inode),
  49. iminor(filp->f_dentry->d_inode));
  50. if(copy_from_user(ary, buf, len) != 0){
  51. retval = -EFAULT;
  52. goto cp_err;
  53. }
  54. printk("[msg]: writing context: %s\n",ary);
  55. return len; //成功返回实际传输的字节数
  56. cp_err:
  57. return retval;
  58. }
  59. static int demo_release (struct inode *pnode, struct file *filp)
  60. {
  61. dem_dbg("[kern func]: %s  major: %d  minor: %d\n",
  62. __FUNCTION__, imajor(pnode), iminor(pnode));
  63. return 0;
  64. }
  65. /*@定义file_operations结构体变量*/
  66. static struct file_operations fops = {
  67. .owner = THIS_MODULE,
  68. .read = demo_read,
  69. .write = demo_write,
  70. .open = demo_open,
  71. .release = demo_release,
  72. };
  73. static struct class *demo_class;
  74. static int __init drvdemo_init(void)
  75. {
  76. struct device *demo_device;
  77. int i;
  78. int retval;
  79. dem_dbg("[msg]:this is a driver demo, in module initial function\n");
  80. /*注册字符驱动函数,成功 返回动态分配好的主设备号,失败
  81. *返回错误码(负值)*/
  82. major = register_chrdev(0, "demo_chrdev", &fops);
  83. if(major < 0){
  84. retval = major;
  85. goto chrdev_err;
  86. }
  87. /*创建设备类*/
  88. demo_class = class_create(THIS_MODULE,"demo_class");
  89. if(IS_ERR(demo_class)){
  90. retval =  PTR_ERR(demo_class);
  91. goto class_err;
  92. }
  93. /*创建设备文件,通知用户在“/dev/”目录下创件名字为demoX的设备文件*/
  94. for(i=0; i<DEVICE_COUNT; i++){ //最多可创建255个设备节点(register_chrdev函数会申请0-254范围的从设备号)
  95. demo_device = device_create(demo_class,NULL, MKDEV(major, i), NULL,"demo%d",i);
  96. if(IS_ERR(demo_device)){
  97. retval = PTR_ERR(demo_device);
  98. goto device_err;
  99. }
  100. }
  101. return 0;
  102. device_err:
  103. while(i--) //设备节点创建的回滚操作 device_destroy(demo_class,MKDEV(major, i));
  104. class_destroy(demo_class); //删除设备类
  105. class_err:
  106. unregister_chrdev(major, "demo_chrdev");
  107. chrdev_err:
  108. return retval;
  109. }
  110. static void __exit drvdemo_exit(void)
  111. {
  112. int i;
  113. dem_dbg("[msg]:in module exit function\n");
  114. /*注销字符驱动函数,无返回值,major为已分配的主设备号*/
  115. unregister_chrdev(major, "demo_chrdev");
  116. /*删除设备节点和设备类*/
  117. for(i=0; i<DEVICE_COUNT; i++)
  118. device_destroy(demo_class,MKDEV(major, i));
  119. class_destroy(demo_class);
  120. }
  121. module_init(drvdemo_init);
  122. module_exit(drvdemo_exit);
  123. MODULE_LICENSE("Dual BSD/GPL"); //BSD/GPL双重许可证
  124. MODULE_AUTHOR("hanbo");  //模块作者(可选)
  125. MODULE_DESCRIPTION("used for studing linux drivers"); //模块儿简介(可选)

2、把自己开发的功能增加到Linux内核的配置选项中,使用户能够选择此功能

vi drivers/char/Konfig   在文件结尾,endmenu的前面加入一个config选项

  1. config  DEMO_CHARDEV
  2. bool  "demo_chardev  driver  for  hanbo  chardev  boards"
  3. default  y
  4. help
  5. this  is  CHARDEV  driver  for  hanbo  chardev  boards.

3、构建或修改Makefile,根据用户的选择,将相应的代码编译到最终生成的Linux内核中去

make  menuconfig(添加配置选项)(如果提示找不到“ncurses”库则执行命令: sudo apt-get install libncurses5-dev )

Device driver -->

character devices ->

[*] demo_chardev driver for hanbo chardev boards

4、vi  drivers/char/Makefile  添加内容如下:

..........

obj-$(CONFIG_DEMO_CHARDEV)        +=demo_chardev.o (添加)

obj-$(CONFIG_JS_RTC)                         +=js-rtc.o(自带)

js-rtc-y = rtc.o (自带)
 5、make  (更新内核镜像到开发板)

6、交叉编译测试程序,放到开发板运行

arm-linux-gcc-gcc  test.c  -o  demo

test.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <string.h>
  6. int main(int argc, char *argv[])
  7. {
  8. int fd1 = 0, fd2 = 0;
  9. unsigned char buf1[100] = "I am a test program!";
  10. unsigned char buf2[100] = {0};
  11. int retval;
  12. //以读写、不阻塞方式打开设备文件
  13. fd1 = open("/dev/demo0", O_RDWR | O_NONBLOCK);
  14. if(fd1 < 0){
  15. perror("open /dev/demo1");
  16. goto out;
  17. }
  18. //以只读、阻塞方式打开设备文件
  19. fd2 = open("/dev/demo1", O_RDONLY);
  20. if(fd2 < 0){
  21. perror("open /dev/demo2");
  22. goto out;
  23. }
  24. //成功返回实际写入字节数,失败返回负值
  25. retval = write(fd1, buf1, strlen(buf1)+1);
  26. if(retval < 0){
  27. perror("writing fd1 failed!");
  28. goto out;
  29. }
  30. printf("<user space>: write bytes: %d   write content: %s\n", retval, buf1);
  31. //成功返回实际读取字节数,失败返回负值
  32. retval = read(fd2, buf2, sizeof(buf2));
  33. if(retval < 0){
  34. perror("reading fd2 failed!");
  35. goto out;
  36. }
  37. printf("<user space>: read bytes: %d   read content: %s\n", retval, buf2);
  38. return 0;
  39. out:
  40. if(fd1 > 0)
  41. close(fd1);
  42. if(fd2 > 0)
  43. close(fd2);
  44. return -1;
  45. }

二、手动加载驱动 .ko文件

1、上面的demo_chardev.c文件放到内核下编译生成 .ko文件

Makefile

  1. #如果已定义KERNELRELEASE,说明是由内核构造系统调用的
  2. #可以利用内建语句
  3. ifneq ($(KERNELRELEASE),)
  4. obj-m +=demo_chrdev.o
  5. #此时由内核构造系统调用
  6. else
  7. #定义并记录内核源码路径
  8. KERNELDIR = /home/hanbo/linux-2.6.35.7(自己源码路径,2.6.35.7指当前内核版本)
  9. #记录当前工程目录
  10. PWD := $(shell pwd)
  11. default:
  12. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  13. @rm -rf *.o .t* .m* .*.cmd *.mod.c *.order *.symvers
  14. endif
  15. clean:
  16. rm -rf *.ko *.o .t* .m* .*.cmd *.mod.c *.order *.symvers

2、 然后用命令加载 .ko 驱动

lsmod          列举当前系统中的所有模块

lsmod          列举当前系统中的所有模块

rmmod  xxx      卸载指定模块(不需要.ko后缀)

3、如果自己编译的代码中没有用

/*创建设备类*/
            demo_class = class_create(THIS_MODULE,"demo_class");

/*创建设备文件,通知用户在“/dev/”目录下创件名字为demoX的设备文件*/

demo_device = device_create(demo_class,NULL, MKDEV(major, i), NULL,"demo%d",i);

则需要手动添加设备节点

mknod /dev/demo1 c 主设备号 0

mknod /dev/demo2 c 主设备号 1

注意:若卸载时出现提示 rmmod:chdir(2.6.35.7):No  such  file  or  directory

则在开发板根文件系统下创建目录:/lib/modules/2.6.35.7(跟当前内核版本同名)

/dev下添加设备节点的方法步骤(通过device_create)的更多相关文章

  1. Linux /dev 自动创建设备节点

    #include <linux/module.h> #include <linux/module.h> #include <linux/kernel.h> #inc ...

  2. Android 6.0中在/dev下添加新设备驱动下Selinux相关设置【转】

    本文转载自:https://blog.csdn.net/fantasy_wxe/article/details/52013922 错误1: 07-23 13:06:57.617   117   117 ...

  3. linux系统下添加新硬盘的方法详解

    对于linux新手来说,在linux上添加新硬盘,是很有挑战性的一项工作. 在Linux服务器上把硬盘接好,启动linux,以root登陆. fdisk -l ## 这里是查看目前系统上有几块硬盘 D ...

  4. android源码framework下添加新资源的方法

    编译带有资源的jar包,需要更改frameworks层,方法如下: 一.增加png类型的图片资源 1.将appupdate模块所有用到的png格式图片拷贝到framework/base/core/re ...

  5. WordPress 添加Meta Box的方法步骤

    需要使用到add meta boxes Action,该Action允许我们为任何文章类型注册Meta Box,在该Action中,我们需要使用add_meta_box()方法来添加Meta Box的 ...

  6. LINUX下添加磁盘空间的方法详解

    给Linux系统添加磁盘空间在工作会经常遇到. 在添加第二块磁盘一般系统默认为hdb(IDE硬盘)sdb(SCSI 硬盘),以hdb为例. linux-isep:~ # fdisk /dev/hdb ...

  7. eclipse下添加viplugin插件的方法

    http://www.viplugin.com/ 在eclipse根目录下建立文件:viplugin2.lic,然后在里面添加以下字符串: nd4UFjUMBADcUSeSW8ocLKoGP3lpbW ...

  8. JS添加父节点的方法。

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. 【总文档】rac增加新节点的方法步骤 How to Add Node/Instance or Remove Node/Instance in 10gR2, 11gR1, 11gR2 and 12c Oracle Clusterware and RAC

    [总文档]How to Add Node/Instance or Remove Node/Instance in 10gR2, 11gR1, 11gR2 and 12c Oracle Clusterw ...

随机推荐

  1. php那些坑

    1.创建数组不是new array(),是$aaa=array(),没有new,数组可以传入键值$aaa=array("key"=>"value"); 2 ...

  2. 在windows下使用Cygwin模拟unix环境,并安装apt-cyg,svn等工具

    在windows下使用Cygwin模拟unix环境,并安装apt-cyg,svn等工具 一.Cygwin的安装 1. 下载Cygwin,这个可以到这里下载 ,至于使用32位的还是64位的版本可以根据自 ...

  3. excel打乱各行的顺序,实现无序随机排列

    由于公司做活动,经常会发些激活码过来,为了让激活码能够充分使用,经常要打乱激活码的顺序,百度了下,看了下网上的介绍,还不错,挺实用,记录下来. 具体方法如下: 1.将文本里的内容复制到Excel里的任 ...

  4. 转 Linux命令-文件管理命令

    http://jingyan.baidu.com/article/9113f81bc1c7a72b3214c7d3.html Linux命令-文件管理命令 浏览:4118 | 更新:2012-11-1 ...

  5. 接口自动化测试之HTTP协议详解

    协议 简单理解,计算机与计算机之间的通讯语言就叫做协议,不同的计算机之间只有使用相同的协议才能通信.所以网络协议就是为计算机网络中进行数据交换而建立的规则,标准或约定的集合. OSI模型 1978年国 ...

  6. Struts2 与SpringMVC之比较

    1.Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上Spr ...

  7. java多线程异步执行

    import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.ut ...

  8. Activiti Model Editor组件

    通过Activiti Modeler架构图可知,Activiti Explorer采用的是Vaadin框架. Vaadin 是一种 Java Web 应用程序的开发框架, 其设计目标是便利地创建和维护 ...

  9. 揭秘jbpm流程引擎内核设计思想及构架

    揭秘jbpm流程引擎内核设计思想及构架 作者 胡长城(银狐999)   1     前言 2     阅读本篇的基础准备 2.1      概念的基础 2.2      环境的基础 3     什么是 ...

  10. Go -- PipleLine

    1.pipeline的产生 从一个现象说起,有一家咖啡吧生意特别好,每天来的客人络绎不绝,客人A来到柜台,客人B紧随其后,客人C排在客人B后面,客人D排在客人C后面,客人E排在客人D后面,一直排到店面 ...