14、字符驱动编程模型

字符驱动编程模型

上面就是内核的cdev的结构。他只有6个成员。有一些是内核自己回去用的,有一些是我们程序员要去用的。例如:count,表明设备有几个可以用。例如,我的开发板支持三个串口。所以count=3.还有设备号:查看设备文件:

我们从前面知道,我们是通过字符设备文件来访问我们的字符设备驱动的。两者是通过主设备号来建立联系的。

一个主设备好可以对应多个此设备号。他们是同一类型的设备。驱动程序就是通过次设备号来区分是串口1还是串口2的

设备号的操作

设备号分配

设备号-注销

这是一个很重要的结构。

上面的方法,存在很多新的类型:

F_pos用来保存读写指针的位置

驱动操作方法:

接下来我们来分析前面的memdev.c:

#include <linux/module.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/cdev.h>

#include <asm/uaccess.h>

int dev1_registers[5];

int dev2_registers[5];

struct cdev cdev;

dev_t devno;

/*文件打开函数*/

int mem_open(struct inode *inode, struct file *filp)

{

/*获取次设备号*/

int num = MINOR(inode->i_rdev);

if (num==0)

filp->private_data = dev1_registers;

else if(num == 1)

filp->private_data = dev2_registers;

else

return -ENODEV; //无效的次设备号

return 0;

}

/*文件释放函数*/

int mem_release(struct inode *inode, struct file *filp)

{

return 0;

}

/*读函数*/

static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)

{

unsigned long p = *ppos;

unsigned int count = size;

int ret = 0;

int *register_addr = filp->private_data; /*获得设备的寄存器地址*/

/*判断读位置是否有效*/

if (p >= 5*sizeof(int))

return 0;

if (count > 5*sizeof(int) - p)

count = 5*sizeof(int) - p;

/*读取数据到用户空间*/

if (copy_to_user(buf, register_addr+p, count))

{

ret = -EFAULT;

}

else

{

*ppos += count;

ret = count;

}

return ret;

}

/*写函数*/

static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)

{

unsigned long p = *ppos;

unsigned int count = size;

int ret = 0;

int *register_addr = filp->private_data; /*获取设备的寄存器地址*/

/*分析和获取有效的写长度*/

if (p >= 5*sizeof(int))

return 0;

if (count > 5*sizeof(int) - p)

count = 5*sizeof(int) - p;

/*从用户空间写入数据*/

if (copy_from_user(register_addr + p, buf, count))

ret = -EFAULT;

else

{

*ppos += count;

ret = count;

}

return ret;

}

/* seek文件定位函数*/

static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)

{

loff_t newpos;

switch(whence) {

case SEEK_SET:

newpos = offset;

break;

case SEEK_CUR:

newpos = filp->f_pos + offset;

break;

case SEEK_END:

newpos = 5*sizeof(int)-1 + offset;

break;

default:

return -EINVAL;

}

if ((newpos<0) || (newpos>5*sizeof(int)))

return -EINVAL;

filp->f_pos = newpos;

return newpos;

}

/*文件操作结构体*/

static const struct file_operations mem_fops =

{

.llseek = mem_llseek,

.read = mem_read,

.write = mem_write,

.open = mem_open,

.release = mem_release,

};

/*设备驱动模块加载函数*/

static int memdev_init(void)

{

/*初始化cdev结构*/

cdev_init(&cdev, &mem_fops);

/* 注册字符设备*/

alloc_chrdev_region(&devno, 0, 2, "memdev");

cdev_add(&cdev, devno, 2);

}

/*模块卸载函数*/

static void memdev_exit(void)

{

cdev_del(&cdev); /*注销设备*/

unregister_chrdev_region(devno, 2); /*释放设备号*/

}

MODULE_LICENSE("GPL");

module_init(memdev_init);

module_exit(memdev_exit);

相关信息:

时间: 2024-10-10 11:34:28

14、字符驱动编程模型的相关文章

at91 linux 4.1.0下dts驱动编程模型

下面的这个驱动文件at91_keyled.c在Atmel提供的linux-at91-linux4sam_5.3下实现了按键控制LED的亮灭过程,通过这个简单的驱动描述了基于DTS的驱动开发模型以及Linux内核里的GPIO相关的操作函数. 1 /********************************************************************************* 2 * Copyright: (C) 2016 Guo Wenxue<[email pro

Linux的I/O模式、事件驱动编程模型

大纲: (1)基础概念回顾 (2)Linux的I/O模式 (3)事件驱动编程模型 (4)select/poll/epoll的区别和Python示例 网络编程里常听到阻塞IO.非阻塞IO.同步IO.异步IO等概念,总听别人装13不如自己下来钻研一下.不过,搞清楚这些概念之前,还得先回顾一些基础的概念. 1.基础知识回顾 注意:咱们下面说的都是Linux环境下,跟Windows不一样哈~~~ 1.1 用户空间和内核空间 现在操作系统都采用虚拟寻址,处理器先产生一个虚拟地址,通过地址翻译成物理地址(内

嵌入式linux驱动开发之点亮led未遂(驱动编程思想之初体验)

有了上两篇文章的基础,我们就可以开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的住,不然真像一些人说的,学了一年嵌入式感觉还没找到门. 另外实践很重要,一年多以前就知道了arm,那时整天用单片机的思维去yy着arm,直到前段时间弄来一块arm板,烧上linux系统后才知道,坑呀!根本不是那回事,所以实践是学习计算机类最重要的基本素质,如果整天看书,那基本上

(转)Windows驱动编程基础教程

版权声明 本书是免费电子书. 作者保留一切权利.但在保证本书完整性(包括版权声明.前言.正文内容.后记.以及作者的信息),并不增删.改变其中任何文字内容的前提下,欢迎任何读者 以任何形式(包括各种格式的文档)复制和转载本书.同时不限制利用此书赢利的行为(如收费注册下载,或者出售光盘或打印版本).不满足此前提的任何转载. 复制.赢利行为则是侵犯版权的行为. 发现本书的错漏之处,请联系作者.请不要修改本文中任何内容,不经过作者的同意发布修改后的版本. 作者信息 作者网名楚狂人.真名谭文.在上海从事W

linux驱动初探之字符驱动

关键字:字符驱动.动态生成设备节点.helloworld linux驱动编程,个人觉得第一件事就是配置好平台文件,这里以字符设备,也就是传说中的helloworld为例~ 此驱动程序基于linux3.0的内核,exynos4412开发板. 首先,打开平台文件,此开发板的平台文件是arch\arm\mach-exynos\mach-itop4412.c,不同平台位置是不一样的. 申明一下设备信息,这里以编译进kernel为例 1 #ifdef CONFIG_HELLO_CHAR_CTL 2 str

8天玩转并行开发——第六天 异步编程模型

在.net里面异步编程模型由来已久,相信大家也知道Begin/End异步模式和事件异步模式,在task出现以后,这些东西都可以被task包装 起来,可能有人会问,这样做有什么好处,下面一一道来. 一: Begin/End模式 1: 委托 在执行委托方法的时候,我们常常会看到一个Invoke,同时也有一对你或许不常使用的BeginInvoke,EndInvoke方法对,当然Invoke方法 是阻塞主线程,而BeginInvoke则是另开一个线程. 1 class Program 2 { 3 sta

第6章 Android驱动编程

第6章  Android驱动编程 通过介绍本章设备驱动.字符设备驱动编程.GPIO驱动程序实例和4*4扫描键盘驱动等内容,熟练掌握了Android驱动编程.Android内核内核模块编程中包括设备驱动和内核模块.模块相关命令.Android内核内核模块编程和内核模块实例程序.Android内核中采用可加载的模块化设计,一般情况下编译的Android内核是支持可插入式模块的,也就是将最基本的核心代码编译在内核中.模块相关命令中lsmod列出了当前系统中加载的模块,rmmood用于当前模块卸载,in

【收藏转】WCF后传系列(9):深度通道编程模型Part 2—实例篇

引言 从本质上说,WCF是一个通信服务框架,它允许我们使用不同的传输协议,使用不同的消息编码形式,跟不同的WS-*系列规范交互,而所有这些细节都是由通道堆栈来处理的.在<WCF专题系列(8):深度通道编程模型Part 1—设计篇>中,对于WCF中的通道模型有了深入的认识,本文中,我将通过实例来说明在通道模型中,服务端是如何接收消息,客户端是如何发送消息的. 服务端通道 本文将不使用WCF的编程模型,而直接利用通道模型来进行通信,这样有助于我们更进一步加深对服务端处理消息的认识,在服务端侦听并接

Linux内核驱动编程

Linux内核驱动编程 2015-02-12 驱动程序基础的东西这儿就不罗嗦了,百度上有更好的资料,此处我们只是注重实际用处. 下面我们开始写程序: 一.初步helloword程序 首先是来一个简单的hello. hello.c代码: 1 /****************************** 2 3 the first program 4 5 Hello World! 6 7 ******************************/ 8 9 #include <linux/mod