日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 驱动笔记(四)

發布時間:2023/12/20 linux 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 驱动笔记(四) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

// ???????????buf[0]哪一個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); //從用戶空間拷貝數據

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--on0-->off

// ???????????buf[0]哪一個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); //從用戶空間拷貝數據

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=%pgpj2dat_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--on0-->off

// ???????????buf[0]哪一個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); //從用戶空間拷貝數據

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 驱动笔记(四)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。