driver core: Convert some drivers to CLASS_ATTR_STRING
[safe/jmp/linux-2.6] / drivers / gpu / drm / drm_sysfs.c
1
2 /*
3  * drm_sysfs.c - Modifications to drm_sysfs_class.c to support
4  *               extra sysfs attribute from DRM. Normal drm_sysfs_class
5  *               does not allow adding attributes.
6  *
7  * Copyright (c) 2004 Jon Smirl <jonsmirl@gmail.com>
8  * Copyright (c) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
9  * Copyright (c) 2003-2004 IBM Corp.
10  *
11  * This file is released under the GPLv2
12  *
13  */
14
15 #include <linux/device.h>
16 #include <linux/kdev_t.h>
17 #include <linux/err.h>
18
19 #include "drm_sysfs.h"
20 #include "drm_core.h"
21 #include "drmP.h"
22
23 #define to_drm_minor(d) container_of(d, struct drm_minor, kdev)
24 #define to_drm_connector(d) container_of(d, struct drm_connector, kdev)
25
26 static struct device_type drm_sysfs_device_minor = {
27         .name = "drm_minor"
28 };
29
30 /**
31  * drm_class_suspend - DRM class suspend hook
32  * @dev: Linux device to suspend
33  * @state: power state to enter
34  *
35  * Just figures out what the actual struct drm_device associated with
36  * @dev is and calls its suspend hook, if present.
37  */
38 static int drm_class_suspend(struct device *dev, pm_message_t state)
39 {
40         if (dev->type == &drm_sysfs_device_minor) {
41                 struct drm_minor *drm_minor = to_drm_minor(dev);
42                 struct drm_device *drm_dev = drm_minor->dev;
43
44                 if (drm_minor->type == DRM_MINOR_LEGACY &&
45                     !drm_core_check_feature(drm_dev, DRIVER_MODESET) &&
46                     drm_dev->driver->suspend)
47                         return drm_dev->driver->suspend(drm_dev, state);
48         }
49         return 0;
50 }
51
52 /**
53  * drm_class_resume - DRM class resume hook
54  * @dev: Linux device to resume
55  *
56  * Just figures out what the actual struct drm_device associated with
57  * @dev is and calls its resume hook, if present.
58  */
59 static int drm_class_resume(struct device *dev)
60 {
61         if (dev->type == &drm_sysfs_device_minor) {
62                 struct drm_minor *drm_minor = to_drm_minor(dev);
63                 struct drm_device *drm_dev = drm_minor->dev;
64
65                 if (drm_minor->type == DRM_MINOR_LEGACY &&
66                     !drm_core_check_feature(drm_dev, DRIVER_MODESET) &&
67                     drm_dev->driver->resume)
68                         return drm_dev->driver->resume(drm_dev);
69         }
70         return 0;
71 }
72
73 static char *drm_devnode(struct device *dev, mode_t *mode)
74 {
75         return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
76 }
77
78 static CLASS_ATTR_STRING(version, S_IRUGO,
79                 CORE_NAME " "
80                 __stringify(CORE_MAJOR) "."
81                 __stringify(CORE_MINOR) "."
82                 __stringify(CORE_PATCHLEVEL) " "
83                 CORE_DATE);
84
85 /**
86  * drm_sysfs_create - create a struct drm_sysfs_class structure
87  * @owner: pointer to the module that is to "own" this struct drm_sysfs_class
88  * @name: pointer to a string for the name of this class.
89  *
90  * This is used to create DRM class pointer that can then be used
91  * in calls to drm_sysfs_device_add().
92  *
93  * Note, the pointer created here is to be destroyed when finished by making a
94  * call to drm_sysfs_destroy().
95  */
96 struct class *drm_sysfs_create(struct module *owner, char *name)
97 {
98         struct class *class;
99         int err;
100
101         class = class_create(owner, name);
102         if (IS_ERR(class)) {
103                 err = PTR_ERR(class);
104                 goto err_out;
105         }
106
107         class->suspend = drm_class_suspend;
108         class->resume = drm_class_resume;
109
110         err = class_create_file(class, &class_attr_version.attr);
111         if (err)
112                 goto err_out_class;
113
114         class->devnode = drm_devnode;
115
116         return class;
117
118 err_out_class:
119         class_destroy(class);
120 err_out:
121         return ERR_PTR(err);
122 }
123
124 /**
125  * drm_sysfs_destroy - destroys DRM class
126  *
127  * Destroy the DRM device class.
128  */
129 void drm_sysfs_destroy(void)
130 {
131         if ((drm_class == NULL) || (IS_ERR(drm_class)))
132                 return;
133         class_remove_file(drm_class, &class_attr_version.attr);
134         class_destroy(drm_class);
135 }
136
137 /**
138  * drm_sysfs_device_release - do nothing
139  * @dev: Linux device
140  *
141  * Normally, this would free the DRM device associated with @dev, along
142  * with cleaning up any other stuff.  But we do that in the DRM core, so
143  * this function can just return and hope that the core does its job.
144  */
145 static void drm_sysfs_device_release(struct device *dev)
146 {
147         memset(dev, 0, sizeof(struct device));
148         return;
149 }
150
151 /*
152  * Connector properties
153  */
154 static ssize_t status_show(struct device *device,
155                            struct device_attribute *attr,
156                            char *buf)
157 {
158         struct drm_connector *connector = to_drm_connector(device);
159         enum drm_connector_status status;
160
161         status = connector->funcs->detect(connector);
162         return snprintf(buf, PAGE_SIZE, "%s\n",
163                         drm_get_connector_status_name(status));
164 }
165
166 static ssize_t dpms_show(struct device *device,
167                            struct device_attribute *attr,
168                            char *buf)
169 {
170         struct drm_connector *connector = to_drm_connector(device);
171         struct drm_device *dev = connector->dev;
172         uint64_t dpms_status;
173         int ret;
174
175         ret = drm_connector_property_get_value(connector,
176                                             dev->mode_config.dpms_property,
177                                             &dpms_status);
178         if (ret)
179                 return 0;
180
181         return snprintf(buf, PAGE_SIZE, "%s\n",
182                         drm_get_dpms_name((int)dpms_status));
183 }
184
185 static ssize_t enabled_show(struct device *device,
186                             struct device_attribute *attr,
187                            char *buf)
188 {
189         struct drm_connector *connector = to_drm_connector(device);
190
191         return snprintf(buf, PAGE_SIZE, "%s\n", connector->encoder ? "enabled" :
192                         "disabled");
193 }
194
195 static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr,
196                          char *buf, loff_t off, size_t count)
197 {
198         struct device *connector_dev = container_of(kobj, struct device, kobj);
199         struct drm_connector *connector = to_drm_connector(connector_dev);
200         unsigned char *edid;
201         size_t size;
202
203         if (!connector->edid_blob_ptr)
204                 return 0;
205
206         edid = connector->edid_blob_ptr->data;
207         size = connector->edid_blob_ptr->length;
208         if (!edid)
209                 return 0;
210
211         if (off >= size)
212                 return 0;
213
214         if (off + count > size)
215                 count = size - off;
216         memcpy(buf, edid + off, count);
217
218         return count;
219 }
220
221 static ssize_t modes_show(struct device *device,
222                            struct device_attribute *attr,
223                            char *buf)
224 {
225         struct drm_connector *connector = to_drm_connector(device);
226         struct drm_display_mode *mode;
227         int written = 0;
228
229         list_for_each_entry(mode, &connector->modes, head) {
230                 written += snprintf(buf + written, PAGE_SIZE - written, "%s\n",
231                                     mode->name);
232         }
233
234         return written;
235 }
236
237 static ssize_t subconnector_show(struct device *device,
238                            struct device_attribute *attr,
239                            char *buf)
240 {
241         struct drm_connector *connector = to_drm_connector(device);
242         struct drm_device *dev = connector->dev;
243         struct drm_property *prop = NULL;
244         uint64_t subconnector;
245         int is_tv = 0;
246         int ret;
247
248         switch (connector->connector_type) {
249                 case DRM_MODE_CONNECTOR_DVII:
250                         prop = dev->mode_config.dvi_i_subconnector_property;
251                         break;
252                 case DRM_MODE_CONNECTOR_Composite:
253                 case DRM_MODE_CONNECTOR_SVIDEO:
254                 case DRM_MODE_CONNECTOR_Component:
255                 case DRM_MODE_CONNECTOR_TV:
256                         prop = dev->mode_config.tv_subconnector_property;
257                         is_tv = 1;
258                         break;
259                 default:
260                         DRM_ERROR("Wrong connector type for this property\n");
261                         return 0;
262         }
263
264         if (!prop) {
265                 DRM_ERROR("Unable to find subconnector property\n");
266                 return 0;
267         }
268
269         ret = drm_connector_property_get_value(connector, prop, &subconnector);
270         if (ret)
271                 return 0;
272
273         return snprintf(buf, PAGE_SIZE, "%s", is_tv ?
274                         drm_get_tv_subconnector_name((int)subconnector) :
275                         drm_get_dvi_i_subconnector_name((int)subconnector));
276 }
277
278 static ssize_t select_subconnector_show(struct device *device,
279                            struct device_attribute *attr,
280                            char *buf)
281 {
282         struct drm_connector *connector = to_drm_connector(device);
283         struct drm_device *dev = connector->dev;
284         struct drm_property *prop = NULL;
285         uint64_t subconnector;
286         int is_tv = 0;
287         int ret;
288
289         switch (connector->connector_type) {
290                 case DRM_MODE_CONNECTOR_DVII:
291                         prop = dev->mode_config.dvi_i_select_subconnector_property;
292                         break;
293                 case DRM_MODE_CONNECTOR_Composite:
294                 case DRM_MODE_CONNECTOR_SVIDEO:
295                 case DRM_MODE_CONNECTOR_Component:
296                 case DRM_MODE_CONNECTOR_TV:
297                         prop = dev->mode_config.tv_select_subconnector_property;
298                         is_tv = 1;
299                         break;
300                 default:
301                         DRM_ERROR("Wrong connector type for this property\n");
302                         return 0;
303         }
304
305         if (!prop) {
306                 DRM_ERROR("Unable to find select subconnector property\n");
307                 return 0;
308         }
309
310         ret = drm_connector_property_get_value(connector, prop, &subconnector);
311         if (ret)
312                 return 0;
313
314         return snprintf(buf, PAGE_SIZE, "%s", is_tv ?
315                         drm_get_tv_select_name((int)subconnector) :
316                         drm_get_dvi_i_select_name((int)subconnector));
317 }
318
319 static struct device_attribute connector_attrs[] = {
320         __ATTR_RO(status),
321         __ATTR_RO(enabled),
322         __ATTR_RO(dpms),
323         __ATTR_RO(modes),
324 };
325
326 /* These attributes are for both DVI-I connectors and all types of tv-out. */
327 static struct device_attribute connector_attrs_opt1[] = {
328         __ATTR_RO(subconnector),
329         __ATTR_RO(select_subconnector),
330 };
331
332 static struct bin_attribute edid_attr = {
333         .attr.name = "edid",
334         .attr.mode = 0444,
335         .size = 128,
336         .read = edid_show,
337 };
338
339 /**
340  * drm_sysfs_connector_add - add an connector to sysfs
341  * @connector: connector to add
342  *
343  * Create an connector device in sysfs, along with its associated connector
344  * properties (so far, connection status, dpms, mode list & edid) and
345  * generate a hotplug event so userspace knows there's a new connector
346  * available.
347  *
348  * Note:
349  * This routine should only be called *once* for each DRM minor registered.
350  * A second call for an already registered device will trigger the BUG_ON
351  * below.
352  */
353 int drm_sysfs_connector_add(struct drm_connector *connector)
354 {
355         struct drm_device *dev = connector->dev;
356         int ret = 0, i, j;
357
358         /* We shouldn't get called more than once for the same connector */
359         BUG_ON(device_is_registered(&connector->kdev));
360
361         connector->kdev.parent = &dev->primary->kdev;
362         connector->kdev.class = drm_class;
363         connector->kdev.release = drm_sysfs_device_release;
364
365         DRM_DEBUG("adding \"%s\" to sysfs\n",
366                   drm_get_connector_name(connector));
367
368         dev_set_name(&connector->kdev, "card%d-%s",
369                      dev->primary->index, drm_get_connector_name(connector));
370         ret = device_register(&connector->kdev);
371
372         if (ret) {
373                 DRM_ERROR("failed to register connector device: %d\n", ret);
374                 goto out;
375         }
376
377         /* Standard attributes */
378
379         for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) {
380                 ret = device_create_file(&connector->kdev, &connector_attrs[i]);
381                 if (ret)
382                         goto err_out_files;
383         }
384
385         /* Optional attributes */
386         /*
387          * In the long run it maybe a good idea to make one set of
388          * optionals per connector type.
389          */
390         switch (connector->connector_type) {
391                 case DRM_MODE_CONNECTOR_DVII:
392                 case DRM_MODE_CONNECTOR_Composite:
393                 case DRM_MODE_CONNECTOR_SVIDEO:
394                 case DRM_MODE_CONNECTOR_Component:
395                 case DRM_MODE_CONNECTOR_TV:
396                         for (i = 0; i < ARRAY_SIZE(connector_attrs_opt1); i++) {
397                                 ret = device_create_file(&connector->kdev, &connector_attrs_opt1[i]);
398                                 if (ret)
399                                         goto err_out_files;
400                         }
401                         break;
402                 default:
403                         break;
404         }
405
406         ret = sysfs_create_bin_file(&connector->kdev.kobj, &edid_attr);
407         if (ret)
408                 goto err_out_files;
409
410         /* Let userspace know we have a new connector */
411         drm_sysfs_hotplug_event(dev);
412
413         return 0;
414
415 err_out_files:
416         if (i > 0)
417                 for (j = 0; j < i; j++)
418                         device_remove_file(&connector->kdev,
419                                            &connector_attrs[i]);
420         device_unregister(&connector->kdev);
421
422 out:
423         return ret;
424 }
425 EXPORT_SYMBOL(drm_sysfs_connector_add);
426
427 /**
428  * drm_sysfs_connector_remove - remove an connector device from sysfs
429  * @connector: connector to remove
430  *
431  * Remove @connector and its associated attributes from sysfs.  Note that
432  * the device model core will take care of sending the "remove" uevent
433  * at this time, so we don't need to do it.
434  *
435  * Note:
436  * This routine should only be called if the connector was previously
437  * successfully registered.  If @connector hasn't been registered yet,
438  * you'll likely see a panic somewhere deep in sysfs code when called.
439  */
440 void drm_sysfs_connector_remove(struct drm_connector *connector)
441 {
442         int i;
443
444         DRM_DEBUG("removing \"%s\" from sysfs\n",
445                   drm_get_connector_name(connector));
446
447         for (i = 0; i < ARRAY_SIZE(connector_attrs); i++)
448                 device_remove_file(&connector->kdev, &connector_attrs[i]);
449         sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr);
450         device_unregister(&connector->kdev);
451 }
452 EXPORT_SYMBOL(drm_sysfs_connector_remove);
453
454 /**
455  * drm_sysfs_hotplug_event - generate a DRM uevent
456  * @dev: DRM device
457  *
458  * Send a uevent for the DRM device specified by @dev.  Currently we only
459  * set HOTPLUG=1 in the uevent environment, but this could be expanded to
460  * deal with other types of events.
461  */
462 void drm_sysfs_hotplug_event(struct drm_device *dev)
463 {
464         char *event_string = "HOTPLUG=1";
465         char *envp[] = { event_string, NULL };
466
467         DRM_DEBUG("generating hotplug event\n");
468
469         kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp);
470 }
471 EXPORT_SYMBOL(drm_sysfs_hotplug_event);
472
473 /**
474  * drm_sysfs_device_add - adds a class device to sysfs for a character driver
475  * @dev: DRM device to be added
476  * @head: DRM head in question
477  *
478  * Add a DRM device to the DRM's device model class.  We use @dev's PCI device
479  * as the parent for the Linux device, and make sure it has a file containing
480  * the driver we're using (for userspace compatibility).
481  */
482 int drm_sysfs_device_add(struct drm_minor *minor)
483 {
484         int err;
485         char *minor_str;
486
487         minor->kdev.parent = &minor->dev->pdev->dev;
488         minor->kdev.class = drm_class;
489         minor->kdev.release = drm_sysfs_device_release;
490         minor->kdev.devt = minor->device;
491         minor->kdev.type = &drm_sysfs_device_minor;
492         if (minor->type == DRM_MINOR_CONTROL)
493                 minor_str = "controlD%d";
494         else if (minor->type == DRM_MINOR_RENDER)
495                 minor_str = "renderD%d";
496         else
497                 minor_str = "card%d";
498
499         dev_set_name(&minor->kdev, minor_str, minor->index);
500
501         err = device_register(&minor->kdev);
502         if (err) {
503                 DRM_ERROR("device add failed: %d\n", err);
504                 goto err_out;
505         }
506
507         return 0;
508
509 err_out:
510         return err;
511 }
512
513 /**
514  * drm_sysfs_device_remove - remove DRM device
515  * @dev: DRM device to remove
516  *
517  * This call unregisters and cleans up a class device that was created with a
518  * call to drm_sysfs_device_add()
519  */
520 void drm_sysfs_device_remove(struct drm_minor *minor)
521 {
522         device_unregister(&minor->kdev);
523 }
524
525
526 /**
527  * drm_class_device_register - Register a struct device in the drm class.
528  *
529  * @dev: pointer to struct device to register.
530  *
531  * @dev should have all relevant members pre-filled with the exception
532  * of the class member. In particular, the device_type member must
533  * be set.
534  */
535
536 int drm_class_device_register(struct device *dev)
537 {
538         dev->class = drm_class;
539         return device_register(dev);
540 }
541 EXPORT_SYMBOL_GPL(drm_class_device_register);
542
543 void drm_class_device_unregister(struct device *dev)
544 {
545         return device_unregister(dev);
546 }
547 EXPORT_SYMBOL_GPL(drm_class_device_unregister);