linux-字符设备驱动(初级)

设备一般分为:
1.字符设备(LCD,keyboard,IIC从设备)传输主要是字节流的形势
2.块设备:以块为单位 进行操作的设备 (磁盘 优盘 flash)
3.网络设备:以太网 wifi 等

设备的驱动要素:
1.设备号 用于对众多设备种类的区分
2.设备节点对应的某类设备文件
3.用户对驱动的操作实质就是文件IO的操作,应用空间的操作在驱动中必定有其对应的操作

编写步骤和规范

一:实现模块加载和驱动入口函数
	module_init();
	module_exit();
	MODULE_LISENCE("GPL");
二:在模块中加载入口函数
	a: 注册注册设备号 register_chrdev();
	b: 创建设备节点  class_create() device_create()
	c: 硬件初始化 
			地址映射:ioremap()
			中断到申请
			硬件寄存器初始化
	d: 上层用户接口的对应操作:file_operations()

以下是设备驱动编写的常用函数

1.//设备号申请注册
	int register_chrdev(unsigned int major, const char * name, const struct file_operations * fops)

	参数1:主设备号(0~255)  参数为0时 系统自动为其分配 返回值为分配的主设备号 
	参数2:设备名 (随便取)
	参数3:上层接口对应的操作函数

	成功:0  失败:负数
2.//创建设备节点
	
	struct class * class_create(owner, name)//先创建一个类
	参数1:THIS_MODULE
	参数2:类名
	成功:返回一个class指针 失败:返回NULL

	struct device *device_create(struct class * class, struct device * parent, dev_t devt, void * drvdata, const char * fmt, ...)
	参数1:class指针
	参数2NULL
	参数3:设备号(MKDEV(ma,mi) 12位的主设备号 + 20位的次设备号)
	参数4NULL
	参数5:设备节点名(设备文件)
	成功:返回一个device 指针 失败:返回NULL

3.//发送数据给用户  一般为 read操作
	
	int copy_to_user(void * to, const void * from, unsigned long n)
	参数1:目的的缓冲区(用户buf)
	参数2:源缓冲区(内核buf)
	参数3:要拷贝的大小
	返回值:拷贝失败的个数
	成功:为0 失败:>0
4.//从用户中获取数据  一般为write操作

int copy_from_user(void * to, const void * from, unsigned long n)
	参数1:目的的缓冲区(内核buf)
	参数2:源缓冲区(用户buf)
	参数3:要拷贝的大小
	返回值:拷贝失败的个数
	成功:为0 失败:>0
5.//地址映射
	
	void*	ioremap(offset, size)//
	参数1:物理地址
	参数2:需要映射的大小
	成功:虚拟地址地址(连续) 失败:返回NULL

6.//删除设备节点
	
	device_destroy(struct class * class, dev_t devt)	
7.//删除类
	
	class_destroy(struct class * cls)
8.//注销设备
	
	unregister_chrdev(unsigned int major, const char * name)
9.//解除映射
	
	iounmap(const void __iomem * addr)
	参数1:要解除映射的虚拟地址

简易字符驱动模型:

#include<linux/fs.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/device.h>
#include<linux/uaccess.h>
#include<linux/types.h>
#include<asm/io.h>
 
 //.ko的名字 就是 驱动的名字
//寄存器配置

volatile unsigned int *GPFSEL1 = NULL; 
volatile unsigned int *GPSET0 = NULL;
volatile unsigned int *GPCLR0 = NULL;


//device  part
static  dev_t devo;
static  int major = 112;
static int minor = 121;
static char *module_name = "pin17";

static struct class *pin17_class;
static struct device *pin17_class_dev;


static int pin17_write(struct file *file,const char __user *buf ,size_t count,loff_t *ppos )
{
	int n_copy, userCmd1;	//先定义变量 在打印 不然会出错
	printk("pin17 write succes\n");
	 n_copy = copy_from_user((void *)&userCmd1,(void *)buf,count);
	if(n_copy == 0)
	{
		printk("copy success \n");
		printk("userCmd1 is %d\n",userCmd1);
	}
	if(userCmd1 == 1)
	{
		*GPSET0 = 0X01 << 17;
		printk("set 1\n");
	}
	else if(userCmd1 == 0)
	{
		*GPCLR0 = 0X01 << 17;
		printk("set 0");
	}
	else 
		printk("undo\n");

		return 0;
}


static int pin17_open(struct inode *inode,struct file *file)
{
	printk("pin17 open succes\n");
	
	*GPFSEL1 &= ~(0x06 << 21);
	*GPFSEL1 |= (0x01 << 21);
	return 0;
}

static struct file_operations  pin17_fops = {

	.owner = THIS_MODULE,
	.open  = pin17_open,
	.write = pin17_write,
};

int __init pin17_dri_init(void)
{
	int ret ;
	devo = MKDEV(major,minor);//设备号
	ret = register_chrdev(major,module_name,&pin17_fops);//模块名 不关心
	if(ret == 0)
		printk("register_chrdev success\n");

	pin17_class = class_create(THIS_MODULE,"pin17 of lsc");	//类名  sys/class
	pin17_class_dev = device_create(pin17_class,NULL,devo,NULL,module_name);//这个 name 才是设备文件的名字
	printk("the pin17 init success\n");
//寄存器初始化 将所需要的io口 的物理地址(寄存器地址  ) 转换为虚拟地址  提供到用户层 给用户使用 
	GPFSEL1 = (unsigned int*)ioremap(0x3f200004,4);
	GPSET0  = (unsigned int*)ioremap(0x3f20001c,4);
	GPCLR0  = (unsigned int*)ioremap(0x3f200028,4);
	return 0;
}


