Linux字符设备驱动--No.1
平台:tiny210SOC:s5pv210内核:Linux 3.0.8字符驱动:按键中断驱动源码:
/*****************************************************************************
简 述:简单字符型驱动程序,手动静态分配设备号,手动创建设备节点
******************************************************************************/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <mach/map.h>
#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/slab.h>
#define DEVICE_NAME "buttons"
struct button_desc {
int gpio;
int number;
char *name;
};
static struct button_desc buttons[] = {
{ S5PV210_GPH2(), , "KEY0" },
{ S5PV210_GPH2(), , "KEY1" },
{ S5PV210_GPH2(), , "KEY2" },
{ S5PV210_GPH2(), , "KEY3" },
{ S5PV210_GPH3(), , "KEY4" },
{ S5PV210_GPH3(), , "KEY5" },
{ S5PV210_GPH3(), , "KEY6" },
{ S5PV210_GPH3(), , "KEY7" },
};
#define OK (0)
#define ERROR (-1)
struct cdev *gDev;
struct file_operations *gFile;
dev_t devNum;
unsigned ;
;
;
static irqreturn_t button_interrupt(int irq, void *dev_id)
{
struct button_desc *bdata = (struct button_desc *)dev_id;
int down;
unsigned tmp;
tmp = gpio_get_value(bdata->gpio);
/* active low */
down = !tmp;
printk("KEY %d: %08x\n", bdata->number, down);
return IRQ_HANDLED;
}
int butsOpen(struct inode *p, struct file *f)
{
int irq;
int i;
;
printk(KERN_EMERG"butsOpen\r\n");
; i < ARRAY_SIZE(buttons); i++) {
if (!buttons[i].gpio)
continue;
irq = gpio_to_irq(buttons[i].gpio);
err = request_irq(irq, button_interrupt, IRQ_TYPE_EDGE_BOTH,
buttons[i].name, (void *)&buttons[i]);
if (err)
break;
}
if (err) {
i--;
; i--) {
if (!buttons[i].gpio)
continue;
irq = gpio_to_irq(buttons[i].gpio);
disable_irq(irq);
free_irq(irq, (void *)&buttons[i]);
}
return -EBUSY;
}
;
}
int charDrvInit(void)
{
devNum = MKDEV(reg_major, reg_minor);
printk(KERN_EMERG"devNum is %d\r\n", devNum);
if(OK == register_chrdev_region(devNum, subDevNum, DEVICE_NAME))
{
printk(KERN_EMERG"register_chrdev_region ok\r\n");
}
else
{
printk(KERN_EMERG"register_chrdev_region error\r\n");
return ERROR;
}
/*if(OK == alloc_chrdev_region(&devNum, subDevNum, subDevNum,"test"))
{
printk(KERN_EMERG"register_chrdev_region ok\r\n");
}
else
{
printk(KERN_EMERG"register_chrdev_region error\r\n");
return ERROR;
}*/
gDev = kzalloc(sizeof(struct cdev), GFP_KERNEL);
gFile = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
gFile->open = butsOpen;
//注册设备函数到file_operations结构体gFile
//gDev->owner = THIS_MODULE;
gFile->owner = THIS_MODULE;
cdev_init(gDev, gFile);
//在cdev结构体中添加指针指向file_operations结构体gFile
cdev_add(gDev, devNum, );
//建立设备号与cdev结构体联系
printk(KERN_EMERG"button driver initial done...\r\n");
;
}
void __exit charDrvExit(void)
{
int i;
cdev_del(gDev);
unregister_chrdev_region(devNum, subDevNum);
return;
}
module_init(charDrvInit);
module_exit(charDrvExit);
MODULE_LICENSE("GPL");
int butsOpen(struct inode *p, struct file *f)
{
int irq;
int i;
;
printk(KERN_EMERG"butsOpen\r\n");
; i < ARRAY_SIZE(buttons); i++) {
if (!buttons[i].gpio)
continue;
irq = gpio_to_irq(buttons[i].gpio);
err = request_irq(irq, button_interrupt, IRQ_TYPE_EDGE_BOTH,
buttons[i].name, (void *)&buttons[i]);
if (err)
break;
}
if (err) {
i--;
; i--) {
if (!buttons[i].gpio)
continue;
irq = gpio_to_irq(buttons[i].gpio);
disable_irq(irq);
free_irq(irq, (void *)&buttons[i]);
}
return -EBUSY;
}
;
}
#define gpio_to_irq __gpio_to_irq
int __gpio_to_irq(unsigned gpio)
{
struct gpio_chip *chip;
chip = gpio_to_chip(gpio);
return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO;
}
int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
{
struct s3c_gpio_chip *s3c_chip = container_of(chip,
struct s3c_gpio_chip, chip);
return s3c_chip->irq_base + offset;
}
static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
{
return gpio_desc[gpio].chip;//此处的gpio_desc[gpio].chip实际完成赋值在gpio-s5pv210.c中的s5pv210_gpiolib_init(void)函数中实现
}
gpio_desc[gpio].chip实际完成赋值在gpio-s5pv210.c中的s5pv210_gpiolib_init(void)函数中的实现:
static __init int s5pv210_gpiolib_init(void)
{
struct s3c_gpio_chip *chip = s5pv210_gpio_4bit;
int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);
;
;
; i < nr_chips; i++, chip++) {
if (chip->config == NULL) {
chip->config = &gpio_cfg;
chip->group = gpioint_group++;
}
if (chip->base == NULL)
chip->base = S5PV210_BANK_BASE(i);
}
samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips);
s5p_register_gpioint_bank(IRQ_GPIOINT, , S5P_GPIOINT_GROUP_MAXNR);
;
}
static struct s3c_gpio_chip s5pv210_gpio_4bit[] = {
{
.chip = {
.),
.ngpio = S5PV210_GPIO_A0_NR,
.label = "GPA0",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_A1_NR,
.label = "GPA1",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_B_NR,
.label = "GPB",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_C0_NR,
.label = "GPC0",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_C1_NR,
.label = "GPC1",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_D0_NR,
.label = "GPD0",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_D1_NR,
.label = "GPD1",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_E0_NR,
.label = "GPE0",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_E1_NR,
.label = "GPE1",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_F0_NR,
.label = "GPF0",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_F1_NR,
.label = "GPF1",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_F2_NR,
.label = "GPF2",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_F3_NR,
.label = "GPF3",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_G0_NR,
.label = "GPG0",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_G1_NR,
.label = "GPG1",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_G2_NR,
.label = "GPG2",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_G3_NR,
.label = "GPG3",
},
}, {
.config = &gpio_cfg_noint,
.chip = {
.),
.ngpio = S5PV210_GPIO_I_NR,
.label = "GPI",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_J0_NR,
.label = "GPJ0",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_J1_NR,
.label = "GPJ1",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_J2_NR,
.label = "GPJ2",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_J3_NR,
.label = "GPJ3",
},
}, {
.chip = {
.),
.ngpio = S5PV210_GPIO_J4_NR,
.label = "GPJ4",
},
}, {
.config = &gpio_cfg_noint,
.chip = {
.),
.ngpio = S5PV210_GPIO_MP01_NR,
.label = "MP01",
},
}, {
.config = &gpio_cfg_noint,
.chip = {
.),
.ngpio = S5PV210_GPIO_MP02_NR,
.label = "MP02",
},
}, {
.config = &gpio_cfg_noint,
.chip = {
.),
.ngpio = S5PV210_GPIO_MP03_NR,
.label = "MP03",
},
}, {
.config = &gpio_cfg_noint,
.chip = {
.),
.ngpio = S5PV210_GPIO_MP04_NR,
.label = "MP04",
},
}, {
.config = &gpio_cfg_noint,
.chip = {
.),
.ngpio = S5PV210_GPIO_MP05_NR,
.label = "MP05",
},
}, {
.base = (S5P_VA_GPIO + 0xC00),
.config = &gpio_cfg_noint,
.irq_base = IRQ_EINT(),
.chip = {
.),
.ngpio = S5PV210_GPIO_H0_NR,
.label = "GPH0",
.to_irq = samsung_gpiolib_to_irq,
},
}, {
.base = (S5P_VA_GPIO + 0xC20),
.config = &gpio_cfg_noint,
.irq_base = IRQ_EINT(),
.chip = {
.),
.ngpio = S5PV210_GPIO_H1_NR,
.label = "GPH1",
.to_irq = samsung_gpiolib_to_irq,
},
}, {
.base = (S5P_VA_GPIO + 0xC40),
.config = &gpio_cfg_noint,
.irq_base = IRQ_EINT(),
.chip = {
.),
.ngpio = S5PV210_GPIO_H2_NR,
.label = "GPH2",
.to_irq = samsung_gpiolib_to_irq,
},
}, {
.base = (S5P_VA_GPIO + 0xC60),
.config = &gpio_cfg_noint,
.irq_base = IRQ_EINT(),
.chip = {
.),
.ngpio = S5PV210_GPIO_H3_NR,
.label = "GPH3",
.to_irq = samsung_gpiolib_to_irq,
},
},
};
struct s3c_gpio_chip s5pv210_gpio_4bit[]
void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip,
2 int nr_chips)
{
; nr_chips--, chip++) {
samsung_gpiolib_add_4bit(chip);
s3c_gpiolib_add(chip);
}
}
__init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
{
struct gpio_chip *gc = &chip->chip;//将struct s3c_gpio_chip结构体成员结构体chip赋值给struct gpio_chip结构体局部变量gc
int ret;
BUG_ON(!chip->base);
BUG_ON(!gc->label);
BUG_ON(!gc->ngpio);
spin_lock_init(&chip->lock);
if (!gc->direction_input)
gc->direction_input = s3c_gpiolib_input;
if (!gc->direction_output)
gc->direction_output = s3c_gpiolib_output;
if (!gc->set)
gc->set = s3c_gpiolib_set;
if (!gc->get)
gc->get = s3c_gpiolib_get;
#ifdef CONFIG_PM
if (chip->pm != NULL) {
if (!chip->pm->save || !chip->pm->resume)
printk(KERN_ERR "gpio: %s has missing PM functions\n",
gc->label);
} else
printk(KERN_ERR "gpio: %s has no PM function\n", gc->label);
#endif
/* gpiochip_add() prints own failure message on error. */
ret = gpiochip_add(gc);
)
s3c_gpiolib_track(chip);
}
int gpiochip_add(struct gpio_chip *chip)
{
unsigned long flags;
;
unsigned id;
int base = chip->base;
))
&& ) {
status = -EINVAL;
goto fail;
}
spin_lock_irqsave(&gpio_lock, flags);
) {
base = gpiochip_find_base(chip->ngpio);
) {
status = base;
goto unlock;
}
chip->base = base;
}
/* these GPIO numbers must not be managed by another gpio_chip */
for (id = base; id < base + chip->ngpio; id++) {
if (gpio_desc[id].chip != NULL) {
status = -EBUSY;
break;
}
}
) {
for (id = base; id < base + chip->ngpio; id++) {
gpio_desc[id].chip = chip;//在这里gpio_desc[id].chip和struct s3c_gpio_chip建立联系
/* REVISIT: most hardware initializes GPIOs as
* inputs (often with pullups enabled) so power
* usage is minimized. Linux code should set the
* gpio direction first thing; but until it does,
* we may expose the wrong direction in sysfs.
*/
gpio_desc[id].flags = !chip->direction_input
? ( << FLAG_IS_OUT)
: ;
}
}
of_gpiochip_add(chip);
unlock:
spin_unlock_irqrestore(&gpio_lock, flags);
if (status)
goto fail;
status = gpiochip_export(chip);
if (status)
goto fail;
;
fail:
/* failures here can mean systems won't boot... */
pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
chip->,
chip->label ? : "generic");
return status;
}
Linux字符设备驱动--No.1的更多相关文章
- 深入理解Linux字符设备驱动
文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...
- Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】
本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...
- Smart210学习记录----beep linux字符设备驱动
今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...
- Linux字符设备驱动实现
Linux字符设备驱动实现 要求 编写一个字符设备驱动,并利用对字符设备的同步操作,设计实现一个聊天程序.可以有一个读,一个写进程共享该字符设备,进行聊天:也可以由多个读和多个写进程共享该字符设备,进 ...
- Linux字符设备驱动基本结构
1.Linux字符设备驱动的基本结构 Linux系统下具有三种设备,分别是字符设备.块设备和网络设备,Linux下的字符设备是指只能一个字节一个字节读写的设备,不能随机读取设备内存中某一数据,读取数据 ...
- (57)Linux驱动开发之三Linux字符设备驱动
1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...
- Linux字符设备驱动框架
字符设备是Linux三大设备之一(另外两种是块设备,网络设备),字符设备就是字节流形式通讯的I/O设备,绝大部分设备都是字符设备,常见的字符设备包括鼠标.键盘.显示器.串口等等,当我们执行ls -l ...
- Linux 字符设备驱动模型
一.使用字符设备驱动程序 1. 编译/安装驱动 在Linux系统中,驱动程序通常采用内核模块的程序结构来进行编码.因此,编译/安装一个驱动程序,其实质就是编译/安装一个内核模块 2. 创建设备文件 通 ...
- linux字符设备驱动学习笔记(一):简单的字符设备驱动
最近在鼓捣lnux字符设备驱动,在网上搜集的各种关于linux设备驱动的代码和注释,要么是针对2.4的,要么是错误百出,根本就不能运行成功,真希望大家在发博客的时候能认真核对下代码的正确性,特别是要把 ...
- Linux字符设备驱动
一.字符设备基础 字符设备 二.字符设备驱动与用户空间访问该设备的程序三者之间的关系 三.字符设备模型 1.Linux内核中,使用 struct cdev 来描述一个字符设备 动态申请(构造)cdev ...
随机推荐
- OSPF-DR与BDR的选举及作用
IERS-DR与BDR的选举及作用 一.问题引出 在运行OSPF的MA网络中包括广播型和NBMA网络会存在两个问题: 1).在一个有n个路由器的网络中,会形成(n*(n-1))/2邻居关系. 2).邻 ...
- python filter&sorted
filter filter()接收一个函数和一个序列和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素在一个list中, ...
- 不错的.net开源项目
Json.NET http://json.codeplex.com/ Json.Net是一个读写Json效率比较高的.Net框架.Json.Net 使得在.Net环境下使用Json更加简单.通过Lin ...
- AWK入门指南
一. AWK入门指南 Awk是一种便于使用且表达能力强的程序设计语言,可应用于各种计算和数据处理任务.本章是个入门指南,让你能够尽快地开始编写你自己的程序.第二章将描述整个语言,而剩下的章节将向你展示 ...
- geos学习笔记:安装和使用
1.首先在https://trac.osgeo.org/geos下载geos-3.6.2.tar.bz2 解压后 cd geos- ./configue //或选择安装的目录./configure - ...
- javascript返回顶部插件+源码
javascript插件->returnTop.js: /* ** 插件名称returnTop.js ** 调用返回头部单例参数说明 ** 调用方式:turn.init(ele,speed); ...
- nodejs 做的带管理后台的东东,主要学习到 ....我忘了学到什么了
效果 http://www.steel-pot.com/ function handleStr(str,isHtml,callback) { if(!isHtml) { callback(str); ...
- Many-to-many relationships in EF Core 2.0 – Part 1: The basics
转载这个系列的文章,主要是因为EF Core 2.0在映射数据库的多对多关系时,并不像老的EntityFramework那样有原生的方法进行支持,希望微软在以后EF Core的版本中加入原生支持多对多 ...
- C语言输入输出函数总结
常见函数: FILE *p char ch char buf[max] fopen("filename","ab")//打开名为filename的文件并返回一个 ...
- 五、MapReduce 发布服务
是一个并行计算框架(计算的数据源比较广泛-HDFS.RDBMS.NoSQL),Hadoop的 MR模块充分利用了HDFS中所有数据节点(datanode)所在机器的内存.CUP以及少量磁盘完成对大数据 ...