编写LED混杂设备驱动:静态映射,如何用Linux内核里的gpio_request(),gpio_set_value()等函数,ioctl函数


如何用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个
*/

 

 

 

 

 

 

 

 

 

 

 

 

 

 


  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
typedef struct { ISRFunction_t handler; void *handler_param; int irq_type; } GpioIrqDesc_t; static GpioIrqDesc_t gpio_irq_descs[GPIO_NUM]; static __INLINE uint32_t gpio_get_regbase(int gpio) { int gpiox = (gpio >> 5) & 0x3; return REGS_GPIO_BASE + 0x80 * gpiox; } /* static __INLINE int GPIO_BANK(unsigned gpio) { return gpio >> 5; } */ static __INLINE int GPIO_OFFSET(unsigned gpio) { if (gpio == 96) return 2; else if (gpio == 97) return 0; else if (gpio == 98) return 3; else if (gpio == 99) return 1; else return gpio & 0x1F; } static __INLINE void *GPIO_MODREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_DDR); } static __INLINE void *GPIO_WDATAREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_DR); } static __INLINE void *GPIO_RDATAREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_EXT_PORTA); } static __INLINE void *GPIO_INTENREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_INTEN); } static __INLINE void *GPIO_INTMASKREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_INTMASK); } static __INLINE void *GPIO_INTLVLREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_INTTYPE_LEVEL); } static __INLINE void *GPIO_INTPOLREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_INT_POLARITY); } void gpio_request(unsigned gpio) { pinctrl_gpio_request(gpio); } void gpio_direction_output(unsigned gpio, int value) { configASSERT(gpio < GPIO_NUM); gpio_request(gpio); writel(readl(GPIO_MODREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_MODREG(gpio)); if (value) writel(readl(GPIO_WDATAREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio)); else writel(readl(GPIO_WDATAREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio)); } void gpio_direction_input(unsigned gpio) { configASSERT(gpio < GPIO_NUM); gpio_request(gpio); writel(readl(GPIO_MODREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_MODREG(gpio)); } void gpio_set_value(unsigned gpio, int value) { configASSERT(gpio < GPIO_NUM); if (value) writel(readl(GPIO_WDATAREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio)); else writel(readl(GPIO_WDATAREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio)); } int gpio_get_value(unsigned gpio) { configASSERT(gpio < GPIO_NUM); return !!(readl(GPIO_RDATAREG(gpio)) & (1 << GPIO_OFFSET(gpio))); } static void gpio_toggle_trigger(unsigned gpio) { u32 pol; pol = readl(GPIO_INTPOLREG(gpio)); if (pol & (1 << GPIO_OFFSET(gpio))) pol &= ~(1 << GPIO_OFFSET(gpio)); else pol |= (1 << GPIO_OFFSET(gpio)); writel(pol, GPIO_INTPOLREG(gpio)); } 根据上述函数配置一个输出模式 频率为24mhz的io口】
07-15

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值