字符设备驱动(一)---led
一、总体架构

二、硬件电路
1.硬件原理图


2.寄存器配置

三、代码编写
写linux的设备驱动操作的是系统的虚拟地址,并不是像裸机程序一样操作的是物理地址。
物理地址要映射成虚拟地址,就要用到ioremap函数,用来把物理地址映射成虚拟地址。
3.1 确定主设备号
执行命令 cat proc/devices 可以查看到已经用了的主设备号,给自己的设备定义设备号的时候,可以选用没有被设备使用的主设备号。或者可以写0,让系统自动给我们的设备分配主设备号。
3.2 设备节点的创建方法
a. 手动创建

b. 自动创建
应用程序里面应用udev机制
mdev机制:mdev会根据系统的信息,sys目录下有很多系统的信息。注册一个驱动程序的时候,会在此目录下生成设备的信息,mdev可以根据设备的信息自动创建设备节点。


3.3 源码
/*
* =====================================================================================
* Filename: led.c
* Description:
* Version: 1.0
* Created: 2017年05月22日 11时40分23秒
* Author: YOUR NAME (),
* Organization:
* =====================================================================================
*/ #include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/class.h>
#include <linux/io.h> /* 1.建立模块
* 1.1 模块初始化模板
* 1.1.1 映射寄存器
* 1.1.2 注册设备驱动,告诉内核
* 1.1.1.1 主设备号
* 1.1.3 设备类的建立
* 1.1.1.2.1 创建变量:设备类和设备
* 1.1.1.2.2 创建设备类
* 1.1.1.2.3 在设备类下创建设备
* 1.2 模块退出模板
*
* 2.建立文件操作
* 2.1 文件打开和关闭函数
* 2.1.1 文件打开函数
* 2.2 文件读写函数
* 2.2.1 文件读函数
* 2.2.2 文件写函数
* 2.2.2.1 设置GPIO引脚输出的数据
* 2.2.2.1.1 从用户空间读取数据
* 2.3 创建文件操作结构体
*/ #define DEVICE_NAME "leds" /* 加载模式后,执行"cat /proc/devices"命令看到设备的名称 */
#define LED_MAJOR 231 /* 主设备号 */
static unsigned long gpio_va; //次设备号 /* 1.1.1.2.1 创建变量:设备类和设备 */
static struct class *leds_class; //创建led类
static struct class_device *leds_class_devs[];//在led类下面创建设备 static char leds_status = 0x0;
static DECLARE_MUTEX(leds_lock); //定义赋值 //volatile unsigned long *gpfcon = NULL;
//volatile unsigned long *gpfdat = NULL;
#define GPIO_OFT(x) ((x) - 0x56000000)
#define GPFCON (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000050)))
#define GPFDAT (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000054))) /* 2.1.1 文件打开函数 */
static int led_open(struct inode *inode, struct file *filp)
{
int minor = MINOR(inode->irdev);//获取次设备号 switch(minor)
{
case :
GPFCON &= ~((0x3 << ( * )) | (0x3 << ( * )) | (0x3 << ( * )));
GPFCON |= ((0x1 << ( * )) | (0x1 << ( * )) | (0x1 << ( * ))); //初始化状态:LED灯全亮,gpf引脚输出0
GPFDAT &= ~((<<) | (<<) | (<<)); down(&leds_lock);
leds_status = 0x0;
up(&leds_lock);
break;
case :
GPFCON &= ~(0x3 <<( * ));
GPFCON |= ( << ( * )); //初始化状态:LED4亮,gpf4引脚输出0
GPFDAT &= ~( << ); down(&leds_lock);
leds_status &= ~( << );
up(&leds_lock);
break;
case :
GPFCON &= ~(0x3 << ( * ));
GPFCON |= ( << ( * )); GPFDAT &= ~( << ); down(&leds_lock);
leds_status &= ~( << );
up(&leds_lock);
break;
case :
GPFCON &= ~(0x3 << ( * ));
GPFCON |= ( << ( * )); GPFDAT &= ~( << ); down(&leds_lock);
leds_status &= ~( << );
up(&leds_lock);
break;
} return ;
} /* 2.2.1 文件读函数 */
static ssize_t led_read(struct file *filp, char __user *buff, ssize_t count, loff_t *oops)
{
int minor = MINOR(filp->f_dentry->d_inode->i_rdev);//获取次设备号
char val; switch(minor)
{
case :
copy_to_user(buff, (const void *)&leds_status, );
break;
case :
down(&leds_lock);
val = leds_status & 0x1;
up(&leds_lock);
copy_to_user(buff, (const void *)&val, );
break;
case :
down(&leds_lock);
val = (leds_status>>) & 0x1;
up(&leds_lock);
copy_to_user(buff, (const void *)&val, );
break;
case :
down(&leds_lock);
val = (leds_status>>) & 0x1;
up(&leds_lock);
copy_to_user(buff, (const void *)&val, );
break;
}
return ;
} /* 2.2.2 文件写函数 */
static ssize_t led_wirte(struct file *filp, const char __user *buff, ssize_t count, loff_t *oops)
{
int minor = MINOR(file->fdentry->d_inode->i_rdev);
char val; /* 2.2.2.1 设置GPIO引脚输出 */
/* 2.2.2.1.1 从用户空间读取设置的数据 */
copy_from_user(&val, buf, conut); switch(minor)
{
case :
if ( == val) //亮灯
GPFDAT &= ~(( << ) | ( << ) | ( << ));
else//灭灯
GPFDAT |= ( << ) | ( << ) | ( << );
down(&leds_lock);
leds_status = val;
up(&leds_lock);
break;
case :
if (val == )
{
GPFDAT &= ~(<<);
down(&leds_lock);
leds_status &= ~(<<);
up(&leds_lock);
}
else
{
GPFDAT |= ( << );
down(&leds_lock);
leds_status |= (<<);
up(&leds_lock);
}
break;
case :
if (val == )
{
GPFDAT &= ~( << );
down(&leds_lock);
leds_status &= ~( << );
up(&leds_lock);
}
else
{
GPFDAT |= ( << );
down(&leds_lock);
leds_status |= ( << );
up(&leds_lock);
}
break;
case :
if(val == )
{
GPFDAT &= ~( << );
down(&leds_lock);
leds_status &= ~( << );
up(&leds_lock);
}
else
{
GPFDAT |= ( << );
down(&leds_lock);
leds_status |= ( << );
up(&leds_lock);
}
break;
} return ;
} struct file_operations led_drv_fops = {
.owner = THIS_MODULE;
.open = led_open;
.release = led_release;
.read = led_read;
.write = led_wirte;
} /* 1.1 模块初始化函数 */
static int __init led_init(void)
{
int ret;
int minor = ; /* 1.1.1 映射寄存器 */
gpio_va = ioremap(0x56000000, 0x100000);
if (!gpio_va) {
return -EIO;
} /* 1.1.2 注册字符设备,将主设备号与file_operations结构联系起来 */
/* LED_MAJOR可以设为0,表示由内核自动分配主设备号 */
ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &led_drv_fops);
if (ret < ) {
printk(DEVICE_NAME " can't register major number!!!\n");
return ret;
} /* 1.1.3 设备类的创建 */
leds_class = class_create(THIS_MODULE, "leds");
if (IS_ERR(leds_class))
return PTR_ERR(leds_class); /* 1.1.4 在leds类下面创建一个设备 */
/* mdev 会自动创建一个/dev/leds 设备节点 */
leds_class_devs[] = class_device_create(leds_class, NULL, MKDEV(LED_MAJOR, ), NULL, "leds");
if (unlikely(IS_ERR(leds_class_devs[])))
return PTR_ERR(leds_class_devs[]);
for(minor = ; minor < ; minor++)
{
leds_class_devs[minor] = class_device_create(leds_class, NULL, MKDEV(LED_MAJOR, minor), NULL, "led%d", minor);
if (unlikely(IS_ERR(leds_class_devs[minor])))
return PTR_ERR(leds_class_devs[minor]);
} printk(DEVICE_NAME " initialized\n");
return ;
} /* 1.2 模块退出函数 */
static void __exit led_exit(void)
{
int minor;
for(minor = ; minor < ; minor++)
{
class_device_unregister(leds_class_devs[minor]);
}
class_destroy(leds_class);
unregister_chrdev(LED_MAJOR, DEVICE_NAME);//卸载
iounmap(gpfcon); return ;
} module_init(led_init);//定义一个结构体,结构体内有一个函数指针,指向led_init这个入口函数
module_exit(led_exit); MODULE_LICENSE("Dual BSD/GPL");
字符设备驱动(一)---led的更多相关文章
- 字符设备驱动之Led驱动学习记录
一.概述 Linux内核就是由各种驱动组成的,内核源码中大约有85%的各种渠道程序的代码.一般来说,编写Linux设备驱动大致流程如下: 1.查看原理图,数据手册,了解设备的操作方法. 2.在内核中找 ...
- 【Linux 驱动】简单字符设备驱动架构(LED驱动)
本文基于icool210开发板,内核版本:linux2.6.35: 驱动代码: (1)头文件:led.h #ifndef __LED_H__ #define __LED_H__ #define LED ...
- 字符设备驱动之LED驱动
实现 ①编写驱动框架 ②编写硬件实现代码 (在Linux系统下操作硬件,需要操作虚拟地址,因此需要先把物理地址转换为虚拟地址 ioremap()) 如何实现单个灯的操作: 实现方法之一--操作次设备号 ...
- fl2440 platform总线led字符设备驱动
首先需要知道的是,设备跟驱动是分开的.设备通过struct device来定义,也可以自己将结构体封装到自己定义的device结构体中: 例如:struct platform_device: 在inc ...
- 嵌入式Linux驱动学习之路(十)字符设备驱动-my_led
首先贴上代码: 字符设备驱动代码: /** *file name: led.c */#include <linux/sched.h> #include <linux/signal.h ...
- 深入理解Linux字符设备驱动
文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...
- Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】
本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...
- 【转】linux设备驱动程序之简单字符设备驱动
原文网址:http://www.cnblogs.com/geneil/archive/2011/12/03/2272869.html 一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用 ...
- Linux字符设备驱动
一.字符设备基础 字符设备 二.字符设备驱动与用户空间访问该设备的程序三者之间的关系 三.字符设备模型 1.Linux内核中,使用 struct cdev 来描述一个字符设备 动态申请(构造)cdev ...
- 字符设备驱动1:新的方式添加cdev + 在open函数中将文件私有数据指向设备结构体
本例中,驱动入口处,使用cdev_add添加驱动,这点也可与字符设备驱动0:一个简单但完整的字符设备驱动程序对比一下. 另外主要讲xx_open实现文件私有数据指向设备结构体. 引子: 偶然看到,在j ...
随机推荐
- cf366C Dima and Salad (dp)
是一个01分数规划的形式,只不过已经帮你二分好了. 把b乘过去,再减回来,找和等于0的a的最大值就行了 #include<bits/stdc++.h> #define pa pair< ...
- bootstrap学习一
bootstrap学习 一.css概览: 1.使用HTML5标准,<!DOCTYPE html>. 2.移动设备优先: <meta name="viewport" ...
- staitc
一.static和非static变量 1. static 修饰的变量称为类变量或全局变量或成员变量,在类被加载的时候成员变量即被初始化,与类关联,只要类存在,static变量就存在.非static修饰 ...
- linux复制文件到一个不存在的文件夹
复制文件到一个不存在的文件夹时,会报错 cp -f aaa /home/admin/.m2/cp: 无法创建普通文件"/home/admin/.m2/": 是一个目录 解决的方式: ...
- python 当前时间获取方法
1.先导入库:import datetime 2.获取当前日期和时间:now_time = datetime.datetime.now() 3.格式化成我们想要的日期:strftime() 比如:“2 ...
- 4招搞定项目年终总结,还有9大PPT模板免费送
作为一名合格的项目经理 一到年末,我们的头等大事就来了 那就是写项目年终总结和计划 但是………初入这行的项目经理有点犯难,因为 不 会 写 不用怕,小编送你年终总结秘籍和好看的PPT模板 先来看秘 ...
- Spring3 (事务管理)
简介: 1.事务管理.2.整合Junit.3.整和Web 1 事务管理 1.1 回顾事务 l 事务:一组业务操作ABCD,要么全部成功,要么全部不成功. l 特性:ACID 原子性 ...
- STM32F4 ------ RTC
如果只执行 HAL_RTC_GetTime(),读取完后时间不再跑 HAL_RTC_GetTime() 和 HAL_RTC_GetDate()
- 爬虫之requests请求库高级应用
1.SSL Cert Verification #证书验证(大部分网站都是https) import requests respone=requests.get('https://www.12306. ...
- python自动化开发-[第七天]-面向对象
今日概要: 1.继承 2.封装 3.多态与多态性 4.反射 5.绑定方法和非绑定方法 一.新式类和经典类的区别 大前提: 1.只有在python2中才分新式类和经典类,python3中统一都是新式类 ...