一、概述

Linux内核就是由各种驱动组成的,内核源码中大约有85%的各种渠道程序的代码。一般来说,编写Linux设备驱动大致流程如下:

1、查看原理图,数据手册,了解设备的操作方法。

2、在内核中找到相近的驱动程序,以它为模板开发。

3、实现驱动的初始化:比如像内核注册这个驱动程序

4、设计要实现的操作:open,close,read,write等

5、实现中断服务(不是必须的)

6、编译该驱动程序到内核中,或insmod命令加载

7、测试驱动程序。

二、驱动程序的加载与卸载

module_init(my_init);
module_exit(my_clearup);

三、字符设备驱动程序主要的数据结构

1、系统调用:应用程序不能直接操作硬件,而是使用统一的接口函数调用硬件驱动程序。这些接口成为系统调用。在库函数中定义了,可以在gilbc的fcntl.h, unistd.h,sys/ioctl.h 等文件找到。open,wirite,read等。

2、数据结构file_operations是在内核中的,在include/linux/fs.h中。定义如下:

/*
* NOTE:
* read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl
* can be called without the big kernel lock held in all filesystems.
*/
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*dir_notify)(struct file *filp, unsigned long arg);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
};

3、设备的主次设备号-=

内核靠这个寻找对应的驱动程序。应用程序在操作设备文件时,Linux系统就会根据设备文件的类型,主设备号在内核中注册的file_operation(对于块设备号是block_device_operations结构),次设备号来分辨它是同类设备中的第几个。

4、注册函数与卸载函数

register_chrdev;unregister_chrdev;

四、LED驱动程序

#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> //定义寄存器
volatile unsigned long *gpfcon=NULL;
volatile unsigned long *gpfdat=NULL; static struct class *myFirD_class;//为了能自动创建mdev
static struct class_device *myFirD_class_dev; //打开
static int myFirD_open(struct inode *inode, struct file *file)
{
printk("myFirD has open\n");
//配置IO口
*gpfcon &= ~((0x3<<(*)) | (0x3<<(*)) | (0x3<<(*)));//相与
*gpfcon |= ((0x1<<(*)) | (0x1<<(*)) | (0x1<<(*)));//相或
return ;
}
//写
static ssize_t myFirD_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 myFirD_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = myFirD_open,
.write = myFirD_write,
};
//需要用函数把结构告诉内核。注册驱动程序
int major; //主设备号
int myFirD_init(void)
{
major=register_chrdev(,"myFirD",&myFirD_fops);//告诉内核
myFirD_class = class_create(THIS_MODULE, "myFirD");//建个类
//设备
myFirD_class_dev = class_device_create(myFirD_class, NULL, MKDEV(major, ), NULL, "xyz");
gpfcon=(volatile unsigned *)ioremap(0x56000050,);
gpfdat = gpfcon + ;;
return ;
}
void myFirD_exit(void)
{
unregister_chrdev(major,"myFirD");//告诉内核 class_device_unregister(myFirD_class_dev);
class_destroy(myFirD_class);
iounmap(gpfcon);
}
module_init(myFirD_init);
module_exit(myFirD_exit);
MODULE_LICENSE("GPL");

五、Makefile文件

KERN_DIR = /work/system/linux-2.6.22.6#内核所在的目录

all:
make -C $(KERN_DIR) M=`pwd` modules clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order obj-m += myFirD.o

