Linux下驱动开发

Linux下驱动开发

1.简介

  驱动,是指驱动计算机里软件的程序。驱动程序全称设备驱动程序,是添加到操作系统中的特殊程序,其中包含有关硬件设备的信息。驱动程序是操作系统与硬件连接的桥梁。
  设备驱动最通俗的解释就是“驱使硬件设备行动”。驱动与底层硬件直接打交道,按照硬件设备的具体工作方式,读写设备的寄存器,完成设备的轮询、中断处理、DMA通信,进行物理内存向虚拟内存的映射等,最终让通信设备能收发数据,让显示设备能显示文字和画面,让存储设备能记录文件和数据。

2.驱动分类

  • Linux驱动分类:
      字符设备、块设备、网络设备。
      网络设备: 有线网卡、无线网卡、其它与网络相关的设备。
      块设备: U盘、SD卡、硬盘、光盘等。
      字符设备: 除了块设备和网络设备,其它都归结于字符设备。
      字符设备中分类: 杂项设备、输入设备(键盘、鼠标、触摸屏)、帧缓冲(显示类设备)、RTC设备、串口设备等。

3.杂项设备

在这里插入图片描述
  驱动程序是应用层和硬件层的连接桥梁,应用层只管完成应用逻辑开发和界面设计,驱动层则处理硬件配置,实现应用层相关接口函数。
   杂项设备:字符设备类的一种,是除了上述输入设备、帧缓冲设备、RTC设备后的其它设备,例LED设备,由于不好归结于上述分类,则可将LED设备按杂项设备类进行注册。杂项设备主设备号为10。
   在生成的设备节点中,主设备号用来区分设备类。如字符设备中杂项设备主设备号为10,帧缓冲设备主设备号为29;次设备号用来区分这个类中的具体硬件。

4.驱动注册框架

4.1开发平台

开发平台:Ubuntu18.04
编译器:arm-linux-gcc
硬件平台:tiny4412基于Cortex-A9 4核1.5GHZ
开发板内核:Linux3.5

在这里插入图片描述

4.2 驱动模板

#include <linux/kernel.h>
#include <linux/module.h>
/*驱动初始化*/
static int __init wbyq_hello_module_init(void)
{
    printk("驱动入口,驱动注册成功\n");
    return 0;
}
/*驱动释放*/
static void __exit wbyq_hello_module_cleanup(void)
{
    printk("驱动出口,驱动注销成功\n");
}
module_init(wbyq_hello_module_init);//驱动入口函数
module_exit(wbyq_hello_module_cleanup);//驱动出口函数

MODULE_LICENSE("GPL");//驱动注册协议
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 hello Driver");

4.3 驱动编译

KER_ADD=/home/wbyq/src_pack/linux-3.5  #linux3.5内核的Makefile位置
all:
	make -C $(KER_ADD) M=`pwd` modules #通过调用linux3.5内核的Makefile文件进行编译
	cp ./*.ko /home/wbyq/src_pack/rootfs/code #将驱动文件拷贝到code目录下
	make -C $(KER_ADD) M=`pwd` modules clean  #清空文件
obj-m +=hello_drv.o #添加依赖文件

4.4 驱动安装

[root@wbyq code]# insmod hello_drv.ko  #安装驱动
[ 4684.795000] 驱动入口,驱动注册成功

[root@wbyq code]# modinfo hello_drv.ko  #查看驱动详细信息
modinfo: can't open '/lib/modules/3.5.0-FriendlyARM/modules.dep': No such file or directory
[root@wbyq code]# mkdir /lib/modules/3.5.0-FriendlyARM/ -p
[root@wbyq code]# touch /lib/modules/3.5.0-FriendlyARM/modules.dep
[root@wbyq code]# lsmod #查看动态安装的驱动
hello_drv 612 0 - Live 0xbf000000 (O)
[root@wbyq code]# rmmod hello_drv.ko #注销驱动
[ 5610.635000] 驱动出口,驱动注销成功

5 编写蜂鸣器驱动

5.1 硬件接口

在这里插入图片描述
  蜂鸣接口:BP1 – GPD0_0 高电平驱动。
在这里插入图片描述
   GPD0_CON:0x1140 0000+0x00A0 --配置寄存器

在这里插入图片描述
   GPD0_DAT:0x1140 0000+0x00A4 --数据寄存器

5.2 蜂鸣器驱动层

   1.调用驱动注册和注销函数,在驱动入口函数中实现BEEP硬件接口配置。在驱动出口函数中完成硬件资源释放。
   2.通调用杂项设备驱动框架完成杂项设备注册,注册成功后在/dev生成beep的设备节点。完成应用层相关接口函数编写。

#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/io.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
/*驱动初始化*/
unsigned int *GPDO_CON;
unsigned int *GPDO_DAT;
int beep_open(struct inode *inode, struct file *file)/*对应应用层open函数*/
{
	printk("open函数调用成功\n");
	return 0;
}

