Chinaunix首页 | 论坛 | 博客
  • 博客访问: 72421
  • 博文数量: 15
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 57
  • 用 户 组: 普通用户
  • 注册时间: 2015-06-30 09:39
个人简介

程序改变世界!

文章分类

全部博文(15)

文章存档

2018年(1)

2017年(4)

2016年(7)

2015年(3)

我的朋友

分类: LINUX

2017-11-12 18:10:13

  linux驱动学习正式开始,开发板:TQ210,在网上搜索资料点亮OLED,先贴出代码:
led_driver.c

点击(此处)折叠或打开

  1. /**********************************************************
  2.  **CopyRight OuYanghan
  3.  **filename            : led_driver.c
  4.  **decription        : driver layer
  5.  **author            : OuYanghan
  6.  **date                : 2017.11.08
  7.  **********************************************************/

  8. #include <linux/module.h>
  9. #include <linux/kernel.h>
  10. #include <linux/fs.h>
  11. #include <linux/init.h>
  12. #include <linux/delay.h>
  13. #include <asm/uaccess.h>
  14. #include <asm/irq.h>
  15. #include <asm/io.h>
  16. #include <linux/device.h>//classcreate的定义
  17. #include <linux/gpio.h>//gpio结构体的定义
  18. //#include <mach/regs-gpio.h>

  19. //#include <asm/arch/regs-gpio.h>
  20. //linux 3.10内核的regs-gpio.h位置不再是<asm/arch/regs-gpio.h>
  21. #include <mach/hardware.h>
  22. #include <linux/platform_device.h>

  23. volatile unsigned long *gpc0con = NULL;
  24. volatile unsigned long *gpc0pud = NULL;
  25. volatile unsigned long *gpc0dat = NULL;

  26. static struct class *led_drv_class;
  27. static struct device *led_drv_class_dev;

  28. ///static volatile unsigned long *gpio_con;
  29. //static volatile unsigned long *gpio_dat;

  30. static int led_open(struct inode *inode, struct file *file)
  31. {
  32.     printk("led_drv_open\n");

  33.     *gpc0con &= ~(0xf<<3*4);
  34.     *gpc0con |= (0x1<<3*4);//1为输出模式
  35.     *gpc0dat &= ~(0x1<<3);//gpc0_3
  36.     *gpc0dat |= (0x0<<3);//高电平亮

  37.     return 0;
  38. }

  39. static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
  40. {

  41.     int val;
  42.     int ret;
  43.     printk("led_drv_write\n");

  44.     ret = copy_from_user(&val, buf, count); // copy_to_user();
  45.     if(ret)
  46.     {
  47.         printk("copy_from_user error\n");
  48.         return -EFAULT;
  49.     }
  50.     if (val == 1)
  51.     {
  52.         *gpc0dat &= ~(0x1<<3);//高电平亮
  53.         *gpc0dat |= (0x1<<3);
  54.     }
  55.     else
  56.     {
  57.         // gpc0dat = (*gpc0dat & ~(0x1<<3)) | (0x1<<3);
  58.         *gpc0dat &= ~(0x1<<3);//
  59.         *gpc0dat |= (0x0<<3);
  60.     }

  61.     return 0;
  62. }

  63. static struct file_operations led_fops = {
  64.     .owner = THIS_MODULE,
  65.     .open = led_open,
  66.     .write = led_write,
  67. };

  68. int major;
  69. static int led_probe(struct platform_device *pdev)
  70. {
  71.     struct resource *res;
  72.     /* 根据platform_device的资源进行ioremap */
  73.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  74.     if(!res){
  75.         printk("get resource error\n");
  76.         return -1;
  77.     }
  78.     gpc0con = ioremap(res->start, res->end - res->start + 1);
  79.     gpc0dat = gpc0con + 1;

  80.     major = register_chrdev(0, "led_cdev", &led_fops);
  81.     led_drv_class = class_create(THIS_MODULE,"class_led_cdev");
  82.     led_drv_class_dev = device_create(led_drv_class, NULL,MKDEV(major, 0), NULL, "led_rocky");
  83.     //MKDEV将主设备号和次设备号转为dev_t类型
  84.     //device_create创建设备信息,udev会自动根据设备信息创建设备节点/dev/led,应用程序根据设备节点(路径)访问设备
  85.     //linux 3.10中,class_device_create替换为device_create
  86.     printk("led_rocky initialize\n");
  87.     return 0;
  88. }

  89. static int led_remove(struct platform_device *pdev)
  90. {
  91.     printk("led_drv_exit\n");
  92.     unregister_chrdev(major, "led_cdev");
  93.     device_unregister(led_drv_class_dev);//linux 3.10中,class_device_unregister替换为device_unregister
  94.     class_destroy(led_drv_class);
  95.     return 0;
  96. }

  97. struct platform_driver led_drv = {
  98.     .probe = led_probe,
  99.     .remove = led_remove,
  100.     .driver = {
  101.         .owner = THIS_MODULE, /* 一定要加上这句,否则运行测试程序会出现段错误 */
  102.         .name = "s5pv210_led",
  103.     }
  104. };

  105. static int __init led_drv_init(void)
  106. {
  107.     platform_driver_register(&led_drv);
  108.     return 0;
  109. }

  110. static void __exit led_drv_exit(void)
  111. {
  112.     platform_driver_unregister(&led_drv);
  113. }

  114. module_init(led_drv_init);
  115. module_exit(led_drv_exit);

  116. MODULE_LICENSE("GPL");

