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 ...
随机推荐
- 设计模式:命令(Command)模式
设计模式:命令(Command)模式 一.前言 命令也是类,将命令作为一个类来保存,当要使用的时候可以直接拿来使用,比如脚本语言写出的脚本,只需要一个命令就能执行得到我们想要的需要操作很长时间才能得到 ...
- 如何使git忽略某些文件或文件夹
为什么要忽略某些文件或文件夹的变化? git作为一款项目文件变更版本管理软件,其主要功能之一就是追踪项目文件夹内各种文件及文件夹的变更情况.但是,在日常使用中,并非项目文件夹下的所有文件及文件夹变更都 ...
- February 19 2017 Week 8 Sunday
We accept the love we think we deserve. 我们接受自己认为配得上的爱. A few months ago, I tried to date with a girl ...
- python进阶介绍(进阶1)
转载请标明出处: http://www.cnblogs.com/why168888/p/6411664.html 本文出自:[Edwin博客园] python进阶介绍(进阶1) 1. python基础 ...
- PTA练习题之7-1 矩阵转置(10 分)
7-1 矩阵转置(10 分) 将一个3×3矩阵转置(即行和列互换). 输入格式: 在一行中输入9个小于100的整数,其间各以一个空格间隔. 输出格式: 输出3行3列的二维数组,每个数据输出占4列. 输 ...
- 郝斌 SqlServer2005 学习笔记
1.0 什么是数据库 狭义:存储数据的仓库. 广义:可以对数据进行存储和管理的软件以及数据本身统称为数据库. 另外一种说法:数据库是由表.关系.操作组成. 2.0 为什么要学习数据库 几乎所有的应用软 ...
- Linux学习总结(四)-两种模式修复系统,单用户,救援模式
一单用户模式 我们举例,比如忘记root 用户密码我们就可以进入单用户模式重置,该单用户模式,类似windos 安全模式开机界面快速按e 进入grub光标定位到 linux16 下一行ro crash ...
- 如何解决“当前上下文中不存在名称“XXXXXXXX””的问题
如果你是用的Visual Studio 2017,如果你项目中的.cshtml文件出现编译调试一切正常,但是在设计时查看出现下面的提示时: 错误 CS0103 当前上下文中不存在名称“ViewBag” ...
- python-正则基础
正则表达式,说的简单些,就是一个匹配的功能,在python中,只要引用 re 模块,就能进行正则匹配操作 一.math匹配 先来看一个简单的例子 import re re.match(pattern, ...
- OC报错,after command failed: Directory not empty
Directory not empty这个错误经常出现,出现的原因也很多,今天主要记录一下楼主自己碰到的这种情况. 全部错误提示: error: couldn't remove ‘路径/app-fzy ...