关键字: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口)的更多相关文章

  1. Linux驱动设计——字符杂项设备

    杂项设备 linux里面的misc杂项设备是主设备号为10的驱动设备,misc设备其实也就是特殊的字符设备,可自动生成设备节点. 定义头文件<linux/miscdevice.h>   杂 ...

  2. Linux 驱动框架---cdev字符设备驱动和misc杂项设备驱动

    字符设备 Linux中设备常见分类是字符设备,块设备.网络设备,其中字符设备也是Linux驱动中最常用的设备类型.因此开发Linux设备驱动肯定是要先学习一下字符设备的抽象的.在内核中使用struct ...

  3. linux驱动开发之块设备学习笔记

    我的博客主要用来存放我的学习笔记,如有侵权,请与我练习,我会立刻删除.学习参考:http://www.cnblogs.com/yuanfang/archive/2010/12/24/1916231.h ...

  4. linux驱动初探之字符驱动

    关键字:字符驱动.动态生成设备节点.helloworld linux驱动编程,个人觉得第一件事就是配置好平台文件,这里以字符设备,也就是传说中的helloworld为例~ 此驱动程序基于linux3. ...

  5. 迅为4412开发板Linux驱动教程——总线_设备_驱动注册流程详解

    本文转自:http://www.topeetboard.com 视频下载地址: 驱动注册:http://pan.baidu.com/s/1i34HcDB 设备注册:http://pan.baidu.c ...

  6. 迅为4412开发板Linux驱动教程——总线_设备_驱动注冊流程具体解释

    视频下载地址: 驱动注冊:http://pan.baidu.com/s/1i34HcDB 设备注冊:http://pan.baidu.com/s/1kTlGkcR 总线_设备_驱动注冊流程具体解释 • ...

  7. Linux驱动技术(五) _设备阻塞/非阻塞读写

    等待队列是内核中实现进程调度的一个十分重要的数据结构,其任务是维护一个链表,链表中每一个节点都是一个PCB(进程控制块),内核会将PCB挂在等待队列中的所有进程都调度为睡眠状态,直到某个唤醒的条件发生 ...

  8. Linux驱动技术(五) _设备阻塞/非阻塞读写【转】

    转自:http://www.cnblogs.com/xiaojiang1025/p/6377925.html 等待队列是内核中实现进程调度的一个十分重要的数据结构,其任务是维护一个链表,链表中每一个节 ...

  9. 【linux驱动分析】misc设备驱动

    misc设备驱动.又称混杂设备驱动. misc设备驱动共享一个设备驱动号MISC_MAJOR.它在include\linux\major.h中定义:         #define MISC_MAJO ...

随机推荐

  1. angularJs之template指令

    template: 如果我们只需要在ng-view 中插入简单的HTML 内容,则使用该参数: .when('/computers',{template:'这是电脑分类页面'}) templateUr ...

  2. Windows Server 2008R2服务器安装及设置教程

    第一篇:系统安装与设置 前言本安装及设置教程适用于使用Windows2008R2为操作系统的服务器,目的是让服务器实现下列环境.语言脚本环境:ASP.ASP.Net1.1.ASP.Net2.0.ASP ...

  3. 白话学习MVC(八)Action的执行二

    一.概述 上篇博文<白话学习MVC(七)Action的执行一>介绍了ASP.NET MVC中Action的执行的简要流程,并且对TempData的运行机制进行了详细的分析,本篇来分析上一篇 ...

  4. LUA 函数式编程demo

    什么是函数式编程 http://www.zhihu.com/topic/19585411/hot 函数式编程的本质函数式编程中的函数这个术语不是指计算机中的函数(实际上是Subroutine),而是指 ...

  5. 隐藏,显示任务栏,桌面 C++代码

    HWND desktop,task; desktop=FindWindow(L"ProgMan",NULL); task=FindWindow(L"Shell_TrayW ...

  6. 学生各门课程成绩统计SQL语句大全

    学生成绩表(stuscore): 姓名:name 课程:subject 分数:score 学号:stuid 张三 数学 89 1 张三 语文 80 1 张三 英语 70 1 李四 数学 90 2 李四 ...

  7. android studio 引入第三方类库jar包

    第三方类库jar包 这就简单多了,直接将jar包拷贝到app/libs下,然后在app下的build.gradle中添加此jar的依赖.如下: dependencies { compile 'com. ...

  8. MVC @Html.TextBox 添加属性和样式

    1.添加属性:@Html.TextBox("CnAddressmodify","", new { maxlength="90" }) 2.添 ...

  9. 在Repeater中嵌套使用Repeater

    在一般的网站中浏览类别的用户控件通常都位于大多数 ASP.NET 页的左边,它使用户能够按类别快速的查找产品.最近遇到一个客户,因为在他网站上展示的产品并不多,所以要求在原有类别浏览的基础上将产品也加 ...

  10. struts2笔记4

    1.自定义struts拦截器 应用场景:如果用户登陆后可以访问action中的所有方法,如果用户没有登陆不允许访问action中的方法,并且提示“你没有操作权限” 1)两个页面,一个用户登陆user. ...