字符设备驱动0:一个简单但完整的字符设备驱动程序

参考:

linux设备驱动程序之简单字符设备驱动 【很详细,必看】http://www.cnblogs.com/geneil/archive/2011/12/03/2272869.html

 

//在驱动入口函数中,使用register_chrdev添加字符设备驱动:

#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>#define DEVICE_NAME "leds" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */ #define LED_MAJOR 231 /* 主设备号 */static struct class *leds_class; static struct class_device *leds_class_devs[4];/* bit0<=>D10, 0:亮, 1:灭* bit1<=>D11, 0:亮, 1:灭* bit2<=>D12, 0:亮, 1:灭*/ static char leds_status = 0x0; static DECLARE_MUTEX(leds_lock); // 定义赋值//static int minor; static unsigned long gpio_va;#define GPIO_OFT(x) ((x) - 0x56000000) #define GPFCON (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000050)))//oo00:GPFCON 0x56000050 R/W 配置端口F的引脚 #define GPFDAT (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000054)))//oo00:gpio_va + 0x54 ,把物理地址0x56000054映射为虚拟地址GPFDAT。 //led驱动中,要操作io口,必须要把物理地址映射为虚拟地址。/* 应用程序对设备文件/dev/leds执行open(...)时,* 就会调用s3c24xx_leds_open函数*/ static int s3c24xx_leds_open(struct inode *inode, struct file *file) {int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);switch(minor){case 0: /* /dev/leds */{// 配置3引脚为输出//s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);GPFCON &= ~(0x3<<(4*2)); //oo00:这里GPFCON是虚拟地址,在驱动模块开始的时候,这个虚拟地址已经通过宏定义 #define GPFCON (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000050)))被映射到物理地址GPFCON |= (1<<(4*2));//s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);GPFCON &= ~(0x3<<(5*2));GPFCON |= (1<<(5*2));//s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);GPFCON &= ~(0x3<<(6*2));GPFCON |= (1<<(6*2));// 都输出0//s3c2410_gpio_setpin(S3C2410_GPF4, 0);GPFDAT &= ~(1<<4);//s3c2410_gpio_setpin(S3C2410_GPF5, 0);GPFDAT &= ~(1<<5);//s3c2410_gpio_setpin(S3C2410_GPF6, 0);GPFDAT &= ~(1<<6);down(&leds_lock);leds_status = 0x0;up(&leds_lock);break;}case 1: /* /dev/led1 */{s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);s3c2410_gpio_setpin(S3C2410_GPF4, 0);down(&leds_lock);leds_status &= ~(1<<0);up(&leds_lock);break;}case 2: /* /dev/led2 */{s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);s3c2410_gpio_setpin(S3C2410_GPF5, 0);leds_status &= ~(1<<1);break;}case 3: /* /dev/led3 */{s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);s3c2410_gpio_setpin(S3C2410_GPF6, 0);down(&leds_lock);leds_status &= ~(1<<2);up(&leds_lock);break;}}return 0; }static int s3c24xx_leds_read(struct file *filp, char __user *buff,size_t count, loff_t *offp) {int minor = MINOR(filp->f_dentry->d_inode->i_rdev);char val;switch (minor){case 0: /* /dev/leds */{copy_to_user(buff, (const void *)&leds_status, 1);break;}case 1: /* /dev/led1 */{down(&leds_lock);val = leds_status & 0x1;up(&leds_lock);copy_to_user(buff, (const void *)&val, 1);break;}case 2: /* /dev/led2 */{down(&leds_lock);val = (leds_status>>1) & 0x1;up(&leds_lock);copy_to_user(buff, (const void *)&val, 1);break;}case 3: /* /dev/led3 */{down(&leds_lock);val = (leds_status>>2) & 0x1;up(&leds_lock);copy_to_user(buff, (const void *)&val, 1);break;}}return 1; }static ssize_t s3c24xx_leds_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) {//int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);int minor = MINOR(file->f_dentry->d_inode->i_rdev);char val;copy_from_user(&val, buf, 1);switch (minor){case 0: /* /dev/leds */{s3c2410_gpio_setpin(S3C2410_GPF4, (val & 0x1));s3c2410_gpio_setpin(S3C2410_GPF5, (val & 0x1));s3c2410_gpio_setpin(S3C2410_GPF6, (val & 0x1));down(&leds_lock);leds_status = val;up(&leds_lock);break;}case 1: /* /dev/led1 */{s3c2410_gpio_setpin(S3C2410_GPF4, val);if (val == 0){down(&leds_lock);leds_status &= ~(1<<0);up(&leds_lock);}else{down(&leds_lock);leds_status |= (1<<0);up(&leds_lock);}break;}case 2: /* /dev/led2 */{s3c2410_gpio_setpin(S3C2410_GPF5, val);if (val == 0){down(&leds_lock);leds_status &= ~(1<<1);up(&leds_lock);}else{down(&leds_lock);leds_status |= (1<<1);up(&leds_lock);}break;}case 3: /* /dev/led3 */{s3c2410_gpio_setpin(S3C2410_GPF6, val);if (val == 0){down(&leds_lock);leds_status &= ~(1<<2);up(&leds_lock);}else{down(&leds_lock);leds_status |= (1<<2);up(&leds_lock);}break;}}return 1; }/* 这个结构是字符设备驱动程序的核心* 当应用程序操作设备文件时所调用的open、read、write等函数,* 最终会调用这个结构中指定的对应函数*/ static struct file_operations s3c24xx_leds_fops = {.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */.open = s3c24xx_leds_open,.read = s3c24xx_leds_read,.write = s3c24xx_leds_write, };/** 执行insmod命令时就会调用这个函数*/ static int __init s3c24xx_leds_init(void) //static int __init init_module(void) {int ret;int minor = 0;gpio_va = ioremap(0x56000000, 0x100000);if (!gpio_va) {return -EIO;}printk(DEVICE_NAME "gpio_va = %x\n",gpio_va);/* 注册字符设备* 参数为主设备号、设备名字、file_operations结构;* 这样,主设备号就和具体的file_operations结构联系起来了,* 操作主设备为LED_MAJOR的设备文件时,就会调用s3c24xx_leds_fops中的相关成员函数* LED_MAJOR可以设为0,表示由内核自动分配主设备号*/ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);if (ret < 0) {printk(DEVICE_NAME " can't register major number\n");return ret;} //oo00 :begin : 分配了四个子设备号 minor == 0 1 2 3leds_class = class_create(THIS_MODULE, "leds");if (IS_ERR(leds_class))return PTR_ERR(leds_class);leds_class_devs[0] = class_device_create(leds_class, NULL, MKDEV(LED_MAJOR, 0), NULL, "leds");for (minor = 1; minor < 4; 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]);} //oo00 :end printk(DEVICE_NAME " initialized\n");return 0; }/** 执行rmmod命令时就会调用这个函数*/ static void __exit s3c24xx_leds_exit(void) {int minor;/* 卸载驱动程序 */unregister_chrdev(LED_MAJOR, DEVICE_NAME);for (minor = 0; minor < 4; minor++){class_device_unregister(leds_class_devs[minor]);}class_destroy(leds_class);iounmap(gpio_va); }/* 这两行指定驱动程序的初始化函数和卸载函数 */ module_init(s3c24xx_leds_init); module_exit(s3c24xx_leds_exit);/* 描述驱动程序的一些信息,不是必须的 */ MODULE_AUTHOR("http://www.100ask.net"); MODULE_VERSION("0.1.0"); MODULE_DESCRIPTION("S3C2410/S3C2440 LED Driver"); MODULE_LICENSE("GPL");

 

