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 ...
随机推荐
- Mysql学习---视图/触发器/存储过程/函数/执行计划/sql优化 180101
视图 视图: 视图是一个虚拟表(非真实存在),动态获取数据,仅仅能做查询操作 本质:[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,并可以将其当作表来使用.由 ...
- 个人Hadoop编程代码记录
**WordCount package cn.cpl.recom; import java.io.IOException; import java.util.StringTokenizer; impo ...
- 轮播图3D效果--roundabout(兼容IE8)升级版
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- MVVM的本质:视图逻辑处理、视图管理、视数中间层
MVVM的核心是将原来Controller中的视图逻辑.视图管理.视数中间层的功能剥离出来,形成单独的模块: 大部分功能与视图相关.少部分与数据相关: 视图逻辑和业务逻辑不通: 解决的问题:UIVie ...
- Linux学习总结(十六)系统用户及用户组管理
先来认识两个文件 /etc/passwd/etc/shadow我们打印出首尾三行,来了解下:每行由:分割为7段,每段含义为:第一段:用户名,比如root 用户,普通用户test,lv,test1第二段 ...
- 二十九、利用 IntelliJ IDEA 进行代码对比的方法
我们会有这样的需求,即:想对比出两个不同版本代码的区别.如何实现? 第 1 种:如果我们是从 SVN 检出的项目,并且想比较本地代码与从 SVN 检出时的代码相比都有那些区别,可以按如下步骤操作, 如 ...
- .net MVC 页面页面跳转后提示消息实现办法
mvc在RedirectToAction之后,会清理掉ViewData中的所有数据,因此通过ViewData给下一个页面传递提示消息不太好,如果是通过参数方式传递,刷新跳转后的页面时,消息还会再次提示 ...
- el表达式不显示值
1.场景是自己搭建一个ssm的项目,登录页面跳转到首页,首页显示登录用户的信息,用request传递的值,用el表达式在jsp页面中没有显示 2.解决办法 早jsp的代码中添加头<%@ page ...
- Haroopad 中文不显示
https://blog.csdn.net/zgf19930504/article/details/51508111 1. 选择文件--> 偏好设置 2. 选择 编辑器--> 编辑--&g ...
- Centos7单网卡带VLAN多IP配置
1.需要使用到vconfig软件,首先yum安装vconfig: 使用指令yum install vconfig:(若是本机找不到vconfig安装包,可以通过其他centos7安装yum-utils ...