一、概述

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. Cheatsheet: 2016 07.01 ~ 07.31

    Mobile What to Expect From Swift 3 Web A practical security guide for web developers Gulp Succinctly ...

  2. Cheatsheet: 2016 04.01 ~ 04.30

    .NET String format Setting up Ubuntu for .NET Development ASP.​NET Core and Angular2 - Part 1 - Upda ...

  3. 1000【入门】熟悉一下Online Judge的环境

    var a,b:longint; begin read(a,b); writeln(a+b); end. #include <stdio.h> int main() { int a,b; ...

  4. 如何在自己的窗体(控件)中显示XAF的视图

    Form form = new Form(); DevExpress.ExpressApp.View listView = Application.CreateListView(Application ...

  5. android:layout_weight的真实含义(转)

    首先声明只有在Linearlayout中,该属性才有效.之所以Android:layout_weight会引起争议,是因为在设置该属性的同时,设置android:layout_width为wrap_c ...

  6. spring+task配置

    1.spring+task文件配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=& ...

  7. C# 利用NPOI 实现Excel转html

    public void ExcelToHtml(string fileName, IWorkbook workbook) { ExcelToHtmlConverter excelToHtmlConve ...

  8. 虚拟机EAL: Error reading from file descriptor

    这个是虚拟机安装固有的BUG,代码差异如下: diff --git a/lib/librte_eal/linuxapp/igb_uio/igb_uio.c b/lib/librte_eal/linux ...

  9. jq弹出一个透明小提示窗,然后逐渐消失

      function show_main(content) { var showWindow = '<div id="show_main" style="borde ...

  10. 【转】 C++模板详解

    C++模板 模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数.返回值取得任意类型. 模板是一种对类型进行参数化的工具: 通常有 ...