initial userspace interface to get modes

main
Dave Airlie 2007-04-05 13:34:50 +10:00
parent 52f9028c84
commit 5bffbd6e27
7 changed files with 229 additions and 15 deletions

View File

@ -23,9 +23,9 @@ libdrm_ladir = $(libdir)
libdrm_la_LDFLAGS = -version-number 2:3:0 -no-undefined libdrm_la_LDFLAGS = -version-number 2:3:0 -no-undefined
AM_CFLAGS = -I$(top_srcdir)/shared-core 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} libdrmincludedir = ${includedir}
libdrminclude_HEADERS = xf86drm.h xf86mm.h libdrminclude_HEADERS = xf86drm.h xf86mm.h xf86drmMode.h
EXTRA_DIST = ChangeLog TODO EXTRA_DIST = ChangeLog TODO

View File

@ -154,7 +154,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
bool ret = false; bool ret = false;
struct drm_output *output; struct drm_output *output;
adjusted_mode = drm_mode_duplicate(mode); adjusted_mode = drm_mode_duplicate(dev, mode);
crtc->enabled = drm_crtc_in_use(crtc); 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 */ /* XXX free adjustedmode */
drm_crtc_mode_destroy(dev, adjusted_mode);
ret = TRUE; ret = TRUE;
/* TODO */ /* TODO */
// if (scrn->pScreen) // if (scrn->pScreen)
@ -401,12 +402,48 @@ bool drm_output_rename(struct drm_output *output, const char *name)
} }
EXPORT_SYMBOL(drm_output_rename); 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) void drm_crtc_config_init(drm_device_t *dev)
{ {
spin_lock_init(&dev->crtc_config.config_lock); spin_lock_init(&dev->crtc_config.config_lock);
INIT_LIST_HEAD(&dev->crtc_config.fb_list); INIT_LIST_HEAD(&dev->crtc_config.fb_list);
INIT_LIST_HEAD(&dev->crtc_config.crtc_list); INIT_LIST_HEAD(&dev->crtc_config.crtc_list);
INIT_LIST_HEAD(&dev->crtc_config.output_list); INIT_LIST_HEAD(&dev->crtc_config.output_list);
idr_init(&dev->crtc_config.mode_idr);
} }
EXPORT_SYMBOL(drm_crtc_config_init); EXPORT_SYMBOL(drm_crtc_config_init);
@ -441,7 +478,7 @@ void drm_framebuffer_set_object(drm_device_t *dev, unsigned long handle)
ret = 0; ret = 0;
out_err: out_err:
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return ret; return;
} }
EXPORT_SYMBOL(drm_framebuffer_set_object); 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); 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;
}

View File

@ -9,6 +9,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/idr.h>
#include "drmP.h" #include "drmP.h"
#include "drm.h" #include "drm.h"
@ -86,6 +87,7 @@ struct drm_display_mode {
/* Header */ /* Header */
struct list_head head; struct list_head head;
char name[DRM_DISPLAY_MODE_LEN]; char name[DRM_DISPLAY_MODE_LEN];
int mode_id;
enum drm_mode_status status; enum drm_mode_status status;
int type; int type;
@ -392,6 +394,7 @@ struct drm_crtc_config_funcs {
*/ */
struct drm_crtc_config { struct drm_crtc_config {
spinlock_t config_lock; spinlock_t config_lock;
struct idr mode_idr;
/* this is limited to one for now */ /* this is limited to one for now */
int num_fb; int num_fb;
struct list_head fb_list; struct list_head fb_list;
@ -419,10 +422,20 @@ int drm_add_edid_modes(struct drm_output *output,
struct i2c_adapter *adapter); struct i2c_adapter *adapter);
void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode); 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); 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, extern void drm_mode_debug_printmodeline(struct drm_device *dev,
struct drm_display_mode *mode); struct drm_display_mode *mode);
extern void drm_crtc_config_init(struct drm_device *dev); extern void drm_crtc_config_init(struct drm_device *dev);
extern void drm_crtc_config_cleanup(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 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__ */ #endif /* __DRM_CRTC_H__ */

View File

@ -123,6 +123,7 @@ static drm_ioctl_desc_t drm_ioctls[] = {
DRM_AUTH }, 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_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 ) #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )

