【Linux】platform设备驱动

Linux platform设备驱动

将globalmem字符设备驱动,修改为platform设备驱动

链接:Linux字符设备驱动

1、platform总线、设备与驱动

【注】所谓的platform_device并不是与字符设备、块设备和网络设备并列的概念,而是Linux系统提供的一种附加手段,例如,我们通常把在SoC内部集成的I2C、RTC、LCD、看门狗等控制器都归纳为platform_device,而它们本身就是字符设备。

2、platform_device结构体定义

3、platform_driver结构体定义 

4、device_driver结构体定义 

 

5、将globalmem作为platform设备

在globalmem_probe探针函数完成对字符设备的初始化与注册

在globalmem_remove删除函数完对字符设备的注销以及资源的释放

(1)填充device_driver结构体

static struct device_driver globalmem_driver = {
                .bus = &platform_bus_type,		//总线类型struct bus_type
                .name = "kp",                   //驱动名称(必须与platform总线设备名称相同)
                
                //原型 int(*probe) (struct device *dev)	参数为设备结构体指针
                .probe= globalmem_probe,		//探针函数,在注册platform设备时调用 函数指针 

                //原型 int(*remove) (struct device *dev)	参数为设备结构体指针
                .remove=globalmem_remove,		//删除函数,在注销platform设备是调用 函数指针 
                };

(2)填充platform_device结构体

static struct platform_device globalmem_device = {
				.name = "kp",				//设备名称(必须与platform总线驱动名称相同)
				.id = -1,						
				.dev = {
				.release = platform_globalmem_release,	//释放资源
				}
};

(3)模块加载函数

模块加载函数中完成platform_device和platform_driver的注册

int  globalmem_init(void)
{
	platform_device_register(&globalmem_device);	//注册platform device
	return driver_register(&globalmem_driver);      //注册platform driver 
}

(4)模块卸载函数

模块卸载函数中完成platform_device和platform_driver的注销

void  globalmem_exit(void)
{
	platform_device_unregister(&globalmem_device);  //注销platform device
	driver_unregister(&globalmem_driver);           //注销platform driver
}

 (5)globalmem_probe探针函数

它将在设备驱动模块加载时被执行,完成对字符设备的初始化与注册

static int globalmem_probe(struct globalmem_dev *dev)
{
	int result;
	//使用宏通过主设备号和次设备号生成dev_t
	dev_t devno = MKDEV(globalmem_major, 0);	/* "globalmem_major"为主设备号(宏定义),"0"为此设备号*/

	printk("initialize start\n");

	/* 申请设备号*/
	if (globalmem_major)
		result = register_chrdev_region(devno, 1, "globalmem");		/*已知起始设备的设备号*/
	else { 
		result = alloc_chrdev_region(&devno, 0, 1, "globalmem");	/* 动态申请设备号 */
		globalmem_major = MAJOR(devno);
	}
	if (result < 0)
		return result;

	/* 动态申请设备结构体的内存*/
	globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
	if (!globalmem_devp) {    /*申请失败*/
		result =  - ENOMEM;
		goto fail_malloc;
	}
	memset(globalmem_devp, 0, sizeof(struct globalmem_dev));		/*设备结构体内存空间清0*/

	globalmem_setup_cdev(globalmem_devp, 0);		    /*初始化并注册cdev字符设备结构*/
	
	printk("globalmem platform set\n");
	return 0;

fail_malloc:
	unregister_chrdev_region(devno, 1);
	return result;
	
}

(6)globalmem_remove删除函数 

它将在设备驱动模块被卸载时被执行,在globalmem_remove删除函数完对字符设备的注销以及资源的释放

 

static void globalmem_remove()
{		
	cdev_del(&globalmem_devp->cdev);						 /*注销cdev*/
	kfree(globalmem_devp);									/*释放设备结构体内存*/
	unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*释放设备号*/
	printk("globalmem platform unset\n");
}

(7)代码

