8.platform驱动分离

1.框架

platformbus总线结构将一个硬件驱动分为device设备和driver驱动两部分。使用platform将两个联系到一起

就是把devicedriver分开注册到内核中去。在根据相应的name之类的去匹配使用。

2.关键函数和结构

device_driver:device和driver的相关性数据和函数存放

struct device_driver {
	const char		*name;            //设备驱动程序的名字
	struct bus_type		*bus;            //所属总线类型

	struct module		*owner;            //模块所有者
	const char		*mod_name;	/* used for built-in modules */

	bool suppress_bind_attrs;	/* disables bind/unbind via sysfs */

	const struct of_device_id	*of_match_table;            //match device table

	int (*probe) (struct device *dev);                        //匹配度到设备的name与driver中的name一致时将会在注册时执行
	int (*remove) (struct device *dev);                        //移除一个绑定的驱动
	void (*shutdown) (struct device *dev);                  //关机
	int (*suspend) (struct device *dev, pm_message_t state);      //将设备调到休眠模式
	int (*resume) (struct device *dev);                        //唤醒休眠模式
	const struct attribute_group **groups;

	const struct dev_pm_ops *pm;                              //电源管理操作

	struct driver_private *p;
};

platform_device :硬件相关

struct platform_device {
	const char	* name;
	int		id;
	struct device	dev;
	u32		num_resources;
	struct resource	* resource;

	const struct platform_device_id	*id_entry;

	/* MFD cell pointer */
	struct mfd_cell *mfd_cell;

	/* arch specific additions */
	struct pdev_archdata	archdata;
};

platform_driver
这里的platform是一个普通的驱动,可用最原始的方法来注册创建class类,再在下面添加具体的设备文件来使用。platform只是bus中的一种,挂载到platform_bus_type。

struct platform_driver {
	int (*probe)(struct platform_device *);
	int (*remove)(struct platform_device *);
	void (*shutdown)(struct platform_device *);
	int (*suspend)(struct platform_device *, pm_message_t state);
	int (*resume)(struct platform_device *);
	struct device_driver driver;
	const struct platform_device_id *id_table;
};

resource

struct resource {
	resource_size_t start;
	resource_size_t end;
	const char *name;
	unsigned long flags;
	struct resource *parent, *sibling, *child;
};

platform_get_resource
获取platform资源

  struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num)
  // type:资源类型
  // num:资源索引

platform_driver_register-

  int platform_driver_register(struct platform_driver *drv)

platform_driver_unregister

  void platform_driver_unregister(struct platform_driver *drv)

platform_device_register

  int platform_device_register(struct platform_device *pdev)

platform_device_unregister

  void platform_device_unregister(struct platform_device *pdev)

3.代码解析

led_dev.c

  //定义资源
static struct resource myled_resource[] = {
        //内存资源
	[0] = {
		.start = 0x56000050,
		.end   = 0x56000050 + 8 - 1,
		.flags = IORESOURCE_MEM,
	},
        //中断资源
	[1] = {
		.start = 4,
		.end   = 4,
		.flags = IORESOURCE_IRQ,
	},
};

static int myled_release(struct platform_device *pdev)
{

}

static struct platform_device myled_dev = {
	.name = "myled",
	.id = -1,
	.num_resources = ARRAY_SIZE(myled_resource),      //申请内存
	.resource = myled_resource,                       //赋值
	.dev = {
		.release = myled_release,                  //释放函数
	},
};

static int myled_init(void)
{
	platform_device_register(&myled_dev);

	return 0;
}

static void myled_exit(void)
{
	platform_device_unregister(&myled_dev);
}

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

led_drv.c

static struct class *myled_class;
static struct class_device *myled_device_class;

static volatile unsigned long *gpfcon;
static volatile unsigned long *gpfdat;

static unsigned int pin;

static int myled_open (struct inode *inode, struct file *file)
{
	/*	设置gpio	*/
	*gpfcon &= ~(3 << (pin * 2));
	*gpfcon |= (1 << (pin * 2));

	return 0;
}

static ssize_t myled_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	int val;

	copy_from_user(&val, buf, count);

	if(val)
	{
		/*	点灯	*/
		*gpfdat &= ~(1 << pin);
	}
	else
	{
		/*	灭灯	*/
		*gpfdat |= (1 << pin);
	}

	return 0;
}


static struct file_operations myled_fops = {
	.owner = THIS_MODULE,
	.open  = myled_open,
	.write = myled_write,
};

int major;

static int myled_probe (struct platform_device *pdev)
{
	struct resource *res;
	/*	从平台获取信息	*/
        //根据platform_device的资源进行ioremap
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

	gpfcon = ioremap(res->start, res->end - res->start + 1);
	gpfdat = gpfcon + 1;

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	pin = res->start;
	
	/*	注册字符设备	*/
	major = register_chrdev(0, "myled", &myled_fops);

	myled_class = class_create(THIS_MODULE, "myled");
	myled_device_class = class_device_create(myled_class, NULL, MKDEV(major, 0), NULL, "myled");

	return 0;
}

static int myled_remove(struct platform_device *pdev)
{
	/*	卸载字符设备	*/
	unregister_chrdev(major, "myled");

	class_device_unregister(myled_device_class);
	class_destroy(myled_class);

	iounmap(gpfcon);
}

static struct platform_driver myled_drv = {
	.probe = myled_probe,
	.remove = myled_remove,
	.driver = {
		.name = "myled",
	},
};

static int myled_drv_init(void)
{
	platform_driver_register(&myled_drv);

	return 0;
}

static void myled_drv_exit(void)
{
	platform_driver_unregister(&myled_drv);
}

module_init(myled_drv_init);
module_exit(myled_drv_exit);
MODULE_LICENSE("GPL");

led_test.c

int main(int argc, char **argv)
{
	int fb;
	int val;

	fb = open("/dev/myled", O_RDWR);

	if(fb < 0)
	{
		printf("can't open!\n");
	}

	if(argc != 2)
	{
		printf("Uage: \n");
		printf("%s <on | off>\n", argv[0]);
		return 0;
	}

	if(strcmp(argv[1], "on") == 0)
	{
		val = 1;
	}
	else
	{
		val = 0;
	}

	write(fb, &val, 4);

	return 0;
}

Makefile

KERN_DIR = /home/book/linux-2.6.22.6

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
obj-m	+= led_dev.o
posted @ 2020-07-18 23:47  人民广场的二道贩子  阅读(197)  评论(0编辑  收藏  举报