linux驱动学习正式开始,开发板:TQ210,在网上搜索资料点亮OLED,先贴出代码:
led_driver.c
-
/**********************************************************
-
**CopyRight OuYanghan
-
**filename : led_driver.c
-
**decription : driver layer
-
**author : OuYanghan
-
**date : 2017.11.08
-
**********************************************************/
-
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/fs.h>
-
#include <linux/init.h>
-
#include <linux/delay.h>
-
#include <asm/uaccess.h>
-
#include <asm/irq.h>
-
#include <asm/io.h>
-
#include <linux/device.h>//classcreate的定义
-
#include <linux/gpio.h>//gpio结构体的定义
-
//#include <mach/regs-gpio.h>
-
-
//#include <asm/arch/regs-gpio.h>
-
//linux 3.10内核的regs-gpio.h位置不再是<asm/arch/regs-gpio.h>
-
#include <mach/hardware.h>
-
#include <linux/platform_device.h>
-
-
volatile unsigned long *gpc0con = NULL;
-
volatile unsigned long *gpc0pud = NULL;
-
volatile unsigned long *gpc0dat = NULL;
-
-
static struct class *led_drv_class;
-
static struct device *led_drv_class_dev;
-
-
///static volatile unsigned long *gpio_con;
-
//static volatile unsigned long *gpio_dat;
-
-
static int led_open(struct inode *inode, struct file *file)
-
{
-
printk("led_drv_open\n");
-
-
*gpc0con &= ~(0xf<<3*4);
-
*gpc0con |= (0x1<<3*4);//1为输出模式
-
*gpc0dat &= ~(0x1<<3);//gpc0_3
-
*gpc0dat |= (0x0<<3);//高电平亮
-
-
return 0;
-
}
-
-
static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
-
{
-
-
int val;
-
int ret;
-
printk("led_drv_write\n");
-
-
ret = copy_from_user(&val, buf, count); // copy_to_user();
-
if(ret)
-
{
-
printk("copy_from_user error\n");
-
return -EFAULT;
-
}
-
if (val == 1)
-
{
-
*gpc0dat &= ~(0x1<<3);//高电平亮
-
*gpc0dat |= (0x1<<3);
-
}
-
else
-
{
-
// gpc0dat = (*gpc0dat & ~(0x1<<3)) | (0x1<<3);
-
*gpc0dat &= ~(0x1<<3);//
-
*gpc0dat |= (0x0<<3);
-
}
-
-
return 0;
-
}
-
-
static struct file_operations led_fops = {
-
.owner = THIS_MODULE,
-
.open = led_open,
-
.write = led_write,
-
};
-
-
int major;
-
static int led_probe(struct platform_device *pdev)
-
{
-
struct resource *res;
-
/* 根据platform_device的资源进行ioremap */
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
if(!res){
-
printk("get resource error\n");
-
return -1;
-
}
-
gpc0con = ioremap(res->start, res->end - res->start + 1);
-
gpc0dat = gpc0con + 1;
-
-
major = register_chrdev(0, "led_cdev", &led_fops);
-
led_drv_class = class_create(THIS_MODULE,"class_led_cdev");
-
led_drv_class_dev = device_create(led_drv_class, NULL,MKDEV(major, 0), NULL, "led_rocky");
-
//MKDEV将主设备号和次设备号转为dev_t类型
-
//device_create创建设备信息,udev会自动根据设备信息创建设备节点/dev/led,应用程序根据设备节点(路径)访问设备
-
//linux 3.10中,class_device_create替换为device_create
-
printk("led_rocky initialize\n");
-
return 0;
-
}
-
-
static int led_remove(struct platform_device *pdev)
-
{
-
printk("led_drv_exit\n");
-
unregister_chrdev(major, "led_cdev");
-
device_unregister(led_drv_class_dev);//linux 3.10中,class_device_unregister替换为device_unregister
-
class_destroy(led_drv_class);
-
return 0;
-
}
-
-
struct platform_driver led_drv = {
-
.probe = led_probe,
-
.remove = led_remove,
-
.driver = {
-
.owner = THIS_MODULE, /* 一定要加上这句,否则运行测试程序会出现段错误 */
-
.name = "s5pv210_led",
-
}
-
};
-
-
static int __init led_drv_init(void)
-
{
-
platform_driver_register(&led_drv);
-
return 0;
-
}
-
-
static void __exit led_drv_exit(void)
-
{
-
platform_driver_unregister(&led_drv);
-
}
-
-
module_init(led_drv_init);
-
module_exit(led_drv_exit);
-
-
MODULE_LICENSE("GPL");
led_test.c:
-
/**********************************************************
-
**CopyRight OuYanghan
-
**filename : led_test.c
-
**decription : user test demo
-
**author : OuYanghan
-
**date : 2017.11.08
-
**********************************************************/
-
-
#include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
-
/* ledtest on
-
* ledtest off
-
*/
-
int main(int argc, char **argv)
-
{
-
int fd;
-
int val = 1;
-
fd = open("/dev/led_rocky", O_RDWR);
-
if (fd < 0)
-
{
-
printf("can't open!\n");
-
}
-
if (argc != 2)
-
{
-
printf("Usage :\n");
-
printf("%s \n", argv[0]);
-
return 0;
-
}
-
-
if (strcmp(argv[1], "on") == 0)
-
{
-
val = 1;
-
}
-
else
-
{
-
val = 0;
-
}
-
-
write(fd, &val, 4);
-
return 0;
-
}
Makefile:
-
KERN_DIR = /home/rocky/practise/tq210learn/Kernel_3.0.8_TQ210_for_Linux_v2.1
-
obj-m += led_driver.o
-
-
target = main
-
-
.PHONY:all
-
all:
-
make ARCH=arm -C $(KERN_DIR) M=`pwd` modules
-
arm-linux-gcc -o $(target) led_test.c
-
-
.PHONY:clean
-
clean:
-
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:
-
#include <generated/utsrelease.h>
-
#include <linux/module.h>
-
-
/* Simply sanity version stamp for modules. */
-
#ifdef CONFIG_SMP
-
#define MODULE_VERMAGIC_SMP "SMP "
-
#else
-
#define MODULE_VERMAGIC_SMP ""
-
#endif
-
#ifdef CONFIG_PREEMPT
-
#define MODULE_VERMAGIC_PREEMPT "preempt "
-
#else
-
#define MODULE_VERMAGIC_PREEMPT ""
-
#endif
-
#ifdef CONFIG_MODULE_UNLOAD
-
#define MODULE_VERMAGIC_MODULE_UNLOAD "mod_unload "
-
#else
-
#define MODULE_VERMAGIC_MODULE_UNLOAD ""
-
#endif
-
#ifdef CONFIG_MODVERSIONS
-
#define MODULE_VERMAGIC_MODVERSIONS "modversions "
-
#else
-
#define MODULE_VERMAGIC_MODVERSIONS ""
-
#endif
-
#ifndef MODULE_ARCH_VERMAGIC
-
#define MODULE_ARCH_VERMAGIC ""
-
#endif
-
-
#define VERMAGIC_STRING \
-
UTS_RELEASE " " \
-
MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT \
-
MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS \
-
MODULE_ARCH_VERMAGIC
step3.然后
UTS_RELEASE查找其位置,include/generated/utsrelease.h,如下图,将其改为3.0.8-EmbedSky,:
-
#define UTS_RELEASE "3.0.8"
重新make,insmod加载时未提示上述错误,运行测试文件,提示“can not open”,查看以下/dev下并没有出现我创建的文件节点!!
好吧这次就到这里,我要继续学习韦东山老师的视频,立帖为证,这个问题我还会回来的。
阅读(2796) | 评论(0) | 转发(0) |