led_test.c:

点击(此处)折叠或打开

  1. /**********************************************************
  2.  **CopyRight OuYanghan
  3.  **filename            : led_test.c
  4.  **decription        : user test demo
  5.  **author            : OuYanghan
  6.  **date                : 2017.11.08
  7.  **********************************************************/

  8. #include <stdio.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <fcntl.h>

  12. /* ledtest on
  13.  * ledtest off
  14.  */
  15. int main(int argc, char **argv)
  16. {
  17.     int fd;
  18.     int val = 1;
  19.     fd = open("/dev/led_rocky", O_RDWR);
  20.     if (fd < 0)
  21.     {
  22.         printf("can't open!\n");
  23.     }
  24.     if (argc != 2)
  25.     {
  26.         printf("Usage :\n");
  27.         printf("%s \n", argv[0]);
  28.         return 0;
  29.     }

  30.     if (strcmp(argv[1], "on") == 0)
  31.     {
  32.         val = 1;
  33.     }
  34.     else
  35.     {
  36.         val = 0;
  37.     }

  38.     write(fd, &val, 4);
  39.     return 0;
  40. }

Makefile:

点击(此处)折叠或打开

  1. KERN_DIR = /home/rocky/practise/tq210learn/Kernel_3.0.8_TQ210_for_Linux_v2.1
  2. obj-m += led_driver.o

  3. target = main

  4. .PHONY:all
  5. all:
  6.     make ARCH=arm -C $(KERN_DIR) M=`pwd` modules
  7.     arm-linux-gcc -o $(target) led_test.c

  8. .PHONY:clean
  9. clean:
  10.     rm -rf $(target) *.ko *.mod.c *.mod.o *.o *.order *.symvers *.cmd .*.o.* .*.ko.*

问题一. 写好这三个文件之后,能猜测到Makefile中的“KERN_DIR”是指内核的根目录路径,为什么要去执行该目录下的makefile?
    带着问题我去找了tq提供的linux3.0.8,尝试着执行make menuconfig配置下内核,于是出现了问题二。

问题二. p { margin-bottom: 0.25cm; line-height: 120% 解压天嵌提供的linux内核3.0.8版本,在根目录下执行make menuconfig,提示下面错误:

*** Unable to find the ncurses libraries or the

*** required header files.

*** 'make menuconfig' requires the ncurses libraries.

***

*** Install ncurses (ncurses-devel) and try again.

***

/home/rocky/practise/tq210learn/Kernel_3.0.8_TQ210_for_Linux_v2.1/scripts/kconfig/Makefile:215: recipe for target 'scripts/kconfig/dochecklxdialog' failed

make[1]: *** [scripts/kconfig/dochecklxdialog] Error 1

Makefile:492: recipe for target 'menuconfig' failed

make: *** [menuconfig] Error 2



解决方法:
    根据提示知:缺少终端图形库ncurses库,下载ncurse-devel,报错,正确打开方式:sudo apt-get install libncurses5-dev!!

然后尝试在led测试代码目录下执行make,得到文件如下:
led_driver.c  led_driver.ko  led_driver.mod.c  led_driver.mod.o  led_driver.o  led_test.c  main  Makefile  modules.order  Module.symvers

然后将led_driver.ko 和目标文件main拷贝到开发板上,运行insmod led_driver.ko,报错,问题三:
问题三:提示错误如下:
td p { margin-bottom: 0cm; }p { margin-bottom: 0.25cm; line-height: 120%; }

led_driver: version magic '3.0.8 mod_unload ARMv5 ' should be '3.0.8-EmbedSky preempt mod_unload ARMv7 '

insmod: can't insert 'led_driver.ko': invalid module format

解决方法:
     step1.其中搜索了很多资料,直接搜索问题,也知道是因为vermagic的问题,就是你拿在自己内核版本里编译的ko文件,在目标开发板上insmod的时候,目标开发板内核会检测这个vermagic的值,其实就是一串字符串。不过出发点不多,都是在搜出现的问题,弄了两天没找到解决方法,于是换了思路直接搜索vermagic的概念,才有了突破。以我使用的Linux3.0.8为例:
     step2.vermagic由include/generated/utsrelease.h文件定义VERMAGIC_STRING

点击(此处)折叠或打开

  1. #include <generated/utsrelease.h>
  2. #include <linux/module.h>

  3. /* Simply sanity version stamp for modules. */
  4. #ifdef CONFIG_SMP
  5. #define MODULE_VERMAGIC_SMP "SMP "
  6. #else
  7. #define MODULE_VERMAGIC_SMP ""
  8. #endif
  9. #ifdef CONFIG_PREEMPT
  10. #define MODULE_VERMAGIC_PREEMPT "preempt "
  11. #else
  12. #define MODULE_VERMAGIC_PREEMPT ""
  13. #endif
  14. #ifdef CONFIG_MODULE_UNLOAD
  15. #define MODULE_VERMAGIC_MODULE_UNLOAD "mod_unload "
  16. #else
  17. #define MODULE_VERMAGIC_MODULE_UNLOAD ""
  18. #endif
  19. #ifdef CONFIG_MODVERSIONS
  20. #define MODULE_VERMAGIC_MODVERSIONS "modversions "
  21. #else
  22. #define MODULE_VERMAGIC_MODVERSIONS ""
  23. #endif
  24. #ifndef MODULE_ARCH_VERMAGIC
  25. #define MODULE_ARCH_VERMAGIC ""
  26. #endif

  27. #define VERMAGIC_STRING                         \
  28.     UTS_RELEASE " "                            \
  29.     MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT             \
  30.     MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS    \
  31.     MODULE_ARCH_VERMAGIC
    step3.然后UTS_RELEASE查找其位置,include/generated/utsrelease.h,如下图,将其改为3.0.8-EmbedSky,

点击(此处)折叠或打开

  1. #define UTS_RELEASE "3.0.8"
重新make,insmod加载时未提示上述错误,运行测试文件,提示“can not open”,查看以下/dev下并没有出现我创建的文件节点!!
好吧这次就到这里,我要继续学习韦东山老师的视频,立帖为证,这个问题我还会回来的。






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