如何用Linux内核里的gpio_request(),gpio_set_value()等函数编写LED驱动
步骤一:打开Linux内核源代码里的Documentation文件夹下的gpio.txt文档
文档里介绍了要用到的头文件和gpio函数介绍,用到的头文件是
#include <linux/gpio.h>
步骤二:打开Linux sourceindight工程搜索gpio.h,打开Linux目录下的那个里面是gpio函数的介绍,还有要包含的头文件,头文件里是gpio引脚号的定义
#include<asm/gpio.h>
找到arch/arm/include/asm/gpio.h,里面需要包含的头文件是
#include<mach/gpio.h>这个头文件和具体的平台有关,这里我们以S5PC100平台为例
linux/arch/arm/mach-s5pc100/include/mach/gpio.h
按键驱动程序设计
/*******************************
*
*混杂设备驱动:miscdevice
*majior=10;
*
* *****************************/
/********************************/转载请注明原文地址:http://blog.csdn.net/oyhb_1992/article/details/77227276
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/init.h>
//#include <linux/moduleparam.h>
//#include <linux/slab.h>//kcalloc,kzalloc等内存分配函数
//---------ioctl------------
#include <linux/ioctl.h>
//---------misc_register----
#include <linux/miscdevice.h>
//----------cdev--------------
#include <linux/cdev.h>
//----------delay-------------
#include <linux/delay.h>
//----------GPIO---------------
#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#define MISC_DYNAMIC_MINOR 0
#define DEVICE_NAME "leds"
//静态映射的管脚虚拟地址
static int led_gpios[] = {
S5PV210_MP04(4),
S5PV210_MP04(5),
S5PV210_MP04(6),
S5PV210_MP04(7),
};//4个LED
#define LED_NUM ARRAY_SIZE(led_gpios)
static long fl210_leds_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg) //第二个参数是命令号,第三个参数是附加参数
{
switch(cmd) {
case 0: //命令码:如果写规范格式如:#define LED2_OFF _IOR(‘L’,0,unsigned char)
case 1: //命令码:如果写规范格式如:#define LED2_ON _IOR(‘L’,1,unsigned char) 也可以把命令码放在一个头文件里,应用和驱动都包含它
if (arg > LED_NUM) {
return -EINVAL;
}
gpio_set_value(led_gpios[arg], !cmd);//根据cmd设置LED的暗灭
printk(DEVICE_NAME": %ld %d\n", arg, cmd);
break;
default:
return -EINVAL;
}
return 0;
}
static struct file_operations fl210_led_dev_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = fl210_leds_ioctl,
};
//----------------miscdevice------------------
static struct miscdevice fl210_led_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &fl210_led_dev_fops,
};
//--------------------------------------------
static int __init fl210_led_dev_init(void) {
int ret;
int i;
//申请gpio,只有在gpio_request后才可以调用gpio_set_value,gpio_get_value等函数
for (i = 0; i < LED_NUM; i++) {
ret = gpio_request(led_gpios[i], "LED");//申请GPIO口
if (ret) {
printk("%s: request GPIO %d for LED failed, ret = %d\n", DEVICE_NAME,
led_gpios[i], ret);
return ret;
}
s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);//设置GPIO口为输出
//也可以用函数gpio_direction_output(unsigned gpio, int value);
gpio_set_value(led_gpios[i], 1);//初始化GPIO口的值
}
ret = misc_register(&fl210_led_dev);//注册混杂设备
printk(DEVICE_NAME"\tinitialized\n");
printk("led num is: %d\n",LED_NUM);
return ret;
}
static void __exit fl210_led_dev_exit(void) {
int i;
for (i = 0; i < LED_NUM; i++) {
gpio_free(led_gpios[i]);//释放GPIO口
}
misc_deregister(&fl210_led_dev);//注销设备
}
module_init(fl210_led_dev_init);
module_exit(fl210_led_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("");
按键应用程序设计
#include <stdio.h>
//#include "sys/types.h"
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>//read,write等等
//#include "termios.h"
//#include "sys/stat.h"
#include <fcntl.h>
#define LED2_ON 0x1 //命令码:如果写规范格式如:#define LED2_ON _IOR(‘L’,0,unsigned char)
#define LED2_OFF 0x0 //命令码:如果写规范格式如:#define LED2_OFF _IOR(‘L’,1,unsigned char)
main(int argc,char *argv[])
{
int fd;
if ((fd=open("/dev/leds",O_RDWR /*| O_NDELAY | O_NOCTTY*/)) < 0)
{
printf("Open Device failed.\r\n");
exit(1);
}
else
{
printf("Open Device successed.\r\n");
}
if (argc<3)
{
/* code */
printf("Usage: %s <on|off num>\n",argv[0]);
exit(1);
}
if(!strcmp(argv[1],"on"))//命令号为1
{
printf("led1 will on!!\n");
if(ioctl(fd,LED2_ON,atoi(argv[2]))<0)//命令附加参数是atoi(argv[2])
{
printf("ioctl err!!\n");
}
}
if(!strcmp(argv[1],"off"))
{
printf("led1 will off!!\n");
if(ioctl(fd,LED2_OFF,atoi(argv[2]))<0)
{
printf("ioctl err!!\n");
}
}
close(fd);
}
/*应用层里ioctl函数的原型是:
*#man ioctl
*int ioctl(int d, int request, ...)
*内核驱动源码里ioctl函数的原型是:
*long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
*可以知道虽然应用层是可变参数...,但是实际上应用层和驱动层的ioctl函数是对应的,
*所以我们知道,虽然应用层是用...,表示ioctl参数,但是我们应该明白
*应用层的ioctl函数的参数最多只能有3个
*/