drivers/gpu/drm/drm_sysfs.c: sysfs files error handling
[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 attr_cnt = 0;
357         int opt_cnt = 0;
358         int i;
359         int ret = 0;
360
361         /* We shouldn't get called more than once for the same connector */
362         BUG_ON(device_is_registered(&connector->kdev));
363
364         connector->kdev.parent = &dev->primary->kdev;
365         connector->kdev.class = drm_class;
366         connector->kdev.release = drm_sysfs_device_release;
367
368         DRM_DEBUG("adding \"%s\" to sysfs\n",
369                   drm_get_connector_name(connector));
370
371         dev_set_name(&connector->kdev, "card%d-%s",
372                      dev->primary->index, drm_get_connector_name(connector));
373         ret = device_register(&connector->kdev);
374
375         if (ret) {
376                 DRM_ERROR("failed to register connector device: %d\n", ret);
377                 goto out;
378         }
379
380         /* Standard attributes */
381
382         for (attr_cnt = 0; attr_cnt < ARRAY_SIZE(connector_attrs); attr_cnt++) {
383                 ret = device_create_file(&connector->kdev, &connector_attrs[attr_cnt]);
384                 if (ret)
385                         goto err_out_files;
386         }
387
388         /* Optional attributes */
389         /*
390          * In the long run it maybe a good idea to make one set of
391          * optionals per connector type.
392          */
393         switch (connector->connector_type) {
394                 case DRM_MODE_CONNECTOR_DVII:
395                 case DRM_MODE_CONNECTOR_Composite:
396                 case DRM_MODE_CONNECTOR_SVIDEO:
397                 case DRM_MODE_CONNECTOR_Component:
398                 case DRM_MODE_CONNECTOR_TV:
399                         for (opt_cnt = 0; opt_cnt < ARRAY_SIZE(connector_attrs_opt1); opt_cnt++) {
400                                 ret = device_create_file(&connector->kdev, &connector_attrs_opt1[opt_cnt]);
401                                 if (ret)
402                                         goto err_out_files;
403                         }
404                         break;
405                 default:
406                         break;
407         }
408
409         ret = sysfs_create_bin_file(&connector->kdev.kobj, &edid_attr);
410         if (ret)
411                 goto err_out_files;
412
413         /* Let userspace know we have a new connector */
414         drm_sysfs_hotplug_event(dev);
415
416         return 0;
417
418 err_out_files:
419         for (i = 0; i < opt_cnt; i++)
420                 device_remove_file(&connector->kdev, &connector_attrs_opt1[i]);
421         for (i = 0; i < attr_cnt; i++)
422                 device_remove_file(&connector->kdev, &connector_attrs[i]);
423         device_unregister(&connector->kdev);
424
425 out:
426         return ret;
427 }
428 EXPORT_SYMBOL(drm_sysfs_connector_add);
429
430 /**
431  * drm_sysfs_connector_remove - remove an connector device from sysfs
432  * @connector: connector to remove
433  *
434  * Remove @connector and its associated attributes from sysfs.  Note that
435  * the device model core will take care of sending the "remove" uevent
436  * at this time, so we don't need to do it.
437  *
438  * Note:
439  * This routine should only be called if the connector was previously
440  * successfully registered.  If @connector hasn't been registered yet,
441  * you'll likely see a panic somewhere deep in sysfs code when called.
442  */
443 void drm_sysfs_connector_remove(struct drm_connector *connector)
444 {
445         int i;
446
447         DRM_DEBUG("removing \"%s\" from sysfs\n",
448                   drm_get_connector_name(connector));
449
450         for (i = 0; i < ARRAY_SIZE(connector_attrs); i++)
451                 device_remove_file(&connector->kdev, &connector_attrs[i]);
452         sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr);
453         device_unregister(&connector->kdev);
454 }
455 EXPORT_SYMBOL(drm_sysfs_connector_remove);
456
457 /**
458  * drm_sysfs_hotplug_event - generate a DRM uevent
459  * @dev: DRM device
460  *
461  * Send a uevent for the DRM device specified by @dev.  Currently we only
462  * set HOTPLUG=1 in the uevent environment, but this could be expanded to
463  * deal with other types of events.
464  */
465 void drm_sysfs_hotplug_event(struct drm_device *dev)
466 {
467         char *event_string = "HOTPLUG=1";
468         char *envp[] = { event_string, NULL };
469
470         DRM_DEBUG("generating hotplug event\n");
471
472         kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp);
473 }
474 EXPORT_SYMBOL(drm_sysfs_hotplug_event);
475
476 /**
477  * drm_sysfs_device_add - adds a class device to sysfs for a character driver
478  * @dev: DRM device to be added
479  * @head: DRM head in question
480  *
481  * Add a DRM device to the DRM's device model class.  We use @dev's PCI device
482  * as the parent for the Linux device, and make sure it has a file containing
483  * the driver we're using (for userspace compatibility).
484  */
485 int drm_sysfs_device_add(struct drm_minor *minor)
486 {
487         int err;
488         char *minor_str;
489
490         minor->kdev.parent = &minor->dev->pdev->dev;
491         minor->kdev.class = drm_class;
492         minor->kdev.release = drm_sysfs_device_release;
493         minor->kdev.devt = minor->device;
494         minor->kdev.type = &drm_sysfs_device_minor;
495         if (minor->type == DRM_MINOR_CONTROL)
496                 minor_str = "controlD%d";
497         else if (minor->type == DRM_MINOR_RENDER)
498                 minor_str = "renderD%d";
499         else
500                 minor_str = "card%d";
501
502         dev_set_name(&minor->kdev, minor_str, minor->index);
503
504         err = device_register(&minor->kdev);
505         if (err) {
506                 DRM_ERROR("device add failed: %d\n", err);
507                 goto err_out;
508         }
509
510         return 0;
511
512 err_out:
513         return err;
514 }
515
516 /**
517  * drm_sysfs_device_remove - remove DRM device
518  * @dev: DRM device to remove
519  *
520  * This call unregisters and cleans up a class device that was created with a
521  * call to drm_sysfs_device_add()
522  */
523 void drm_sysfs_device_remove(struct drm_minor *minor)
524 {
525         device_unregister(&minor->kdev);
526 }
527
528
529 /**
530  * drm_class_device_register - Register a struct device in the drm class.
531  *
532  * @dev: pointer to struct device to register.
533  *
534  * @dev should have all relevant members pre-filled with the exception
535  * of the class member. In particular, the device_type member must
536  * be set.
537  */
538
539 int drm_class_device_register(struct device *dev)
540 {
541         dev->class = drm_class;
542         return device_register(dev);
543 }
544 EXPORT_SYMBOL_GPL(drm_class_device_register);
545
546 void drm_class_device_unregister(struct device *dev)
547 {
548         return device_unregister(dev);
549 }
550 EXPORT_SYMBOL_GPL(drm_class_device_unregister);