第一个驱动步骤

第一个驱动步骤如下:

1、理解驱动从应用到内核应该有哪些步骤,如下图

app 应用 -》 调用c库 -> c库通过swi触发不同的软中断 调用不同的系统接口->系统接口根据 打开的文件属性调用对应的驱动(VFS干的活)

这里的对应驱动如何调用可以先不管;

以led驱动举例:

步骤是: 打开对应的led设备文件,向设备文件中写入值  开 或者 关灯;

应用程序如下

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
/*
	输入 on 表示开灯
	输入 off 表示关灯
*/
int main(int argc, char **argv)
{
	int fd = 0;
	int val = 1;
	if (argc < 2)
	{
		printf("Usage: \n");
		printf("	led <on/off> \n");
	}
	
	fd = open("/dev/led", O_RDWR);
	if (fd < 0)
	{
		printf("/dev/xxx file open failed \n");
		return -1;
	}
	if (strcmp(argv[1], "on") == 0)
	{
		val = 0;
	}else if(strcmp(argv[1], "off") == 0)
	{
		val = 1;
	}else
	{
		printf("input error \n");
	}
	
	write(fd, &val, 4);
}

驱动框架:
1\写出 led_open led_write 对应的操作,供我们应用层调用。

2\怎么告诉内核?

答:

a、定义一个file_operations 结构并填充

b、告诉内核 register_chrdev() 使用这个函数

c、谁来调用它? 这就是驱动入口函数:

如有三个驱动程序:

first_drv_init

second_drv_init

third_drv_init

.....

 

内核怎么知道对应关系?

我们通过统一的接口调用 module_init(驱动入口函数);module_exit(驱动卸载接口函数)
修饰入口函数 module_init 定义一个结构体,结构中一个函数指针指向入口函数

app : open , read write

 

app : open ("/dev/xxx") 这个设备文件属性如上图

应用 程序如何找到对应的驱动调用呢?

用设备类型 + 主设备号 +此设备号 找到对应的file_operations 结构

chrdev数组: 0 1 2 3 4 5 6 7 8 9 。。。。

以major作为索引 挂载对应file_operations结构

 

驱动程序如下:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/soundcard.h>
#include <linux/ac97_codec.h>
#include <linux/sound.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>

#define GPFCON 0x56000050
#define GPFDAT 0x56000054
static struct class * first_drv_class;
static struct class_device * first_dev_class; 
volatile unsigned int * gpfcon = NULL;
volatile unsigned int * gpfdata = NULL;

//对应硬件的操作
static int first_drv_open(struct inode * node , struct file * file)
{
	printk("first_drv_open\n");
	/* 设置为输出模式  4,5,6 */
	*gpfcon &= ~(0x3<<8)|(0x3<<10)|(0x3<<12);
	*gpfcon |= (0x1<<8)|(0x1<<10)|(0x1<<12);
		
	return 0;
}

//ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
//ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
static int first_drv_write(struct file * fp, const char __user * buf, int len, loff_t * offset)
{
	int val = 0;
	copy_from_user(&val, buf, len);

	if(val == 0)
	{
		/* 点灯 */
		*gpfdata &= ~((0x1<<4)|(0x1<<5)|(0x1<<6));
	}else
	{
		/* 关灯 */
		*gpfdata |= ((0x1<<4)|(0x1<<5)|(0x1<<6));
	}
	
	return 0;
}

//定义file_operations 结构
struct file_operations first_drv_ops = {
	.owner = THIS_MODULE,
	.open = first_drv_open,
	.write = first_drv_write
};

int major = 0;

//你驱动的入口函数
int first_drv_init(void)
{
//用 file_operations和主设备号去注册字符设备驱动
	major = register_chrdev(0, "led", &first_drv_ops);
//这个是根据sys/下信息来自动创建设备文件的
	first_drv_class = class_create(THIS_MODULE, "led");
	first_dev_class = class_device_create(first_drv_class, NULL, MKDEV(major, 0), NULL, "led");

//这里已经在跑系统了,所以要使用虚拟地址(这就是地址映射)
	gpfcon = (volatile unsigned int *)ioremap(GPFCON, 8);
	gpfdata = gpfcon + 1;
	return 0;
}

void first_drv_exit(void)
{
	unregister_chrdev(major, "led");
	class_device_unregister(first_dev_class);
	class_destroy(first_drv_class);
	iounmap(gpfcon);
	iounmap(gpfdata);
}


//驱动通用接口,告诉内核你写的驱动
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值