字符设备驱动之Led驱动学习记录的更多相关文章

  1. 芯灵思Sinlinx A64 linux 通过设备树写LED驱动(附参考代码,未测试)

    开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 全志A64设备树结构体 #inc ...

  2. linux驱动之LED驱动

    通过之前的学习,了解到linux驱动编写的流程是:先通过注册函数注册我们编写的入口函数,然后在入口函数中获取设备号->注册字符设备->自动创建设备节点->获取设备树信息,最后通过销毁 ...

  3. Linux驱动之LED驱动编写

    从上到下,一个软件系统可以分为:应用程序.操作系统(内核).驱动程序.结构图如下:我们需要做的就是写出open.read.write等驱动层的函数.一个LED驱动的步骤如下: 1.查看原理图,确定需要 ...

  4. 【Linux 驱动】简单字符设备驱动架构(LED驱动)

    本文基于icool210开发板,内核版本:linux2.6.35: 驱动代码: (1)头文件:led.h #ifndef __LED_H__ #define __LED_H__ #define LED ...

  5. 字符设备驱动之LED驱动

    实现 ①编写驱动框架 ②编写硬件实现代码 (在Linux系统下操作硬件,需要操作虚拟地址,因此需要先把物理地址转换为虚拟地址 ioremap()) 如何实现单个灯的操作: 实现方法之一--操作次设备号 ...

  6. linux驱动之LED驱动_1

    步骤: 1.框架 2.完好硬件的操作: a.看原理图.引脚 b.看2440手冊 c.写代码: IO口须要用ioremap映射 我的板子电路例如以下所看到的 1.配置GPBCON 寄存器,配置输出   ...

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

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

  8. Linux 驱动框架---cdev字符设备驱动和misc杂项设备驱动

    字符设备 Linux中设备常见分类是字符设备,块设备.网络设备,其中字符设备也是Linux驱动中最常用的设备类型.因此开发Linux设备驱动肯定是要先学习一下字符设备的抽象的.在内核中使用struct ...

  9. Linux字符设备驱动框架

    字符设备是Linux三大设备之一(另外两种是块设备,网络设备),字符设备就是字节流形式通讯的I/O设备,绝大部分设备都是字符设备,常见的字符设备包括鼠标.键盘.显示器.串口等等,当我们执行ls -l ...

随机推荐

  1. SYSTick 定时器

        CM3 内核的处理器,内部包含了一个 SysTick 定时器,(SysTick 的时钟源自 HCLK 的 8 分频,8个系统时钟周期systick跳一个,即8*1/72M=1/9 us)Sys ...

  2. MySQL索引原理及慢查询优化 转载

    原文地址: http://tech.meituan.com/mysql-index.html MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能 ...

  3. java贪吃蛇

    这个贪吃蛇有很多功能没有实现,比如说穿墙(本来可以实现,但是穿墙后,就会出现坐标混乱,吃不到食物了),还有碰到自己的身体死亡的情况也没有实现,现在我知道如何判断是否碰到身体,但是,我不知道,如何处理碰 ...

  4. [转载]自己编写 php 在线问卷调查程序

        <html> <head> <title>问卷调查</title> <meta http-equiv="Content-Type ...

  5. c#_1:后台post请求

    1:aspx内容 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Push.as ...

  6. spring 注解重复(防重复请求)

    1.配置拦截器 spring-mvc.xml <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/ ...

  7. public private, protect. 以及继承。 草稿。

    #include <iostream>#include <thread>#include <memory> // | 父类的public成员 | 父类的protec ...

  8. (转)pymysql 连接mysql数据库---不支持中文解决

    往数据库里插入中文时出现异常:UnicodeEncodeError: 'latin-1' codec can't encode characters 就是编码的问题,pymysql默认的编码是lati ...

  9. easyui combobox 左匹配模糊查询

    之前一直不知道,easyui 的combobox还有从左匹配查询显示数据的. 样式是这样的:(这是数据是已经存在下拉列表里的) 在这样操作的时候,遇到了一个问题.(其实也不算问题的). 就是操作人员在 ...

  10. 使用Kylin构建企业大数据分析平台的4种部署方式

    本篇博客重点介绍如何使用Kylin来构建大数据分析平台.根据官网介绍,其实部署Kylin非常简单,称为非侵入式安装,也就是不需要去修改已有的 Hadoop大数据平台.你只需要根据的环境下载适合的Kyl ...