文章的分析基於linux2.6.22。
文章led驅動-1分析了s3c24xx的led驅動和設備的match過程,然後後調用s3c24xx_led_probe函數,本文分析下這個過程,目的是瞭解led驅動到底怎麼與應用結合起來。
1.
static int s3c24xx_led_probe(struct platform_device *dev)
{
struct s3c24xx_led_platdata *pdata = dev->dev.platform_data;
struct s3c24xx_gpio_led *led;
int ret;
led = kzalloc(sizeof(struct s3c24xx_gpio_led), GFP_KERNEL);
...
platform_set_drvdata(dev, led);
led->cdev.brightness_set = s3c24xx_led_set;
led->cdev.default_trigger = pdata->def_trigger;
led->cdev.name = pdata->name;
led->pdata = pdata;
/* no point in having a pull-up if we are always driving */
if (pdata->flags & S3C24XX_LEDF_TRISTATE) {
s3c2410_gpio_setpin(pdata->gpio, 0);
s3c2410_gpio_cfgpin(pdata->gpio, S3C2410_GPIO_INPUT);
} else {
s3c2410_gpio_pullup(pdata->gpio, 0);
s3c2410_gpio_setpin(pdata->gpio, 0);
s3c2410_gpio_cfgpin(pdata->gpio, S3C2410_GPIO_OUTPUT);
}
/* register our new led device */
ret = led_classdev_register(&dev->dev, &led->cdev);
...
return 0;
exit_err1:
kfree(led);
return ret;
}
static struct platform_device __initdata *smdk_devs[] = {
...
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
};
static struct platform_device smdk_led4 = {
.name = "s3c24xx_led",
.id = 0,
.dev = {
.platform_data = &smdk_pdata_led4,
},
};
static struct s3c24xx_led_platdata smdk_pdata_led4 = {
.gpio = S3C2410_GPF4,
.flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
.name = "led4",
.def_trigger = "timer",
};
2.
/**
* led_classdev_register - register a new object of led_classdev class.
* @dev: The device to register.
* @led_cdev: the led_classdev structure for this device.
*/
int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
{
...
led_cdev->class_dev = class_device_create(leds_class, NULL, 0,
parent, "%s", led_cdev->name);
...
class_set_devdata(led_cdev->class_dev, led_cdev);
...
}
2.1
/**
* class_device_create - creates a class device and registers it with sysfs
* @cls: pointer to the struct class that this device should be registered to.
* @parent: pointer to the parent struct class_device of this new device, if any.
* @devt: the dev_t for the char device to be added.
* @device: a pointer to a struct device that is assiociated with this class device.
* @fmt: string for the class device's name
*
* This function can be used by char device classes. A struct
* class_device will be created in sysfs, registered to the specified
* class.
* A "dev" file will be created, showing the dev_t for the device, if
* the dev_t is not 0,0.
* If a pointer to a parent struct class_device is passed in, the newly
* created struct class_device will be a child of that device in sysfs.
* The pointer to the struct class_device will be returned from the
* call. Any further sysfs files that might be required can be created
* using this pointer.
*
* Note: the struct class passed to this function must have previously
* been created with a call to class_create().
*/
struct class_device *class_device_create(struct class *cls,
struct class_device *parent,
dev_t devt,
struct device *device,
const char *fmt, ...)
{
...
struct class_device *class_dev = NULL;
...
class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL);
...
class_dev->devt = devt;
class_dev->dev = device;
class_dev->class = cls;
class_dev->parent = parent;
class_dev->release = class_device_create_release;
class_dev->uevent = class_device_create_uevent;
...
vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);
...
retval = class_device_register(class_dev);
...
return class_dev;
error:
kfree(class_dev);
return ERR_PTR(retval);
}
2.1.1
int class_device_register(struct class_device *class_dev)
{
class_device_initialize(class_dev);
return class_device_add(class_dev);
}
A.
void class_device_initialize(struct class_device *class_dev)
{
kobj_set_kset_s(class_dev, class_obj_subsys);
kobject_init(&class_dev->kobj);
INIT_LIST_HEAD(&class_dev->node);
}
static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);
#define decl_subsys(_name,_type,_uevent_ops) \
struct kset _name##_subsys = { \
.kobj = { .name = __stringify(_name) }, \
.ktype = _type, \
.uevent_ops =_uevent_ops, \
}
B.
int class_device_add(struct class_device *class_dev)
{
...
class_dev = class_device_get(class_dev);
...
parent_class = class_get(class_dev->class);
...
parent_class_dev = class_device_get(class_dev->parent);
...
error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
...
if (parent_class_dev) //parent_class_dev爲NULL
class_dev->kobj.parent = &parent_class_dev->kobj;
else
class_dev->kobj.parent = &parent_class->subsys.kobj; //執行該分支
}
2.2
static inline void
class_set_devdata (struct class_device *dev, void *data)
{
dev->class_data = data;
}