对应的led应用程序:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>/**  ledtest <dev> <on|off>*/void print_usage(char *file)
{printf("Usage:\n");printf("%s <dev> <on|off>\n",file);printf("eg. \n");printf("%s /dev/leds on\n", file);printf("%s /dev/leds off\n", file);printf("%s /dev/led1 on\n", file);printf("%s /dev/led1 off\n", file);
}int main(int argc, char **argv)
{int fd;char* filename;char val;if (argc != 3){print_usage(argv[0]);return 0;}filename = argv[1];fd = open(filename, O_RDWR);if (fd < 0){printf("error, can't open %s\n", filename);return 0;}if (!strcmp("on", argv[2])){// 亮灯val = 0;write(fd, &val, 1);}else if (!strcmp("off", argv[2])){// 灭灯val = 1;write(fd, &val, 1);}else{print_usage(argv[0]);return 0;}return 0;
}

 

加载模块后,执行”cat /proc/devices”命令看设备名称;// register_chrdev(LED_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);
执行ls /dev/ 命令查看class名称。//class_device_create(leds_class, NULL, MKDEV(LED_MAJOR, minor), NULL, "led%d", minor);


附例:
int major;
static int first_drv_init(void)
{major = register_chrdev(0, "first_drv", &first_drv_fops); // 注册, 告诉内核
firstdrv_class = class_create(THIS_MODULE, "firstdrv");firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);gpfdat = gpfcon + 1;return 0;
}
---------------------------------
# cat /proc/devices
Character devices:
1 mem
2 pty
204 s3c2410_serial
252 first_drv
254 rtc# ls -l /dev
crw-rw----    1 0        0        204,  64 Jan  1 00:56 s3c2410_serial0
crw-rw----    1 0        0        204,  65 Jan  1 00:00 s3c2410_serial1
crw-rw----    1 0        0        204,  66 Jan  1 00:00 s3c2410_serial2
crw-rw----    1 0        0        252,   0 Jan  1 00:44 xyz
-------------------------------------
fd = open("/dev/xyz", O_RDWR);if (fd < 0){printf("can't open!\n");}

 

