summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@linux.ie>2007-04-05 13:34:50 +1000
committerDave Airlie <airlied@linux.ie>2007-04-05 13:34:50 +1000
commit5bffbd6e275efffbb649c20c528a11412ccf99cd (patch)
treef13ee4a2a6027d463ea2d11573b8de693cedffc1
parent52f9028c84baea81230dc673b756552e8e90aecd (diff)
initial userspace interface to get modes
-rw-r--r--libdrm/Makefile.am4
-rw-r--r--linux-core/drm_crtc.c124
-rw-r--r--linux-core/drm_crtc.h15
-rw-r--r--linux-core/drm_drv.c1
-rw-r--r--linux-core/drm_edid.c21
-rw-r--r--linux-core/drm_modes.c7
-rw-r--r--shared-core/drm.h72
7 files changed, 229 insertions, 15 deletions
diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am
index e7e07e47..24c32038 100644
--- a/libdrm/Makefile.am
+++ b/libdrm/Makefile.am
@@ -23,9 +23,9 @@ libdrm_ladir = $(libdir)
libdrm_la_LDFLAGS = -version-number 2:3:0 -no-undefined
AM_CFLAGS = -I$(top_srcdir)/shared-core
-libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c
+libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c xf86drmMode.c
libdrmincludedir = ${includedir}
-libdrminclude_HEADERS = xf86drm.h xf86mm.h
+libdrminclude_HEADERS = xf86drm.h xf86mm.h xf86drmMode.h
EXTRA_DIST = ChangeLog TODO
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
index a52d82bc..1311fa63 100644
--- a/linux-core/drm_crtc.c
+++ b/linux-core/drm_crtc.c
@@ -154,7 +154,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
bool ret = false;
struct drm_output *output;
- adjusted_mode = drm_mode_duplicate(mode);
+ adjusted_mode = drm_mode_duplicate(dev, mode);
crtc->enabled = drm_crtc_in_use(crtc);
@@ -230,6 +230,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
}
/* XXX free adjustedmode */
+ drm_crtc_mode_destroy(dev, adjusted_mode);
ret = TRUE;
/* TODO */
// if (scrn->pScreen)
@@ -401,12 +402,48 @@ bool drm_output_rename(struct drm_output *output, const char *name)
}
EXPORT_SYMBOL(drm_output_rename);
+struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev)
+{
+ int ret;
+ struct drm_display_mode *nmode;
+
+ nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
+ if (!nmode)
+ return NULL;
+
+again:
+ if (idr_pre_get(&dev->crtc_config.mode_idr, GFP_KERNEL) == 0) {
+ DRM_ERROR("Ran out memory getting a mode number\n");
+ kfree(nmode);
+ return NULL;
+ }
+
+ spin_lock(&dev->crtc_config.config_lock);
+
+ ret = idr_get_new(&dev->crtc_config.mode_idr, nmode, &nmode->mode_id);
+ if (ret == -EAGAIN) {
+ udelay(1);
+ spin_unlock(&dev->crtc_config.config_lock);
+ goto again;
+ }
+ spin_unlock(&dev->crtc_config.config_lock);
+ return nmode;
+}
+
+void drm_crtc_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
+{
+ idr_remove(&dev->crtc_config.mode_idr, mode->mode_id);
+
+ kfree(mode);
+}
+
void drm_crtc_config_init(drm_device_t *dev)
{
spin_lock_init(&dev->crtc_config.config_lock);
INIT_LIST_HEAD(&dev->crtc_config.fb_list);
INIT_LIST_HEAD(&dev->crtc_config.crtc_list);
INIT_LIST_HEAD(&dev->crtc_config.output_list);
+ idr_init(&dev->crtc_config.mode_idr);
}
EXPORT_SYMBOL(drm_crtc_config_init);
@@ -441,7 +478,7 @@ void drm_framebuffer_set_object(drm_device_t *dev, unsigned long handle)
ret = 0;
out_err:
mutex_unlock(&dev->struct_mutex);
- return ret;
+ return;
}
EXPORT_SYMBOL(drm_framebuffer_set_object);
@@ -538,3 +575,86 @@ void drm_crtc_config_cleanup(drm_device_t *dev)
}
EXPORT_SYMBOL(drm_crtc_config_cleanup);
+void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display_mode *in)
+{
+
+ out->id = in->mode_id;
+ out->clock = in->clock;
+ out->hdisplay = in->hdisplay;
+ out->hsync_start = in->hsync_start;
+ out->hsync_end = in->hsync_end;
+ out->htotal = in->htotal;
+ out->hskew = in->hskew;
+ out->vdisplay = in->vdisplay;
+ out->vsync_start = in->vsync_start;
+ out->vsync_end = in->vsync_end;
+ out->vtotal = in->vtotal;
+ out->vscan = in->vscan;
+
+ out->flags = in->flags;
+}
+
+
+/* IOCTL code from userspace */
+int drm_mode_getresources(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ struct drm_mode_card_res __user *argp = (void __user *)arg;
+ struct drm_mode_card_res card_res;
+ struct list_head *lh;
+ struct drm_output *output;
+ struct drm_mode_modeinfo u_mode;
+ struct drm_display_mode *mode;
+ int retcode = 0;
+ int mode_count= 0;
+
+ memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
+ list_for_each_entry(output, &dev->crtc_config.output_list,
+ head)
+ {
+ list_for_each(lh, &output->modes)
+ mode_count++;
+ }
+
+ if (copy_from_user(&card_res, argp, sizeof(card_res)))
+ return -EFAULT;
+
+ if (card_res.count_modes >= mode_count) {
+ int copied = 0;
+ list_for_each_entry(output, &dev->crtc_config.output_list,
+ head) {
+ list_for_each_entry(mode, &output->modes, head) {
+ drm_crtc_convert_to_umode(&u_mode, mode);
+ if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct drm_mode_modeinfo))) {
+ retcode = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ }
+
+ else {
+ list_for_each(lh, &dev->crtc_config.crtc_list)
+ card_res.count_crtcs++;
+
+ list_for_each_entry(output, &dev->crtc_config.output_list,
+ head)
+ {
+ list_for_each(lh, &output->modes)
+ card_res.count_modes++;
+ card_res.count_outputs++;
+ }
+ }
+
+done:
+ DRM_DEBUG("Counted %d %d %d\n", card_res.count_crtcs,
+ card_res.count_outputs,
+ card_res.count_modes);
+
+ if (copy_to_user(argp, &card_res, sizeof(card_res)))
+ return -EFAULT;
+
+ return retcode;
+}
diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h
index 1be115d1..003946bc 100644
--- a/linux-core/drm_crtc.h
+++ b/linux-core/drm_crtc.h
@@ -9,6 +9,7 @@
#include <linux/i2c.h>
#include <linux/spinlock.h>
#include <linux/types.h>
+#include <linux/idr.h>
#include "drmP.h"
#include "drm.h"
@@ -86,6 +87,7 @@ struct drm_display_mode {
/* Header */
struct list_head head;
char name[DRM_DISPLAY_MODE_LEN];
+ int mode_id;
enum drm_mode_status status;
int type;
@@ -392,6 +394,7 @@ struct drm_crtc_config_funcs {
*/
struct drm_crtc_config {
spinlock_t config_lock;
+ struct idr mode_idr;
/* this is limited to one for now */
int num_fb;
struct list_head fb_list;
@@ -419,10 +422,20 @@ int drm_add_edid_modes(struct drm_output *output,
struct i2c_adapter *adapter);
void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode);
void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode);
-extern struct drm_display_mode *drm_mode_duplicate(struct drm_display_mode *mode);
+extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
+ struct drm_display_mode *mode);
extern void drm_mode_debug_printmodeline(struct drm_device *dev,
struct drm_display_mode *mode);
extern void drm_crtc_config_init(struct drm_device *dev);
extern void drm_crtc_config_cleanup(struct drm_device *dev);
extern void drm_disable_unused_functions(struct drm_device *dev);
+
+extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev);
+extern void drm_crtc_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode);
+
+/* IOCTLs */
+extern int drm_mode_getresources(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
#endif /* __DRM_CRTC_H__ */
+
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index b95f796f..9877db13 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -123,6 +123,7 @@ static drm_ioctl_desc_t drm_ioctls[] = {
DRM_AUTH },
[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETRESOURCES)] = {drm_mode_getresources, DRM_ROOT_ONLY},
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c
index 3c123751..bf1ea94c 100644
--- a/linux-core/drm_edid.c
+++ b/linux-core/drm_edid.c
@@ -212,7 +212,8 @@ bad:
*
* Punts for now.
*/
-struct drm_display_mode *drm_mode_std(struct std_timing *t)
+struct drm_display_mode *drm_mode_std(struct drm_device *dev,
+ struct std_timing *t)
{
// struct fb_videomode mode;
@@ -221,7 +222,7 @@ struct drm_display_mode *drm_mode_std(struct std_timing *t)
struct drm_display_mode *mode;
int hsize = t->hsize * 8 + 248, vsize;
- mode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
+ mode = drm_crtc_mode_create(dev);
if (!mode)
return NULL;
@@ -239,7 +240,8 @@ struct drm_display_mode *drm_mode_std(struct std_timing *t)
return mode;
}
-struct drm_display_mode *drm_mode_detailed(struct detailed_timing *timing,
+struct drm_display_mode *drm_mode_detailed(drm_device_t *dev,
+ struct detailed_timing *timing,
bool preferred)
{
struct drm_display_mode *mode;
@@ -254,7 +256,7 @@ struct drm_display_mode *drm_mode_detailed(struct detailed_timing *timing,
return NULL;
}
- mode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
+ mode = drm_crtc_mode_create(dev);
if (!mode)
return NULL;
@@ -357,6 +359,7 @@ static struct drm_display_mode established_modes[] = {
*/
static int add_established_modes(struct drm_output *output, struct edid *edid)
{
+ struct drm_device *dev = output->dev;
unsigned long est_bits = edid->established_timings.t1 |
(edid->established_timings.t2 << 8) |
((edid->established_timings.mfg_rsvd & 0x80) << 9);
@@ -365,7 +368,7 @@ static int add_established_modes(struct drm_output *output, struct edid *edid)
for (i = 0; i <= EDID_EST_TIMINGS; i++)
if (est_bits & (1<<i)) {
drm_mode_probed_add(output,
- drm_mode_duplicate(&established_modes[i]));
+ drm_mode_duplicate(dev, &established_modes[i]));
modes++;
}
@@ -382,6 +385,7 @@ static int add_established_modes(struct drm_output *output, struct edid *edid)
static int add_standard_modes(struct drm_output *output, struct edid *edid)
{
int i, modes = 0;
+ struct drm_device *dev = output->dev;
for (i = 0; i < EDID_STD_TIMINGS; i++) {
struct std_timing *t = &edid->standard_timings[i];
@@ -391,7 +395,7 @@ static int add_standard_modes(struct drm_output *output, struct edid *edid)
continue;
drm_mode_probed_add(output,
- drm_mode_std(&edid->standard_timings[i]));
+ drm_mode_std(dev, &edid->standard_timings[i]));
modes++;
}
@@ -409,6 +413,7 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid)
{
int i, j, modes = 0;
bool preferred = 0;
+ struct drm_device *dev = output->dev;
for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
struct detailed_timing *timing = &edid->detailed_timings[i];
@@ -423,7 +428,7 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid)
if (i == 0 && edid->preferred_timing)
preferred = 1;
drm_mode_probed_add(output,
- drm_mode_detailed(timing, preferred));
+ drm_mode_detailed(dev, timing, preferred));
modes++;
continue;
}
@@ -446,7 +451,7 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid)
struct std_timing *std;
std = &data->data.timings[j];
- drm_mode_probed_add(output, drm_mode_std(std));
+ drm_mode_probed_add(output, drm_mode_std(dev, std));
modes++;
}
break;
diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c
index 2347a669..940fc981 100644
--- a/linux-core/drm_modes.c
+++ b/linux-core/drm_modes.c
@@ -115,15 +115,18 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
EXPORT_SYMBOL(drm_mode_set_crtcinfo);
-struct drm_display_mode *drm_mode_duplicate(struct drm_display_mode *mode)
+struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, struct drm_display_mode *mode)
{
struct drm_display_mode *nmode;
+ int new_id;
- nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
+ nmode = drm_crtc_mode_create(dev);
if (!nmode)
return NULL;
+ new_id = nmode->mode_id;
*nmode = *mode;
+ nmode->mode_id = new_id;
INIT_LIST_HEAD(&nmode->head);
return nmode;
}
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 3c59cd40..33194dcc 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -888,6 +888,74 @@ typedef union drm_mm_init_arg{
} rep;
} drm_mm_init_arg_t;
+/*
+ * Drm mode setting
+ */
+
+struct drm_mode_modeinfo {
+
+ unsigned int id;
+
+ unsigned int clock;
+ unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew;
+ unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan;
+
+ unsigned int flags;
+// int count_flag;
+// unsigned int __user *modeFlags;
+};
+
+struct drm_mode_card_res {
+
+ unsigned int fb_id;
+
+ int count_crtcs;
+ int count_outputs;
+ int count_modes;
+ struct drm_mode_modeinfo __user *modes;
+
+};
+
+struct drm_mode_crtc {
+ unsigned int crtc_id; /**< Id */
+ unsigned int buffer_id; /**< Id of framebuffer */
+
+ int x, y; /**< Position on the frameuffer */
+ unsigned int width, height;
+ unsigned int mode; /**< Current mode used */
+
+ int count_outputs;
+ unsigned int outputs; /**< Outputs that are connected */
+
+ int count_possibles;
+ unsigned int possibles; /**< Outputs that can be connected */
+
+ unsigned int __user *set_outputs; /**< Outputs to be connected */
+
+ int gamma_size;
+
+};
+
+struct drm_mode_get_output {
+
+ unsigned int output; /**< Id */
+ unsigned int crtc; /**< Id of crtc */
+
+ unsigned int connection;
+ unsigned int width, height; /**< HxW in millimeters */
+ unsigned int subpixel;
+
+ int count_crtcs;
+ unsigned int crtcs; /**< possible crtc to connect to */
+
+ int count_clones;
+ unsigned int clones; /**< list of clones */
+
+ int count_modes;
+ unsigned int __user *modes; /**< list of modes it supports */
+
+};
+
/**
* \name Ioctls Definitions
*/
@@ -959,6 +1027,10 @@ typedef union drm_mm_init_arg{
#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t)
+#define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res)
+#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, drm_mode_crtc_t)
+#define DRM_IOCTL_MODE_GETOUTPUT DRM_IOWR(0xA2, drm_mode_get_output_t)
+
/*@}*/
/**