View File

@ -212,7 +212,8 @@ bad:
* *
* Punts for now. * 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; // struct fb_videomode mode;
@ -221,7 +222,7 @@ struct drm_display_mode *drm_mode_std(struct std_timing *t)
struct drm_display_mode *mode; struct drm_display_mode *mode;
int hsize = t->hsize * 8 + 248, vsize; int hsize = t->hsize * 8 + 248, vsize;
mode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL); mode = drm_crtc_mode_create(dev);
if (!mode) if (!mode)
return NULL; return NULL;
@ -239,7 +240,8 @@ struct drm_display_mode *drm_mode_std(struct std_timing *t)
return mode; 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) bool preferred)
{ {
struct drm_display_mode *mode; struct drm_display_mode *mode;
@ -254,7 +256,7 @@ struct drm_display_mode *drm_mode_detailed(struct detailed_timing *timing,
return NULL; return NULL;
} }
mode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL); mode = drm_crtc_mode_create(dev);
if (!mode) if (!mode)
return NULL; 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) 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 | unsigned long est_bits = edid->established_timings.t1 |
(edid->established_timings.t2 << 8) | (edid->established_timings.t2 << 8) |
((edid->established_timings.mfg_rsvd & 0x80) << 9); ((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++) for (i = 0; i <= EDID_EST_TIMINGS; i++)
if (est_bits & (1<<i)) { if (est_bits & (1<<i)) {
drm_mode_probed_add(output, drm_mode_probed_add(output,
drm_mode_duplicate(&established_modes[i])); drm_mode_duplicate(dev, &established_modes[i]));
modes++; 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) static int add_standard_modes(struct drm_output *output, struct edid *edid)
{ {
int i, modes = 0; int i, modes = 0;
struct drm_device *dev = output->dev;
for (i = 0; i < EDID_STD_TIMINGS; i++) { for (i = 0; i < EDID_STD_TIMINGS; i++) {
struct std_timing *t = &edid->standard_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; continue;
drm_mode_probed_add(output, drm_mode_probed_add(output,
drm_mode_std(&edid->standard_timings[i])); drm_mode_std(dev, &edid->standard_timings[i]));
modes++; modes++;
} }
@ -409,6 +413,7 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid)
{ {
int i, j, modes = 0; int i, j, modes = 0;
bool preferred = 0; bool preferred = 0;
struct drm_device *dev = output->dev;
for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
struct detailed_timing *timing = &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) if (i == 0 && edid->preferred_timing)
preferred = 1; preferred = 1;
drm_mode_probed_add(output, drm_mode_probed_add(output,
drm_mode_detailed(timing, preferred)); drm_mode_detailed(dev, timing, preferred));
modes++; modes++;
continue; continue;
} }
@ -446,7 +451,7 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid)
struct std_timing *std; struct std_timing *std;
std = &data->data.timings[j]; 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++; modes++;
} }
break; break;

View File

@ -115,15 +115,18 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
EXPORT_SYMBOL(drm_mode_set_crtcinfo); 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; 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) if (!nmode)
return NULL; return NULL;
new_id = nmode->mode_id;
*nmode = *mode; *nmode = *mode;
nmode->mode_id = new_id;
INIT_LIST_HEAD(&nmode->head); INIT_LIST_HEAD(&nmode->head);
return nmode; return nmode;
} }

View File

@ -888,6 +888,74 @@ typedef union drm_mm_init_arg{
} rep; } rep;
} drm_mm_init_arg_t; } 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 * \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_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)
/*@}*/ /*@}*/
/** /**