linux 驱动笔记(四)
来源:互联网 发布:java的编译命令是哪个 编辑:程序博客网 时间:2024/05/16 04:58
第六章 GPIO的标准接口函数
1 什么是GPIO的标准接口函数
思考:
1.1设计GPIO驱动的方法???
1.1.1 找到配置/控制GPIO的寄存器,得到了访问该寄存器的物理地址
1.1.2 申请SFR的物理内存区
1.1.3 IO内存的动态映射,由物理地址得到虚拟地址
1.1.4 通过虚拟地址设置寄存器
1.2有没有简单的方法??
应为GPIO 中断 时钟....在嵌入式平台上都是非常常用的模块。这样linux内核将这个模块的控制封装成的函数,当这些封装好的函数的时候,大大简化程序的设计过程。
2 GPIO标准接口函数的用法
#include <linux/gpio.h>
2.1 GPIO的申请与释放
/* request GPIO, returning 0 or negative errno.
* non-null labels may be useful for diagnostics.
*/
int gpio_request(unsigned gpio, const char *label);
/* release previously-claimed GPIO */
void gpio_free(unsigned gpio);
参数说明:
unsigned gpio ---GPIO号,每个GPIO都有唯一的ID
const char *label ---自定义的GPIO的名字
2.2 设置GPIO的方向
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
2.3 设置GPIO的输出值或者读取GPIO的输入值
/* GPIO INPUT: return zero or nonzero */
int gpio_get_value(unsigned gpio);
/* GPIO OUTPUT */
void gpio_set_value(unsigned gpio, int value);
3 GPIO号
GPIO口号是和处理器是相关的,不同处理器GPIO的数量 名字都是不一样的。
GPIO号应该是在一个头文件中定义的。
linux/arch/arm/mach-s5pv210/include/mach/gpio.h
/* S5PV210 GPIO number definitions */
#define S5PV210_GPA0(_nr) (S5PV210_GPIO_A0_START + (_nr))
#define S5PV210_GPA1(_nr) (S5PV210_GPIO_A1_START + (_nr))
#define S5PV210_GPB(_nr) (S5PV210_GPIO_B_START + (_nr))
#define S5PV210_GPC0(_nr) (S5PV210_GPIO_C0_START + (_nr))
#define S5PV210_GPC1(_nr) (S5PV210_GPIO_C1_START + (_nr))
#define S5PV210_GPD0(_nr) (S5PV210_GPIO_D0_START + (_nr))
#define S5PV210_GPD1(_nr) (S5PV210_GPIO_D1_START + (_nr))
#define S5PV210_GPE0(_nr) (S5PV210_GPIO_E0_START + (_nr))
#define S5PV210_GPE1(_nr) (S5PV210_GPIO_E1_START + (_nr))
#define S5PV210_GPF0(_nr) (S5PV210_GPIO_F0_START + (_nr))
#define S5PV210_GPF1(_nr) (S5PV210_GPIO_F1_START + (_nr))
#define S5PV210_GPF2(_nr) (S5PV210_GPIO_F2_START + (_nr))
#define S5PV210_GPF3(_nr) (S5PV210_GPIO_F3_START + (_nr))
#define S5PV210_GPG0(_nr) (S5PV210_GPIO_G0_START + (_nr))
#define S5PV210_GPG1(_nr) (S5PV210_GPIO_G1_START + (_nr))
#define S5PV210_GPG2(_nr) (S5PV210_GPIO_G2_START + (_nr))
#define S5PV210_GPG3(_nr) (S5PV210_GPIO_G3_START + (_nr))
#define S5PV210_GPH0(_nr) (S5PV210_GPIO_H0_START + (_nr))
#define S5PV210_GPH1(_nr) (S5PV210_GPIO_H1_START + (_nr))
#define S5PV210_GPH2(_nr) (S5PV210_GPIO_H2_START + (_nr))
#define S5PV210_GPH3(_nr) (S5PV210_GPIO_H3_START + (_nr))
#define S5PV210_GPI(_nr) (S5PV210_GPIO_I_START + (_nr))
#define S5PV210_GPJ0(_nr) (S5PV210_GPIO_J0_START + (_nr))
#define S5PV210_GPJ1(_nr) (S5PV210_GPIO_J1_START + (_nr))
#define S5PV210_GPJ2(_nr) (S5PV210_GPIO_J2_START + (_nr))
#define S5PV210_GPJ3(_nr) (S5PV210_GPIO_J3_START + (_nr))
#define S5PV210_GPJ4(_nr) (S5PV210_GPIO_J4_START + (_nr))
#define S5PV210_MP01(_nr) (S5PV210_GPIO_MP01_START + (_nr))
#define S5PV210_MP02(_nr) (S5PV210_GPIO_MP02_START + (_nr))
#define S5PV210_MP03(_nr) (S5PV210_GPIO_MP03_START + (_nr))
#define S5PV210_MP04(_nr) (S5PV210_GPIO_MP04_START + (_nr))
#define S5PV210_MP05(_nr) (S5PV210_GPIO_MP05_START + (_nr))
#define S5PV210_MP06(_nr) (S5PV210_GPIO_MP06_START + (_nr))
#define S5PV210_MP07(_nr) (S5PV210_GPIO_MP07_START + (_nr))
#define S5PV210_MP10(_nr) (S5PV210_GPIO_MP10_START + (_nr))
#define S5PV210_MP11(_nr) (S5PV210_GPIO_MP11_START + (_nr))
#define S5PV210_MP12(_nr) (S5PV210_GPIO_MP12_START + (_nr))
#define S5PV210_MP13(_nr) (S5PV210_GPIO_MP13_START + (_nr))
#define S5PV210_MP14(_nr) (S5PV210_GPIO_MP14_START + (_nr))
#define S5PV210_MP15(_nr) (S5PV210_GPIO_MP15_START + (_nr))
#define S5PV210_MP16(_nr) (S5PV210_GPIO_MP16_START + (_nr))
#define S5PV210_MP17(_nr) (S5PV210_GPIO_MP17_START + (_nr))
#define S5PV210_MP18(_nr) (S5PV210_GPIO_MP18_START + (_nr))
#define S5PV210_MP20(_nr) (S5PV210_GPIO_MP20_START + (_nr))
#define S5PV210_MP21(_nr) (S5PV210_GPIO_MP21_START + (_nr))
#define S5PV210_MP22(_nr) (S5PV210_GPIO_MP22_START + (_nr))
#define S5PV210_MP23(_nr) (S5PV210_GPIO_MP23_START + (_nr))
#define S5PV210_MP24(_nr) (S5PV210_GPIO_MP24_START + (_nr))
#define S5PV210_MP25(_nr) (S5PV210_GPIO_MP25_START + (_nr))
#define S5PV210_MP26(_nr) (S5PV210_GPIO_MP26_START + (_nr))
#define S5PV210_MP27(_nr) (S5PV210_GPIO_MP27_START + (_nr))
#define S5PV210_MP28(_nr) (S5PV210_GPIO_MP28_START + (_nr))
#define S5PV210_ETC0(_nr) (S5PV210_GPIO_ETC0_START + (_nr))
#define S5PV210_ETC1(_nr) (S5PV210_GPIO_ETC1_START + (_nr))
#define S5PV210_ETC2(_nr) (S5PV210_GPIO_ETC2_START + (_nr))
#define S5PV210_ETC4(_nr) (S5PV210_GPIO_ETC4_START + (_nr))
例:
LED1 --- GPJ2_0 --- S5PV210_GPJ2(0)
LED2 --- GPJ2_1 --- S5PV210_GPJ2(1)
LED3 --- GPJ2_2 --- S5PV210_GPJ2(2)
LED4 --- GPJ2_3 --- S5PV210_GPJ2(3)
BEEP --- GPD0_0 --- S5PV210_GPD0(0)
4 使用gpio标准接口函数设计驱动的思路
//char buf[2],buf[1]灯的状态:1--on,0-->off
// buf[0]哪一个led:1/2/3/4
ssize_t gec210_led_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
int ret;
char kbuf[2];
if(len != 2)
return -EINVAL;
ret = copy_from_user(kbuf,buf,len); //从用户空间拷贝数据
if(ret!= 0)
return -EFAULT;
if( (kbuf[0]<1) || (kbuf[0]>4) )
return -EINVAL;
gpio_set_value(unsigned gpio, int value);
else
return -EINVAL;
return len;
}
static struct file_operations gec210_led_fops = {
.owner = THIS_MODULE,
.write = gec210_led_write,
};
static int __init gec210_led_init(void) //驱动的初始化及安装函数
{
int gpio_request(unsigned gpio, const char *label);
int gpio_direction_output(unsigned gpio, int value);
}
static void __exit gec210_led_exit(void) //驱动卸载函数
{
gpio_free(unsigned gpio);
}
module_init(gec210_led_init); //驱动的入口
module_exit(gec210_led_exit); //驱动的出口
A代码一
1. filename: led_drv.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/device.h>
//1)定义一个字符设备cdev
static struct cdev led_drv;
static unsigned int led_major = 0; //0-->动态分配,>0-->静态注册
static unsigned int led_minor = 0;
static dev_t led_drv_num;
static struct resource * gec210_led_res;
static unsigned int *gpj2con_va; //0xe0200280对应的虚拟地址指针
static unsigned int *gpj2dat_va; //0xe0200284对应的虚拟地址指针
static struct class *gec210_led_class;
static struct device *gec210_led_device;
//3)定义文件操作集,并初始化
//char buf[2],buf[1]灯的状态:1--on,0-->off
// buf[0]哪一个led:1/2/3/4
ssize_t gec210_led_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
int ret;
char kbuf[2];
if(len != 2)
return -EINVAL;
ret = copy_from_user(kbuf,buf,len); //从用户空间拷贝数据
if(ret!= 0)
return -EFAULT;
if( (kbuf[0]<1) || (kbuf[0]>4) )
return -EINVAL;
if(kbuf[1]==1)
*gpj2dat_va &= ~(1<<(kbuf[0]-1));
else if(kbuf[1]==0)
*gpj2dat_va |= (1<<(kbuf[0]-1));
else
return -EINVAL;
return len;
}
static struct file_operations gec210_led_fops = {
.owner = THIS_MODULE,
.write = gec210_led_write,
};
static int __init gec210_led_init(void) //驱动的初始化及安装函数
{
int ret;
//2)申请/注册设备号
if(led_major == 0){
ret = alloc_chrdev_region(&led_drv_num, led_minor, 1, "gec210_leds");
}
else{
led_drv_num = MKDEV(led_major,led_minor);
ret = register_chrdev_region(led_drv_num, 1, "gec210_leds");
}
if(ret < 0){
printk("led_drv_num is error \n");
return ret;
}
//4)初始化cdev
cdev_init(&led_drv, &gec210_led_fops);
//5)将cdev加入kernel
ret = cdev_add(&led_drv,led_drv_num, 1 );
if(ret < 0){
printk("cdev add error\n");
goto failed_cdev_add;
}
//6)申请物理内存区,作为一个资源
gec210_led_res = request_mem_region(0xe0200280,8,"GPJ2_LED"); //cat /proc/iomem
if(gec210_led_res == NULL)
{
printk("requst mem region error\n");
ret = -EBUSY;
goto failed_request_mem_region;
}
//7)io内存动态映射
gpj2con_va = ioremap(0xe0200280,8);
if(gpj2con_va == NULL)
{
printk("ioremap error\n");
ret = -EFAULT;
goto failed_ioremap;
}
gpj2dat_va = gpj2con_va + 1; //不是4
printk("gpj2con_va=%p,gpj2dat_va=%p\n", gpj2con_va,gpj2dat_va);
//8)创建class
gec210_led_class = class_create(THIS_MODULE, "led_class");
if(gec210_led_class == NULL)
{
printk("class create error\n");
ret = -EBUSY;
goto failed_class_create;
}
//9)创建device
gec210_led_device = device_create(gec210_led_class,NULL,
led_drv_num,NULL,"led_drv"); // /dev/led_drv
if(gec210_led_device == NULL)
{
printk("class device error\n");
ret = -EBUSY;
goto failed_device_create;
}
//led1~4,初始状态是灭的
*gpj2con_va &= ~0xffff;
*gpj2con_va |= 0x1111;
*gpj2dat_va |= 0xf;
return 0;
failed_device_create:
class_destroy(gec210_led_class);
failed_class_create:
iounmap(gpj2con_va);
failed_ioremap:
release_mem_region(0xe0200280,8);
failed_request_mem_region:
cdev_del(&led_drv);
failed_cdev_add:
unregister_chrdev_region(led_drv_num, 1);
return ret;
}
static void __exit gec210_led_exit(void) //驱动卸载函数
{
unregister_chrdev_region(led_drv_num, 1);
cdev_del(&led_drv);
release_mem_region(0xe0200280,8);
iounmap(gpj2con_va);
device_destroy(gec210_led_class,led_drv_num);
class_destroy(gec210_led_class);
printk("good bye gec210\n");
}
module_init(gec210_led_init); //驱动的入口
module_exit(gec210_led_exit); //驱动的出口
//内核模块的描述
MODULE_AUTHOR("bobeyfeng@163.com");
MODULE_DESCRIPTION("the first demo of module");
MODULE_LICENSE("GPL"); //符合GPL协议
MODULE_VERSION("V1.0");
//-----------------------------------
2. filename: test.c
#include <stdio.h>
#include <fcntl.h>
int main(void)
{
int fd;
int ret;
char buf[2];
//"/dev/led_drv" ---linux驱动的设备文件节点(node)
fd = open("/dev/led_drv", O_WRONLY);
if(fd <0)
{
perror("open led_drv:");
return -1;
}
while(1)
{
buf[1] = 1;buf[0]=3; //led3 on
ret = write(fd,buf,sizeof(buf));
if(ret < 0)
{
perror("write led_drv: ");
return -1;
}
sleep(1);
buf[1] = 0;buf[0]=3; //led3 on
ret = write(fd,buf,sizeof(buf));
if(ret < 0)
{
perror("write led_drv: ");
return -1;
}
sleep(1);
}
close(fd);
return 0;
}
//------------------------------------
3. filename: Makefile
obj-m += led_drv.o
#KERNELDIR := /lib/modules/$(shell uname -r)/build
KERNELDIR := /home/gec/linux-2.6.35.7-gec-v3.0-gt110
PWD:=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.mod.o *.ko
//------------------------------------
A代码二
1. filename: led_drv.c
/*LED1 --- GPJ2_0 --- S5PV210_GPJ2(0)
LED2 --- GPJ2_1 --- S5PV210_GPJ2(1)
LED3 --- GPJ2_2 --- S5PV210_GPJ2(2)
LED4 --- GPJ2_3 --- S5PV210_GPJ2(3)*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/gpio.h> //GPIO标准接口函数
//1)定义一个字符设备cdev
static struct cdev led_drv;
static unsigned int led_major = 0; //0-->动态分配,>0-->静态注册
static unsigned int led_minor = 0;
static dev_t led_drv_num;
static struct class *gec210_led_class;
static struct device *gec210_led_device;
struct led_gpio{
unsigned int gpio_num;
char gpio_name[12];
};
static struct led_gpio gec210_leds[4] = {
{
.gpio_num = S5PV210_GPJ2(0),
.gpio_name = "GPJ2_0-LED1",
},
{
.gpio_num = S5PV210_GPJ2(1),
.gpio_name = "GPJ2_1-LED2",
},
{
.gpio_num = S5PV210_GPJ2(2),
.gpio_name = "GPJ2_2-LED2",
},
{
.gpio_num = S5PV210_GPJ2(3),
.gpio_name = "GPJ2_3-LED4",
},
};
//3)定义文件操作集,并初始化
//char buf[2],buf[1]灯的状态:1--on,0-->off
// buf[0]哪一个led:1/2/3/4
ssize_t gec210_led_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
int ret;
char kbuf[2];
if(len != 2)
return -EINVAL;
ret = copy_from_user(kbuf,buf,len); //从用户空间拷贝数据
if(ret!= 0)
return -EFAULT;
if( (kbuf[0]<1) || (kbuf[0]>4) )
return -EINVAL;
if(kbuf[1]==1)
gpio_set_value(gec210_leds[kbuf[0]-1].gpio_num, 0);
else if(kbuf[1]==0)
gpio_set_value(gec210_leds[kbuf[0]-1].gpio_num, 1);
else
return -EINVAL;
return len;
}
static struct file_operations gec210_led_fops = {
.owner = THIS_MODULE,
.write = gec210_led_write,
};
static int __init gec210_led_init(void) //驱动的初始化及安装函数
{
int ret;
int i;
//2)申请/注册设备号
if(led_major == 0){
ret = alloc_chrdev_region(&led_drv_num, led_minor, 1, "gec210_leds");
}
else{
led_drv_num = MKDEV(led_major,led_minor);
ret = register_chrdev_region(led_drv_num, 1, "gec210_leds");
}
if(ret < 0){
printk("led_drv_num is error \n");
return ret;
}
//4)初始化cdev
cdev_init(&led_drv, &gec210_led_fops);
//5)将cdev加入kernel
ret = cdev_add(&led_drv,led_drv_num, 1 );
if(ret < 0){
printk("cdev add error\n");
goto failed_cdev_add;
}
//6)创建class
gec210_led_class = class_create(THIS_MODULE, "led_class");
if(gec210_led_class == NULL)
{
printk("class create error\n");
ret = -EBUSY;
goto failed_class_create;
}
//7)创建device
gec210_led_device = device_create(gec210_led_class,NULL,
led_drv_num,NULL,"led_drv"); // /dev/led_drv
if(gec210_led_device == NULL)
{
printk("class device error\n");
ret = -EBUSY;
goto failed_device_create;
}
for(i=0;i<4;i++)
{
ret = gpio_request(gec210_leds[i].gpio_num, gec210_leds[i].gpio_name);
if(ret < 0)
{
printk("gpio request error %s\n", gec210_leds[i].gpio_name);
goto failed_gpio_request;
}
gpio_direction_output(gec210_leds[i].gpio_num,0x1);
}
return 0;
failed_gpio_request:
while(i--)//--i
gpio_free(gec210_leds[i].gpio_num);
device_destroy(gec210_led_class,led_drv_num);
failed_device_create:
class_destroy(gec210_led_class);
failed_class_create:
cdev_del(&led_drv);
failed_cdev_add:
unregister_chrdev_region(led_drv_num, 1);
return ret;
}
static void __exit gec210_led_exit(void) //驱动卸载函数
{
int i;
unregister_chrdev_region(led_drv_num, 1);
cdev_del(&led_drv);
device_destroy(gec210_led_class,led_drv_num);
class_destroy(gec210_led_class);
for(i=0;i<4;i++)
gpio_free(gec210_leds[i].gpio_num);
printk("good bye gec210\n");
}
module_init(gec210_led_init); //驱动的入口
module_exit(gec210_led_exit); //驱动的出口
//内核模块的描述
MODULE_AUTHOR("bobeyfeng@163.com");
MODULE_DESCRIPTION("the first demo of module");
MODULE_LICENSE("GPL"); //符合GPL协议
MODULE_VERSION("V1.0");
//-------------------------------------------------
2. Filename: test.c
#include <stdio.h>
#include <fcntl.h>
int main(void)
{
int fd;
int ret;
char buf[2];
//"/dev/led_drv" ---linux驱动的设备文件节点(node)
fd = open("/dev/led_drv", O_WRONLY);
if(fd <0)
{
perror("open led_drv:");
return -1;
}
while(1)
{
buf[1] = 1;buf[0]=3; //led3 on
ret = write(fd,buf,sizeof(buf));
if(ret < 0)
{
perror("write led_drv: ");
return -1;
}
sleep(1);
buf[1] = 0;buf[0]=3; //led3 on
ret = write(fd,buf,sizeof(buf));
if(ret < 0)
{
perror("write led_drv: ");
return -1;
}
sleep(1);
}
close(fd);
return 0;
}
//--------------------------------------------------
3. Filename: Makefile
obj-m += led_drv.o
#KERNELDIR := /lib/modules/$(shell uname -r)/build
KERNELDIR := /home/gec/linux-2.6.35.7-gec-v3.0-gt110
PWD:=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.mod.o *.ko
- linux 驱动笔记(四)
- QT6410移植linux-2.6.39 笔记(四)-dm9k驱动移植
- S3C6410移植linux-2.6.39 笔记(四)-dm9k驱动移植
- 嵌入式Linux设备驱动开发笔记(四)
- 嵌入式Linux驱动笔记(四)------USB键盘驱动程序
- 四 linux tty驱动
- 四 linux tty驱动
- Windows 驱动开发笔记(四)
- Linux驱动笔记:SPI驱动
- linux LCD驱动(四) --- 驱动实现
- Linux终端设备驱动(四)
- linux lcd驱动分析四
- Linux-FLASH驱动设计四
- [linux驱动]linux块设备学习笔记(四)——请求处理
- linux驱动阅读笔记
- linux i2c驱动笔记
- linux 8250驱动笔记
- Linux 驱动学习笔记
- Android图片加载神器之Fresco,基于各种使用场景的讲解
- 开发日记:KBEngine+Unity+php做个扑克小游戏-DAY2
- linux 驱动笔记(一)
- linux 驱动笔记(二)
- linux 驱动笔记(三)
- linux 驱动笔记(四)
- linux 驱动笔记(五)
- linux 驱动笔记(六)
- linux 驱动笔记(七)
- matlab event notify recursive
- ubuntu网易源
- K-Nearest Neighbor(KNN) 最邻近分类算法及Python实现方式
- dlgdata.cpp line 40 断言失败
- 堆排序(HeapSort)