diff options
author | James Simmons <jsimmons@infradead.org> | 2007-05-08 03:37:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 14:15:26 -0400 |
commit | 2ee121631b9dd0291502ccac6f897907505faf8c (patch) | |
tree | 241c6fed7da9fe24c998674d6ba9d8ec1bf10f52 /drivers | |
parent | 825d0a97f3b9031235b1ee77b1e22fec15c758ba (diff) |
fbdev: display class
Add the new display class. This is meant to unite the various solutions to
display units ie acpi output device, auxdisplay and the defunct lcd class
in the backlight directory.
Signed-off-by: James Simmons <jsimmons@infradead.org>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/Kconfig | 1 | ||||
-rw-r--r-- | drivers/video/Makefile | 2 | ||||
-rw-r--r-- | drivers/video/display/Kconfig | 24 | ||||
-rw-r--r-- | drivers/video/display/Makefile | 6 | ||||
-rw-r--r-- | drivers/video/display/display-sysfs.c | 217 |
5 files changed, 249 insertions, 1 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 344c37595305..8dfa88a68ae9 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -5,6 +5,7 @@ | |||
5 | menu "Graphics support" | 5 | menu "Graphics support" |
6 | 6 | ||
7 | source "drivers/video/backlight/Kconfig" | 7 | source "drivers/video/backlight/Kconfig" |
8 | source "drivers/video/display/Kconfig" | ||
8 | 9 | ||
9 | config FB | 10 | config FB |
10 | tristate "Support for frame buffer devices" | 11 | tristate "Support for frame buffer devices" |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 558473d040d6..281462414930 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -12,7 +12,7 @@ fb-objs := $(fb-y) | |||
12 | 12 | ||
13 | obj-$(CONFIG_VT) += console/ | 13 | obj-$(CONFIG_VT) += console/ |
14 | obj-$(CONFIG_LOGO) += logo/ | 14 | obj-$(CONFIG_LOGO) += logo/ |
15 | obj-y += backlight/ | 15 | obj-y += backlight/ display/ |
16 | 16 | ||
17 | obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o | 17 | obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o |
18 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o | 18 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o |
diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig new file mode 100644 index 000000000000..f99af931d4f8 --- /dev/null +++ b/drivers/video/display/Kconfig | |||
@@ -0,0 +1,24 @@ | |||
1 | # | ||
2 | # Display drivers configuration | ||
3 | # | ||
4 | |||
5 | menu "Display device support" | ||
6 | |||
7 | config DISPLAY_SUPPORT | ||
8 | tristate "Display panel/monitor support" | ||
9 | ---help--- | ||
10 | This framework adds support for low-level control of a display. | ||
11 | This includes support for power. | ||
12 | |||
13 | Enable this to be able to choose the drivers for controlling the | ||
14 | physical display panel/monitor on some platforms. This not only | ||
15 | covers LCD displays for PDAs but also other types of displays | ||
16 | such as CRT, TVout etc. | ||
17 | |||
18 | To have support for your specific display panel you will have to | ||
19 | select the proper drivers which depend on this option. | ||
20 | |||
21 | comment "Display hardware drivers" | ||
22 | depends on DISPLAY_SUPPORT | ||
23 | |||
24 | endmenu | ||
diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile new file mode 100644 index 000000000000..c0ea832bf171 --- /dev/null +++ b/drivers/video/display/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # Display drivers | ||
2 | |||
3 | display-objs := display-sysfs.o | ||
4 | |||
5 | obj-$(CONFIG_DISPLAY_SUPPORT) += display.o | ||
6 | |||
diff --git a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c new file mode 100644 index 000000000000..39c27b604cc3 --- /dev/null +++ b/drivers/video/display/display-sysfs.c | |||
@@ -0,0 +1,217 @@ | |||
1 | /* | ||
2 | * display-sysfs.c - Display output driver sysfs interface | ||
3 | * | ||
4 | * Copyright (C) 2007 James Simmons <jsimmons@infradead.org> | ||
5 | * | ||
6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or (at | ||
11 | * your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | */ | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/display.h> | ||
26 | #include <linux/ctype.h> | ||
27 | #include <linux/idr.h> | ||
28 | #include <linux/err.h> | ||
29 | |||
30 | static ssize_t display_show_name(struct device *dev, | ||
31 | struct device_attribute *attr, char *buf) | ||
32 | { | ||
33 | struct display_device *dsp = dev_get_drvdata(dev); | ||
34 | return snprintf(buf, PAGE_SIZE, "%s\n", dsp->name); | ||
35 | } | ||
36 | |||
37 | static ssize_t display_show_type(struct device *dev, | ||
38 | struct device_attribute *attr, char *buf) | ||
39 | { | ||
40 | struct display_device *dsp = dev_get_drvdata(dev); | ||
41 | return snprintf(buf, PAGE_SIZE, "%s\n", dsp->type); | ||
42 | } | ||
43 | |||
44 | static ssize_t display_show_contrast(struct device *dev, | ||
45 | struct device_attribute *attr, char *buf) | ||
46 | { | ||
47 | struct display_device *dsp = dev_get_drvdata(dev); | ||
48 | ssize_t rc = -ENXIO; | ||
49 | |||
50 | mutex_lock(&dsp->lock); | ||
51 | if (likely(dsp->driver) && dsp->driver->get_contrast) | ||
52 | rc = sprintf(buf, "%d\n", dsp->driver->get_contrast(dsp)); | ||
53 | mutex_unlock(&dsp->lock); | ||
54 | return rc; | ||
55 | } | ||
56 | |||
57 | static ssize_t display_store_contrast(struct device *dev, | ||
58 | struct device_attribute *attr, | ||
59 | const char *buf, size_t count) | ||
60 | { | ||
61 | struct display_device *dsp = dev_get_drvdata(dev); | ||
62 | ssize_t ret = -EINVAL, size; | ||
63 | int contrast; | ||
64 | char *endp; | ||
65 | |||
66 | contrast = simple_strtoul(buf, &endp, 0); | ||
67 | size = endp - buf; | ||
68 | |||
69 | if (*endp && isspace(*endp)) | ||
70 | size++; | ||
71 | |||
72 | if (size != count) | ||
73 | return ret; | ||
74 | |||
75 | mutex_lock(&dsp->lock); | ||
76 | if (likely(dsp->driver && dsp->driver->set_contrast)) { | ||
77 | pr_debug("display: set contrast to %d\n", contrast); | ||
78 | dsp->driver->set_contrast(dsp, contrast); | ||
79 | ret = count; | ||
80 | } | ||
81 | mutex_unlock(&dsp->lock); | ||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | static ssize_t display_show_max_contrast(struct device *dev, | ||
86 | struct device_attribute *attr, | ||
87 | char *buf) | ||
88 | { | ||
89 | struct display_device *dsp = dev_get_drvdata(dev); | ||
90 | ssize_t rc = -ENXIO; | ||
91 | |||
92 | mutex_lock(&dsp->lock); | ||
93 | if (likely(dsp->driver)) | ||
94 | rc = sprintf(buf, "%d\n", dsp->driver->max_contrast); | ||
95 | mutex_unlock(&dsp->lock); | ||
96 | return rc; | ||
97 | } | ||
98 | |||
99 | static struct device_attribute display_attrs[] = { | ||
100 | __ATTR(name, S_IRUGO, display_show_name, NULL), | ||
101 | __ATTR(type, S_IRUGO, display_show_type, NULL), | ||
102 | __ATTR(contrast, S_IRUGO | S_IWUSR, display_show_contrast, display_store_contrast), | ||
103 | __ATTR(max_contrast, S_IRUGO, display_show_max_contrast, NULL), | ||
104 | }; | ||
105 | |||
106 | static int display_suspend(struct device *dev, pm_message_t state) | ||
107 | { | ||
108 | struct display_device *dsp = dev_get_drvdata(dev); | ||
109 | |||
110 | mutex_lock(&dsp->lock); | ||
111 | if (likely(dsp->driver->suspend)) | ||
112 | dsp->driver->suspend(dsp, state); | ||
113 | mutex_unlock(&dsp->lock); | ||
114 | return 0; | ||
115 | }; | ||
116 | |||
117 | static int display_resume(struct device *dev) | ||
118 | { | ||
119 | struct display_device *dsp = dev_get_drvdata(dev); | ||
120 | |||
121 | mutex_lock(&dsp->lock); | ||
122 | if (likely(dsp->driver->resume)) | ||
123 | dsp->driver->resume(dsp); | ||
124 | mutex_unlock(&dsp->lock); | ||
125 | return 0; | ||
126 | }; | ||
127 | |||
128 | static struct mutex allocated_dsp_lock; | ||
129 | static DEFINE_IDR(allocated_dsp); | ||
130 | struct class *display_class; | ||
131 | |||
132 | struct display_device *display_device_register(struct display_driver *driver, | ||
133 | struct device *parent, void *devdata) | ||
134 | { | ||
135 | struct display_device *new_dev = NULL; | ||
136 | int ret = -EINVAL; | ||
137 | |||
138 | if (unlikely(!driver)) | ||
139 | return ERR_PTR(ret); | ||
140 | |||
141 | mutex_lock(&allocated_dsp_lock); | ||
142 | ret = idr_pre_get(&allocated_dsp, GFP_KERNEL); | ||
143 | mutex_unlock(&allocated_dsp_lock); | ||
144 | if (!ret) | ||
145 | return ERR_PTR(ret); | ||
146 | |||
147 | new_dev = kzalloc(sizeof(struct display_device), GFP_KERNEL); | ||
148 | if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) { | ||
149 | // Reserve the index for this display | ||
150 | mutex_lock(&allocated_dsp_lock); | ||
151 | ret = idr_get_new(&allocated_dsp, new_dev, &new_dev->idx); | ||
152 | mutex_unlock(&allocated_dsp_lock); | ||
153 | |||
154 | if (!ret) { | ||
155 | new_dev->dev = device_create(display_class, parent, 0, | ||
156 | "display%d", new_dev->idx); | ||
157 | if (!IS_ERR(new_dev->dev)) { | ||
158 | dev_set_drvdata(new_dev->dev, new_dev); | ||
159 | new_dev->parent = parent; | ||
160 | new_dev->driver = driver; | ||
161 | mutex_init(&new_dev->lock); | ||
162 | return new_dev; | ||
163 | } | ||
164 | mutex_lock(&allocated_dsp_lock); | ||
165 | idr_remove(&allocated_dsp, new_dev->idx); | ||
166 | mutex_unlock(&allocated_dsp_lock); | ||
167 | ret = -EINVAL; | ||
168 | } | ||
169 | } | ||
170 | kfree(new_dev); | ||
171 | return ERR_PTR(ret); | ||
172 | } | ||
173 | EXPORT_SYMBOL(display_device_register); | ||
174 | |||
175 | void display_device_unregister(struct display_device *ddev) | ||
176 | { | ||
177 | if (!ddev) | ||
178 | return; | ||
179 | // Free device | ||
180 | mutex_lock(&ddev->lock); | ||
181 | device_unregister(ddev->dev); | ||
182 | mutex_unlock(&ddev->lock); | ||
183 | // Mark device index as avaliable | ||
184 | mutex_lock(&allocated_dsp_lock); | ||
185 | idr_remove(&allocated_dsp, ddev->idx); | ||
186 | mutex_unlock(&allocated_dsp_lock); | ||
187 | kfree(ddev); | ||
188 | } | ||
189 | EXPORT_SYMBOL(display_device_unregister); | ||
190 | |||
191 | static int __init display_class_init(void) | ||
192 | { | ||
193 | display_class = class_create(THIS_MODULE, "display"); | ||
194 | if (IS_ERR(display_class)) { | ||
195 | printk(KERN_ERR "Failed to create display class\n"); | ||
196 | display_class = NULL; | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | display_class->dev_attrs = display_attrs; | ||
200 | display_class->suspend = display_suspend; | ||
201 | display_class->resume = display_resume; | ||
202 | mutex_init(&allocated_dsp_lock); | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static void __exit display_class_exit(void) | ||
207 | { | ||
208 | class_destroy(display_class); | ||
209 | } | ||
210 | |||
211 | module_init(display_class_init); | ||
212 | module_exit(display_class_exit); | ||
213 | |||
214 | MODULE_DESCRIPTION("Display Hardware handling"); | ||
215 | MODULE_AUTHOR("James Simmons <jsimmons@infradead.org>"); | ||
216 | MODULE_LICENSE("GPL"); | ||
217 | |||