void __exit pin17_dri_exit(void)
{
	device_destroy(pin17_class,devo);
	class_destroy(pin17_class);
	unregister_chrdev(major,module_name);
	
	iounmap(GPCLR0);//映射释放
	iounmap(GPSET0);
	iounmap(GPFSEL1);
	printk("p17 had unstall success\n");

}

module_init(pin17_dri_init);
module_exit(pin17_dri_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("lsc")

标准:

#include<linux/slab.h>
#include<linux/fs.h>                                                                                                              
#include<linux/module.h>
#include<linux/init.h>
#include<linux/device.h>
#include<stdbool.h>
#include<linux/uaccess.h>
#include<linux/types.h>
#include<asm/io.h>

struct pin17_des{
				unsigned int dev_major;//主设备号
				struct class *cls;//设备类
				struct device *dev;//设备节点

				void *reg_map_GPFSEL1;//寄存器配置 存放其虚拟地址
				void *reg_map_GPSET0;
				void *reg_map_GPCLR0;
	};


struct pin17_des *pin17_dev;//全局 

 static int pin17_dri_open(struct inode *filep, struct file *file)
 	{
			writel(readl(pin17_dev->reg_map_GPFSEL1)&~(0x7<<21),pin17_dev->reg_map_GPFSEL1);
			writel(readl(pin17_dev->reg_map_GPFSEL1)|(0x1<<21),pin17_dev->reg_map_GPFSEL1);
			printk("pin17 open success\n");
			return 0;
 	}

 static ssize_t pin17_dri_write(struct file *file, const char __user *user_buf,size_t count, loff_t *ppos)
 	{
 			int a;int ret;
			printk("write success\n");
			ret = copy_from_user((void *)&a, (void *)user_buf, count);
 			if(ret)
 				{
 					printk("copy from user error\n");
 				}
			if(a == 1)
				{
					writel(readl(pin17_dev->reg_map_GPSET0)|(0x1<<17),pin17_dev->reg_map_GPSET0);
				}
			else if(a == 0)
				{
					writel(readl(pin17_dev->reg_map_GPCLR0)|(0x1<<17),pin17_dev->reg_map_GPCLR0);
				}
			
			return 0;		
 	}
  static ssize_t pin17_dri_read(struct file *file, char __user *user_buf,size_t count, loff_t *ppos)
 	{
 			int a = 888;int ret;
			printk("read success");
			ret = copy_to_user((void*)user_buf, (void *)&a,4);
			if(ret)
				{
					printk("copy to user error\n");
				}
			return 0;					
 	}


static struct  file_operations myfops =	{
		.owner = THIS_MODULE,
		.open = pin17_dri_open,
		.read = pin17_dri_read,
		.write = pin17_dri_write,
};
		
static  int __init pin17_dri_init(void)
{
	int ret;
	 pin17_dev = kmalloc(sizeof(struct pin17_des),GFP_KERNEL);
	if(IS_ERR(pin17_dev))
		{
			printk(KERN_ERR"malloc error\n");
			return -ENOMEM;//内存出错宏
		}
	pin17_dev->dev_major = register_chrdev(0,"pin17",&myfops);//Ö÷É豸ºÅ ϵͳ·ÖÅä  Çý¶¯Ãû:pin17
	if(pin17_dev->dev_major < 0)
		{
			printk(KERN_ERR"register error\n");
			ret = -EINVAL;
			goto err_0;
		}
	pin17_dev->cls = class_create(THIS_MODULE, "pin17_class");//类的文件夹名 里面装的是设备文件
	if(IS_ERR(pin17_dev->cls))
		{
			printk(KERN_ERR"class create error\n");
			ret  =  PTR_ERR(pin17_dev->cls);
			goto err_1;
		}
	pin17_dev->dev = device_create(pin17_dev->cls, NULL, MKDEV(pin17_dev->dev_major, 0), NULL,"pin17test");//pin17test 设备节点(文件)名
	if(IS_ERR(pin17_dev->dev))
		{
			printk(KERN_ERR"device create error\n");
			ret = PTR_ERR(pin17_dev->dev);
			goto err_2;
		}
		
			pin17_dev->reg_map_GPFSEL1 = ioremap(0x3f200004,4);//映射
   			pin17_dev->reg_map_GPSET0 = ioremap(0x3f20001c,4);
   			pin17_dev->reg_map_GPCLR0 = ioremap(0x3f200028,4);
		if(IS_ERR(pin17_dev->reg_map_GPFSEL1)||IS_ERR(pin17_dev->reg_map_GPSET0)||IS_ERR(pin17_dev->reg_map_GPCLR0))
			{
				printk(KERN_ERR"ioremap error\n");
				ret = -ENOMEM;
				goto err_3;
			}
			printk("pin17 dri insert success\n");
			return 0; 
err_3:
		device_destroy(pin17_dev->cls, MKDEV(pin17_dev->dev_major,0));
err_2:
		class_destroy(pin17_dev->cls);
err_1:
		class_destroy(pin17_dev->cls);
err_0:
		kfree(pin17_dev);
		return ret;
}

static void  __exit pin17_dri_exit(void)
{
	
	device_destroy(pin17_dev->cls, MKDEV(pin17_dev->dev_major,0));
	class_destroy(pin17_dev->cls);
	unregister_chrdev(pin17_dev->dev_major,"pin17");
	
	iounmap(pin17_dev->reg_map_GPCLR0);
	iounmap(pin17_dev->reg_map_GPSET0);
	iounmap(pin17_dev->reg_map_GPFSEL1);
	kfree(pin17_dev);

	printk("pin17 exit success\n");
}

module_init(pin17_dri_init);
module_exit(pin17_dri_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("pin17 control to pin17");
MODULE_AUTHOR("the monkey king");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值