转载于:https://www.cnblogs.com/mylinux/p/4010908.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/472942.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

同一个项目相互调接口_408计算机网络D3-第二章:网络体系结构与参考模型(上)分层结构-协议-接口-服务...

网络体系结构是从功能上描述计算机网络结构。计算机网络体系结构简称网络体系结构是分层结构&#xff1b;是计算机网络的各层及其协议的集合。每层遵循某个/些网络协议以完成本层功能。分层结构-协议-接口-服务首先就是为什么要分层发送文件前要完成的工作发起通信的计算机必须…

自动摘要

#!/user/bin/python # coding:utf-8 import nltk import numpy import jieba import codecs import os class SummaryTxt: def __init__(self,stopwordspath): # 单词数量 self.N 100 # 单词间的距离 self.CLUSTER_THRESHOLD 5 …

专家 安全_船级社专家组到公司开展安全生产标准化考核

12月17日&#xff0c;船级社专家组一行到公司开展安全生产标准化考核工作&#xff0c;公司党委书记、执行董事曲贝贝&#xff0c;执行总经理(主持生产经营工作)陈飞&#xff0c;执行总经理、安全总监李中华&#xff0c;党委副书记、纪委书记、工会主席刘小丽&#xff0c;总经济…

LeetCode 1750. 删除字符串两端相同字符后的最短长度(双指针)

文章目录1. 题目2. 解题322 / 1676&#xff0c; 19.2%1166 / 8426&#xff0c;13.8%https://leetcode-cn.com/contest/biweekly-contest-45/ranking/ 前两题&#xff1a; LeetCode 1748. 唯一元素的和 LeetCode 1749. 任意子数组和的绝对值的最大值&#xff08;前缀和&#xf…

分词、语法树

######Jieba分词###### import jieba string如果一个文法存在某个句子对应两棵不同的语法树&#xff0c;则称这个文法是二义的 print(string) seg_listjieba.cut(string,cut_allFalse,HMMTrue) seg_str .join(seg_list) ######PCFG句法分析###### from nltk.parse import stan…

Android开发学习笔记-自定义组合控件

为了能让代码能够更多的复用&#xff0c;故使用组合控件。下面是我正在写的项目中用到的方法。 1、先写要组合的一些需要的控件&#xff0c;将其封装到一个布局xml布局文件中。 <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:an…

python基础实例 韦玮 pdf_Python基础实例教程(微课版)

第 1章 初识Python 1 1.1 快速了解Python 2 1.1.1 Python的起源与背景 2 1.1.2 Python的功能 3 1.1.3 Python的优势与特色 4 1.2 在Windows下搭建Python开发环境 6 1.2.1 操作系统的选择 6 1.2.2 在Windows下安装Python 7 1.3 在Linux下搭建Python开发环境 1…

测试是否支持跨域_浅谈跨域威胁与安全

WEB前端中最常见的两种安全风险&#xff0c;XSS与CSRF&#xff0c;XSS&#xff0c;即跨站脚本攻击、CSRF即跨站请求伪造,两者属于跨域安全攻击&#xff0c;对于常见的XSS以及CSRF在此不多谈论&#xff0c;仅谈论一些不太常见的跨域技术以及安全威胁。一、 域域&#xff0c;即域…

LeetCode 1752. 检查数组是否经排序和轮转得到

文章目录1. 题目2. 解题1. 题目 给你一个数组 nums 。 nums 的源数组中&#xff0c;所有元素与 nums 相同&#xff0c;但按非递减顺序排列。 如果 nums 能够由源数组轮转若干位置&#xff08;包括 0 个位置&#xff09;得到&#xff0c;则返回 true &#xff1b;否则&#xf…

linux-3.4.2移植到FL2440上(一)--只是基本移植

