linux 驱动笔记(四)
第六章 GPIO的標(biāo)準(zhǔn)接口函數(shù)
1 什么是GPIO的標(biāo)準(zhǔn)接口函數(shù)
思考:
1.1設(shè)計(jì)GPIO驅(qū)動(dòng)的方法???
?
1.1.1 找到配置/控制GPIO的寄存器,得到了訪問(wèn)該寄存器的物理地址
1.1.2 申請(qǐng)SFR的物理內(nèi)存區(qū)
1.1.3 IO內(nèi)存的動(dòng)態(tài)映射,由物理地址得到虛擬地址
1.1.4 通過(guò)虛擬地址設(shè)置寄存器
?
?
1.2有沒(méi)有簡(jiǎn)單的方法??
?
應(yīng)為GPIO 中斷 時(shí)鐘....在嵌入式平臺(tái)上都是非常常用的模塊。這樣linux內(nèi)核將這個(gè)模塊的控制封裝成的函數(shù),當(dāng)這些封裝好的函數(shù)的時(shí)候,大大簡(jiǎn)化程序的設(shè)計(jì)過(guò)程。
?
2 GPIO標(biāo)準(zhǔn)接口函數(shù)的用法
?
#include <linux/gpio.h>
?
2.1 GPIO的申請(qǐng)與釋放
/* 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);
參數(shù)說(shuō)明:
unsigned gpio ---GPIO號(hào),每個(gè)GPIO都有唯一的ID
const char *label ---自定義的GPIO的名字
?
2.2 設(shè)置GPIO的方向
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
?
2.3 設(shè)置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號(hào)
GPIO口號(hào)是和處理器是相關(guān)的,不同處理器GPIO的數(shù)量 名字都是不一樣的。
GPIO號(hào)應(yīng)該是在一個(gè)頭文件中定義的。
?
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標(biāo)準(zhǔn)接口函數(shù)設(shè)計(jì)驅(qū)動(dòng)的思路
?
//char buf[2],buf[1]燈的狀態(tài):1--on,0-->off
// ???????????buf[0]哪一個(gè)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); //從用戶(hù)空間拷貝數(shù)據(jù)
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) //驅(qū)動(dòng)的初始化及安裝函數(shù)
{
int gpio_request(unsigned gpio, const char *label);
int gpio_direction_output(unsigned gpio, int value);
?
}
?
static void __exit gec210_led_exit(void) //驅(qū)動(dòng)卸載函數(shù)
{
gpio_free(unsigned gpio);
}
?
module_init(gec210_led_init); //驅(qū)動(dòng)的入口
module_exit(gec210_led_exit); //驅(qū)動(dòng)的出口
?
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)定義一個(gè)字符設(shè)備cdev
static struct cdev led_drv;
?
static unsigned int led_major = 0; //0-->動(dòng)態(tài)分配,>0-->靜態(tài)注冊(cè)
static unsigned int led_minor = 0;
static dev_t led_drv_num;
?
static struct resource * ?gec210_led_res;
static unsigned int *gpj2con_va; //0xe0200280對(duì)應(yīng)的虛擬地址指針
static unsigned int *gpj2dat_va; //0xe0200284對(duì)應(yīng)的虛擬地址指針
?
static struct class *gec210_led_class;
static struct device *gec210_led_device;
?
?
?//3)定義文件操作集,并初始化
//char buf[2],buf[1]燈的狀態(tài):1--on,0-->off
// ???????????buf[0]哪一個(gè)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); //從用戶(hù)空間拷貝數(shù)據(jù)
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) //驅(qū)動(dòng)的初始化及安裝函數(shù)
{
int ret;
//2)申請(qǐng)/注冊(cè)設(shè)備號(hào)
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)申請(qǐng)物理內(nèi)存區(qū),作為一個(gè)資源
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內(nèi)存動(dòng)態(tài)映射
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)創(chuàng)建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)創(chuàng)建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,初始狀態(tài)是滅的
*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) //驅(qū)動(dòng)卸載函數(shù)
{
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); //驅(qū)動(dòng)的入口
module_exit(gec210_led_exit); //驅(qū)動(dòng)的出口
?
//內(nèi)核模塊的描述
MODULE_AUTHOR("bobeyfeng@163.com");
MODULE_DESCRIPTION("the first demo of module");
MODULE_LICENSE("GPL"); //符合GPL協(xié)議
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驅(qū)動(dòng)的設(shè)備文件節(jié)點(diǎn)(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標(biāo)準(zhǔn)接口函數(shù)
?
//1)定義一個(gè)字符設(shè)備cdev
static struct cdev led_drv;
?
static unsigned int led_major = 0; //0-->動(dòng)態(tài)分配,>0-->靜態(tài)注冊(cè)
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]燈的狀態(tài):1--on,0-->off
// ???????????buf[0]哪一個(gè)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); //從用戶(hù)空間拷貝數(shù)據(jù)
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) //驅(qū)動(dòng)的初始化及安裝函數(shù)
{
int ret;
int i;
//2)申請(qǐng)/注冊(cè)設(shè)備號(hào)
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)創(chuàng)建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)創(chuàng)建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) //驅(qū)動(dòng)卸載函數(shù)
{
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); //驅(qū)動(dòng)的入口
module_exit(gec210_led_exit); //驅(qū)動(dòng)的出口
?
//內(nèi)核模塊的描述
MODULE_AUTHOR("bobeyfeng@163.com");
MODULE_DESCRIPTION("the first demo of module");
MODULE_LICENSE("GPL"); //符合GPL協(xié)議
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驅(qū)動(dòng)的設(shè)備文件節(jié)點(diǎn)(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?
總結(jié)
以上是生活随笔為你收集整理的linux 驱动笔记(四)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Scons
- 下一篇: 流量监测NetLimiter v4.1.