/*
 * A globalmem driver as an example of char device drivers
 *
 * The initial developer of the original code is Barry Song
 * <author@linuxdriver.cn>. All Rights Reserved.
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include<linux/device.h>
#define GLOBALMEM_SIZE	0x1000	/*全局内存最大4K字节*/
#define MEM_CLEAR 0x1  /*清0全局内存*/
#define GLOBALMEM_MAJOR 250    /*预设的globalmem的主设备号*/
struct class *myclass;
/*struct class_simple *myclass;*/
static int globalmem_major = GLOBALMEM_MAJOR;
/*globalmem设备结构体*/
struct globalmem_dev {
	struct cdev cdev; /*cdev结构体*/
	unsigned char mem[GLOBALMEM_SIZE]; /*全局内存*/
};

struct globalmem_dev *globalmem_devp; /*设备结构体指针*/
/*文件打开函数*/
int globalmem_open(struct inode *inode, struct file *filp)
{
	/*将设备结构体指针赋值给文件私有数据指针*/
	filp->private_data = globalmem_devp;
	return 0;
}

/*文件释放函数*/
int globalmem_release(struct inode *inode, struct file *filp)
{
	return 0;
}

/* ioctl设备控制函数 */
static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned
	int cmd, unsigned long arg)
{
	struct globalmem_dev *dev = filp->private_data;/*获得设备结构体指针*/

	switch (cmd) {
	case MEM_CLEAR:
		memset(dev->mem, 0, GLOBALMEM_SIZE);
		printk(KERN_INFO "globalmem is set to zero\n");
		break;

	default:
		return  - EINVAL;
	}

	return 0;
}

/*读函数*/
static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size,
	loff_t *ppos)
{
	unsigned long p =  *ppos;
	unsigned int count = size;
	int ret = 0;
	struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/

	/*分析和获取有效的写长度*/
	if (p >= GLOBALMEM_SIZE)
		return 0;
	if (count > GLOBALMEM_SIZE - p)
		count = GLOBALMEM_SIZE - p;

	/*内核空间->用户空间*/
	if (copy_to_user(buf, (void *)(dev->mem + p), count)) {
		ret =  - EFAULT;
	} else {
		*ppos += count;
		ret = count;

		printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);
	}

	return ret;
}

/*写函数*/
static ssize_t globalmem_write(struct file *filp, const char __user *buf,
	size_t size, loff_t *ppos)
{
	unsigned long p =  *ppos;
	unsigned int count = size;
	int ret = 0;
	struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/

	/*分析和获取有效的写长度*/
	if (p >= GLOBALMEM_SIZE)
		return 0;
	if (count > GLOBALMEM_SIZE - p)
		count = GLOBALMEM_SIZE - p;

	/*用户空间->内核空间*/
	if (copy_from_user(dev->mem + p, buf, count))
		ret =  - EFAULT;
	else {
		*ppos += count;
		ret = count;

		printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p);
	}

	return ret;
}

/* seek文件定位函数 */
static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
{
	loff_t ret = 0;
	switch (orig) {
	case 0:   /*相对文件开始位置偏移*/
		if (offset < 0)	{
			ret =  - EINVAL;
			break;
		}
		if ((unsigned int)offset > GLOBALMEM_SIZE) {
			ret =  - EINVAL;
			break;
		}
		filp->f_pos = (unsigned int)offset;
		ret = filp->f_pos;
		break;
	case 1:   /*相对文件当前位置偏移*/
		if ((filp->f_pos + offset) > GLOBALMEM_SIZE) {
			ret =  - EINVAL;
			break;
		}
		if ((filp->f_pos + offset) < 0) {
			ret =  - EINVAL;
			break;
		}
		filp->f_pos += offset;
		ret = filp->f_pos;
		break;
	default:
		ret =  - EINVAL;
		break;
	}
	return ret;
}

/*文件操作结构体*/
static const struct file_operations globalmem_fops = {
	.owner = THIS_MODULE,
	.llseek = globalmem_llseek,
	.read = globalmem_read,
	.write = globalmem_write,
	.ioctl = globalmem_ioctl,
	.open = globalmem_open,
	.release = globalmem_release,
};

