linux驱动初探之杂项设备(控制两个GPIO口)
关键字:linux驱动、杂项设备、GPIO
此驱动程序控制了外接的两个二极管,二极管是低电平有效。
上一篇博客中已经介绍了linux驱动程序的编写流程,这篇博客算是前一篇的提高篇,也是下一篇博客(JNI)的底层程序
一样的在平台文件中配置设备信息
#ifdef CONFIG_HELLO_CTL
struct platform_device s3c_device_hello_ctl = {
.name = "jni",
.id = -,
};
#endif
#ifdef CONFIG_HELLO_CTL
&s3c_device_hello_ctl,
#endif
在编写驱动程序之前要确定需要控制哪个GPIO接口,同时要保证该GPIO口没有被其他程序占用,若被占用则需要取消编译那个驱动程序。
经过查找开发板原理图准备使用CAM_VSYNC和CAM_HREF两个端口

这两个端口对应于平台文件的EXYNOS4212_GPIO(1)与EXYNOS4212_GPIO(2)两个脚,也就是说只要控制这两个脚,就是控制了硬件上的两个脚。

使用杂项设备编写驱动会比字符类设备简单,因为杂项设备的主设备号规定了为10,他能够挂255个从设备号。
同样的,从init函数开始:
static void jni_exit(void){
printk("jni_exit ...\n");
platform_driver_unregister(&jni_driver);
}
static int jni_init(void){
int err;
printk("jni_init start...\n");
err = platform_driver_register(&jni_driver);
printk("state is %d\n",err);
return ;
}
module_init(jni_init);
module_exit(jni_exit);
通过platform_driver进行注册,然后申明一个platform_driver结构体,在这里要注意!!这里的.name与我们刚开始时在平台文件中的.name必须要一致,否则会注册失败!也就是说内核会自动进行匹配
struct platform_driver jni_driver = {
.probe = jni_probe,
.remove = jni_remove,
.shutdown = jni_shutdown,
.suspend = jni_suspend,
.resume = jni_resume,
.driver = {
.name = "jni",
.owner = THIS_MODULE,
}
};
如果匹配成功,那么会进入驱动的probe函数中,所以一般初始化操作都写在了probe函数中,而不像字符类设备是写在init函数中!
static int jni_probe(struct platform_device *pdv){
int ret,i;
printk("jni_probe start..\n");
for(i=; i<GPIO_NUM; i++)
{
ret = gpio_request(led_gpios[i], "LED");
if (ret < ) {
printk("%s: request GPIO %d for LED failed, ret = %d\n", DEVICE_NAME,i, ret);
}
else{
printk("%s: request GPIO %d for LED success, ret = %d\n", DEVICE_NAME,i, ret);
s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);
gpio_set_value(led_gpios[i], );
//gpio_free(led_gpios[i]);
}
}
ret = misc_register(&jni_dev);
if(ret<)
{
printk("jni:register device failed!\n");
goto exit;
}
return ;
exit:
misc_deregister(&jni_dev);
return ret;
}
static int jni_remove(struct platform_device *pdv){
//int i;
printk("jni_remove...\n");
misc_deregister(&jni_dev);
return ;
}
static void jni_shutdown(struct platform_device *pdv){
return ;
}
static int jni_suspend(struct platform_device *pdv,pm_message_t pmt){
return ;
}
static int jni_resume(struct platform_device *pdv){
return ;
}
在probe函数中会请求gpio口,即gpio_request,如果请求失败,那肯定是某个驱动占用了该gpio口,需要手动取消。
然后设置为输出。最后调用杂项设备注册函数misc_register进行注册。
static struct miscdevice jni_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &jni_ops,
};
这里终于出现久违的fops函数了,也就是驱动操作函数。
static struct file_operations jni_ops = {
.owner = THIS_MODULE,
.open = jni_open,
.release = jni_release,
.unlocked_ioctl = jni_ioctl,
};
这里的函数接口就是为上层应用提供啦。
static long jni_ioctl( struct file *files, unsigned int cmd, unsigned long arg){
int ret;
printk("Hello JNI and cmd is %d,arg is %d\n",cmd,arg);
switch(cmd)
{
case :
case :
if (arg > ) {
return -EINVAL;
}
gpio_set_value(led_gpios[arg], cmd);
break;
default:
return -EINVAL;
}
return ;
}
static int jni_release(struct inode *inode, struct file *file){
printk("jni release\n");
return ;
}
static int jni_open(struct inode *inode, struct file *file){
printk("jni open\n");
return nonseekable_open(inode,file);
}
最后附上完整的驱动代码
#include <linux/init.h>
#include <linux/module.h> /*驱动注册的头文件,platform结构体和驱动注册与注销*/
#include <linux/platform_device.h> /*杂项设备头文件*/
#include <linux/miscdevice.h> /*设备节点头文件*/
#include <linux/fs.h> /*Linux中申请GPIO的头文件*/
#include <linux/gpio.h>
/*三星平台的GPIO配置函数头文件*/
/*三星平台EXYNOS系列平台,GPIO配置参数宏定义头文件*/
#include <plat/gpio-cfg.h>
#include <mach/gpio.h>
/*三星平台4412平台,GPIO宏定义头文件*/
#include <mach/gpio-exynos4.h> #include <linux/delay.h> //设备节点
#define DEVICE_NAME "jni"
//匹配项
#define DRIVER_NAME "jni" MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("PNGCUI"); static int led_gpios[] = {
EXYNOS4212_GPJ0(),EXYNOS4212_GPJ0(),
}; #define GPIO_NUM ARRAY_SIZE(led_gpios) static long jni_ioctl( struct file *files, unsigned int cmd, unsigned long arg){
int ret;
printk("Hello JNI and cmd is %d,arg is %d\n",cmd,arg); switch(cmd)
{
case :
case :
if (arg > ) {
return -EINVAL;
}
gpio_set_value(led_gpios[arg], cmd); break; default:
return -EINVAL;
} return ;
} static int jni_release(struct inode *inode, struct file *file){ printk("jni release\n"); return ;
} static int jni_open(struct inode *inode, struct file *file){ printk("jni open\n"); return nonseekable_open(inode,file);
} static struct file_operations jni_ops = {
.owner = THIS_MODULE,
.open = jni_open,
.release = jni_release,
.unlocked_ioctl = jni_ioctl,
}; static struct miscdevice jni_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &jni_ops,
}; static int jni_probe(struct platform_device *pdv){
int ret,i;
printk("jni_probe start..\n"); for(i=; i<GPIO_NUM; i++)
{
ret = gpio_request(led_gpios[i], "LED");
if (ret < ) {
printk("%s: request GPIO %d for LED failed, ret = %d\n", DEVICE_NAME,i, ret);
}
else{
printk("%s: request GPIO %d for LED success, ret = %d\n", DEVICE_NAME,i, ret);
s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);
gpio_set_value(led_gpios[i], );
//gpio_free(led_gpios[i]);
}
} ret = misc_register(&jni_dev);
if(ret<)
{
printk("jni:register device failed!\n");
goto exit;
} return ; exit:
misc_deregister(&jni_dev);
return ret;
} static int jni_remove(struct platform_device *pdv){
//int i;
printk("jni_remove...\n"); misc_deregister(&jni_dev); return ;
} static void jni_shutdown(struct platform_device *pdv){ return ;
} static int jni_suspend(struct platform_device *pdv,pm_message_t pmt){ return ;
} static int jni_resume(struct platform_device *pdv){ return ;
} struct platform_driver jni_driver = {
.probe = jni_probe,
.remove = jni_remove,
.shutdown = jni_shutdown,
.suspend = jni_suspend,
.resume = jni_resume,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
}
}; static void jni_exit(void){ printk("jni_exit ...\n"); platform_driver_unregister(&jni_driver); } static int jni_init(void){ int err; printk("jni_init start...\n"); err = platform_driver_register(&jni_driver); printk("state is %d\n",err); return ;
} module_init(jni_init);
module_exit(jni_exit);
linux驱动初探之杂项设备(控制两个GPIO口)的更多相关文章
- Linux驱动设计——字符杂项设备
杂项设备 linux里面的misc杂项设备是主设备号为10的驱动设备,misc设备其实也就是特殊的字符设备,可自动生成设备节点. 定义头文件<linux/miscdevice.h> 杂 ...
- Linux 驱动框架---cdev字符设备驱动和misc杂项设备驱动
字符设备 Linux中设备常见分类是字符设备,块设备.网络设备,其中字符设备也是Linux驱动中最常用的设备类型.因此开发Linux设备驱动肯定是要先学习一下字符设备的抽象的.在内核中使用struct ...
- linux驱动开发之块设备学习笔记
我的博客主要用来存放我的学习笔记,如有侵权,请与我练习,我会立刻删除.学习参考:http://www.cnblogs.com/yuanfang/archive/2010/12/24/1916231.h ...
- linux驱动初探之字符驱动
关键字:字符驱动.动态生成设备节点.helloworld linux驱动编程,个人觉得第一件事就是配置好平台文件,这里以字符设备,也就是传说中的helloworld为例~ 此驱动程序基于linux3. ...
- 迅为4412开发板Linux驱动教程——总线_设备_驱动注册流程详解
本文转自:http://www.topeetboard.com 视频下载地址: 驱动注册:http://pan.baidu.com/s/1i34HcDB 设备注册:http://pan.baidu.c ...
- 迅为4412开发板Linux驱动教程——总线_设备_驱动注冊流程具体解释
视频下载地址: 驱动注冊:http://pan.baidu.com/s/1i34HcDB 设备注冊:http://pan.baidu.com/s/1kTlGkcR 总线_设备_驱动注冊流程具体解释 • ...
- Linux驱动技术(五) _设备阻塞/非阻塞读写
等待队列是内核中实现进程调度的一个十分重要的数据结构,其任务是维护一个链表,链表中每一个节点都是一个PCB(进程控制块),内核会将PCB挂在等待队列中的所有进程都调度为睡眠状态,直到某个唤醒的条件发生 ...
- Linux驱动技术(五) _设备阻塞/非阻塞读写【转】
转自:http://www.cnblogs.com/xiaojiang1025/p/6377925.html 等待队列是内核中实现进程调度的一个十分重要的数据结构,其任务是维护一个链表,链表中每一个节 ...
- 【linux驱动分析】misc设备驱动
misc设备驱动.又称混杂设备驱动. misc设备驱动共享一个设备驱动号MISC_MAJOR.它在include\linux\major.h中定义: #define MISC_MAJO ...
随机推荐
- Win10如何设置防火墙开放特定端口 windows10防火墙设置对特定端口开放的方法
Win10防火墙虽然能够很好地保护我们的系统,但同时也会因限制了某些端口,而给我们的操作带了一些不便.对于既想使用某些端口,又不愿关闭防火墙的用户而言,在Win10系统中设置防火墙开放特定端口就非常必 ...
- JS小数点加减乘除运算后位数增加的解决方案
/** * 加法运算,避免数据相加小数点后产生多位数和计算精度损失. * * @param num1加数1 | num2加数2 */ function numAdd(num1, num2) { var ...
- 使用Go开发HTTP中间件
原文地址 再web开发的背景下,"中间件"通常意思是"包装原始应用并添加一些额外的功能的应用的一部分".这个概念似乎总是不被人理解,但是我认为中间件非常棒 ...
- ActiveMQ的使用笔记(基本实现原理)
具体原理不进行深入,会用就好. 第一:当然是先安装ActiveMQ,选择操作系统位数,安装成功以后,输入网址http://ip:8161/admin/,会出现相关页面,账号密码都是admin.在这个页 ...
- 【笔记】jquery阻止冒泡事件发生的语句
时间触发时会执行两个步骤:1.捕获 2.冒泡,而很多浏览器包括jquery都不支持捕获动作所以只能执行冒泡动作. 所谓冒泡就是当点击就是事件的执行顺序,本人的理解为:但某一元素触发时间时它的祖先元素( ...
- phpcms V9 首页模板文件解析
在了解了<phpcms V9 URL访问解析>之后,我们已经知道首页最终执行的是content模块下index控制器的init方法. 下面, 我们逐步分析过程如下: 第一.首页默认执行的是 ...
- 鸟哥的linux私房菜学习记录之系统设定工具与硬件检测
这部分没啥用,就不记录了,关于服务器的在服务器篇
- UICollectionViewDelegateFlowLayout 使用
import UIKit //UICollectionViewLayout //itemSize属性 //设定全局的Cell尺寸,如果想要单独定义某个Cell的尺寸,可以使用下面方法: // - (C ...
- js-统计选项个数
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 图论$\cdot$强连通分量
和无向图的连通分量类似,有向图有“强连通分量”的说法.“相互可达”的关系在有向图中也是等价关系.每一个集合称为有向图的一个强连通分量(scc).如果把一个集合看成一个点,那么所有的scc构成了一个sc ...