日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

linux 驱动笔记(四)

發(fā)布時(shí)間:2023/12/20 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 驱动笔记(四) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

第六章 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--on0-->off

// ???????????buf[0]哪一個(gè)led1/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); //從用戶空間拷貝數(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--on0-->off

// ???????????buf[0]哪一個(gè)led1/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); //從用戶空間拷貝數(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=%pgpj2dat_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--on0-->off

// ???????????buf[0]哪一個(gè)led1/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); //從用戶空間拷貝數(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)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。