Commit e8b962b6 authored by Jesse Barnes's avatar Jesse Barnes Committed by Dave Airlie

drm: update DRM sysfs support

Make DRM devices use real Linux devices instead of class devices, which are
going away.  While we're at it, clean up some of the interfaces to take
struct drm_device * or struct device * and use the global drm_class where
needed instead of passing it around.
Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent 8b409580
...@@ -568,6 +568,8 @@ struct drm_driver { ...@@ -568,6 +568,8 @@ struct drm_driver {
void (*postclose) (struct drm_device *, struct drm_file *); void (*postclose) (struct drm_device *, struct drm_file *);
void (*lastclose) (struct drm_device *); void (*lastclose) (struct drm_device *);
int (*unload) (struct drm_device *); int (*unload) (struct drm_device *);
int (*suspend) (struct drm_device *);
int (*resume) (struct drm_device *);
int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
void (*dma_ready) (struct drm_device *); void (*dma_ready) (struct drm_device *);
int (*dma_quiescent) (struct drm_device *); int (*dma_quiescent) (struct drm_device *);
...@@ -643,6 +645,7 @@ struct drm_head { ...@@ -643,6 +645,7 @@ struct drm_head {
* may contain multiple heads. * may contain multiple heads.
*/ */
struct drm_device { struct drm_device {
struct device dev; /**< Linux device */
char *unique; /**< Unique identifier: e.g., busid */ char *unique; /**< Unique identifier: e.g., busid */
int unique_len; /**< Length of unique field */ int unique_len; /**< Length of unique field */
char *devname; /**< For /proc/interrupts */ char *devname; /**< For /proc/interrupts */
...@@ -1063,11 +1066,11 @@ extern void __drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); ...@@ -1063,11 +1066,11 @@ extern void __drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
/* sysfs support (drm_sysfs.c) */ /* sysfs support (drm_sysfs.c) */
struct drm_sysfs_class;
extern struct class *drm_sysfs_create(struct module *owner, char *name); extern struct class *drm_sysfs_create(struct module *owner, char *name);
extern void drm_sysfs_destroy(struct class *cs); extern void drm_sysfs_destroy(void);
extern struct class_device *drm_sysfs_device_add(struct class *cs, extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head);
struct drm_head *head); extern void drm_sysfs_device_remove(struct drm_device *dev);
extern void drm_sysfs_device_remove(struct class_device *class_dev);
/* /*
* Basic memory manager support (drm_mm.c) * Basic memory manager support (drm_mm.c)
......
...@@ -386,19 +386,19 @@ static int __init drm_core_init(void) ...@@ -386,19 +386,19 @@ static int __init drm_core_init(void)
DRM_INFO("Initialized %s %d.%d.%d %s\n", DRM_INFO("Initialized %s %d.%d.%d %s\n",
CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
return 0; return 0;
err_p3: err_p3:
drm_sysfs_destroy(drm_class); drm_sysfs_destroy();
err_p2: err_p2:
unregister_chrdev(DRM_MAJOR, "drm"); unregister_chrdev(DRM_MAJOR, "drm");
drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB);
err_p1: err_p1:
return ret; return ret;
} }
static void __exit drm_core_exit(void) static void __exit drm_core_exit(void)
{ {
remove_proc_entry("dri", NULL); remove_proc_entry("dri", NULL);
drm_sysfs_destroy(drm_class); drm_sysfs_destroy();
unregister_chrdev(DRM_MAJOR, "drm"); unregister_chrdev(DRM_MAJOR, "drm");
......
...@@ -168,11 +168,10 @@ static int drm_get_head(struct drm_device * dev, struct drm_head * head) ...@@ -168,11 +168,10 @@ static int drm_get_head(struct drm_device * dev, struct drm_head * head)
goto err_g1; goto err_g1;
} }
head->dev_class = drm_sysfs_device_add(drm_class, head); ret = drm_sysfs_device_add(dev, head);
if (IS_ERR(head->dev_class)) { if (ret) {
printk(KERN_ERR printk(KERN_ERR
"DRM: Error sysfs_device_add.\n"); "DRM: Error sysfs_device_add.\n");
ret = PTR_ERR(head->dev_class);
goto err_g2; goto err_g2;
} }
*heads = head; *heads = head;
...@@ -283,7 +282,7 @@ int drm_put_head(struct drm_head * head) ...@@ -283,7 +282,7 @@ int drm_put_head(struct drm_head * head)
DRM_DEBUG("release secondary minor %d\n", minor); DRM_DEBUG("release secondary minor %d\n", minor);
drm_proc_cleanup(minor, drm_proc_root, head->dev_root); drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
drm_sysfs_device_remove(head->dev_class); drm_sysfs_device_remove(head->dev);
*head = (struct drm_head) {.dev = NULL}; *head = (struct drm_head) {.dev = NULL};
......
...@@ -19,6 +19,45 @@ ...@@ -19,6 +19,45 @@
#include "drm_core.h" #include "drm_core.h"
#include "drmP.h" #include "drmP.h"
#define to_drm_device(d) container_of(d, struct drm_device, dev)
/**
* drm_sysfs_suspend - DRM class suspend hook
* @dev: Linux device to suspend
* @state: power state to enter
*
* Just figures out what the actual struct drm_device associated with
* @dev is and calls its suspend hook, if present.
*/
static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
{
struct drm_device *drm_dev = to_drm_device(dev);
printk(KERN_ERR "%s\n", __FUNCTION__);
if (drm_dev->driver->suspend)
return drm_dev->driver->suspend(drm_dev);
return 0;
}
/**
* drm_sysfs_resume - DRM class resume hook
* @dev: Linux device to resume
*
* Just figures out what the actual struct drm_device associated with
* @dev is and calls its resume hook, if present.
*/
static int drm_sysfs_resume(struct device *dev)
{
struct drm_device *drm_dev = to_drm_device(dev);
if (drm_dev->driver->resume)
return drm_dev->driver->resume(drm_dev);
return 0;
}
/* Display the version of drm_core. This doesn't work right in current design */ /* Display the version of drm_core. This doesn't work right in current design */
static ssize_t version_show(struct class *dev, char *buf) static ssize_t version_show(struct class *dev, char *buf)
{ {
...@@ -33,7 +72,7 @@ static CLASS_ATTR(version, S_IRUGO, version_show, NULL); ...@@ -33,7 +72,7 @@ static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
* @owner: pointer to the module that is to "own" this struct drm_sysfs_class * @owner: pointer to the module that is to "own" this struct drm_sysfs_class
* @name: pointer to a string for the name of this class. * @name: pointer to a string for the name of this class.
* *
* This is used to create a struct drm_sysfs_class pointer that can then be used * This is used to create DRM class pointer that can then be used
* in calls to drm_sysfs_device_add(). * in calls to drm_sysfs_device_add().
* *
* Note, the pointer created here is to be destroyed when finished by making a * Note, the pointer created here is to be destroyed when finished by making a
...@@ -50,6 +89,9 @@ struct class *drm_sysfs_create(struct module *owner, char *name) ...@@ -50,6 +89,9 @@ struct class *drm_sysfs_create(struct module *owner, char *name)
goto err_out; goto err_out;
} }
class->suspend = drm_sysfs_suspend;
class->resume = drm_sysfs_resume;
err = class_create_file(class, &class_attr_version); err = class_create_file(class, &class_attr_version);
if (err) if (err)
goto err_out_class; goto err_out_class;
...@@ -63,94 +105,105 @@ struct class *drm_sysfs_create(struct module *owner, char *name) ...@@ -63,94 +105,105 @@ struct class *drm_sysfs_create(struct module *owner, char *name)
} }
/** /**
* drm_sysfs_destroy - destroys a struct drm_sysfs_class structure * drm_sysfs_destroy - destroys DRM class
* @cs: pointer to the struct drm_sysfs_class that is to be destroyed
* *
* Note, the pointer to be destroyed must have been created with a call to * Destroy the DRM device class.
* drm_sysfs_create().
*/ */
void drm_sysfs_destroy(struct class *class) void drm_sysfs_destroy(void)
{ {
if ((class == NULL) || (IS_ERR(class))) if ((drm_class == NULL) || (IS_ERR(drm_class)))
return; return;
class_remove_file(drm_class, &class_attr_version);
class_remove_file(class, &class_attr_version); class_destroy(drm_class);
class_destroy(class);
} }
static ssize_t show_dri(struct class_device *class_device, char *buf) static ssize_t show_dri(struct device *device, struct device_attribute *attr,
char *buf)
{ {
struct drm_device * dev = ((struct drm_head *)class_get_devdata(class_device))->dev; struct drm_device *dev = to_drm_device(device);
if (dev->driver->dri_library_name) if (dev->driver->dri_library_name)
return dev->driver->dri_library_name(dev, buf); return dev->driver->dri_library_name(dev, buf);
return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name); return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name);
} }
static struct class_device_attribute class_device_attrs[] = { static struct device_attribute device_attrs[] = {
__ATTR(dri_library_name, S_IRUGO, show_dri, NULL), __ATTR(dri_library_name, S_IRUGO, show_dri, NULL),
}; };
/**
* drm_sysfs_device_release - do nothing
* @dev: Linux device
*
* Normally, this would free the DRM device associated with @dev, along
* with cleaning up any other stuff. But we do that in the DRM core, so
* this function can just return and hope that the core does its job.
*/
static void drm_sysfs_device_release(struct device *dev)
{
return;
}
/** /**
* drm_sysfs_device_add - adds a class device to sysfs for a character driver * drm_sysfs_device_add - adds a class device to sysfs for a character driver
* @cs: pointer to the struct class that this device should be registered to. * @dev: DRM device to be added
* @dev: the dev_t for the device to be added. * @head: DRM head in question
* @device: a pointer to a struct device that is assiociated with this class device.
* @fmt: string for the class device's name
* *
* A struct class_device will be created in sysfs, registered to the specified * Add a DRM device to the DRM's device model class. We use @dev's PCI device
* class. A "dev" file will be created, showing the dev_t for the device. The * as the parent for the Linux device, and make sure it has a file containing
* pointer to the struct class_device will be returned from the call. Any further * the driver we're using (for userspace compatibility).
* sysfs files that might be required can be created using this pointer.
* Note: the struct class passed to this function must have previously been
* created with a call to drm_sysfs_create().
*/ */
struct class_device *drm_sysfs_device_add(struct class *cs, struct drm_head *head) int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head)
{ {
struct class_device *class_dev; int err;
int i, j, err; int i, j;
class_dev = class_device_create(cs, NULL, dev->dev.parent = &dev->pdev->dev;
MKDEV(DRM_MAJOR, head->minor), dev->dev.class = drm_class;
&(head->dev->pdev)->dev, dev->dev.release = drm_sysfs_device_release;
"card%d", head->minor); /*
if (IS_ERR(class_dev)) { * This will actually add the major:minor file so that udev
err = PTR_ERR(class_dev); * will create the device node. We don't want to do that just
* yet...
*/
/* dev->dev.devt = head->device; */
snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", head->minor);
err = device_register(&dev->dev);
if (err) {
DRM_ERROR("device add failed: %d\n", err);
goto err_out; goto err_out;
} }
class_set_devdata(class_dev, head); for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
err = device_create_file(&dev->dev, &device_attrs[i]);
for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
err = class_device_create_file(class_dev,
&class_device_attrs[i]);
if (err) if (err)
goto err_out_files; goto err_out_files;
} }
return class_dev; return 0;
err_out_files: err_out_files:
if (i > 0) if (i > 0)
for (j = 0; j < i; j++) for (j = 0; j < i; j++)
class_device_remove_file(class_dev, device_remove_file(&dev->dev, &device_attrs[i]);
&class_device_attrs[i]); device_unregister(&dev->dev);
class_device_unregister(class_dev);
err_out: err_out:
return ERR_PTR(err);
return err;
} }
/** /**
* drm_sysfs_device_remove - removes a class device that was created with drm_sysfs_device_add() * drm_sysfs_device_remove - remove DRM device
* @dev: the dev_t of the device that was previously registered. * @dev: DRM device to remove
* *
* This call unregisters and cleans up a class device that was created with a * This call unregisters and cleans up a class device that was created with a
* call to drm_sysfs_device_add() * call to drm_sysfs_device_add()
*/ */
void drm_sysfs_device_remove(struct class_device *class_dev) void drm_sysfs_device_remove(struct drm_device *dev)
{ {
int i; int i;
for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
class_device_remove_file(class_dev, &class_device_attrs[i]); device_remove_file(&dev->dev, &device_attrs[i]);
class_device_unregister(class_dev); device_unregister(&dev->dev);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment