drm: add initial support for a drm control device node
parent
df9cfeff37
commit
d3da253adb
|
@ -699,6 +699,7 @@ struct drm_minor {
|
|||
int minor; /**< Minor device number */
|
||||
int type; /**< Control or render */
|
||||
dev_t device; /**< Device number for mknod */
|
||||
struct device kdev; /**< Linux device */
|
||||
struct drm_device *dev;
|
||||
/* for render nodes */
|
||||
struct proc_dir_entry *dev_root; /**< proc directory entry */
|
||||
|
@ -711,7 +712,6 @@ struct drm_minor {
|
|||
* may contain multiple heads.
|
||||
*/
|
||||
struct drm_device {
|
||||
struct device dev; /**< Linux device */
|
||||
char *unique; /**< Unique identifier: e.g., busid */
|
||||
int unique_len; /**< Length of unique field */
|
||||
char *devname; /**< For /proc/interrupts */
|
||||
|
@ -1158,7 +1158,7 @@ extern void drm_agp_chipset_flush(struct drm_device *dev);
|
|||
extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
|
||||
struct drm_driver *driver);
|
||||
extern int drm_put_dev(struct drm_device *dev);
|
||||
extern int drm_put_head(struct drm_minor *minor);
|
||||
extern int drm_put_minor(struct drm_minor *minor);
|
||||
extern unsigned int drm_debug; /* 1 to enable debug output */
|
||||
extern unsigned int drm_minors_limit;
|
||||
extern struct drm_minor **drm_minors;
|
||||
|
@ -1198,8 +1198,8 @@ extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah);
|
|||
struct drm_sysfs_class;
|
||||
extern struct class *drm_sysfs_create(struct module *owner, char *name);
|
||||
extern void drm_sysfs_destroy(void);
|
||||
extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor);
|
||||
extern void drm_sysfs_device_remove(struct drm_device *dev);
|
||||
extern int drm_sysfs_device_add(struct drm_minor *minor);
|
||||
extern void drm_sysfs_device_remove(struct drm_minor *minor);
|
||||
|
||||
/*
|
||||
* Basic memory manager support (drm_mm.c)
|
||||
|
|
|
@ -423,7 +423,8 @@ static void drm_cleanup(struct drm_device * dev)
|
|||
drm_mm_takedown(&dev->offset_manager);
|
||||
drm_ht_remove(&dev->object_hash);
|
||||
|
||||
drm_put_head(&dev->primary);
|
||||
drm_put_minor(&dev->primary);
|
||||
drm_put_minor(&dev->control);
|
||||
if (drm_put_dev(dev))
|
||||
DRM_ERROR("Cannot unload module\n");
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ error_out_unreg:
|
|||
* create the proc init entry via proc_init(). This routines assigns
|
||||
* minor numbers to secondary heads of multi-headed cards
|
||||
*/
|
||||
static int drm_get_head(struct drm_device * dev, struct drm_minor *minor)
|
||||
static int drm_get_minor(struct drm_device *dev, struct drm_minor *minor, int type)
|
||||
{
|
||||
struct drm_minor **minors = drm_minors;
|
||||
int ret;
|
||||
|
@ -172,19 +172,23 @@ static int drm_get_head(struct drm_device * dev, struct drm_minor *minor)
|
|||
if (!*minors) {
|
||||
|
||||
*minor = (struct drm_minor) {
|
||||
.type = type,
|
||||
.dev = dev,
|
||||
.device = MKDEV(DRM_MAJOR, index),
|
||||
.minor = index,
|
||||
};
|
||||
if ((ret =
|
||||
drm_proc_init(dev, index, drm_proc_root,
|
||||
&minor->dev_root))) {
|
||||
printk(KERN_ERR
|
||||
"DRM: Failed to initialize /proc/dri.\n");
|
||||
goto err_g1;
|
||||
}
|
||||
|
||||
ret = drm_sysfs_device_add(dev, minor);
|
||||
if (type == DRM_MINOR_RENDER) {
|
||||
ret = drm_proc_init(dev, index, drm_proc_root,
|
||||
&minor->dev_root);
|
||||
if (ret) {
|
||||
DRM_ERROR("DRM: Failed to initialize /proc/dri.\n");
|
||||
goto err_g1;
|
||||
}
|
||||
} else
|
||||
minor->dev_root = NULL;
|
||||
|
||||
ret = drm_sysfs_device_add(minor);
|
||||
if (ret) {
|
||||
printk(KERN_ERR
|
||||
"DRM: Error sysfs_device_add.\n");
|
||||
|
@ -199,7 +203,8 @@ static int drm_get_head(struct drm_device * dev, struct drm_minor *minor)
|
|||
DRM_ERROR("out of minors\n");
|
||||
return -ENOMEM;
|
||||
err_g2:
|
||||
drm_proc_cleanup(index, drm_proc_root, minor->dev_root);
|
||||
if (minor->type == DRM_MINOR_RENDER)
|
||||
drm_proc_cleanup(index, drm_proc_root, minor->dev_root);
|
||||
err_g1:
|
||||
*minor = (struct drm_minor) {
|
||||
.dev = NULL};
|
||||
|
@ -245,22 +250,28 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
|
|||
printk(KERN_ERR "DRM: fill_in_dev failed\n");
|
||||
goto err_g3;
|
||||
}
|
||||
if ((ret = drm_get_head(dev, &dev->primary)))
|
||||
|
||||
if ((ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL)))
|
||||
goto err_g3;
|
||||
|
||||
if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_RENDER)))
|
||||
goto err_g4;
|
||||
|
||||
DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
|
||||
driver->name, driver->major, driver->minor, driver->patchlevel,
|
||||
driver->date, dev->primary.minor);
|
||||
|
||||
return 0;
|
||||
|
||||
err_g3:
|
||||
err_g4:
|
||||
drm_put_minor(&dev->control);
|
||||
err_g3:
|
||||
if (!drm_fb_loaded)
|
||||
pci_disable_device(pdev);
|
||||
err_g2:
|
||||
err_g2:
|
||||
if (!drm_fb_loaded)
|
||||
pci_release_regions(pdev);
|
||||
err_g1:
|
||||
err_g1:
|
||||
if (!drm_fb_loaded)
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
|
||||
|
@ -315,8 +326,9 @@ int drm_put_minor(struct drm_minor *minor)
|
|||
|
||||
DRM_DEBUG("release secondary minor %d\n", index);
|
||||
|
||||
drm_proc_cleanup(index, drm_proc_root, minor->dev_root);
|
||||
drm_sysfs_device_remove(minor->dev);
|
||||
if (minor->type == DRM_MINOR_RENDER)
|
||||
drm_proc_cleanup(index, drm_proc_root, minor->dev_root);
|
||||
drm_sysfs_device_remove(minor);
|
||||
|
||||
*minor = (struct drm_minor) {.type = DRM_MINOR_UNASSIGNED,
|
||||
.dev = NULL};
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "drm_core.h"
|
||||
#include "drmP.h"
|
||||
|
||||
#define to_drm_device(d) container_of(d, struct drm_device, dev)
|
||||
#define to_drm_minor(d) container_of(d, struct drm_minor, kdev)
|
||||
|
||||
/**
|
||||
* drm_sysfs_suspend - DRM class suspend hook
|
||||
|
@ -31,7 +31,8 @@
|
|||
*/
|
||||
static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
|
||||
{
|
||||
struct drm_device *drm_dev = to_drm_device(dev);
|
||||
struct drm_minor *drm_minor = to_drm_minor(dev);
|
||||
struct drm_device *drm_dev = drm_minor->dev;
|
||||
|
||||
printk(KERN_ERR "%s\n", __FUNCTION__);
|
||||
|
||||
|
@ -50,7 +51,8 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
|
|||
*/
|
||||
static int drm_sysfs_resume(struct device *dev)
|
||||
{
|
||||
struct drm_device *drm_dev = to_drm_device(dev);
|
||||
struct drm_minor *drm_minor = to_drm_minor(dev);
|
||||
struct drm_device *drm_dev = drm_minor->dev;
|
||||
|
||||
if (drm_dev->driver->resume)
|
||||
return drm_dev->driver->resume(drm_dev);
|
||||
|
@ -122,10 +124,11 @@ void drm_sysfs_destroy(void)
|
|||
static ssize_t show_dri(struct device *device, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct drm_device *dev = to_drm_device(device);
|
||||
if (dev->driver->dri_library_name)
|
||||
return dev->driver->dri_library_name(dev, buf);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name);
|
||||
struct drm_minor *drm_minor = to_drm_minor(device);
|
||||
struct drm_device *drm_dev = drm_minor->dev;
|
||||
if (drm_dev->driver->dri_library_name)
|
||||
return drm_dev->driver->dri_library_name(drm_dev, buf);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name);
|
||||
}
|
||||
|
||||
static struct device_attribute device_attrs[] = {
|
||||
|
@ -154,25 +157,31 @@ static void drm_sysfs_device_release(struct device *dev)
|
|||
* as the parent for the Linux device, and make sure it has a file containing
|
||||
* the driver we're using (for userspace compatibility).
|
||||
*/
|
||||
int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor)
|
||||
int drm_sysfs_device_add(struct drm_minor *minor)
|
||||
{
|
||||
int err;
|
||||
int i, j;
|
||||
char *minor_str;
|
||||
|
||||
dev->dev.parent = &dev->pdev->dev;
|
||||
dev->dev.class = drm_class;
|
||||
dev->dev.release = drm_sysfs_device_release;
|
||||
dev->dev.devt = minor->device;
|
||||
snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", minor->minor);
|
||||
minor->kdev.parent = &minor->dev->pdev->dev;
|
||||
minor->kdev.class = drm_class;
|
||||
minor->kdev.release = drm_sysfs_device_release;
|
||||
minor->kdev.devt = minor->device;
|
||||
if (minor->type == DRM_MINOR_CONTROL)
|
||||
minor_str = "controlD%d";
|
||||
else
|
||||
minor_str = "card%d";
|
||||
|
||||
snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->minor);
|
||||
|
||||
err = device_register(&dev->dev);
|
||||
err = device_register(&minor->kdev);
|
||||
if (err) {
|
||||
DRM_ERROR("device add failed: %d\n", err);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
|
||||
err = device_create_file(&dev->dev, &device_attrs[i]);
|
||||
err = device_create_file(&minor->kdev, &device_attrs[i]);
|
||||
if (err)
|
||||
goto err_out_files;
|
||||
}
|
||||
|
@ -182,8 +191,8 @@ int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor)
|
|||
err_out_files:
|
||||
if (i > 0)
|
||||
for (j = 0; j < i; j++)
|
||||
device_remove_file(&dev->dev, &device_attrs[i]);
|
||||
device_unregister(&dev->dev);
|
||||
device_remove_file(&minor->kdev, &device_attrs[i]);
|
||||
device_unregister(&minor->kdev);
|
||||
err_out:
|
||||
|
||||
return err;
|
||||
|
@ -196,11 +205,11 @@ err_out:
|
|||
* This call unregisters and cleans up a class device that was created with a
|
||||
* call to drm_sysfs_device_add()
|
||||
*/
|
||||
void drm_sysfs_device_remove(struct drm_device *dev)
|
||||
void drm_sysfs_device_remove(struct drm_minor *minor)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
|
||||
device_remove_file(&dev->dev, &device_attrs[i]);
|
||||
device_unregister(&dev->dev);
|
||||
device_remove_file(&minor->kdev, &device_attrs[i]);
|
||||
device_unregister(&minor->kdev);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue