您的位置:首页 > 其它

GPIO(led灯)驱动和测试程序

2010-01-15 15:26 615 查看
看着内核分析,慢慢的感觉这些内核里面的驱动就那么纠结呢,先把内核分析放一边吧,看下以前弄的驱动,算是借鉴别人的驱动,修改了下而已。

环境:



内核:Linux-2.6.25.4


交叉编译器:arm-linux-3.4.5


GPIO_led.c

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/delay.h>

#include <asm/irq.h>

#include <asm/arch/regs-gpio.h>

#include <asm/hardware.h>

#include <linux/device.h> /*所用到的头文件*/

#define DEVICE_NAME "GPIO-leds" /*device name,you will see device name when execute "cat /proc/devices" */

#define LED_MAJOR 231 /*major devive number*/

/*the second parameter of ioctl(fd,cmd
,arg) */

#define IOCTL_LED_ON 1

#define IOCTL_LED_OFF 0

/*制定LED所用的 GPIO pins */

static unsigned long led_port [] =

{

S3C2410_GPB5,

S3C2410_GPB6,

S3C2410_GPB7,

S3C2410_GPB8,//我用的就是TQ2440板,用到的GPIO是GPB5-8。

};

/*用来指定GPIO pin的功能:output*/

static unsigned int led_out [] =

{

S3C2410_GPB5_OUTP,

S3C2410_GPB6_OUTP,

S3C2410_GPB7_OUTP,

S3C2410_GPB8_OUTP,

};

/* 应用程序对设备文件/dev/GPIO-leds执行 open(...)时,

* 就会调用iFico_leds_open函数

*/

static int iFico_leds_open(struct inode *inode, struct file *file)

{

// int i;

// for (i = 0; i < 4; i++)

// {

//

// s3c2410_gpio_cfgpin(led_led[i], led_out[i]);

// }

return 0;

}

/* 应用程序对设备文件/dev/GPIO-leds执行 ioctl(...)时,

* 就会调用iFico_leds_ioctl函数

*/

static int iFico_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:

// 设置指定引脚的输出电平为0

s3c2410_gpio_setpin(led_port[arg], 0);

return 0;

case IOCTL_LED_OFF:

// 设置指定引脚的输出电平为1

s3c2410_gpio_setpin(led_port[arg], 1);

return 0;

default:

return -EINVAL;

}

}

/* 这个结构是字符设备驱动程序的核心

* 当应用程序操作设备文件时所调用的open、read、write等函数,

* 最终会调用这个结构中指定的对应函数

*/

static struct file_operations iFico_leds_fops =

{

.owner = THIS_MODULE, /* 这是一个宏,指向编译模块时自动创建的__this_module变量 */

.open = iFico_leds_open,

.ioctl = iFico_leds_ioctl,

};

static char __initdata banner[] = "iFico2440 LEDS,Sunny/n";

static struct class *led_class;

/*

* 执行“insmod GPIO_leds.ko”命令时就会调用这个函数

*/

static int __init iFico_leds_init(void)

{

int ret;

printk(banner);

/* 注册字符设备驱动程序

* 参数为主设备号、设备名字、file_operation结构;

* 这样,主设备号就和具体的file_operation结构联系起来了,

* 操作主设备为LED_MAJOR的设备文件时,就会调用iFico_leds_fops中的相关成员函数

* LED_MAJOR可以设为0,表示由内核自动分配主设备号

*/

ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &iFico_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 GPIO-leds class. /n");

return -1;

}

//创建一个设备节点,节点名为DEVICE_NAME

class_device_create(led_class, NULL, MKDEV(LED_MAJOR, 0), NULL, DEVICE_NAME);

printk(DEVICE_NAME " initialized/n");

return 0;

}

/*

* 执行“rmmod GPIO_leds.ko”命令时就会调用这个函数

*/

static void __exit iFico_leds_exit(void)

{

/* 卸载驱动程序 */

unregister_chrdev(LED_MAJOR, DEVICE_NAME);

class_device_destroy(led_class, MKDEV(LED_MAJOR, 0)); //删掉设备节点

class_destroy(led_class); //注销类

}

/* 这两行指定驱动程序的初始化函数和卸载函数 */

module_init(iFico_leds_init);

module_exit(iFico_leds_exit);

/* 描述驱动程序的一些信息,不是必须的*/

MODULE_AUTHOR("Sunny"); // 驱动程序的作者

MODULE_DESCRIPTION("Sunny LED Driver"); // 一些描述信息

MODULE_LICENSE("GPL"); // 遵循的协议

编写好驱动程序后,放到drivers/char/目录下,修改此目录下的Makefiel 和Kconfig:

修改“Kconfig
”文件,在
6

行开始添加如下内容(红色部分所示):

#

# Character device configuration

#

menu "Character devices"

config iFico_LEDS

tristate "Sunny LEDs Driver"

depends on ARCH_S3C2440

help

2440 User leds.

然后修改“Makefile
”文件,在大概
12

行添加如下内容(红色部分所示):

#

# Makefile for the kernel character device drivers.

#

#

# This file contains the font map for the default (hardware) font

#

FONTMAPFILE = cp437.uni

obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o

obj-$(CONFIG_iFico_LEDS) += GPIO_leds.o

obj-$(CONFIG_LEGACY_PTYS) += pty.o

添加完毕以上内容之后,输入:#

make menuconfig
,然后配置如下:

Device Drivers --->

Character devices --->

<*>
Sunny
LEDs Driver

保存编译内核,烧写到开发板中。在系统中的/dev目录下会看到
GPIO-leds,说明驱动加载成功。

然后再编写测试程序。

/*************************************

NAME:leds.c

*************************************/

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/ioctl.h>

#define IOCTL_LED_ON 1

#define IOCTL_LED_OFF 0

void usage(char *exename)

{

printf("Usage:/n");

printf(" %s<led_no><on/off>/n",exename);

printf(" led_no=1,2/n");

}

int main(int argc, char **argv)

{

unsigned int led_no;

int fd;

if(argc !=3)

goto err;

// system("/etc/rc.d/init.d/leds stop");

fd = open("/dev/GPIO-leds", 0);

if (fd < 0) {

perror("Can't open /dev/GPIO-leds/n");

return -1;

}

led_no= strtoul(argv[1],0,0)-1;

if(led_no>3)

goto err;

if(!strcmp(argv[2],"on")){

ioctl(fd,IOCTL_LED_ON,led_no);

}else if(!strcmp(argv[2],"off")){

ioctl(fd,IOCTL_LED_OFF,led_no);

}else {

goto err;

}

close(fd);

return 0;

err:

if(fd>0)

close(fd);

usage(argv[0]);

return -1;

}

[root@sunny /]# arm-linux-gcc -o ledtest leds.c
[root@sunny /]# arm-linux-strip ledtest

然后将ledtest通过NFS或者U盘拷贝到开发板中/sbin目录下,重启
[root@sunny /]# ledtest 1 on 就会看到开发板上的led1亮;
[root@sunny /]# ledtest 1 off 就会看到开发板上的led1灭;

这是一个比较简单的例子,仅仅是控制IO口,驱动是一个复杂的圈圈,还是要好好的学习啊!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: