public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* two patches - request for comments
@ 2004-05-28 21:20 Andrew Zabolotny
  2004-05-28 21:59 ` Todd Poynor
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Andrew Zabolotny @ 2004-05-28 21:20 UTC (permalink / raw)
  To: linux-kernel; +Cc: Greg KH

[-- Attachment #1: Type: text/plain, Size: 1003 bytes --]

Hello!

I'm going to submit the class_find_device() patch (attached for your
convenience) as a pre-requisite for the backlight/lcd device class patch
(also included so that you can take at it as well) via Russel King (the
backlight/lcd patch is needed for our ARM-based handhelds framebuffer
devices). Any comments/objections are welcome.

The LCD and backlight device classes were implemented with the following in
mind:

a) Allow user-mode code to control backlight and lcd (notably for
handhelds this is a must). This is done via sysfs (/sys/class/backlight/XXX/
and /sys/class/lcd/XXX/ where XXX is something like mq1100fb0).

b) Allow framebuffer devices to find and contact the respective backlight and
lcd devices (they are using the same name as the framebuffer device). This is
needed to implement the respective calls to backlight and lcd devices for
power management.

--
Greetings,
   Andrew

P.S. I've posted a similar message on linux-fbdev mailing listt; forgive me if
you seen it twice.

[-- Attachment #2: class.diff --]
[-- Type: application/octet-stream, Size: 2520 bytes --]

--- linux-2.6.6/drivers/base/class.c	2004-05-10 06:33:21.000000000 +0400
+++ linux-2.6.6-hh0/drivers/base/class.c	2004-05-25 15:17:57.000000000 +0400
@@ -359,7 +359,7 @@
 	class_device_put(class_dev);
 }
 
-int class_device_rename(struct class_device *class_dev, char *new_name)
+int class_device_rename(struct class_device *class_dev, const char *new_name)
 {
 	class_dev = class_device_get(class_dev);
 	if (!class_dev)
@@ -377,6 +377,33 @@
 	return 0;
 }
 
+/**
+ * class_device_find - find a struct class_device in a specific class
+ * @class: the class to search
+ * @class_id: the class_id to search for
+ *
+ * Iterates through the list of all class devices registered to a class. If
+ * the class_id is found, its reference count is incremented and returned to
+ * the caller. If the class_id does not match any existing struct class_device
+ * registered to this struct class, then NULL is returned.
+ */
+struct class_device * class_device_find(struct class *class, const char *class_id)
+{
+	struct class_device *class_dev;
+	struct class_device *found = NULL;
+
+	down_read(&class->subsys.rwsem);
+	list_for_each_entry(class_dev, &class->children, node) {
+		if (strcmp(class_dev->class_id, class_id) == 0) {
+			found = class_device_get(class_dev);
+			break;
+		}
+	}
+	up_read(&class->subsys.rwsem);
+
+	return found;
+}
+
 struct class_device * class_device_get(struct class_device *class_dev)
 {
 	if (class_dev)
@@ -389,7 +416,6 @@
 	kobject_put(&class_dev->kobj);
 }
 
-
 int class_interface_register(struct class_interface *class_intf)
 {
 	struct class * parent;
@@ -468,6 +494,8 @@
 EXPORT_SYMBOL(class_device_put);
 EXPORT_SYMBOL(class_device_create_file);
 EXPORT_SYMBOL(class_device_remove_file);
+EXPORT_SYMBOL(class_device_rename);
+EXPORT_SYMBOL(class_device_find);
 
 EXPORT_SYMBOL(class_interface_register);
 EXPORT_SYMBOL(class_interface_unregister);
--- linux-2.6.6/include/linux/device.h	2004-05-10 06:33:19.000000000 +0400
+++ linux-2.6.6-hh0/include/linux/device.h	2004-05-25 01:54:30.000000000 +0400
@@ -212,8 +212,9 @@
 extern int class_device_add(struct class_device *);
 extern void class_device_del(struct class_device *);
 
-extern int class_device_rename(struct class_device *, char *);
+extern int class_device_rename(struct class_device *, const char *);
 
+extern struct class_device * class_device_find(struct class *class, const char *class_id);
 extern struct class_device * class_device_get(struct class_device *);
 extern void class_device_put(struct class_device *);
 

[-- Attachment #3: bl-lcd.diff --]
[-- Type: application/octet-stream, Size: 23553 bytes --]

--- linux-2.6.6/include/linux/lcd.h	1970-01-01 03:00:00.000000000 +0300
+++ linux-2.6.6-hh0/include/linux/lcd.h	2004-05-27 22:48:18.000000000 +0400
@@ -0,0 +1,60 @@
+/*
+ * LCD Lowlevel Control Abstraction
+ * 
+ * Copyright (C) 2003,2004 Hewlett-Packard Company
+ * 
+ */
+
+#ifndef _LINUX_LCD_H
+#define _LINUX_LCD_H
+
+#include <linux/device.h>
+
+struct lcd_device;
+
+/* This structure defines all the properties of a LCD flat panel. */
+struct lcd_properties {
+	/* Owner module */
+	struct module *owner;
+	/* Get the power enabled status (0/1) */
+	int (*get_power) (struct lcd_device *);
+	/* Enable or disable power to the LCD */
+	int (*set_power) (struct lcd_device *, int power);
+	/* Get the LCD controller enabled status (0/1) */
+	int (*get_enable) (struct lcd_device *);
+	/* Enable or disable the LCD controller */
+	int (*set_enable) (struct lcd_device *, int enable);
+	/* The maximum value for contrast (read-only) */
+	int max_contrast;
+	/* Get the current contrast setting (0-max_contrast) */
+	int (*get_contrast) (struct lcd_device *);
+	/* Set LCD panel contrast */
+	int (*set_contrast) (struct lcd_device *, int contrast);
+};
+
+struct lcd_device {
+	/* This protects the 'props' field. If 'props' is NULL, the driver that
+	   registered this device has been unloaded, and if class_devdata()
+	   points to something in the body of that driver, it is also invalid. */
+	struct semaphore sem;
+	/* If this is NULL, the backing module is unloaded */
+	struct lcd_properties *props;
+	/* The class device structure */
+	struct class_device class_dev;
+};
+
+extern int lcd_device_register(const char *name, void *devdata,
+	struct lcd_properties *lp);
+extern void lcd_device_unregister(const char *name);
+
+extern struct lcd_device *lcd_device_find(const char *name);
+extern struct lcd_device *lcd_device_get(struct lcd_device *ld);
+extern void lcd_device_put(struct lcd_device *ld);
+
+#define to_lcd_device(obj) container_of(obj, struct lcd_device, class_dev)
+
+/* The registered clients of this notifier chain will be called every time
+   a new lcd class_device is registered */
+extern struct notifier_block *lcd_device_chain;
+
+#endif
--- linux-2.6.6/include/linux/backlight.h	1970-01-01 03:00:00.000000000 +0300
+++ linux-2.6.6-hh0/include/linux/backlight.h	2004-05-27 22:48:27.000000000 +0400
@@ -0,0 +1,57 @@
+/*
+ * Backlight Lowlevel Control Abstraction
+ * 
+ * Copyright (C) 2003,2004 Hewlett-Packard Company
+ * 
+ */
+
+#ifndef _LINUX_BACKLIGHT_H
+#define _LINUX_BACKLIGHT_H
+
+#include <linux/device.h>
+
+struct backlight_device;
+
+/* This structure defines all the properties of a backlight
+   (usually attached to a LCD). */
+struct backlight_properties {
+	/* Owner module */
+	struct module *owner;
+	/* Get the power enabled status (0/1) */
+	int (*get_power) (struct backlight_device *);
+	/* Enable or disable power to the LCD */
+	int (*set_power) (struct backlight_device *, int power);
+	/* Maximal value for brightness (read-only) */
+	int max_brightness;
+	/* Get current backlight brightness */
+	int (*get_brightness) (struct backlight_device *);
+	/* Set backlight brightness (0..max_brightness) */
+	int (*set_brightness) (struct backlight_device *, int brightness);
+};
+
+struct backlight_device {
+	/* This protects the 'props' field. If 'props' is NULL, the driver that
+	   registered this device has been unloaded, and if class_devdata()
+	   points to something in the body of that driver, it is also invalid. */
+	struct semaphore sem;
+	/* If this is NULL, the backing module is unloaded */
+	struct backlight_properties *props;
+	/* The class device structure */
+	struct class_device class_dev;
+};
+
+extern int backlight_device_register(const char *name, void *devdata,
+				     struct backlight_properties *bp);
+extern void backlight_device_unregister(const char *name);
+
+extern struct backlight_device *backlight_device_find(const char *name);
+extern struct backlight_device *backlight_device_get(struct backlight_device *bd);
+extern void backlight_device_put(struct backlight_device *bd);
+
+#define to_backlight_device(obj) container_of(obj, struct backlight_device, class_dev)
+
+/* The registered clients of this notifier chain will be called every time
+   a new backlight class_device is registered */
+extern struct notifier_block *backlight_device_chain;
+
+#endif
--- linux-2.6.6/drivers/video/lcd.c	1970-01-01 03:00:00.000000000 +0300
+++ linux-2.6.6-hh0/drivers/video/lcd.c	2004-05-29 01:00:52.000000000 +0400
@@ -0,0 +1,339 @@
+/*
+ * LCD Lowlevel Control Abstraction
+ * 
+ * Copyright (C) 2003,2004 Hewlett-Packard Company
+ * 
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/lcd.h>
+#include <linux/notifier.h>
+#include <linux/ctype.h>
+#include <asm/bug.h>
+
+struct notifier_block *lcd_device_chain;
+EXPORT_SYMBOL (lcd_device_chain);
+
+static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct lcd_device *ld = to_lcd_device(cdev);
+
+	down (&ld->sem);
+	if (likely (ld->props && ld->props->get_power))
+		rc = sprintf (buf, "%d\n", ld->props->get_power (ld));
+	else
+		rc = -ENXIO;
+	up (&ld->sem);
+
+	return rc;
+}
+
+static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_t count)
+{
+	int rc, power;
+	char *endp;
+	struct lcd_device *ld = to_lcd_device(cdev);
+
+	power = simple_strtoul(buf, &endp, 0);
+	if (*endp && !isspace (*endp))
+		return -EINVAL;
+
+	down (&ld->sem);
+	if (likely (ld->props && ld->props->set_power)) {
+		pr_debug("lcd: set power to %d\n", power);
+		ld->props->set_power(ld, power);
+		rc = count;
+	} else
+		rc = -ENXIO;
+	up (&ld->sem);
+
+	return rc;
+}
+
+static ssize_t lcd_show_enable(struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct lcd_device *ld = to_lcd_device(cdev);
+
+	down (&ld->sem);
+	if (likely(ld->props && ld->props->get_enable))
+		rc = sprintf (buf, "%d\n", ld->props->get_enable(ld));
+	else
+		rc = -ENXIO;
+	up (&ld->sem);
+
+	return rc;
+}
+
+static ssize_t lcd_store_enable(struct class_device *cdev, const char *buf, size_t count)
+{
+	int rc, enable;
+	char *endp;
+	struct lcd_device *ld = to_lcd_device(cdev);
+
+	enable = simple_strtoul(buf, &endp, 0);
+	if (*endp && !isspace (*endp))
+		return -EINVAL;
+
+	down (&ld->sem);
+	if (likely (ld->props && ld->props->set_enable)) {
+		pr_debug("lcd: set enable to %d\n", enable);
+		ld->props->set_enable(ld, enable);
+		rc = count;
+	} else
+		rc = -ENXIO;
+	up (&ld->sem);
+
+	return rc;
+}
+
+static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct lcd_device *ld = to_lcd_device(cdev);
+
+	down (&ld->sem);
+	if (likely (ld->props && ld->props->get_contrast))
+		rc = sprintf (buf, "%d\n", ld->props->get_contrast(ld));
+	else
+		rc = -ENXIO;
+	up (&ld->sem);
+
+	return rc;
+}
+
+static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, size_t count)
+{
+	int rc, contrast;
+	char *endp;
+	struct lcd_device *ld = to_lcd_device(cdev);
+
+	contrast = simple_strtoul(buf, &endp, 0);
+	if (*endp && !isspace (*endp))
+		return -EINVAL;
+
+	down (&ld->sem);
+	if (likely (ld->props && ld->props->set_contrast)) {
+		pr_debug("lcd: set contrast to %d\n", contrast);
+		ld->props->set_contrast(ld, contrast);
+		rc = count;
+	} else
+		rc = -ENXIO;
+	up (&ld->sem);
+
+	return rc;
+}
+
+static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct lcd_device *ld = to_lcd_device(cdev);
+
+	down (&ld->sem);
+	if (likely (ld->props))
+		rc = sprintf (buf, "%d\n", ld->props->max_contrast);
+	else
+		rc = -ENXIO;
+	up (&ld->sem);
+
+	return rc;
+}
+
+static void lcd_class_release(struct class_device *dev)
+{
+	struct lcd_device *ld = to_lcd_device (dev);
+	kfree (ld);
+}
+
+struct class lcd_class = {
+	.name = "lcd",
+	.release = lcd_class_release,
+};
+
+#define DECLARE_ATTR(_name,_mode,_show,_store)			\
+{							 	\
+	.attr	= { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },	\
+	.show	= _show,					\
+	.store	= _store,					\
+}
+
+static struct class_device_attribute lcd_class_device_attributes[] = {
+	DECLARE_ATTR (power, 0644, lcd_show_power, lcd_store_power),
+	DECLARE_ATTR (enable, 0644, lcd_show_enable, lcd_store_enable),
+	DECLARE_ATTR (contrast, 0644, lcd_show_contrast, lcd_store_contrast),
+	DECLARE_ATTR (max_contrast, 0444, lcd_show_max_contrast, NULL),
+};
+
+/**
+ * lcd_device_register - register a new object of lcd_device class.
+ * @name: the name of the new object (must be the same as the name of the
+ *   respective framebuffer device).
+ * @devdata: an optional pointer to be stored in the class_device. The
+ *   methods may retrieve it by using class_get_devdata (ld->class_dev).
+ * @lp: the lcd properties structure.
+ *
+ * Creates a new lcd class_device and copies data from the received ld
+ * structure into the new object. Returns after registering the new object.
+ */
+int lcd_device_register (const char *name, void *devdata,
+			 struct lcd_properties *lp)
+{
+	int i, rc;
+	struct lcd_device *new_ld;
+
+	pr_debug("lcd_device_register: name=%s\n", name);
+
+	new_ld = kmalloc (sizeof (struct lcd_device), GFP_KERNEL);
+	if (unlikely (!new_ld))
+		return -ENOMEM;
+
+	init_MUTEX (&new_ld->sem);
+	new_ld->props = lp;
+	new_ld->class_dev.class = &lcd_class;
+	strlcpy (new_ld->class_dev.class_id, name, KOBJ_NAME_LEN);
+	class_set_devdata (&new_ld->class_dev, devdata);
+	rc = class_device_register (&new_ld->class_dev);
+	if (unlikely (rc)) {
+		kfree (new_ld);
+		return rc;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++) {
+		rc = class_device_create_file(&new_ld->class_dev,
+					      &lcd_class_device_attributes[i]);
+		if (unlikely (rc)) {
+			while (--i >= 0)
+				class_device_remove_file(&new_ld->class_dev,
+							 &lcd_class_device_attributes[i]);
+			class_device_unregister(&new_ld->class_dev);
+			return rc;
+		}
+	}
+
+	notifier_call_chain (&lcd_device_chain, 0, new_ld);
+
+	return 0;
+}
+EXPORT_SYMBOL(lcd_device_register);
+
+/**
+ * lcd_device_unregister - unregisters a object of lcd_device class.
+ * @name: the name of the object (must be the same as the name of the
+ *   respective framebuffer device).
+ *
+ * Unregisters a previously registered via lcd_device_register object.
+ */
+void lcd_device_unregister(const char *name)
+{
+	int i;
+	struct lcd_device *ld;
+	struct class_device *class_dev =
+		class_device_find (&lcd_class, name);
+
+	if (!class_dev)
+		return;
+
+	pr_debug("lcd_device_unregister: name=%s\n", name);
+
+	for (i = 0; i < ARRAY_SIZE (lcd_class_device_attributes); i++)
+		class_device_remove_file (class_dev,
+					  &lcd_class_device_attributes[i]);
+
+	ld = to_lcd_device (class_dev);
+	down (&ld->sem);
+	ld->props = NULL;
+	up (&ld->sem);
+
+	class_device_unregister(class_dev);
+	/* We got the reference counter incremented by class_device_find() */
+	class_device_put(class_dev);
+}
+EXPORT_SYMBOL(lcd_device_unregister);
+
+/**
+ * lcd_device_find - find a LCD device by name.
+ * @name: the name of the LCD object to find.
+ *
+ * The reference counter of the returned object as well as on the module
+ * that implements the backlight functions are incremented.
+ */
+struct lcd_device *lcd_device_find(const char *name)
+{
+	struct lcd_device *ld;
+	struct class_device *class_dev =
+		class_device_find (&lcd_class, name);
+
+	if (unlikely (!class_dev))
+		return NULL;
+
+	ld = lcd_device_get (to_lcd_device (class_dev));
+	class_device_put (class_dev);
+	return ld;
+}
+EXPORT_SYMBOL(lcd_device_find);
+
+/**
+ * lcd_device_get - increment reference counter of a LCD device
+ *   and on the module that implements the LCD device methods.
+ * @ld: the LCD device object.
+ *
+ * Increments the reference counter on both the LCD device and on the
+ * module that implements this LCD device.
+ */
+struct lcd_device *lcd_device_get(struct lcd_device *ld)
+{
+	struct class_device *class_dev = class_device_get (&ld->class_dev);
+
+	if (likely (class_dev)) {
+		down (&ld->sem);
+		if (likely (ld->props && try_module_get (ld->props->owner))) {
+			up (&ld->sem);
+			return ld;
+		}
+		up (&ld->sem);
+
+		class_device_put(class_dev);
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(lcd_device_get);
+
+/**
+ * lcd_device_put - decrement reference counter of a LCD device.
+ * @ld: the LCD device object.
+ *
+ * Decrements the reference counter on both the LCD device and on the
+ * module that implements this LCD device.
+ */
+void lcd_device_put(struct lcd_device *ld)
+{
+	if (ld) {
+		down (&ld->sem);
+		if (ld->props)
+			module_put(ld->props->owner);
+		up (&ld->sem);
+		class_device_put (&ld->class_dev);
+	}
+}
+EXPORT_SYMBOL(lcd_device_put);
+
+static void __exit lcd_class_exit(void)
+{
+	class_unregister(&lcd_class);
+}
+
+static int __init lcd_class_init(void)
+{
+	return class_register(&lcd_class);
+}
+
+/*
+ * if this is compiled into the kernel, we need to ensure that the
+ * class is registered before users of the class try to register lcd's
+ */
+postcore_initcall(lcd_class_init);
+module_exit(lcd_class_exit);
--- linux-2.6.6/drivers/video/backlight.c	1970-01-01 03:00:00.000000000 +0300
+++ linux-2.6.6-hh0/drivers/video/backlight.c	2004-05-29 00:56:53.000000000 +0400
@@ -0,0 +1,301 @@
+/*
+ * Backlight Lowlevel Control Abstraction
+ * 
+ * Copyright (C) 2003,2004 Hewlett-Packard Company
+ * 
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/backlight.h>
+#include <linux/notifier.h>
+#include <linux/ctype.h>
+#include <asm/bug.h>
+
+struct notifier_block *backlight_device_chain;
+EXPORT_SYMBOL (backlight_device_chain);
+
+static ssize_t backlight_show_power (struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct backlight_device *bd = to_backlight_device (cdev);
+
+	down (&bd->sem);
+	if (likely (bd->props && bd->props->get_power))
+		rc = sprintf (buf, "%d\n", bd->props->get_power (bd));
+	else
+		rc = -ENXIO;
+	up (&bd->sem);
+
+	return rc;
+}
+
+static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count)
+{
+	int rc, power;
+	char *endp;
+	struct backlight_device *bd = to_backlight_device (cdev);
+
+	power = simple_strtoul (buf, &endp, 0);
+	if (*endp && !isspace (*endp))
+		return -EINVAL;
+
+	down (&bd->sem);
+	if (likely (bd->props && bd->props->set_power)) {
+		pr_debug("backlight: set power to %d\n", power);
+		bd->props->set_power(bd, power);
+		rc = count;
+	} else
+		rc = -ENXIO;
+	up (&bd->sem);
+
+	return rc;
+}
+
+static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct backlight_device *bd = to_backlight_device (cdev);
+
+	down (&bd->sem);
+	if (likely (bd->props && bd->props->get_brightness))
+		rc = sprintf (buf, "%d\n", bd->props->get_brightness (bd));
+	else
+		rc = -ENXIO;
+	up (&bd->sem);
+
+	return rc;
+}
+
+static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count)
+{
+	int rc, brightness;
+	char *endp;
+	struct backlight_device *bd = to_backlight_device (cdev);
+
+	brightness = simple_strtoul (buf, &endp, 0);
+	if (*endp && !isspace (*endp))
+		return -EINVAL;
+
+	down (&bd->sem);
+	if (likely (bd->props && bd->props->set_brightness)) {
+		pr_debug("backlight: set brightness to %d\n", brightness);
+		bd->props->set_brightness(bd, brightness);
+		rc = count;
+	} else
+		rc = -ENXIO;
+	up (&bd->sem);
+
+	return rc;
+}
+
+static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct backlight_device *bd = to_backlight_device (cdev);
+
+	down (&bd->sem);
+	if (likely (bd->props))
+		rc = sprintf(buf, "%d\n", bd->props->max_brightness);
+	else
+		rc = -ENXIO;
+	up (&bd->sem);
+
+	return rc;
+}
+
+static void backlight_class_release(struct class_device *dev)
+{
+	struct backlight_device *bd = to_backlight_device (dev);
+	kfree (bd);
+}
+
+struct class backlight_class = {
+	.name = "backlight",
+	.release = backlight_class_release,
+};
+
+#define DECLARE_ATTR(_name,_mode,_show,_store)			\
+{							 	\
+	.attr	= { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },	\
+	.show	= _show,					\
+	.store	= _store,					\
+}
+
+static struct class_device_attribute bl_class_device_attributes[] = {
+	DECLARE_ATTR (power, 0644, backlight_show_power, backlight_store_power),
+	DECLARE_ATTR (brightness, 0644, backlight_show_brightness, backlight_store_brightness),
+	DECLARE_ATTR (max_brightness, 0444, backlight_show_max_brightness, NULL),
+};
+
+/**
+ * backlight_device_register - register a new object of backlight_device class.
+ * @name: the name of the new object (must be the same as the name of the
+ *   respective framebuffer device).
+ * @devdata: an optional pointer to be stored in the class_device. The
+ *   methods may retrieve it by using class_get_devdata (&bd->class_dev).
+ * @bp: the backlight properties structure.
+ *
+ * Creates a new backlight class_device. Returns after registering the
+ * new object.
+ */
+int backlight_device_register(const char *name, void *devdata,
+			      struct backlight_properties *bp)
+{
+	int i, rc;
+	struct backlight_device *new_bd;
+
+	pr_debug("backlight_device_register: name=%s\n", name);
+
+	new_bd = kmalloc (sizeof (struct backlight_device), GFP_KERNEL);
+	if (unlikely (!new_bd))
+		return -ENOMEM;
+
+	init_MUTEX (&new_bd->sem);
+	new_bd->props = bp;
+	new_bd->class_dev.class = &backlight_class;
+	strlcpy (new_bd->class_dev.class_id, name, KOBJ_NAME_LEN);
+	class_set_devdata (&new_bd->class_dev, devdata);
+	rc = class_device_register (&new_bd->class_dev);
+	if (unlikely (rc)) {
+		kfree (new_bd);
+		return rc;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) {
+		rc = class_device_create_file(&new_bd->class_dev,
+					      &bl_class_device_attributes[i]);
+		if (unlikely (rc)) {
+			while (--i >= 0)
+				class_device_remove_file(&new_bd->class_dev,
+							 &bl_class_device_attributes[i]);
+			class_device_unregister(&new_bd->class_dev);
+			return rc;
+		}
+	}
+
+	notifier_call_chain (&backlight_device_chain, 0, new_bd);
+
+	return 0;
+}
+EXPORT_SYMBOL(backlight_device_register);
+
+/**
+ * backlight_device_unregister - unregisters a object of backlight_device class.
+ * @name: the name of the object (must be the same as the name of the
+ *   respective framebuffer device).
+ *
+ * Unregisters a previously registered via backlight_device_register object.
+ */
+void backlight_device_unregister(const char *name)
+{
+	int i;
+	struct backlight_device *bd;
+	struct class_device *class_dev =
+		class_device_find (&backlight_class, name);
+
+	if (!class_dev)
+		return;
+
+	pr_debug("backlight_device_unregister: name=%s\n", name);
+
+	for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++)
+		class_device_remove_file (class_dev,
+                                          &bl_class_device_attributes[i]);
+
+	bd = to_backlight_device (class_dev);
+	down (&bd->sem);
+	bd->props = NULL;
+	up (&bd->sem);
+
+	class_device_unregister(class_dev);
+	/* We got the reference counter incremented by class_device_find() */
+	class_device_put(class_dev);
+}
+EXPORT_SYMBOL(backlight_device_unregister);
+
+/**
+ * backlight_device_find - find a backlight device by name.
+ * @name: the name of the backlight object to find.
+ *
+ * The reference counter of the returned object as well as on the module
+ * that implements the backlight functions are incremented.
+ */
+struct backlight_device *backlight_device_find(const char *name)
+{
+	struct backlight_device *bd;
+	struct class_device *class_dev =
+		class_device_find (&backlight_class, name);
+
+	if (unlikely (!class_dev))
+		return NULL;
+
+	bd = backlight_device_get (to_backlight_device (class_dev));
+	class_device_put (class_dev);
+	return bd;
+}
+EXPORT_SYMBOL(backlight_device_find);
+
+/**
+ * backlight_device_get - increment reference counter of a backlight device
+ *   and on the module that implements the backlight device methods.
+ * @bd: the backlight device object.
+ *
+ * Increments the reference counter on both the backlight device and on the
+ * module that implements this backlight device.
+ */
+struct backlight_device *backlight_device_get(struct backlight_device *bd)
+{
+	struct class_device *class_dev = class_device_get (&bd->class_dev);
+
+	if (likely (class_dev)) {
+		down (&bd->sem);
+		if (likely (bd->props && try_module_get (bd->props->owner))) {
+			up (&bd->sem);
+			return bd;
+		}
+                up (&bd->sem);
+
+		class_device_put(class_dev);
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(backlight_device_get);
+
+/**
+ * backlight_device_put - decrement reference counter of a backlight device.
+ * @ld: the backlight device object.
+ *
+ * Decrements the reference counter on both the backlight device and on the
+ * module that implements this backlight device.
+ */
+void backlight_device_put(struct backlight_device *bd)
+{
+	if (bd) {
+		down (&bd->sem);
+		if (bd->props)
+			module_put(bd->props->owner);
+		up (&bd->sem);
+		class_device_put (&bd->class_dev);
+	}
+}
+EXPORT_SYMBOL(backlight_device_put);
+
+static void __exit backlight_class_exit(void)
+{
+	class_unregister(&backlight_class);
+}
+
+static int __init backlight_class_init(void)
+{
+	return class_register(&backlight_class);
+}
+
+/*
+ * if this is compiled into the kernel, we need to ensure that the
+ * class is registered before users of the class try to register lcd's
+ */
+postcore_initcall(backlight_class_init);
+module_exit(backlight_class_exit);
--- linux-2.6.6/drivers/video/Kconfig	2004-05-10 06:31:59.000000000 +0400
+++ replacement/drivers/video/Kconfig	2004-05-28 23:19:45.000000000 +0400
@@ -38,6 +38,38 @@
 	  (e.g. an accelerated X server) and that are not frame buffer
 	  device-aware may cause unexpected results. If unsure, say N.
 
+config LCD_CLASS_DEVICE
+        tristate "Lowlevel LCD controls"
+	depends on FB
+	help
+	  This framework adds support for low-level control of LCD.
+	  Some framebuffer devices connect to platform-specific LCD modules
+	  in order to have a platform-specific way to control the flat panel
+	  (contrast and applying power to the LCD (not to the backlight!)).
+
+	  To have support for your specific LCD panel you will have to
+	  select the proper drivers which depend on this option.
+
+config LCD_DEVICE
+	bool
+	depends on LCD_CLASS_DEVICE
+	default FB
+
+config BACKLIGHT_CLASS_DEVICE
+        tristate "Lowlevel Backlight controls"
+	depends on FB
+	help
+	  This framework adds support for low-level control of the LCD
+          backlight. This includes support for brightness and power.
+
+	  To have support for your specific LCD panel you will have to
+	  select the proper drivers which depend on this option.
+
+config BACKLIGHT_DEVICE
+	bool
+	depends on BACKLIGHT_CLASS_DEVICE
+	default FB
+
 config FB_CIRRUS
 	tristate "Cirrus Logic support"
 	depends on FB && (AMIGA || PCI) && BROKEN
--- linux-2.6.6/drivers/video/Makefile	2004-05-10 06:32:00.000000000 +0400
+++ replacement/drivers/video/Makefile	2004-05-25 21:29:26.000000000 +0400
@@ -13,6 +13,9 @@
 obj-$(CONFIG_PPC)                 += macmodes.o
 endif
 
+obj-$(CONFIG_LCD_DEVICE)          += lcd.o
+obj-$(CONFIG_BACKLIGHT_DEVICE)    += backlight.o
+
 obj-$(CONFIG_FB_ACORN)            += acornfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_AMIGA)            += amifb.o c2p.o
 obj-$(CONFIG_FB_PM2)              += pm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2004-06-04 22:48 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-05-28 21:20 two patches - request for comments Andrew Zabolotny
2004-05-28 21:59 ` Todd Poynor
2004-05-29  8:10   ` Andrew Zabolotny
2004-06-01 20:09     ` Todd Poynor
2004-06-01 21:00       ` Andrew Zabolotny
2004-06-02 17:15         ` Greg KH
2004-06-02 21:25           ` Andrew Zabolotny
2004-06-02 21:32           ` Russell King
2004-06-04 20:43             ` Greg KH
2004-05-28 22:10 ` Greg KH
2004-05-29  8:44   ` Andrew Zabolotny
2004-06-01 21:23     ` Jeff Garzik
2004-06-01 21:57       ` Andrew Zabolotny
2004-06-02 17:12         ` Greg KH
2004-05-29 13:46 ` Denis Vlasenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox