/* 内核如何调用驱动入口函数 ? */
/* 答: 使用module_init()函数,
module_init()函数定义一个结构体,这个结构体里面有一个函数指针,
指向first_drv_init()这个驱动入口函数,当我们加载或安装一个驱动程序时,
内核就会自动找到这样一个结构体,然后调用这个结构体中的函数指针,
从而调用了驱动入口函数first_drv_init(void),该驱动入口函数中有
register_chrdev(主设备号,设备名,struct file_operations结构体指针)函数,
该函数会将驱动程序的file_operations结构体连同其主设备号一起向内核进行注册,
从而该驱动入口函数将一个struct file_operations 类型的结构体传送给内核,
内核可以调用这个结构中的函数指针,从而调用具体的驱动操作函数,
    应用程序操作设备文件时所调用的open, read,write等函数,最终都会
调用struct file_operations类型的结构体,例如在应用程序中用Open()函数打开驱动文件时,

linux内核会根据该设备文件的类型以及主设备号找到在内核中注册的file_operations类型的结构体*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h> static struct class *firstdrv_class;
static struct class_device *firstdrv_class_dev; volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL; static int first_drv_open(struct inode *inode, struct file *file)
{
//printk("first_drv_open\n");
/* 配置GPF4,5,6为输出 */
*gpfcon &= ~((0x3<<(*)) | (0x3<<(*)) | (0x3<<(*)));
*gpfcon |= ((0x1<<(*)) | (0x1<<(*)) | (0x1<<(*)));
return ;
} static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
int val; //printk("first_drv_write\n"); copy_from_user(&val, buf, count); // copy_to_user(); if (val == )
{
// 点灯
*gpfdat &= ~((<<) | (<<) | (<<));
}
else
{
// 灭灯
*gpfdat |= (<<) | (<<) | (<<);
} return ;
} static struct file_operations first_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = first_drv_open,
.write = first_drv_write,
}; int major;
static int first_drv_init(void)/*驱动的入口函数*/
{
major = register_chrdev(, "first_drv", &first_drv_fops); /*注册, 把first_drv_fops告诉内核*/ firstdrv_class = class_create(THIS_MODULE, "firstdrv"); firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, ), NULL, "xyz"); /* /dev/xyz */ gpfcon = (volatile unsigned long *)ioremap(0x56000050, );
gpfdat = gpfcon + ; return ;
} static void first_drv_exit(void)
{
unregister_chrdev(major, "first_drv"); // 卸载 class_device_unregister(firstdrv_class_dev);
class_destroy(firstdrv_class);
iounmap(gpfcon);
}
/* 内核如何调用驱动入口函数 ? */
/* 答: 使用module_init()函数,
module_init()函数定义一个结构体,这个结构体里面有一个函数指针,
指向first_drv_init()这个驱动入口函数,当我们加载或安装一个驱动程序时,
内核就会自动找到这样一个结构体,然后调用这个结构体中的函数指针,
从而调用了驱动入口函数first_drv_init(void),该驱动入口函数中有
register_chrdev(主设备号,设备名,struct file_operations结构体指针)函数,
该函数会将驱动程序的file_operations结构体连同其主设备号一起向内核进行注册,
从而该驱动入口函数将一个struct file_operations 类型的结构体传送给内核,
内核可以调用这个结构中的函数指针,从而调用具体的驱动操作函数,
应用程序操作设备文件时所调用的open, read,write等函数,最终都会
调用struct file_operations类型的结构体*/
module_init(first_drv_init);
/**/
module_exit(first_drv_exit); /**/
MODULE_LICENSE("GPL");

