MINI2440驱动程序编译进内核
开发环境:
SYSTEM : Ubuntu-12.04
Board : Mini2440-t35
Bootloader : u-boot-1.1.6
Kernel : Linux-2.6.22.6
CROSS_COMPILE: arm-linux-gcc v3.4.5
一、驱动程序编译进内核的步骤
在 linux 内核中增加程序需要完成以下三项工作:
1. 将编写的源代码复制到 Linux 内核源代码的相应目录;
2. 在目录的 Kconfig 文件中增加新源代码对应项目的编译配置选项;
3. 在目录的 Makefile 文件中增加对新源代码的编译条目。
二、将前面MINI2440的LED驱动程序编译进内核
1. 将led_drv.c文件拷入内核的drivers/char目录下。
2. 修改drivers/char目录下的Kconfig文件,加入如下条目
-
config MINI2440_LED_MODULE
-
tristate "LED Support for Mini2440 GPIO LEDs"
-
depends on ARCH_S3C2410
-
help
-
This option enables support for LEDs
3. 执行make menuconfig,在Device Drivers --->Character devices ---><*> LED Support for Mini2440 GPIO LEDs 加入MINI2440_LED_MODULE的编译选项。
4. 修改drivers/char目录下的Makefile文件增加如下内容
-
obj-$(CONFIG_MINI2440_LED_MODULE) += led_drv.o
5. 执行make uImage即可得到带有LED驱动的内核。
三、将内核重新烧入开发板
启动开发板,执行cat /proc/devices即可看到MINI2440_LEDS驱动程序。
至此,我们只是将驱动加入了内核,但是在/dev目录下并没有该驱动对应的设备节点,原因是我们的驱动程序中并没有加入自动创建设备节点的相应代码。
四、自动创建设备节点
在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点,当然前提条件是用户空间移植了udev。
内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。
我们就是使用这种方式自动创建设备节点,修改后的led_drv.c完整代码如下:
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/fs.h>
-
#include <linux/init.h>
-
#include <linux/device.h> //提供class_create、class_device_create等函数
-
#include <asm/arch/regs-gpio.h>
-
#include <asm/hardware.h>
-
-
#define DEVICE_NAME "MINI2440_LEDS" //设备名称
-
-
#define IOCTL_LED_ON 0
-
#define IOCTL_LED_OFF 1
-
-
static struct class *led_drv_class;
-
static struct class_device *led_drv_class_dev;
-
-
static unsigned long led_table[] = {
-
S3C2410_GPB5,
-
S3C2410_GPB6,
-
S3C2410_GPB7,
-
S3C2410_GPB8,
-
};
-
-
static unsigned long led_cfg_table[] = {
-
S3C2410_GPIO_OUTPUT,
-
S3C2410_GPIO_OUTPUT,
-
S3C2410_GPIO_OUTPUT,
-
S3C2410_GPIO_OUTPUT,
-
};
-
static int led_drv_open(struct inode *inode, struct file *file)
-
{
-
int i;
-
for(i=0;i<4;i++)
-
{
-
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
-
}
-
return 0;
-
}
-
static int led_drv_ioctl(
-
struct inode *inode,
-
struct file *file,
-
unsigned int cmd,
-
unsigned long arg)
-
{
-
if(arg > 4)
-
return -EINVAL;
-
switch(cmd){
-
case IOCTL_LED_ON:
-
s3c2410_gpio_setpin(led_table[arg],0);
-
return 0;
-
case IOCTL_LED_OFF:
-
s3c2410_gpio_setpin(led_table[arg],1);
-
return 0;
-
default:
-
return -EINVAL;
-
}
-
}
-
static struct file_operations led_drv_fops = {
-
.owner = THIS_MODULE,
-
.open = led_drv_open,
-
.ioctl = led_drv_ioctl,
-
};
-
-
int major;
-
static int __init led_drv_init(void)
-
{
-
major = register_chrdev(0, DEVICE_NAME, &led_drv_fops);
-
if(major < 0)
-
{
-
printk(DEVICE_NAME "\tcan't register major number!\n");
-
}
-
led_drv_class = class_create(THIS_MODULE, DEVICE_NAME);
-
led_drv_class_dev = class_device_create(led_drv_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); /* /dev/buttons */
-
-
printk(DEVICE_NAME"\tinitialized!\n");
-
return 0;
-
}
-
static void __exit led_drv_exit(void)
-
{
-
unregister_chrdev(major, DEVICE_NAME);
-
class_device_unregister(led_drv_class_dev);
-
class_destroy(led_drv_class);
-
}
-
-
module_init(led_drv_init);
-
module_exit(led_drv_exit);
-
MODULE_LICENSE("GPL");
阅读(2201) | 评论(0) | 转发(1) |