一、编译led驱动中遇到的问题
在编译led驱动的时候我使用了linux-2.6.29的内核,在开发板上执行 insmod led_init.ko
发现会出现 version magic '2.6.29.4-FriendlyARM mod_unload ARMv4 ' should be '2.6'的信息
网上搜索发现这是由于我编译时使用的内核与开发板上运行的内核是不匹配的,开发板的内核为2.6.29.4-FriendlyARM。
然后再使用友善之臂光盘上提供的内核linux-2.6.32.2编译我的驱动内核模块,将编译生成的led_init.ko文件下载到开发板上,执行 insmod led_init.ko这时候产生了更多的错误信息,基本上是没看懂,但是我就看懂了最后一句话, led_init.ko installed,这就说明我要安装的内核模块其实已经在内核中安装过了,这时我再安装这个模块才导致了上面那些错误信息。
然后我重新配置内核 make menuconfig ,将device—>character 下面的LEDs前面的编译选项清楚,重新编译内核 make zImage,然后将编译好的内核下载到开发板上再次执行insmod led_init.ko,这时出现leds initialized 这是源文件中由printk (DEVICE_NAME"\tinitialized\n"); 这条语句打印出来的,而且核心板上的四个LED灯亮了,说明我的内核模块已经安装成功了。
二、led驱动编译时使用的Linux内核版本不同会造成头文件的改变,
2.6.30以前的内核:
s3c2410_gpio_cfgpin ()定义在arch/arm/mach-s3c2410/include/mach/regs-gpio.h
数据寄存器:
static unsigned long led_table [] = {
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8,
};
配置寄存器:
static unsigned int led_cfg_table [] = {
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};
2.6.30以后的内核:
s3c2410_gpio_cfgpin( S3C2410_GPB(5), S3C2410_GPIO_OUTPUT);
s3c2410_gpio_cfgpin()的定义在arch/arm/march-2410/include/mach/gpio-fns.h
S3C2410_GPB()的定义在arch/arm/march-2410/include/mach/gpio-nrs.h
S3C2410_GPIO_OUTPUT的定义在arch/arm/march-2410/include/mach/regs-gpio.h
三、关于ioctl函数的问题
在应用程序中这是一个系统调用,原型为
int ioctl(int fd, ind cmd, …);
其中fd就是用户程序打开设备时使用open函数返回的文件标示符,cmd就是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,有或没有是和cmd的意义相关的。这个函数用于访问内核空间通过内核来控制设备。
在编译led驱动的时候我使用了linux-2.6.29的内核,在开发板上执行 insmod led_init.ko
发现会出现 version magic '2.6.29.4-FriendlyARM mod_unload ARMv4 ' should be '2.6'的信息
网上搜索发现这是由于我编译时使用的内核与开发板上运行的内核是不匹配的,开发板的内核为2.6.29.4-FriendlyARM。
然后再使用友善之臂光盘上提供的内核linux-2.6.32.2编译我的驱动内核模块,将编译生成的led_init.ko文件下载到开发板上,执行 insmod led_init.ko这时候产生了更多的错误信息,基本上是没看懂,但是我就看懂了最后一句话, led_init.ko installed,这就说明我要安装的内核模块其实已经在内核中安装过了,这时我再安装这个模块才导致了上面那些错误信息。
然后我重新配置内核 make menuconfig ,将device—>character 下面的LEDs前面的编译选项清楚,重新编译内核 make zImage,然后将编译好的内核下载到开发板上再次执行insmod led_init.ko,这时出现leds initialized 这是源文件中由printk (DEVICE_NAME"\tinitialized\n"); 这条语句打印出来的,而且核心板上的四个LED灯亮了,说明我的内核模块已经安装成功了。
二、led驱动编译时使用的Linux内核版本不同会造成头文件的改变,
2.6.30以前的内核:
s3c2410_gpio_cfgpin ()定义在arch/arm/mach-s3c2410/include/mach/regs-gpio.h
数据寄存器:
static unsigned long led_table [] = {
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8,
};
配置寄存器:
static unsigned int led_cfg_table [] = {
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};
2.6.30以后的内核:
s3c2410_gpio_cfgpin( S3C2410_GPB(5), S3C2410_GPIO_OUTPUT);
s3c2410_gpio_cfgpin()的定义在arch/arm/march-2410/include/mach/gpio-fns.h
S3C2410_GPB()的定义在arch/arm/march-2410/include/mach/gpio-nrs.h
S3C2410_GPIO_OUTPUT的定义在arch/arm/march-2410/include/mach/regs-gpio.h
三、关于ioctl函数的问题
在应用程序中这是一个系统调用,原型为
int ioctl(int fd, ind cmd, …);
其中fd就是用户程序打开设备时使用open函数返回的文件标示符,cmd就是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,有或没有是和cmd的意义相关的。这个函数用于访问内核空间通过内核来控制设备。
此外还有ioctl 驱动方法有和用户空间版本不同的原型:
int (*ioctl)(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
cmd参数从用户空间传下来,可选的参数 arg 以一个unsigned long 的形 传递,不管它是一个整数或一个指针。如果cmd命令不涉及数据传输,则第 3个 参数arg的值无任何意义。现在的问题是我在驱动中定义了一些ioctl的命令,例如
#define LED_CTL 'k'
#define LED_ALL_OPEN _IO(LED_CTL,0)
#define LED_ALL_CLOSE _IO(LED_CTL,1)
我在用户程序中不知道如何使用这些命令,我是不是可以这么理解:这里的定义的命令是不是就是宏定义,只不过如果命令多了的话,通过命令名字我可以知道这些命令是什么的,而不是对着一堆数字不知道命令干嘛用的。而我在用户程序中呢,我也进行相应的宏定义,然后将命令填写到系统调用的ioctl第二个参数中?
一点小总结:
驱动是用户在用户空间使用物理空间的一种途径。正常情况下,用户进程只能分配到3G的虚拟内存,没办法用到物理空间,其实内核用的也是虚拟空间,而内核通过一些机制或者函数(ioremap)来将物理地址、寄存器地址映射到内核所用的1G的虚拟空间中,而我们用户则通过系统调用来访问内核空间模块,进而达到操控硬件的效果。
驱动的开发有两种方式,一是编译成内核模块,这个有一定限制就是编译时使用的内核makefile必须与开发板相同;另一个方式是将直接将模块编译进内核,不过这个很麻烦需要配置内核中的.config makefile等文件,而且花费的时间也很长(编译一遍内核需要20分钟,这还是不出现错误的情况下,而且编译的内核也不一定能用)所以最好不用这个而且这个是要开放源码的哦。
代码
#include <linux/module.h> //模块加载的头文件
#include <linux/kernel.h> // 内核头文件
#include <linux/fs.h> //定义file_operations结构
#include <linux/init.h> //用户定义的模块初始化函数需要引用的头文件
#include <linux/delay.h> //延时函数的头文件
#include <mach/regs-gpio.h> //定义GPIO寄存器相关的宏
#include <mach/hardware.h> //硬件相关的函数
#include <linux/miscdevice.h>
#include <linux/bounds.h>
#include <asm/io.h>
#include <linux/gpio.h>
#define DEVICE_NAME "leds"
#define LED_CTR 'k'
#define LED_ALL_CLOSE _IO(LED_CTR,0)
#define LED_ALL_OPEN _IO(LED_CTR,1)
static int led_data_table[]={
S3C2410_GPB(5),
S3C2410_GPB(6),
S3C2410_GPB(7),
S3C2410_GPB(8),
};
/*配置引脚为输出*/
static int s3c2440_leds_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
int i;
switch(cmd) {
case 0:
for(i=0;i<4;i++)
s3c2410_gpio_setpin(led_data_table[i], 0);
return 0;break;
case 1:
for(i=0;i<4;i++)
s3c2410_gpio_setpin(led_data_table[i], 1);
return 0;break;
default:
return -EINVAL;
}
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.ioctl = s3c2440_leds_ioctl,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init dev_init(void)
{ int ret;
int i;
for (i = 0; i < 4; i++) {
s3c2410_gpio_cfgpin(led_data_table[i], S3C2410_GPIO_OUTPUT);
s3c2410_gpio_setpin(led_data_table[i], 0);
}
ret = misc_register(&misc);
printk (DEVICE_NAME"\tinitialized\n");
#include <linux/kernel.h> // 内核头文件
#include <linux/fs.h> //定义file_operations结构
#include <linux/init.h> //用户定义的模块初始化函数需要引用的头文件
#include <linux/delay.h> //延时函数的头文件
#include <mach/regs-gpio.h> //定义GPIO寄存器相关的宏
#include <mach/hardware.h> //硬件相关的函数
#include <linux/miscdevice.h>
#include <linux/bounds.h>
#include <asm/io.h>
#include <linux/gpio.h>
#define DEVICE_NAME "leds"
#define LED_CTR 'k'
#define LED_ALL_CLOSE _IO(LED_CTR,0)
#define LED_ALL_OPEN _IO(LED_CTR,1)
static int led_data_table[]={
S3C2410_GPB(5),
S3C2410_GPB(6),
S3C2410_GPB(7),
S3C2410_GPB(8),
};
/*配置引脚为输出*/
static int s3c2440_leds_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
int i;
switch(cmd) {
case 0:
for(i=0;i<4;i++)
s3c2410_gpio_setpin(led_data_table[i], 0);
return 0;break;
case 1:
for(i=0;i<4;i++)
s3c2410_gpio_setpin(led_data_table[i], 1);
return 0;break;
default:
return -EINVAL;
}
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.ioctl = s3c2440_leds_ioctl,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init dev_init(void)
{ int ret;
int i;
for (i = 0; i < 4; i++) {
s3c2410_gpio_cfgpin(led_data_table[i], S3C2410_GPIO_OUTPUT);
s3c2410_gpio_setpin(led_data_table[i], 0);
}
ret = misc_register(&misc);
printk (DEVICE_NAME"\tinitialized\n");
测试程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
int on;
int fd;
int cmd;
sscanf(argv[1],"%d", &on);
if(on==1)
cmd=LED_ALL_CLOSED;
if(on==0)
cmd=LED_ALL_OPEN;
fd = open("/dev/leds0", 0);
if (fd < 0) {
fd = open("/dev/leds", 0);
}
if (fd < 0) {
perror("open device leds");
exit(1);
}
ioctl(fd,cmd);
close(fd);
return 0;
}
return ret;
}
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
int on;
int fd;
int cmd;
sscanf(argv[1],"%d", &on);
if(on==1)
cmd=LED_ALL_CLOSED;
if(on==0)
cmd=LED_ALL_OPEN;
fd = open("/dev/leds0", 0);
if (fd < 0) {
fd = open("/dev/leds", 0);
}
if (fd < 0) {
perror("open device leds");
exit(1);
}
ioctl(fd,cmd);
close(fd);
return 0;
}
return ret;
}
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");