閱讀807 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Linux驅動2_總線設備(一)

//	參考	Linux設備驅動程序(lld3)

//	實現一個簡單的虛擬總線 simple bus
//		simple_bus_type為總線類型
//		simple_bus為總線設備
//	

//	simple.c 實現
#include "simple.h"

//	增加設備引用計數
static struct simple_device *simple_dev_get(struct simple_device *dev)
{
	if (dev)
		get_device(&dev->device);
	return dev;
}
//	遞減設備引用計數
static void simple_dev_put(struct simple_device *dev)
{
	if (dev)
		put_device(&dev->device);

}

//	匹配設備/驅動
//		當有新設備或新驅動添加到總線時,判斷是否匹配
//	調用路徑:核心設備子係統->	
static int simple_device_match(struct device *dev, struct device_driver *drv)
{
	struct simple_device *sim_dev = to_simple_device(dev);
	struct simple_driver *sim_drv = to_simple_driver(drv);
	struct simple_class_id *ids = sim_drv->classes;

	if (ids)
		while (ids->class_id != SIMPLE_CLASS_END)
		{
			if (ids->class_id == sim_dev->class_id.class_id)
				return 1;
			ids++;
		}
	return 0;
}


//	添加設備/驅動
//		當simple_device_match返回true,說明device和driver匹配,通過
//		調用probe調用驅動的probe函數,初始化設備
//	調用路徑:核心設備子係統->	
static int simple_device_probe(struct device *dev)
{
	int ret = 0;
	struct simple_device *sim_dev;
	struct simple_driver *sim_drv;
	sim_dev = to_simple_device(dev);
	sim_drv = to_simple_driver(dev->driver);
	simple_dev_get(sim_dev);
	if (sim_drv->probe)
		ret = sim_drv->probe(sim_dev);
	if (ret)
		simple_dev_put(sim_dev);
	return ret;
}

//	熱插拔設備
//		總線上設備被熱插拔
//	調用路徑:核心設備子係統->	
static int simple_device_remove(struct device *dev)
{
	struct simple_device *sim_dev = to_simple_device(dev);
	struct simple_driver *sim_drv = to_simple_driver(dev->driver);
	if (sim_drv)
	{
		if (sim_drv->remove)
		{
			sim_drv->remove(sim_dev);
		}
	}

	simple_dev_put(sim_dev);
	return 0;
}

//	獲取設備class id
static ssize_t simple_device_show_class_id(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct simple_device *sim_dev = to_simple_device(dev);
	sprintf(buf, "0x%x\n", sim_dev->class_id.class_id);
	return strlen(buf) + 1;
}
//	simple bus 設備屬性

struct device_attribute simple_device_attrs[] = 
{
	__ATTR(class_id, S_IRUGO, simple_device_show_class_id, NULL),
	__ATTR_NULL
};

//	simple bus 總線類型
struct bus_type simple_bus_type = 
{
	.name 		= "simple",
	.match 		= simple_device_match,
	.probe 		= simple_device_probe,
	.remove 	= simple_device_remove,
	.dev_attrs 	= simple_device_attrs 
};

static void simple_bus_release(struct device *dev)
{
	return;
}

//	simple bus 總線設備
struct simple_bus simple_bus;

//	simple bus 模塊初始化
static int __init simple_init(void)
{
    int ret;
    /* create /sys/bus/simple.*/
    if ((ret = bus_register(&simple_bus_type)) < 0)
    {
    	printk(KERN_ALERT "[SIMPLE] bus_register failed.\n");
    	goto err_bus_register;
    }

    simple_bus.dev.release = simple_bus_release;
    //simple_bus.dev.parent為null,表示為該總線的頂層設備
    dev_set_name(&simple_bus.dev, "simple");
    /* create /sys/devices/simple.*/
    if ((ret = device_register(&simple_bus.dev)))
    {
    	printk(KERN_ALERT "[SIMPLE] device_register failed.\n");
    	goto err_dev_register;
    }
    return ret;
err_dev_register:
	bus_unregister(&simple_bus_type);
err_bus_register:
	return ret;
}

//	simple bus 模塊卸載
static void __exit simple_exit(void)
{
	device_unregister(&simple_bus.dev);
	bus_unregister(&simple_bus_type);
}

static void simple_device_release(struct device *dev)
{
	return;
}



//	注冊設備
//		向simple bus注冊設備
int simple_register_device(struct simple_device *dev)
{
	dev_set_name(&dev->device, dev->name);
	//設備類型為實現的simple_bus_type
	dev->device.bus 	= &simple_bus_type;
	//掛載的總線為simple_bus
	dev->device.parent 	= &simple_bus.dev; 
	dev->device.release = simple_device_release;
	return device_register(&dev->device);
}
EXPORT_SYMBOL(simple_register_device);


//	注銷設備
//		從simple bus注銷設備
void simple_unregister_device(struct simple_device *dev)
{
	/* 
	 *	device_unregister will do in two parts, first, remove it from all the subsystems with device_del(), 
	 *	then decrement the reference count via put_device(). If that is the final reference count,
	 *	the device will be cleaned up via device_release() above. Otherwise, the structure will stick 
	 *	around until the final reference to the device is dropped.
	 */
	device_unregister(&dev->device);
} 
EXPORT_SYMBOL(simple_unregister_device);


//	注冊驅動
//		向simple bus注冊驅動
int simple_register_driver(struct simple_driver *drv)
{
	int ret = 0;
	drv->driver.name= drv->name;
	drv->driver.bus = &simple_bus_type;
	ret = driver_register(&drv->driver);
	return ret;
}
EXPORT_SYMBOL(simple_register_driver);

//	注銷驅動
//		從simple bus注銷驅動
void simple_unregister_driver(struct simple_driver *drv)
{
	driver_unregister(&drv->driver);
}
EXPORT_SYMBOL(simple_unregister_driver);



module_init(simple_init);
module_exit(simple_exit);
MODULE_LICENSE("GPL");

//	simple.h,類型聲明
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>

#ifndef _SIMPLE_BUS_H_
#define _SIMPLE_BUS_H_

#define to_simple_device(dev) container_of(dev, struct simple_device, device)
#define to_simple_driver(drv) container_of(drv, struct simple_driver, driver)
#define SIMPLE_CLASS_END  	0xffff



struct simple_class_id
{
	u16 class_id;
};

struct simple_device
{
	char *name;
	struct device device;
	struct simple_class_id class_id;
};

struct simple_driver
{
	char *name;
	struct device_driver driver;
	struct simple_class_id *classes;
	int (*probe) (struct simple_device *dev);
	/*Device removed (NULL if not a hot-plug capable driver) */
	int (*remove) (struct simple_device *dev);
};


struct simple_bus
{
	struct device dev;
};

extern int simple_register_device(struct simple_device *dev);
extern void simple_unregister_device(struct simple_device *dev);
extern int simple_register_driver(struct simple_driver *drv);
extern void simple_unregister_driver(struct simple_driver *drv);

#endif





最後更新:2017-04-03 12:54:06

  上一篇:go 仿大眾點評懸浮購買框效果
  下一篇:go JSTL包重複報錯java.lang.NoSuchFieldError: deferredExpression