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 ...
随机推荐
- CI框架, 参数验证
/** * 统一API参数检验方法 * * 调用示例 check_param(array('money' => array('required', 'integer', 'greater_tha ...
- hearbeat
heartbeat介绍: 作用: 通过heartbeat,可以将资源(IP及程序服务等资源)从一台已经故障的计算机快速转移到另一台正常运转的机器上继续提供服务,一般称之为高可用服务.在升级生产应用场景 ...
- yii2.0里别名的定义
别名用来表示文件路径和URL,为了避免在代码中硬编码一些绝对路径和URL,一个别名必须以‘@’符开头. 用Yii::setAlias()的方法来设置: //文件别名 Yii::setAlias('@f ...
- February 11 2017 Week 6 Saturday
Love means never having to say you're sorry. 爱就是永远不必说对不起. Yesterday I heard an interesting story fro ...
- AngularJs学习笔记--Understanding the Model Component
原版地址:http://docs.angularjs.org/guide/dev_guide.mvc.understanding_model 在angular文档讨论的上下文中,术语“model”可以 ...
- postgresql+postgis+pgrouting实现最短路径查询(2)---openlayers+geoserver实现最短路径
自己的最短路径实现基本上是按照参考博文的1.2和3进行的,实现的时候也是问题不断,只能是一个一个解决. 问题1:自己发布的geoserver服务无法和OSM底图叠加到一起. 解决:参考博文2提到发布服 ...
- [转]SQL Server 安全性概論與無法刪除資料庫使用者的解決辦法
經常有人來問我特定 SQL Server 資料庫裡的使用者無法刪除的問題,這問題其實跟 SQL Server 的安全性架構有很大關係,解決這個問題當然還是瞭解觀念的重要性大於知道如何解決問題.除了講解 ...
- 【题解】UVA10298 Power String(KMP)
UVA10298:https://www.luogu.org/problemnew/show/UVA10298 思路 设P[x]数组为 前x个字符的最大前缀长度等于后缀字串 由P数组的定义我们可以知道 ...
- MVC验证码生成类库
public class ValidateCode { /// <summary> /// 验证码的最大长度 /// </summary> public int MaxLeng ...
- TortoiseSVN 分支创建与合并
前提准备: 确保本地Work Copy 和 服务器上的 版本一致.( 所有代码都提交到SVN,并update一次) 1 从主干创建分支代码 在本地Work Copy 选中项目文件夹,鼠标右键选择 ...