1.修改Makefile&#xff1a;ARCH ? armCROSS_COMPILE ? arm-linux-2.修改串口时钟&#xff1a;在/arch/arm/mach-s3c24xx/mach-smdk2440.c改为12Ms3c24xx_init_clocks(12000000);/* by zhutao */3.裁剪内核&#xff1a; │ -> System Type …

ts自动编译声明文件_拥抱 TS:细数选择 TS 的 N 种理由

作者 | 马靖day day up, bye bye bug最近在做一个新项目&#xff0c;技术大佬告知前端要用 TS 。前端小白的我内心疑惑“弱类型语言它不香嘛&#xff0c;为什么选择 TS &#xff1f;” 为了紧随大佬的流星大步&#xff0c;拥抱变化。带着这个疑惑我积(被)极(破)主(营)动(业)点开…

java分治法求数列的最大子段和_Java十大经典排序算法动画解析和 代码实现

排序算法是《数据结构与算法》中最基本的算法之一。排序算法可以分为内部排序和外部排序。内部排序是数据记录在内存中进行排序。而外部排序是因排序的数据很大&#xff0c;一次不能容纳全部的排序记录&#xff0c;在排序过程中需要访问外存。常见的内部排序算法有&#xff1a;…

岭回归预测PM2.5

# -*- coding: utf-8 -*- # File : demo2.py # Author : CJH # Date : 2019/4/9 # Software: PyCharm # Desc : 天气PM2.5预测import csv import numpy as np from numpy import * import matplotlib.pyplot as plt from sklearn import linear_modeltrainingData t…

LeetCode 1753. 移除石子的最大得分(优先队列)

文章目录1. 题目2. 解题2.1 优先队列2.2 脑筋急转弯1. 题目 你正在玩一个单人游戏&#xff0c;面前放置着大小分别为 a​​​​​​、b 和 c​​​​​​ 的 三堆 石子。 每回合你都要从两个 不同的非空堆 中取出一颗石子&#xff0c;并在得分上加 1 分。 当存在 两个或更多 …

基于Spring框架的Shiro配置

http://kdboy.iteye.com/blog/1103794 一、在web.xml中添加shiro过滤器 Xml代码 <!-- Shiro filter--> <filter> <filter-name>shiroFilter</filter-name> <filter-class> org.springframework.web.filter.Delegating…

dat文本导入mysql_mysql学习笔记(九) 增删改查的优化

一、大批量插入数据当使用load命令导入数据的时候&#xff0c;可以适当的提高导入的速度。对于myisam存储引擎的表可以通过下述方法快速的导入大量的数据。Alter table tablename disable keys;Loading dateAlter table tabename enable keys;其中disable keys和enable keys用来…

asp.net接受表单验证格式后再提交数据_如何解析 el-form-renderer 表单渲染器1.14.0...

DEEPEXI 大前端常人道&#xff0c;一入开发深似海&#xff0c;技术学习无止境。在新技术层出不穷的前端开发领域&#xff0c;有一群身怀绝技的开发&#xff0c;他们在钻研前沿技术的同时&#xff0c;也不忘分享他们的成果&#xff0c;回馈社区。下面&#xff0c;就由小水滴带大…

债券收益率预测模型_利率预测模型系列之二:利率预测模型带来的启示

利率预测模型带来的启示在《利率预测模型系列之一&#xff1a;简单的N-S 模型运用》中&#xff0c;我们对收益率曲线预测模型进行了简单介绍&#xff0c;该模型能够给我们提供较好的利率及收益率曲线预测效果。当然&#xff0c;在理论上&#xff0c;还有更多更复杂的利率预测模…

LeetCode 1751. 最多可以参加的会议数目 II(DP + 二分查找)

文章目录1. 题目2. 解题1. 题目 给你一个 events 数组&#xff0c;其中 events[i] [startDayi, endDayi, valuei] &#xff0c;表示第 i 个会议在 startDayi 天开始&#xff0c;第 endDayi 天结束&#xff0c;如果你参加这个会议&#xff0c;你能得到价值 valuei 。 同时给你…

SemEval-2010任务8:成对名词之间的语义关系的多分类

摘要SemEval-2任务8专注于名词对之间语义关系的多分类。 该任务旨在比较语义关系分类的不同方法&#xff0c;并为将来的研究提供标准的测试平台。 本文定义了任务&#xff0c;描述了训练和测试数据及其创建过程&#xff0c;列出了参与的系统&#xff08;10个团队&#xff0c;28…