/*初始化并注册cdev*/
static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
{
	int err, devno = MKDEV(globalmem_major, index);

	cdev_init(&dev->cdev, &globalmem_fops);
	dev->cdev.owner = THIS_MODULE;
	err = cdev_add(&dev->cdev, devno, 1);
	if (err)
		printk(KERN_NOTICE "Error %d adding LED%d", err, index);
}

//==========================================================
//********************* globalmem_prebe*********************
static int globalmem_probe(struct globalmem_dev *dev)
{
	int result;
	//使用宏通过主设备号和次设备号生成dev_t
	dev_t devno = MKDEV(globalmem_major, 0);	/* "globalmem_major"为主设备号(宏定义),"0"为此设备号*/

	printk("initialize start\n");

	/* 申请设备号*/
	if (globalmem_major)
		result = register_chrdev_region(devno, 1, "globalmem");		/*已知起始设备的设备号*/
	else { 
		result = alloc_chrdev_region(&devno, 0, 1, "globalmem");	/* 动态申请设备号 */
		globalmem_major = MAJOR(devno);
	}
	if (result < 0)
		return result;

	/* 动态申请设备结构体的内存*/
	globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
	if (!globalmem_devp) {    /*申请失败*/
		result =  - ENOMEM;
		goto fail_malloc;
	}
	memset(globalmem_devp, 0, sizeof(struct globalmem_dev));	/*设备结构体内存空间清0*/

	globalmem_setup_cdev(globalmem_devp, 0);		/*初始化并注册cdev字符设备结构*/
	
	printk("globalmem platform set\n");
	return 0;

fail_malloc:
	unregister_chrdev_region(devno, 1);
	return result;
	
}
//============================================================

//myclass=class_simple_create(THIS_MODULE,"globalmem");
//class_simple_device_add(myclass,MKDEV(globalmem_major,0),NULL,"globalmem%d",0);

//============================================================
//********************* globalmem_remove *********************
static void globalmem_remove()
{		
	cdev_del(&globalmem_devp->cdev);						   /*注销cdev*/
	kfree(globalmem_devp);							/*释放设备结构体内存*/
	unregister_chrdev_region(MKDEV(globalmem_major, 0), 1);    /*释放设备号*/
	printk("globalmem platform unset\n");
}
//============================================================


//class_simple_device_remove(MKDEV(globalmem_major,0));	/
//class_simple_destroy(myclass);

//=========================================================
//********************* device_driver *********************
static struct device_driver globalmem_driver = {
                .bus = &platform_bus_type,		//总线类型struct bus_type
                .name = "kp",					//驱动名称(必须与platform总线设备名称相同)
                
                //原型 int(*probe) (struct device *dev)	参数为设备结构体指针
                .probe= globalmem_probe,	//探针函数,在注册platform设备时调用 函数指针 

                //原型 int(*remove) (struct device *dev)	参数为设备结构体指针
                .remove=globalmem_remove,	//删除函数,在注销platform设备是调用 函数指针 
                };
//=========================================================

static void platform_globalmem_release(struct device * dev)
{
	return ;	//本例中未获得资源,直接返回
}
//=========================================================
//********************* device_device *********************
static struct platform_device globalmem_device = {
				.name = "kp",					//设备名称(必须与platform总线驱动名称相同)
				.id = -1,						
				.dev = {
				.release = platform_globalmem_release,	//释放资源
				}
};
//==========================================================

//==========================================================
//********************* globalmem_init *********************
int  globalmem_init(void)
{
	platform_device_register(&globalmem_device);	//注册platform device
	return driver_register(&globalmem_driver);		//注册platform driver 
}
//==========================================================


//==========================================================
//********************* globalmem_exit *********************
void  globalmem_exit(void)
{
	platform_device_unregister(&globalmem_device);	//注销platform device
	driver_unregister(&globalmem_driver);			//注销platform driver
}
//==========================================================

MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_LICENSE("Dual BSD/GPL");

module_param(globalmem_major, int, S_IRUGO);

module_init(globalmem_init);
module_exit(globalmem_exit);

6、参考

Linux设备驱动开发详解基于最新的Linux4.0内核》作者:宋宝华

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值