linux简单驱动程序

怎么写驱动程序?

看原理图

确定引脚

看芯片手册,确定怎么操作这些引脚

写驱动代码

为什么写驱动?

怎么写?

那怎么在驱动中指定引脚?

led_drv.c

led_test.c

Makefile


看原理图

确定引脚

看芯片手册,确定怎么操作这些引脚

写驱动代码

为什么写驱动?

驱动的作用起一个封装作用,应用程序需要操作文件或硬件是一套标准的APP接口,open某个设备文件,read得到设备状态,write设备状态,或各种ioctl,相应的在驱动程序中就有相应的drv_open drv_read drv_write drv_ioctl

怎么写?

  • 分配一个file_operations结构体,里面封装了各种函数,例如点灯。
  • 设置结构体中的函数:.open = led_open 做什么:把led引脚配置为输出引脚。.read = led_read 做什么:根据APP传入的值设置引脚的状态。
  • 注册(告诉内核): 把这个register_chrdev(主设备号,file_operations结构体,名字)结构体放入内核的一个数组中,放入数组中的哪一项也就是主设备号
  • 入口:用来调用register_chrdev
  • 出口:用来调用unregister_chrdev

那怎么在驱动中指定引脚?

  • 传统方法:在代码中写死,led_drv.c(分配、注册fileopetation结构体)
  • 总线设备驱动模型:分为led_drv.c(分配、注册fileopetation结构体)和led_dev.c,在led_dev.c中指定引脚
  • 使用设备数指明引脚:led_drv.c(分配、注册fileopetation结构体)和imax7.dts,在imax7.dts中指定引脚
  • 总结驱动写法:核心写法不变,差别在于如何指定硬件资源。

led_drv.c

#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/uaccess.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<linux/of.h>
#include<linux/of_device.h>
#include<linux/of_platform.h>

static int major;
static struct class *led_class;
static unsigned int gpio_base[] = {
	0x56000000,//GPACON
	0x56000010,//GPBCON
	0x56000020,//GPCCON
	0x56000030,//GPDCON
	0x56000040,//GPECON
	0x56000050,//GPFCON
	0x56000060,//GPGCON
	0x56000070,//GPHCON
	0         ,//GPICON
	0x560000D0,//GPJCON
};
#define S3C2440_GPA(n)  (0<<16 | n)
#define S3C2440_GPB(n)  (1<<16 | n)
#define S3C2440_GPC(n)  (2<<16 | n)
#define S3C2440_GPD(n)  (3<<16 | n)
#define S3C2440_GPE(n)  (4<<16 | n)
#define S3C2440_GPF(n)  (5<<16 | n)
#define S3C2440_GPG(n)  (6<<16 | n)
#define S3C2440_GPH(n)  (7<<16 | n)
#define S3C2440_GPI(n)  (8<<16 | n)
#define S3C2440_GPJ(n)  (9<<16 | n)

static int led_pin = S3C2440_GPF(5);
static volatile unsigned int *gpio_con;
static volatile unsigned int *gpio_dat;

/*1.分配file_operations结构体
*2.设置file_operations结构体
*3.注册file_operations结构体
*4.入口
*5.出口
*/

static int led_release(struct inode *node,struct file *filp)
{
	printk("iounmap(0x%x)\n",gpio_con);
	iounmap(gpio_con);
	return 0;
}
static struct file_operations myled_oprs = {
	.owner   = THIS_MODULE,
	.open    = led_open,
	.write   = led_write,
	.release = led_release,
};
static int led_open(struct inode *node,struct file *filp)
{
	//把LED引脚配置为输出引脚
	//例如引脚GPF5 基地址0x56000050 
	//linux驱动中,不能直接操作物理地址,需要映射到虚拟地址。
	int bank = led_pin >> 16;
	int base = gpio_base[bank];
	int pin  = led_pin & 0xffff;
	//映射
	gpio_con = ioremap(base,8);
	if(gpio_con)
	{
		printk("ioremap(0x%x) = 0x%x\n",base,gpio_con);
	}
	else
	{
		return -EINVAL;
	}
	gpio_dat = gpio_con + 1;
	//先清0
	*gpio_con &= ~(3<<(pin * 2));
	//置1
	*gpio_con |= (1<<(pin * 2));
	return 0;
}

static ssize_t led_write(struct file *filp,const char __user *buf,size_t size,loff_t *off)
{
	//根据应用程序APP传入的值来设置LED引脚
	//怎么传给内核
	unsigned char val;
	int pin = led_pin & 0xffff;
	
	copy_from_user(&val,buf,1);
	if(val)
	{
		//点灯
		*gpio_dat &= ~(1<<pin);
	}
	else
	{
		//灭灯
		*gpio_dat |= (1<<pin);
	}
	return 1; //已经写入一个数据
	
}
static int myled_init(void)
{
	major = register_chrdev(0,"myled",&myled_oprs);
	//自动分配设备号
	led_class = class_create(THIS_MODULE,“myled”);
	device_create(led_class,NULL,MKDEV(major,0),NULL,"led");//   /dev/led
	//此后就可以open/dev/led来设置灯。
	
	return 0;
}

static int myled_exit(void)
{
	unregister_chrdev(major,"myled");
	device_destroy(led_class,MKDEV(major,0));
	class_destroy(led_class);
}

module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");

led_test.c

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>

//ledtest on
//ledtest off

int main(int argc,char *argv[])
{
	int fd;
	unsigned char val = 1;
	fd = open("dev/led",O_RDWR);
	if(fd < 0)
	{
		printf("cant't error!\n");
	}
	if(argc != 2)
	{
		printf("Usage :\n");
		printf("%s <on|off>\n",argv[0]);
		return 0;
	}
	if(strcmp(argv[1],"on") == 0)
	{
		val = 1;
	}
	else
	{
		val = 0;
	}
	
	write(fd,&val,1);
	return 0;
}

Makefile

KERN_DIR = /work/system/ccclinux

all:
	make -C $(KERN_DIR) M = 'pwd' modules
clean:
	make -C $(KERN_DIR) M = 'pwd' modules clean
	rm -rf modules.order
obj_m +=led_drv.o

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

雲烟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值