将自己开发的内核代码加入到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. 【2018.9.20】JOI 2017 Final T3「JOIOI 王国 / The Kingdom of JOIOI」

    题目链接 题目描述 JOIOI 王国是一个 $H$ 行 $W$ 列的长方形网格,每个 $1\times 1$ 的子网格都是一个正方形的小区块.为了提高管理效率,我们决定把整个国家划分成两个省 $JOI ...

  2. 转载: LINK : fatal error LNK1104: 无法打开文件“mfc71.lib”的原因又一例

    转载地址:http://blog.csdn.net/mxclxp/article/details/8196142 LINK : fatal error LNK1104: 无法打开文件“mfc71.li ...

  3. java多线程总结一:线程的两种创建方式及比较

    1.线程的概念:线程(thread)是指一个任务从头至尾的执行流,线程提供一个运行任务的机制,对于java而言,一个程序中可以并发的执行多个线程,这些线程可以在多处理器系统上同时运行.当程序作为一个应 ...

  4. 隐藏video标签的下载按钮

    问题: 使用video标签时,有些浏览器会显示视频的下载按钮,而这并不是我们需要的功能,必须想办法去掉. 解决方法: 使用下面的css可以达到隐藏下载按钮的效果,但是点击下载的位置,还是能出现开始下载 ...

  5. android图片上传

    package com.example.center; import java.io.ByteArrayOutputStream;import java.io.InputStream; import ...

  6. Perl、PHP、Python、Java和Ruby的比较

    提问 ◆ Perl.Python.Ruby和PHP各自有何特点? ◆ 为什么动态语言多作为轻量级的解决方案? ◆ LAMP为什么受欢迎? ◆ Ruby on Rails为什么会流行? ◆ 编程语言的发 ...

  7. [bzoj3308]九月的咖啡店_欧拉筛素数_费用流

    bzoj-3308 九月的咖啡店 题目大意:深绘里在九份开了一家咖啡让,如何调配咖啡民了她每天的头等大事我们假设她有N种原料,第i种原料编号为i,调配一杯咖啡则需要在这里若干种兑在一起.不过有些原料不 ...

  8. All you need to know about SYN floods

    http://blog.dubbelboer.com/ Date: 09 Apr 2012Author: Erik Dubbelboer SYN cookies So one day I notice ...

  9. CentOS6.5升级手动安装GCC4.8.2 与 CentOS 6.4 编译安装 gcc 4.8.1

    http://blog.163.com/zhu329599788@126/blog/static/6669335020161179259975 http://www.cnblogs.com/codem ...

  10. 【kotlin】报错:required:LIst<XXX> found:List<Unit>此类型的问题

    出现问题如下: 解决方式如下: 解决思路:上面报出来的错误很明显,就是说想要的是List<XXX>类型但是给的却是List<Unit>类型,给的不是它想要的嘛 关键就是解决问题 ...