Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.32-rc3 218 lines 6.1 kB view raw
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#include <linux/kdev_t.h> 30 31static ssize_t display_show_name(struct device *dev, 32 struct device_attribute *attr, char *buf) 33{ 34 struct display_device *dsp = dev_get_drvdata(dev); 35 return snprintf(buf, PAGE_SIZE, "%s\n", dsp->name); 36} 37 38static ssize_t display_show_type(struct device *dev, 39 struct device_attribute *attr, char *buf) 40{ 41 struct display_device *dsp = dev_get_drvdata(dev); 42 return snprintf(buf, PAGE_SIZE, "%s\n", dsp->type); 43} 44 45static ssize_t display_show_contrast(struct device *dev, 46 struct device_attribute *attr, char *buf) 47{ 48 struct display_device *dsp = dev_get_drvdata(dev); 49 ssize_t rc = -ENXIO; 50 51 mutex_lock(&dsp->lock); 52 if (likely(dsp->driver) && dsp->driver->get_contrast) 53 rc = sprintf(buf, "%d\n", dsp->driver->get_contrast(dsp)); 54 mutex_unlock(&dsp->lock); 55 return rc; 56} 57 58static ssize_t display_store_contrast(struct device *dev, 59 struct device_attribute *attr, 60 const char *buf, size_t count) 61{ 62 struct display_device *dsp = dev_get_drvdata(dev); 63 ssize_t ret = -EINVAL, size; 64 int contrast; 65 char *endp; 66 67 contrast = simple_strtoul(buf, &endp, 0); 68 size = endp - buf; 69 70 if (*endp && isspace(*endp)) 71 size++; 72 73 if (size != count) 74 return ret; 75 76 mutex_lock(&dsp->lock); 77 if (likely(dsp->driver && dsp->driver->set_contrast)) { 78 pr_debug("display: set contrast to %d\n", contrast); 79 dsp->driver->set_contrast(dsp, contrast); 80 ret = count; 81 } 82 mutex_unlock(&dsp->lock); 83 return ret; 84} 85 86static ssize_t display_show_max_contrast(struct device *dev, 87 struct device_attribute *attr, 88 char *buf) 89{ 90 struct display_device *dsp = dev_get_drvdata(dev); 91 ssize_t rc = -ENXIO; 92 93 mutex_lock(&dsp->lock); 94 if (likely(dsp->driver)) 95 rc = sprintf(buf, "%d\n", dsp->driver->max_contrast); 96 mutex_unlock(&dsp->lock); 97 return rc; 98} 99 100static struct device_attribute display_attrs[] = { 101 __ATTR(name, S_IRUGO, display_show_name, NULL), 102 __ATTR(type, S_IRUGO, display_show_type, NULL), 103 __ATTR(contrast, S_IRUGO | S_IWUSR, display_show_contrast, display_store_contrast), 104 __ATTR(max_contrast, S_IRUGO, display_show_max_contrast, NULL), 105}; 106 107static int display_suspend(struct device *dev, pm_message_t state) 108{ 109 struct display_device *dsp = dev_get_drvdata(dev); 110 111 mutex_lock(&dsp->lock); 112 if (likely(dsp->driver->suspend)) 113 dsp->driver->suspend(dsp, state); 114 mutex_unlock(&dsp->lock); 115 return 0; 116}; 117 118static int display_resume(struct device *dev) 119{ 120 struct display_device *dsp = dev_get_drvdata(dev); 121 122 mutex_lock(&dsp->lock); 123 if (likely(dsp->driver->resume)) 124 dsp->driver->resume(dsp); 125 mutex_unlock(&dsp->lock); 126 return 0; 127}; 128 129static struct mutex allocated_dsp_lock; 130static DEFINE_IDR(allocated_dsp); 131static struct class *display_class; 132 133struct display_device *display_device_register(struct display_driver *driver, 134 struct device *parent, void *devdata) 135{ 136 struct display_device *new_dev = NULL; 137 int ret = -EINVAL; 138 139 if (unlikely(!driver)) 140 return ERR_PTR(ret); 141 142 mutex_lock(&allocated_dsp_lock); 143 ret = idr_pre_get(&allocated_dsp, GFP_KERNEL); 144 mutex_unlock(&allocated_dsp_lock); 145 if (!ret) 146 return ERR_PTR(ret); 147 148 new_dev = kzalloc(sizeof(struct display_device), GFP_KERNEL); 149 if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) { 150 // Reserve the index for this display 151 mutex_lock(&allocated_dsp_lock); 152 ret = idr_get_new(&allocated_dsp, new_dev, &new_dev->idx); 153 mutex_unlock(&allocated_dsp_lock); 154 155 if (!ret) { 156 new_dev->dev = device_create(display_class, parent, 157 MKDEV(0, 0), new_dev, 158 "display%d", new_dev->idx); 159 if (!IS_ERR(new_dev->dev)) { 160 new_dev->parent = parent; 161 new_dev->driver = driver; 162 mutex_init(&new_dev->lock); 163 return new_dev; 164 } 165 mutex_lock(&allocated_dsp_lock); 166 idr_remove(&allocated_dsp, new_dev->idx); 167 mutex_unlock(&allocated_dsp_lock); 168 ret = -EINVAL; 169 } 170 } 171 kfree(new_dev); 172 return ERR_PTR(ret); 173} 174EXPORT_SYMBOL(display_device_register); 175 176void display_device_unregister(struct display_device *ddev) 177{ 178 if (!ddev) 179 return; 180 // Free device 181 mutex_lock(&ddev->lock); 182 device_unregister(ddev->dev); 183 mutex_unlock(&ddev->lock); 184 // Mark device index as avaliable 185 mutex_lock(&allocated_dsp_lock); 186 idr_remove(&allocated_dsp, ddev->idx); 187 mutex_unlock(&allocated_dsp_lock); 188 kfree(ddev); 189} 190EXPORT_SYMBOL(display_device_unregister); 191 192static int __init display_class_init(void) 193{ 194 display_class = class_create(THIS_MODULE, "display"); 195 if (IS_ERR(display_class)) { 196 printk(KERN_ERR "Failed to create display class\n"); 197 display_class = NULL; 198 return -EINVAL; 199 } 200 display_class->dev_attrs = display_attrs; 201 display_class->suspend = display_suspend; 202 display_class->resume = display_resume; 203 mutex_init(&allocated_dsp_lock); 204 return 0; 205} 206 207static void __exit display_class_exit(void) 208{ 209 class_destroy(display_class); 210} 211 212module_init(display_class_init); 213module_exit(display_class_exit); 214 215MODULE_DESCRIPTION("Display Hardware handling"); 216MODULE_AUTHOR("James Simmons <jsimmons@infradead.org>"); 217MODULE_LICENSE("GPL"); 218