Linux 字符驱动程序(一)
Linux 字符驱动程序(一)
一般来说。字符设备不支持随机訪问。
在系统和驱动程序之间定义有专门的数据结构进行数据的传递。系统里支持对发送数据和接收数据的缓存,提高流量控制机制。提供对多协议的支持。
或者在编写驱动程序时动态的获取主设备号以及动态产生设备节点。
#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>
//相关的头文件,我们仿照其它模块载入就可以。
#define DEVICE_NAME "leds" /* 载入模式后。运行”cat /proc/devices”命令看到的设备名称 */
static struct class *leds_class;
static struct class_device * leds_class_devs[4];
volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;
//应用程序运行open时调用该函数。
static int first_drv_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);
switch(minor)
{
case 0: /* /dev/leds */
{
*gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2)));
*gpfcon |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2)));
break;
}
case 1: /* /dev/led1 */
{
*gpfcon &= ~((0x3<<(4*2));
*gpfcon |= ((0x1<<(4*2));
break;
}
case 2: /* /dev/led2 */
{
*gpfcon &= ~ (0x3<<(5*2));
*gpfcon |= (0x1<<(5*2));
break;
}
case 3: /* /dev/led3 */
{
*gpfcon &= ~(0x3<<(6*2));
*gpfcon |= (0x1<<(6*2));
break;
}
}
return 0;
}
//应用程序运行write时调用该函数;
static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
int val;
copy_from_user(&val, buf, count);
switch (minor)
{
case 0: /* /dev/leds */
{
if (val == 1)
{
// 点灯
*gpfdat &= ~((1<<4) | (1<<5) | (1<<6));
}
else
{
// 灭灯
*gpfdat |= (1<<4) | (1<<5) | (1<<6);
}
break;
}
case 1: /* /dev/led1 */
{
if (val == 1)
{
// 点灯
*gpfdat &= ~(1<<4);
}
else
{
// 灭灯
*gpfdat |= (1<<4);
}
break;
}
case 2: /* /dev/led2 */
{
if (val == 1)
{
// 点灯
*gpfdat &= ~(1<<5);
}
else
{
// 灭灯
*gpfdat |= (1<<5);
}
break;
}
case 3: /* /dev/led3 */
{
if (val == 1)
{
// 点灯
*gpfdat &= ~(1<<6);
}
else
{
// 灭灯
*gpfdat |= (1<<6);
}
break;
}
}
return 0;
}
//驱动程序与内核的接口;
static struct file_operations first_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自己主动创建的__this_module变量 */
.open = first_drv_open,
.write = first_drv_write,
};
int major; //记录动态获取的设备号
* 运行insmod命令时就会调用这个函数
*/
static int first_drv_init(void)
{
int minor = 0; //次设备号
printk(DEVICE_NAME " can't register major number\n");
return major;
}
leds_class = class_create(THIS_MODULE, "leds"); // 产生节点类,以leds_class声明的均为同一种设备
if (IS_ERR(leds_class))
return PTR_ERR(leds_class);
leds_class_devs[0] = class_device_create(leds_class, NULL, MKDEV(major, 0), NULL, "leds");
//产生不同的从设备,并以不同的名字挂接在/dev文件夹下。
for (minor = 1; minor < 4; minor++)
{
leds_class_devs[minor] = class_device_create(leds_class, NULL, MKDEV(major, minor), NULL, "led%d", minor);
if (unlikely(IS_ERR(leds_class_devs[minor])))
return PTR_ERR(leds_class_devs[minor]);
}
gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);//控制寄存器地址
gpfdat = gpfcon + 1; // 0x56000054 //数据寄存器地址。
printk(DEVICE_NAME " initialized\n");
return 0;
}
/*
* 运行rmmod命令时就会调用这个函数
*/
static void first_drv_exit(void)
{
int minor;
/* 卸载驱动程序 */
unregister_chrdev(major, DEVICE_NAME);
for (minor = 0; minor < 4; minor++)
{
class_device_unregister(leds_class_devs[minor]);
}
class_destroy(leds_class);
iounmap(gpfcon);
}
module_init(first_drv_init);
module_exit(first_drv_exit);
/* 描写叙述驱动程序的一些信息。不是必须的 */
MODULE_AUTHOR("http://www.100ask.net");
MODULE_VERSION("0.1.0");
MODULE_DESCRIPTION("LED Driver");
MODULE_LICENSE("GPL");
我们写应用程序时。打开对应的设备/dev/leds , /dev/led1, /dev/led2, /dev/led3 向当中写1,0 就能够控制所有led或者某个led的亮灭.
版权声明:本文博主原创文章,博客,未经同意不得转载。
Linux 字符驱动程序(一)的更多相关文章
- linux字符驱动程序结构
linux内核为字符设备的驱动程序设计,提供了一些数据结构,和函数,供开发人员调用,将设备驱动程序注册到内核去.现代操作系统几乎都不直接和硬件通信,而是通过定义的接口,是硬件厂商自己来开发符合标准某个 ...
- 简单linux字符设备驱动程序
本文代码参考<LINUX设备驱动程序>第三章 字符设备驱动程序 本文中的“字符设备”是一段大小为PAGE_SIZE的内存空间 功能:向字符设备写入字符串:从字符设备读出字符串 代码: 1. ...
- ARM Linux字符设备驱动程序
1.主设备号和次设备号(二者一起为设备号): 一个字符设备或块设备都有一个主设备号和一个次设备号.主设备号用来标识与设备文件相连的驱动程序,用来反 映设备类型.次设备号被驱动程序用来辨别操作的是哪个 ...
- 浅析Linux字符设备驱动程序内核机制
前段时间在学习linux设备驱动的时候,看了陈学松著的<深入Linux设备驱动程序内核机制>一书. 说实话.这是一本非常好的书,作者不但给出了在设备驱动程序开发过程中的所须要的知识点(如对 ...
- Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】
本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...
- Smart210学习记录----beep linux字符设备驱动
今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...
- linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)
原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...
- 【转】linux设备驱动程序中的阻塞机制
原文网址:http://www.cnblogs.com/geneil/archive/2011/12/04/2275272.html 阻塞与非阻塞是设备访问的两种方式.在写阻塞与非阻塞的驱动程序时,经 ...
- Linux 字符设备驱动模型
一.使用字符设备驱动程序 1. 编译/安装驱动 在Linux系统中,驱动程序通常采用内核模块的程序结构来进行编码.因此,编译/安装一个驱动程序,其实质就是编译/安装一个内核模块 2. 创建设备文件 通 ...
随机推荐
- 2012天津C题
行李箱上的密码锁大家都知道, 现在给我们长度为n(n<=1000)的两个密码串,每次可以转动连续的1->3个字符1格,问最少多少次可以使得第一个串变成第二个串 经历了搜索,贪心,的思路后, ...
- Microsoft Build 2016
Microsoft Build 2016 Day 1 记录 去年今日:Microsoft Build 2015 汇总 今年的 Bulid 时间是 3.30-4.1,第一天的主角主要是 Window ...
- STM32W108无线传感器网络嵌入式uCOS-II的移植及实时环境监測
基于STM32W108无线开发板,将ucos-ii v2.86内核移植到其上,并加入用户任务.实现对温湿度.超声波.声音.光敏等传感器的控制及实时数据採集. 14.1开发环境说明 硬件:STM32W1 ...
- 新型I/O架构引领存储之变(四)
新型I/O架构引领存储之变(四) 作者:廖恒 应对挑战--商务及技术考量 本文前面的部分分析了砖块模式与生俱来的总拥有成本(TCO)过高的问题.为了战胜这一挑战,超大规模数据中心的运营者须要从两个不同 ...
- LeetCode18:4Sum
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = tar ...
- SIP基本呼叫
我们首先来看下主要的呼叫流程. INVITEsip:69690067@beijing.chinamobile.com;user=phone SIP/2.0 From:"+8610696900 ...
- IM设计与实现的系统模块的聊天记录
到非常多开发IM系统的朋友都想实现聊天记录存储和查询这一不可或缺的功能,这里我就把自己前段时间为傲瑞通(OrayTalk)开发聊天记录模块的经验分享出来,供须要的朋友參考下. 一.整体设计 1.存储位 ...
- 谈论高并发(二十二)解决java.util.concurrent各种组件(四) 深入了解AQS(二)
上一页介绍AQS其基本设计思路以及两个内部类Node和ConditionObject实现 聊聊高并发(二十一)解析java.util.concurrent各个组件(三) 深入理解AQS(一) 这篇说一 ...
- POJ---2243 Knight Moves 使用A*算法的广度优先搜索
题目链接:http://poj.org/problem?id=2243 启发式搜索:启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标.这样可以省 ...
- div 浮动框