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 ...
随机推荐
- 关于asp.net与jquery ajax 的一些补充
补充1:asp.net 与后台交互除了用之前写得$.ajsx()外 还可以直接使用$.get() , $.post()等. 补充2:jquery 跨域请求 例如: JSONP 跨域: $.ajax( ...
- CAShapeLayer(持续更新)
CAShapeLayer 之前讲过CALayer动画相关知识,再来看看更加复杂的CAShapeLayer相关的动画知识. 普通CALayer在被初始化时是需要给一个frame值的,这个frame值一般 ...
- php随机数、时间、字符串函数,正则,数组函数
<?php//1.随机数和时间//echo rand(); //随机数生成器//echo rand(0,10); //生成某个范围内的随机数 //echo time(); //取当前时间戳//e ...
- 20145320 《Java程序设计》第1周学习总结
20145320 <Java程序设计>第1周学习总结 教材学习内容总结 第一章 Java最早是Sun公司的项目Green Project中编写Star7应用程序的程序语言,1995年5月2 ...
- Python介绍、安装、使用
Python介绍.安装.使用 搬运工:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Python语言介绍 说到Python语言,就不得不说一下它的创始人Guido van Rossu ...
- Centos7中源码安装Nodejs
Step 1.确认服务器有nodejs编译及依赖相关软件,如果没有可通过运行以下命令安装. [root@BobServerStation local]# yum -y install gcc gcc- ...
- 如何设置一个严格30分钟过期的Session(转载)
本文地址: http://www.laruence.com/2012/01/10/2469.html 今天在我的微博(Laruence)上发出一个问题: 我在面试的时候, 经常会问一个问题: &quo ...
- mvc与三层结构
http://www.cnblogs.com/zhhh/archive/2011/06/10/2077519.html 又看到有人在问三层架构和MVC的关系,感觉这种问题有点教条化了.因为它们都在逻辑 ...
- 如何拥有一个自己的Vagrant box
这是一个关于Vagrant的学习系列,包含如下文章: Vagrant入门 创建自己的Vagrant box 用Vagrant搭建Jenkins构建环境 用Vagrant和Ansible搭建持续交付平台 ...
- javax.servlet.ServletException: com.ibatis.sqlmap.client.SqlMapException: There is no statement named...问题
可能存在3种情况: 1.在xxx.xml文件中有两个标签的id命名相同: 2.DAO实现类方法中没有写对应xxx.xml的id名称: 3.实体映射文件xxx.xml未加入到sqlMap-Config. ...