linux字符设备驱动中内核如何调用驱动入口函数 一点记录的更多相关文章

  1. 深入理解Linux字符设备驱动

    文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...

  2. Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】

    本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...

  3. Linux字符设备中的两个重要结构体(file、inode)

    对于Linux系统中,一般字符设备和驱动之间的函数调用关系如下图所示 上图描述了用户空间应用程序通过系统调用来调用程序的过程.一般而言在驱动程序的设计中,会关系 struct file 和 struc ...

  4. Linux字符设备驱动

    一.字符设备基础 字符设备 二.字符设备驱动与用户空间访问该设备的程序三者之间的关系 三.字符设备模型 1.Linux内核中,使用 struct cdev 来描述一个字符设备 动态申请(构造)cdev ...

  5. Linux字符设备驱动实现

    Linux字符设备驱动实现 要求 编写一个字符设备驱动,并利用对字符设备的同步操作,设计实现一个聊天程序.可以有一个读,一个写进程共享该字符设备,进行聊天:也可以由多个读和多个写进程共享该字符设备,进 ...

  6. linux字符设备驱动--基本知识介绍

    一.设备驱动的分类 1.字符设备 字符设备是指那些能一个字节一个字节读取数据的设备,如LED灯.键盘.鼠标等.字符设备一般需要在驱动层实现open().close().read().write().i ...

  7. Linux字符设备驱动基本结构

    1.Linux字符设备驱动的基本结构 Linux系统下具有三种设备,分别是字符设备.块设备和网络设备,Linux下的字符设备是指只能一个字节一个字节读写的设备,不能随机读取设备内存中某一数据,读取数据 ...

  8. (57)Linux驱动开发之三Linux字符设备驱动

    1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...

  9. 谈谈Linux字符设备驱动的实现

    @ 目录 字符设备驱动基础 申请设备号 创建设备节点 在驱动中实现操作方法 文件IO调用驱动中的操作 应用程序与驱动的数据交互 内核驱动如何控制外设 控制LED的简单驱动实例 驱动程序的改进 框架复盘 ...

随机推荐

  1. [Vue 牛刀小试]:第十四章 - 编程式导航与实现组件与 Vue Router 之间的解耦

    一.前言 在上一章的学习中,通过举例说明,我们了解了 Vue Router 中命名路由.命名视图的使用方法,以及如何通过 query 查询参数传参,或者是采用 param 传参的方式实现路由间的参数传 ...

  2. HTML行内元素、块级元素、行内块级元素的特点与区别

    元素 HTML 元素指的是从开始标签(start tag)到结束标签(end tag)的所有代码. 元素分类方式 HTML 可以将元素分类方式分为行内元素.块状元素和行内块状元素三种,这三者可以通过设 ...

  3. phpstorm+xdebug手机app调试

    1.安装过程网上搜一下全都是,这里省略. 2.由于debug调试需要去判断cookie中XDEBUG_SESSION,然后去调试.由于app接口请求没法去传,而且就算去传递也很麻烦,还要让app去改动 ...

  4. Django中CBV View的as_view()源码解析

    CBV与FBV路由区别 urlpatterns = [ url(r'^publish/$', views.Publishs.as_view()), # CBV写法 url(r'^publish/$', ...

  5. 戴尔R720安装ESXI系统

    1.U盘安装系统,使用UltraISO制作启动盘 参考地址:https://jingyan.baidu.com/article/5225f26b0bb45fe6fa0908bc.html 2.插上U盘 ...

  6. kali Linux渗透测试技术详解

    kali Linux渗透测试技术详解 下载:https://pan.baidu.com/s/1g7dTFfzFRtPDmMiEsrZDkQ 提取码:p23d <Kali Linux渗透测试技术详 ...

  7. BZOJ 2957:楼房重建(分块)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2957 题意:…… 思路:对于每一个块,维护一个单调递增的斜率(因为小于前面的斜率的话是肯定看不见的) ...

  8. POJ 1113:Wall(凸包)

    http://poj.org/problem?id=1113 Wall Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 346 ...

  9. spring的context:exclude-filter 与 context:include-filter

    1 在主容器中(applicationContext.xml),将Controller的注解打消掉 <context:component-scan base-package="com& ...

  10. 数字IC前后端设计中的时序收敛(三)--Hold违反的修复方法

    本文转自:自己的微信公众号<数字集成电路设计及EDA教程>(二维码见博文底部) 里面主要讲解数字IC前端.后端.DFT.低功耗设计以及验证等相关知识,并且讲解了其中用到的各种EDA工具的教 ...