int beep_release(struct inode *inode, struct file *file) /*对应应用层close*/
{
	printk("releasse函数调用成功\n");
	*GPDO_DAT&=~(1<<0);
	return 0;
}
ssize_t beep_read(struct file *file, char __user * data, size_t size, loff_t *offset)/*对应应用层read*/
{
	int *p=(int *)data;
	*p=123;
	printk("read函数调用成功\n");
	return 4;
}
ssize_t beep_write(struct file *file, const char __user *data, size_t size, loff_t *offset)/*对应应用层write*/
{
	char buff[20];
	memcpy(buff,data,size);
	buff[size]='\0';
	printk("buff=%s\n",buff);
	if(strcmp(buff,"beep_on")==0)//开蜂鸣器
	{
		*GPDO_DAT|=1<<0;
	}
	else if(strcmp(buff,"beep_off")==0)//关蜂鸣器
	{
		*GPDO_DAT&=~(1<<0);
	}
	return size;//返回写入成功的字节数
}

/*文件操作集合结构体*/
static struct file_operations beep_fops=
{
	.owner		= THIS_MODULE,/*当前模块*/
	.open		= beep_open,
	.release	= beep_release,
	.read		=beep_read,
	.write		=beep_write
};
/*杂项设备结构体*/
static struct miscdevice tiny4412_beep = {
	.minor			= MISC_DYNAMIC_MINOR,//次设备号,255表示由系统自动分配
	.name			= "beep", /*在/dev生成的设备节点名字*/
	.fops			= &beep_fops,
};
static int __init wbyq_beep_init(void)
{
    printk("驱动入口,驱动注册成功\n");
	/*蜂鸣器配置*/
	GPDO_CON=ioremap(0x114000A0, 4);//将GPDO_CON物理地址转换虚拟地址
	GPDO_DAT=ioremap(0x114000A4, 4);//将GPDO_DAT物理地址转换虚拟地址
	/*蜂鸣器*/
	*GPDO_CON&=0xfffffff0;//清除当前GPD0_0的配置
	*GPDO_CON|=0x00000001;//设置为输出模式
	/*注册杂项设备:在/dev下生成设备节点,实现应用层接口函数*/
	misc_register(&tiny4412_beep);
    return 0;
}
/*驱动释放*/
static void __exit wbyq_beep_cleanup(void)
{
    printk("驱动出口,驱动注销成功\n");
	/*注销杂项设备*/
	misc_deregister(&tiny4412_beep);
	iounmap(GPDO_CON);
	iounmap(GPDO_DAT);
}
module_init(wbyq_beep_init);//驱动入口函数
module_exit(wbyq_beep_cleanup);//驱动出口函数

MODULE_LICENSE("GPL");//驱动注册协议
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 beep Driver");

   杂项设备主设备为10,次设备可填值为0~254;当次设备号填255时表示有系统分配。

5.3 蜂鸣器应用层

   Linux下一切皆文件,操作设备就和操作文件一样。只需要open打开设备、读写设备、操作完成关闭设备即可。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main()
{
	/*1.打开设备*/
	int fd=open("/dev/beep",2);
	if(fd<0)
	{
		printf("/dev/beep 设备打开失败\n");
		return 0;
	}
	int data=0;
	int size;
	/*读写文件*/
	size=read(fd,&data,4);
	printf("size=%d,data=%d\n",size,data);
	while(1)
	{
		write(fd,"beep_on",strlen("beep_on"));//开蜂鸣器
		sleep(1);
		write(fd,"beep_off",strlen("beep_off"));//关蜂鸣器
		sleep(1);
	}
	close(fd);//关闭文件
}

   在Linux内核中,设备节点的访问是通过主设备+次设备号的组合来完成的,占32位,主设备号是20 ~ 31位。次设备号是0 ~ 19位。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT_阿水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值