diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 6615ac7..43aae31 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -13,11 +13,46 @@ #include #include #include +#include #ifdef CONFIG_PMAC_BACKLIGHT #include #endif +static struct class *backlight_class; +static struct list_head displays; + +static struct backlight_display *backlight_find_display(const char *name) +{ + struct list_head *ptr; + struct backlight_display *entry; + + list_for_each(ptr, &displays) { + entry = list_entry(ptr, struct backlight_display, list); + if (strcmp(entry->name, name) == 0) { + return entry; + } + } + + return NULL; +} + +static struct backlight_device *backlight_best_device(struct backlight_display *display) +{ + struct list_head *ptr; + struct backlight_device *entry; + + printk(KERN_WARNING "[DBG] get_device called for %s\n", display->name); + list_for_each(ptr, &display->devices) { + /* FIXME: return best, not first */ + entry = list_entry(ptr, struct backlight_device, list); + return entry; + } + + printk(KERN_WARNING "[DBG] ohhhhh noooo, list empty?\n"); + return NULL; +} + #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)) /* This callback gets called when something important happens inside a @@ -73,6 +108,42 @@ static inline void backlight_unregister_fb(struct backlight_device *bd) } #endif /* CONFIG_FB */ +static int backlight_pick_up_device(struct backlight_display *display) +{ + int result; + struct backlight_device *device = backlight_best_device(display); + + if (!device) { + printk(KERN_WARNING "[DBG] can't find best device for %s\n", display->name); + return -1; + } + + if (device == display->curr) { + /* Currently used device is still the best choice */ + printk(KERN_WARNING "[DBG] current is the best\n"); + return 0; + } + + if (display->curr) { + printk(KERN_WARNING "[DBG] unregistering symlink %s for old device\n", display->name); + sysfs_remove_link(backlight_class->dev_kobj, display->name); + display->curr = NULL; + } + + printk(KERN_WARNING "[DBG] registering new symlink %s for new device\n", display->name); + + result = sysfs_create_link(backlight_class->dev_kobj, + &device->dev.kobj, display->name); + if (result) { + printk(KERN_WARNING "[DBG] failed to symlink\n"); + return result; + } + + display->curr = device; + + return 0; +} + static void backlight_generate_event(struct backlight_device *bd, enum backlight_update_reason reason) { @@ -190,8 +261,6 @@ static ssize_t backlight_show_actual_brightness(struct device *dev, return rc; } -static struct class *backlight_class; - static int backlight_suspend(struct device *dev, pm_message_t state) { struct backlight_device *bd = to_backlight_device(dev); @@ -271,10 +340,26 @@ EXPORT_SYMBOL(backlight_force_update); struct backlight_device *backlight_device_register(const char *name, struct device *parent, void *devdata, struct backlight_ops *ops) { + struct backlight_display *display; struct backlight_device *new_bd; + char *mod_name; int rc; pr_debug("backlight_device_register: name=%s\n", name); + printk(KERN_WARNING "[DBG] registering new backlight: %s\n", name); + + display = backlight_find_display("panel0"); + if (!display) { + display = kzalloc(sizeof(struct backlight_display), GFP_KERNEL); + if (!display) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&display->devices); + display->name = kstrdup("panel0", GFP_KERNEL); + list_add_tail(&display->list, &displays); + + printk(KERN_WARNING "[DBG] we have new display %s\n", display->name); + } new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL); if (!new_bd) @@ -283,11 +368,16 @@ struct backlight_device *backlight_device_register(const char *name, mutex_init(&new_bd->update_lock); mutex_init(&new_bd->ops_lock); + mod_name = kzalloc(strlen(name) + 2, GFP_KERNEL); + if (!mod_name) + return ERR_PTR(-ENOMEM); + sprintf(mod_name, ".%s", name); new_bd->dev.class = backlight_class; new_bd->dev.parent = parent; new_bd->dev.release = bl_device_release; - dev_set_name(&new_bd->dev, name); + dev_set_name(&new_bd->dev, mod_name); dev_set_drvdata(&new_bd->dev, devdata); + kfree(mod_name); rc = device_register(&new_bd->dev); if (rc) { @@ -301,6 +391,10 @@ struct backlight_device *backlight_device_register(const char *name, return ERR_PTR(rc); } + list_add_tail(&new_bd->list, &display->devices); + + backlight_pick_up_device(display); + new_bd->ops = ops; #ifdef CONFIG_PMAC_BACKLIGHT @@ -347,6 +441,8 @@ static void __exit backlight_class_exit(void) static int __init backlight_class_init(void) { + INIT_LIST_HEAD(&displays); + backlight_class = class_create(THIS_MODULE, "backlight"); if (IS_ERR(backlight_class)) { printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n", diff --git a/include/linux/backlight.h b/include/linux/backlight.h index 0f5f578..5b148f4 100644 --- a/include/linux/backlight.h +++ b/include/linux/backlight.h @@ -35,6 +35,18 @@ enum backlight_update_reason { struct backlight_device; struct fb_info; +struct backlight_display { + /* List of displays */ + struct list_head list; + + char *name; + + /* Devices controlling display's backlight */ + struct list_head devices; + + struct backlight_device *curr; +}; + struct backlight_ops { unsigned int options; @@ -76,6 +88,11 @@ struct backlight_properties { }; struct backlight_device { + /* List of devices */ + struct list_head list; + + struct backlight_display *display; + /* Backlight properties */ struct backlight_properties props;