1硬件分析
在天嵌科技提供的开发板中4 个LED
灯(TQ2440)分别使用了S3C2440芯片的:GPB5、GPB6、GPB7 和GPB8下面列出来对应的原理图
根据上图可以知道,当CPU
的GPB5 到8 是低电平时,LED 灯亮;当为高电平时LED 灯灭。2编写驱动程序
然后再在内核源码的drivers/char目录下新建一个名为EmbedSky_leds.c的文件:
#include
#include
#include
#include
#include
#include
#include//官方此处为#i
nclude
//#include
#include//官方为#i
nclude
//#include
#include
#define DEVICE_NAME "EmbedSky-leds"
#define LED_MAJOR 231
#define IOCTL_LED_ON 1
#define IOCTL_LED_OFF 0
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,
};
static int EmbedSky_leds_open(struct inode *inode, struct file
*file)
{
// int i;
// for (i = 0; i < 4; i++)
// {
// 设置GPIO 引脚的功能:本驱动中LED 所涉及的GPIO 引脚设为输出功能
// s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
// }
return 0;
}
static int EmbedSky_leds_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 EmbedSky_leds_fops =
{
.owner = THIS_MODULE,
.open = EmbedSky_leds_open,
.ioctl = EmbedSky_leds_ioctl,
};
static char __initdata banner[] = "TQ2440LEDS";
static struct class *led_class;
static int __init EmbedSky_leds_init(void)
{
int ret;
printk(banner);
ret = register_chrdev(LED_MAJOR, DEVICE_NAME,
&EmbedSky_leds_fops);
if (ret < 0)
{
printk(DEVICE_NAME " can't register major number\n");
return ret;
}
//注册一个类,使mdev 可以在"/dev/"目录下面建立设备节点
led_class = class_create(THIS_MODULE, DEVICE_NAME);
if(IS_ERR(led_class))
{
printk("Err: failed in EmbedSky-leds class. \n");
return -1;
}
//创建一个设备节点,节点名为DEVICE_NAME
device_create(led_class, NULL, MKDEV(LED_MAJOR, 0), NULL,
DEVICE_NAME);
//官方文档为class_device_create(led_class, NULL, MKDEV(LED_MAJOR, 0),
NULL, DEVICE_NAME);
//class_device_create(led_class, NULL, MKDEV(LED_MAJOR, 0),
NULL, DEVICE_NAME);
printk(DEVICE_NAME " initialized\n");
return 0;
}
static void __exit EmbedSky_leds_exit(void)
{
unregister_chrdev(LED_MAJOR, DEVICE_NAME);
device_destroy(led_class, MKDEV(LED_MAJOR,
0));
//删掉设备节点官方文档为class_device_destroy(led_class, MKDEV(LED_MAJOR,
0));
//class_device_destroy(led_class, MKDEV(LED_MAJOR, 0));
class_destroy(led_class); //注销类
}
module_init(EmbedSky_leds_init);
module_exit(EmbedSky_leds_exit);
MODULE_AUTHOR("http://www.embedsky.net");
MODULE_DESCRIPTION("TQ2440/SKY2440 LED Driver");
MODULE_LICENSE("GPL");
注意:以上红色部分被屏蔽了,因为在“arch/arm/plat-s3c24xx/common-smdk.c”文件中已经完成了这个初始化了。
3在内核源码中添加对驱动的支持
然后修改同目录下的“Kconfig”文件即linux-2.6.30.4/drivers/char/Kconfig
config
EmbedSky_LEDS
tristate
"TQ2440/SKY2440 LEDs Driver"
depends on
ARCH_S3C2440
help
EmbedSky TQ2440/SKY2440 User leds.
然后修改同目录的“Makefile”文件
obj-$(CONFIG_EmbedSky_LEDS) +=
EmbedSky_leds.o
添加完以上内容之后,输入:#make
menuconfig,然后配置如下:
Device Drivers
--->
Character devices
--->
TQ2440/SKY2440
LEDs Driver
将其选择为“M”(模块),然后保存配置,编译出内核镜像烧写到开发板中。
然后再使用命令#make
SUBDIR=drivers/char/
modules,然后编译出驱动模块,在内核目录下面的也可以将其配置为“*”(添加到内核中),然后编译出镜像,烧写到开发板中,LED
灯就可以进行控制了。下面是加载模块的情况,在/dev/目录下面有EmbedSky-leds的设备名:“drivers/char/”目录下面,名为:EmbedSky_leds.ko,将其复制到开发板中/lib/下。
4编写LED灯控制程序
下面列出LED
灯的控制程序,这里的控制程序直接使用的SKY2440 或TQ2440 光盘提供的LED 灯的
控制程序代码
//因为开发板中已有leds文件,在/sbin/ 及/etc/rc.d/init.d/下,故此名为leds.1
#include
#include
#include
#include
int main(int argc, char **argv)
{
int on;
int led_no;
int fd;
if (argc != 3 || sscanf(argv[1], "%d", &led_no)
!= 1 || sscanf(argv[2],"%d", &on) != 1 ||on
< 0 || on > 1 || led_no
< 1 || led_no > 4)
{
fprintf(stderr, "Usage: leds led_no 0|1\n");
exit(1);
}
fd = open("/dev/EmbedSky-leds", 0); //对应EmbedSky_leds.ko文件
if (fd < 0)
{
perror("open device leds");
exit(1);
}
ioctl(fd, on, (led_no-1));
close(fd);
return 0;
}
使用#arm-linux-gcc –g
leds1.c –o leds1 来生成leds1程序 下载到开发板中(位置不限),注意更改权限
首先在/dev/中必须有EmbedSky-leds(若没有,到/lib/下,#insmod
EmbedSky_leds.ko即可),否则下面运行出错。
#./leds1 1 1 //点亮第一个led
#./leds1
1 0 //关闭第一个led
直接使用#leds1 1 1 出错,显示-/bin/sh: leds1:not found
若想使用#leds1 1 1需要:
(1)修改/etc/init.d/rcS,添加 /etc/rc.d/init.d/leds1
start
(2)将leds1 复制到 /sbin/中
(3)将leds1 复制到 /etc/rc.d/init.d/下