From 7bb112fecadc6fe42e5828b861600691071ccd91 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Apr 2007 17:06:42 +1000 Subject: checkpoint commit: added getresources, crtc and output This adds the user interfaces from Jakob and hooks them up for 3 ioctls GetResources, GetCrtc and GetOutput. I've made the ids for everything fbs, crtcs, outputs and modes go via idr as per krh's suggestion on irc as it make the code nice and consistent. --- libdrm/xf86drmMode.c | 407 ++++++++++++++++++++++++++++++++++++++++++++++++++ libdrm/xf86drmMode.h | 290 +++++++++++++++++++++++++++++++++++ linux-core/drm_crtc.c | 218 ++++++++++++++++++++++----- linux-core/drm_crtc.h | 12 +- linux-core/drm_drv.c | 4 +- shared-core/drm.h | 20 ++- 6 files changed, 902 insertions(+), 49 deletions(-) create mode 100644 libdrm/xf86drmMode.c create mode 100644 libdrm/xf86drmMode.h diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c new file mode 100644 index 00000000..b48ca838 --- /dev/null +++ b/libdrm/xf86drmMode.c @@ -0,0 +1,407 @@ +/* + * \file xf86drmMode.c + * Header for DRM modesetting interface. + * + * \author Jakob Bornecrantz + * + * \par Acknowledgements: + * Feb 2007, Dave Airlie + */ + +/* + * Copyright (c) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +/* + * TODO the types we are after are defined in diffrent headers on diffrent + * platforms find which headers to include to get uint32_t + */ +#include + +#include "xf86drmMode.h" +#include "xf86drm.h" +#include + +/* + * Util functions + */ + +void* drmAllocCpy(void *array, int count, int entry_size) +{ + char *r; + int i; + + if (!count || !array || !entry_size) + return 0; + + if (!(r = drmMalloc(count*entry_size))) + return 0; + + for (i = 0; i < count; i++) + memcpy(r+(entry_size*i), array+(entry_size*i), entry_size); + + return r; +} + +/** + * Generate crtc and output ids. + * + * Will generate ids starting from 1 up to count if count is greater then 0. + */ +static uint32_t* drmAllocGenerate(int count) +{ + uint32_t *r; + int i; + + if(0 <= count) + return 0; + + if (!(r = drmMalloc(count*sizeof(*r)))) + return 0; + + for (i = 0; i < count; r[i] = ++i); + + return 0; +} + +/* + * A couple of free functions. + */ + +void drmModeFreeModeInfo(struct drm_mode_modeinfo *ptr) +{ + if (!ptr) + return; + + drmFree(ptr); +} + +void drmModeFreeResources(drmModeResPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->modes); + drmFree(ptr); + +} + +void drmModeFreeFrameBuffer(drmModeFrameBufferPtr ptr) +{ + if (!ptr) + return; + + /* we might add more frees later. */ + drmFree(ptr); +} + +void drmModeFreeCrtc(drmModeCrtcPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr); + +} + +void drmModeFreeOutput(drmModeOutputPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->modes); + drmFree(ptr); + +} + +/* + * ModeSetting functions. + */ + +drmModeResPtr drmModeGetResources(int fd) +{ + struct drm_mode_card_res res; + int i; + drmModeResPtr r = 0; + + res.count_crtcs = 0; + res.count_outputs = 0; + res.count_modes = 0; + res.modes = 0; + + if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) + return 0; + + if (res.count_crtcs) + res.crtc_id = drmMalloc(res.count_crtcs*sizeof(uint32_t)); + if (res.count_outputs) + res.output_id = drmMalloc(res.count_outputs*sizeof(uint32_t)); + if (res.count_modes) + res.modes = drmMalloc(res.count_modes*sizeof(*res.modes)); + + if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) + goto err_allocs; + + /* + * return + */ + + + if (!(r = drmMalloc(sizeof(*r)))) + return 0; + + r->frameBufferId = res.fb_id; + r->count_crtcs = res.count_crtcs; + r->count_outputs = res.count_outputs; + r->count_modes = res.count_modes; + /* TODO we realy should test if these allocs fails. */ + r->crtcs = drmAllocCpy(res.crtc_id, res.count_crtcs, sizeof(uint32_t)); + r->outputs = drmAllocCpy(res.output_id, res.count_outputs, sizeof(uint32_t)); + r->modes = drmAllocCpy(res.modes, res.count_modes, sizeof(struct drm_mode_modeinfo)); + + drmFree(res.crtc_id); + drmFree(res.output_id); + drmFree(res.modes); + + return r; + +err_allocs: + drmFree(res.crtc_id); + drmFree(res.output_id); + drmFree(res.modes); + + return 0; +} + +#if 0 +int drmModeForceProbe(int fd, uint32_t outputId) +{ + /* TODO impl/keep? */ +} + +drmModeFrameBufferPtr drmModeGetFrameBuffer(int fd, uint32_t buf) +{ +// struct drm_mode_fb_cmd info; + drmModeFrameBufferPtr r; + + // if (ioctl(fd, DRM_IOCTL_MODE_GETFRAMEBUFFER, &info)) + return 0; + + if (!(r = drmMalloc(sizeof(*r)))) + return 0; + + /* TODO change to new code + r->minWidth = info.minWidth; + r->maxWidth = info.maxWidth; + r->minHeight = info.minHeight; + r->maxHeight = info.maxHeight;*/ + + return r; +} + +uint32_t drmModeNewFrameBuffer(int fd, uint32_t width, uint32_t height, + uint8_t bpp, uint32_t pitch, drmBO *bo) +{ + drm_mode_fb_cmd_t f; + + f.handle = bo->handle; + f.width = width; + f.height = height; + f.pitch = pitch; + + // if (ioctl(fd, DRM_IOCTL_MODE_NEWFRAMEBUFFER, &f)) + return 0; + + return f.bufferId; +} + +int drmModeDesFrameBuffer(int fd, uint32_t bufferId) +{ + // return ioctl(fd, DRM_IOCTL_MODE_DESFRAMEBUFFER, bufferId); +} + +#endif +/* + * Crtc function. + */ + +drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) +{ + struct drm_mode_crtc crtc; + drmModeCrtcPtr r; + int i = 0; + + crtc.count_outputs = 0; + crtc.outputs = 0; + crtc.count_possibles = 0; + crtc.possibles = 0; + crtc.crtc_id = crtcId; + + if (ioctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc)) + return 0; + + /* + * return + */ + + if (!(r = drmMalloc(sizeof(*r)))) + return 0; + + r->x = crtc.x; + r->y = crtc.y; + r->mode = crtc.mode; +// r->width = crtc.width; +// r->height = crtc.height; + r->bufferId = crtc.fb_id; + r->gamma_size = crtc.gamma_size; + r->count_outputs = crtc.count_outputs; + r->count_possibles = crtc.count_possibles; + /* TODO we realy should test if these alloc & cpy fails. */ + r->outputs = crtc.outputs; + r->possibles = crtc.possibles; + + return r; + +err_allocs: + + return 0; +} + +#if 0 +int drmModeSetCrtc( + int fd, uint32_t crtcId, uint32_t bufferId, + uint32_t x, uint32_t y, uint32_t modeId, + uint32_t *outputs, int count + ) +{ + struct drm_mode_crtc crtc; + + crtc.count_outputs = 0; + crtc.outputs = 0; + crtc.count_possibles = 0; + crtc.possibles = 0; + + crtc.x = x; + crtc.y = y; + crtc.crtcId = crtcId; + crtc.bufferId = bufferId; + crtc.set_outputs = outputs; + crtc.count_outputs = count; + crtc.mode = modeId; + + // return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc); +} + +drmModeGammaTriplePtr drmModeGetCrtcGamma(int fd, uint32_t crtc, int *count) +{ + /* TODO impl */ +} + +int drmModeSetCrtcGamma(int fd, uint32_t crtcId, + drmModeGammaTriplePtr ptr, int count) +{ + /* TODO impl */ +} + +#endif +/* + * Output manipulation + */ +drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) +{ + struct drm_mode_get_output out; + drmModeOutputPtr r = 0; + + out.output = output_id; + out.count_crtcs = 0; + out.crtcs = 0; + out.count_clones = 0; + out.clones = 0; + out.count_modes = 0; + out.modes = 0; + + if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) + return 0; + + if (out.count_modes) + out.modes = drmMalloc(out.count_modes*sizeof(uint32_t)); + + if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) + goto err_allocs; + + if(!(r = drmMalloc(sizeof(*r)))) + return 0; + + r->connection = out.connection; + r->mmWidth = out.mm_width; + r->mmHeight = out.mm_height; + r->subpixel = out.subpixel; + r->count_crtcs = out.count_crtcs; + r->count_clones = out.count_clones; + r->count_modes = out.count_modes; + /* TODO we should test if these alloc & cpy fails. */ + r->crtcs = out.crtcs; + r->clones = out.clones; + r->modes = drmAllocCpy(out.modes, out.count_modes, sizeof(uint32_t)); + + return r; + +err_allocs: + drmFree(out.modes); + + return 0; +} + +#if 0 +uint32_t drmModeNewMode(int fd, struct drm_mode_modeinfo *modeInfo) +{ + /* TODO impl */ +} + +int drmModeDesMode(int fd, uint32_t modeId) +{ + // return ioctl(fd, DRM_IOCTL_MODE_DESMODE, modeId); +} + +int drmModeAddMode(int fd, uint32_t outputId, uint32_t modeId) +{ + + drm_mode_outputmode_t res; + + res.outputId = outputId; + res.modeId = modeId; + + // return ioctl(fd, DRM_IOCTL_MODE_ADDMODE, &res); +} + +int drmModeDelMode(int fd, uint32_t outputId, uint32_t modeId) +{ + drm_mode_outputmode_t res; + + res.outputId = outputId; + res.modeId = modeId; + + // return ioctl(fd, DRM_IOCTL_MODE_DELMODE, &res); +} + +#endif + diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h new file mode 100644 index 00000000..c027a16d --- /dev/null +++ b/libdrm/xf86drmMode.h @@ -0,0 +1,290 @@ +/* + * \file xf86drmMode.h + * Header for DRM modesetting interface. + * + * \author Jakob Bornecrantz + * + * \par Acknowledgements: + * Feb 2007, Dave Airlie + */ + +/* + * Copyright (c) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#include +#include "xf86mm.h" + +/* + * This is the interface for modesetting for drm. + * + * In order to use this interface you must include either or another + * header defining uint32_t, int32_t and uint16_t. + * + * It aims to provide a randr compatible interface for modesettings in the + * kernel, the interface is also ment to be used by libraries like EGL. + * + * More information can be found in randrproto.txt which can be found here: + * http://gitweb.freedesktop.org/?p=xorg/proto/randrproto.git + * + * All framebuffer, crtc and output ids start at 1 while 0 is either an invalid + * parameter or used to indicate that the command should disconnect from the + * currently bound target, as with drmModeMapOutput. + * + * Currently only one framebuffer exist and has a id of 1, which is also the + * default framebuffer and should allways be avaible to the client, unless + * it is locked/used or any other limiting state is applied on it. + * + */ + +typedef struct _drmModeGammaTriple { + uint16_t r, g, b; +} drmModeGammaTriple, *drmModeGammaTriplePtr; + +typedef struct _drmModeRes { + + uint32_t frameBufferId; + + int count_crtcs; + uint32_t *crtcs; + + int count_outputs; + uint32_t *outputs; + + int count_modes; + struct drm_mode_modeinfo *modes; + +} drmModeRes, *drmModeResPtr; + +typedef struct _drmModeFrameBuffer { + + uint32_t minWidth, maxWidth; + uint32_t minHeight, maxHeight; + +} drmModeFrameBuffer, *drmModeFrameBufferPtr; + +typedef struct _drmModeCrtc { + + unsigned int bufferId; /**< Buffer currently connected to */ + + uint32_t x, y; /**< Position on the frameuffer */ + uint32_t width, height; + uint32_t mode; /**< Current mode used */ + + int count_outputs; + uint32_t outputs; /**< Outputs that are connected */ + + int count_possibles; + uint32_t possibles; /**< Outputs that can be connected */ + + int gamma_size; /**< Number of gamma stops */ + +} drmModeCrtc, *drmModeCrtcPtr; + +typedef enum { + DRM_MODE_CONNECTED = 1, + DRM_MODE_DISCONNECTED = 2, + DRM_MODE_UNKNOWNCONNECTION = 3 +} drmModeConnection; + +typedef enum { + DRM_MODE_SUBPIXEL_UNKNOWN = 1, + DRM_MODE_SUBPIXEL_HORIZONTAL_RGB = 2, + DRM_MODE_SUBPIXEL_HORIZONTAL_BGR = 3, + DRM_MODE_SUBPIXEL_VERTICAL_RGB = 4, + DRM_MODE_SUBPIXEL_VERTICAL_BGR = 5, + DRM_MODE_SUBPIXEL_NONE = 6 +} drmModeSubPixel; + +typedef struct _drmModeOutput { + + unsigned int crtc; /**< Crtc currently connected to */ + + drmModeConnection connection; + uint32_t mmWidth, mmHeight; /**< HxW in millimeters */ + drmModeSubPixel subpixel; + + int count_crtcs; + uint32_t crtcs; /**< Possible crtc to connect to */ + + int count_clones; + uint32_t clones; /**< Mask of clones */ + + int count_modes; + uint32_t *modes; /**< List of modes ids */ + +} drmModeOutput, *drmModeOutputPtr; + +/* + * RRSetScreenConfig o + * RRGetScreenInfo o + * + * RRGetScreenSizeRange - see frameBuffer info + * RRSetScreenSize + * RRGetScreenResources + * + * RRGetOutputInfo + * + * RRListOutputProperties * + * RRQueryOutputProperty * + * RRConfigureOutputProperty * + * RRChangeOutputProperty * + * RRDeleteOutputProperty * + * RRGetOutputProperty * + * + * RRCreateMode + * RRDestroyMode + * RRAddOutputMode + * RRDeleteOutputMode + * + * RRGetCrtcInfo + * RRSetCrtcConfig + * + * RRGetCrtcGammaSize - see crtc info + * RRGetCrtcGamma + * RRSetCrtcGamma + * + * drmModeGetResources + * drmModeForceProbe + * + * drmModeGetFrameBufferInfo + * drmModeSetFrameBufferSize + * + * drmModeGetCrtcInfo + * drmModeSetCrtcConfig + * drmModeGetCrtcGamma + * drmModeSetCrtcGamma + * + * drmModeGetOutputInfo + * + * drmModeAddMode + * drmModeDestroyMode + * drmModeAddOutputMode + * drmModeDeleteOutputMode + */ + +extern void drmModeFreeModeInfo( struct drm_mode_modeinfo *ptr ); +extern void drmModeFreeResources( drmModeResPtr ptr ); +extern void drmModeFreeFrameBuffer( drmModeFrameBufferPtr ptr ); +extern void drmModeFreeCrtc( drmModeCrtcPtr ptr ); +extern void drmModeFreeOutput( drmModeOutputPtr ptr ); + +/** + * Retrives all of the resources associated with a card. + */ +extern drmModeResPtr drmModeGetResources(int fd); + +/** + * Forces a probe of the give output outputId, on 0 all will be probed. + */ +extern int drmModeForceProbe(int fd, uint32_t outputId); + + +/* + * FrameBuffer manipulation. + */ + +/** + * Retrive information about framebuffer bufferId + */ +extern drmModeFrameBufferPtr drmModeGetFramebuffer(int fd, + uint32_t bufferId); + +/** + * Creates a new framebuffer with an buffer object as its scanout buffer. + */ +extern uint32_t drmModeNewFrameBuffer(int fd, + uint32_t width, uint32_t height, + uint8_t bbp, uint32_t pitch, drmBO *bo); + +/** + * Destroies the given framebuffer. + */ +extern int drmModeDesFrameBuffer(int fd, uint32_t bufferId); + +/** + * Changes the scanout buffer to the given buffer object. + */ +extern int drmModeFlipFrameBuffer(int fd, uint32_t bufferId, drmBO *bo); + +/* + * Crtc function. + */ + +/** + * Retrive information about the ctrt crtcId + */ +extern drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId); + +/** + * Set the mode on a crtc crtcId with the given mode modeId. + */ +extern int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, + uint32_t x, uint32_t y, uint32_t modeId, + uint32_t *outputs, int count); + +/** + * Gets the gamma from a crtc + */ +extern drmModeGammaTriplePtr drmModeGetCrtcGamma(int fd, uint32_t crtcId, + int *count); + +/** + * Sets the gamma on a crtc + */ +extern int drmModeSetCrtcGamma(int fd, uint32_t crtcId, + drmModeGammaTriplePtr ptr, int count); + + + +/* + * Output manipulation + */ + +/** + * Retrive information about the output outputId. + */ +extern drmModeOutputPtr drmModeGetOutput(int fd, + uint32_t outputId); + +/** + * Creates a new mode from the given mode info. + * Name must be unique. + */ +extern uint32_t drmModeNewMode(int fd, struct drm_mode_modeinfo *modeInfo); + +/** + * Destroys a mode created with CreateMode, must be unused. + */ +extern int drmModeDesMode(int fd, uint32_t modeId); + +/** + * Adds the given mode to an output. + */ +extern int drmModeAddMode(int fd, uint32_t outputId, uint32_t modeId); + +/** + * Deletes a mode Added with AddOutputMode from the output, + * must be unused, by the given mode. + */ +extern int drmModeDelMode(int fd, uint32_t outputId, uint32_t modeId); + diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 1311fa63..2dbe6de1 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -3,6 +3,33 @@ #include "drm.h" #include "drm_crtc.h" +int drm_mode_idr_get(struct drm_device *dev, void *ptr) +{ + int new_id = 0; + int ret; +again: + if (idr_pre_get(&dev->crtc_config.crtc_idr, GFP_KERNEL) == 0) { + DRM_ERROR("Ran out memory getting a mode number\n"); + return 0; + } + + spin_lock(&dev->crtc_config.config_lock); + + ret = idr_get_new_above(&dev->crtc_config.crtc_idr, ptr, 1, &new_id); + if (ret == -EAGAIN) { + spin_unlock(&dev->crtc_config.config_lock); + goto again; + } + + spin_unlock(&dev->crtc_config.config_lock); + return new_id; +} + +void drm_mode_idr_put(struct drm_device *dev, int id) +{ + idr_remove(&dev->crtc_config.crtc_idr, id); +} + struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) { struct drm_framebuffer *fb; @@ -20,7 +47,8 @@ struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) return NULL; } - + + fb->id = drm_mode_idr_get(dev, fb); fb->dev = dev; spin_lock(&dev->crtc_config.config_lock); dev->crtc_config.num_fb++; @@ -35,6 +63,7 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) drm_device_t *dev = fb->dev; spin_lock(&dev->crtc_config.config_lock); + drm_mode_idr_put(dev, fb->id); list_del(&fb->head); dev->crtc_config.num_fb--; spin_unlock(&dev->crtc_config.config_lock); @@ -45,19 +74,21 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) struct drm_crtc *drm_crtc_create(drm_device_t *dev, const struct drm_crtc_funcs *funcs) { - struct drm_crtc *crtc = NULL; - crtc = kmalloc(sizeof(struct drm_crtc), GFP_KERNEL); + struct drm_crtc *crtc; + + crtc = kzalloc(sizeof(struct drm_crtc), GFP_KERNEL); if (!crtc) return NULL; crtc->dev = dev; crtc->funcs = funcs; - spin_lock(&dev->crtc_config.config_lock); + crtc->id = drm_mode_idr_get(dev, crtc); + DRM_DEBUG("crtc %p got id %d\n", crtc, crtc->id); + spin_lock(&dev->crtc_config.config_lock); list_add_tail(&crtc->head, &dev->crtc_config.crtc_list); dev->crtc_config.num_crtc++; - spin_unlock(&dev->crtc_config.config_lock); return crtc; @@ -71,7 +102,9 @@ void drm_crtc_destroy(struct drm_crtc *crtc) if (crtc->funcs->cleanup) (*crtc->funcs->cleanup)(crtc); + spin_lock(&dev->crtc_config.config_lock); + drm_mode_idr_put(dev, crtc->id); list_del(&crtc->head); dev->crtc_config.num_crtc--; spin_unlock(&dev->crtc_config.config_lock); @@ -257,6 +290,7 @@ bool drm_set_desired_modes(struct drm_device *dev) list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head) { output = NULL; + DRM_DEBUG("crtc is %d\n", crtc->id); list_for_each_entry(list_output, &dev->crtc_config.output_list, head) { if (list_output->crtc == crtc) { output = list_output; @@ -345,6 +379,7 @@ struct drm_output *drm_output_create(drm_device_t *dev, output->dev = dev; output->funcs = funcs; + output->id = drm_mode_idr_get(dev, output); if (name) strncpy(output->name, name, DRM_OUTPUT_LEN); output->name[DRM_OUTPUT_LEN - 1] = 0; @@ -382,6 +417,7 @@ void drm_output_destroy(struct drm_output *output) drm_mode_remove(output, mode); spin_lock(&dev->crtc_config.config_lock); + drm_mode_idr_put(dev, output->id); list_del(&output->head); spin_unlock(&dev->crtc_config.config_lock); kfree(output); @@ -411,28 +447,13 @@ struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev) 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); + nmode->mode_id = drm_mode_idr_get(dev, nmode); 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); + drm_mode_idr_put(dev, mode->mode_id); kfree(mode); } @@ -443,7 +464,7 @@ void drm_crtc_config_init(drm_device_t *dev) 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); + idr_init(&dev->crtc_config.crtc_idr); } EXPORT_SYMBOL(drm_crtc_config_init); @@ -502,6 +523,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) /* bind both CRTCs to this fb */ /* only initialise one crtc to enabled state */ list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head) { + DRM_DEBUG("crtc is %d\n", crtc->id); crtc->fb = fb; if (!vga_crtc) { vga_crtc = crtc; @@ -568,7 +590,6 @@ void drm_crtc_config_cleanup(drm_device_t *dev) drm_output_destroy(output); } - list_for_each_entry_safe(crtc, ct, &dev->crtc_config.crtc_list, head) { drm_crtc_destroy(crtc); } @@ -592,6 +613,8 @@ void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display out->vscan = in->vscan; out->flags = in->flags; + strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); + out->name[DRM_DISPLAY_MODE_LEN-1] = 0; } @@ -605,15 +628,24 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, struct drm_mode_card_res card_res; struct list_head *lh; struct drm_output *output; + struct drm_crtc *crtc; struct drm_mode_modeinfo u_mode; struct drm_display_mode *mode; int retcode = 0; int mode_count= 0; + int output_count = 0; + int crtc_count = 0; + int copied = 0; memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); + + list_for_each(lh, &dev->crtc_config.crtc_list) + crtc_count++; + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + output_count++; list_for_each(lh, &output->modes) mode_count++; } @@ -621,8 +653,38 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, if (copy_from_user(&card_res, argp, sizeof(card_res))) return -EFAULT; + /* handle this in 3 parts */ + /* CRTCs */ + if (card_res.count_crtcs >= crtc_count) { + copied = 0; + list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head){ + DRM_DEBUG("CRTC ID is %d\n", crtc->id); + if (put_user(crtc->id, &card_res.crtc_id[copied++])) { + retcode = -EFAULT; + goto done; + } + } + } + card_res.count_crtcs = crtc_count; + + + /* Outputs */ + if (card_res.count_outputs >= output_count) { + copied = 0; + list_for_each_entry(output, &dev->crtc_config.output_list, + head) { + DRM_DEBUG("OUTPUT ID is %d\n", output->id); + if (put_user(output->id, &card_res.output_id[copied++])) { + retcode = -EFAULT; + goto done; + } + } + } + card_res.count_outputs = output_count; + + /* Modes */ if (card_res.count_modes >= mode_count) { - int copied = 0; + copied = 0; list_for_each_entry(output, &dev->crtc_config.output_list, head) { list_for_each_entry(mode, &output->modes, head) { @@ -634,19 +696,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, } } } - - 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++; - } - } + card_res.count_modes = mode_count; done: DRM_DEBUG("Counted %d %d %d\n", card_res.count_crtcs, @@ -658,3 +708,95 @@ done: return retcode; } + +int drm_mode_getcrtc(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_crtc __user *argp = (void __user *)arg; + struct drm_mode_crtc crtc_resp; + struct drm_crtc *crtc; + struct drm_output *output; + int ocount; + int retcode = 0; + + if (copy_from_user(&crtc_resp, argp, sizeof(crtc_resp))) + return -EFAULT; + + crtc = idr_find(&dev->crtc_config.crtc_idr, crtc_resp.crtc_id); + if (!crtc || (crtc->id != crtc_resp.crtc_id)) + return -EINVAL; + crtc_resp.x = crtc->x; + crtc_resp.y = crtc->y; + crtc_resp.fb_id = 1; + + crtc_resp.outputs = 0; + if (crtc->enabled) { + + crtc_resp.mode = crtc->mode.mode_id; + ocount = 0; + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + if (output->crtc == crtc) + crtc_resp.outputs |= 1 << (ocount++); + } + } else { + crtc_resp.mode = 0; + } + + if (copy_to_user(argp, &crtc_resp, sizeof(crtc_resp))) + return -EFAULT; + + return retcode; +} + +int drm_mode_getoutput(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_get_output __user *argp = (void __user *)arg; + struct drm_mode_get_output out_resp; + struct drm_crtc *crtc; + struct drm_output *output; + struct drm_display_mode *mode; + int mode_count = 0; + int retcode = 0; + int copied = 0; + + if (copy_from_user(&out_resp, argp, sizeof(out_resp))) + return -EFAULT; + + output= idr_find(&dev->crtc_config.crtc_idr, out_resp.output); + if (!output || (output->id != out_resp.output)) + return -EINVAL; + + list_for_each_entry(mode, &output->modes, head) + mode_count++; + + out_resp.mm_width = output->mm_width; + out_resp.mm_height = output->mm_height; + out_resp.subpixel = output->subpixel_order; + out_resp.connection = output->status; + if (output->crtc) + out_resp.crtc = output->crtc->id; + else + out_resp.crtc = 0; + + if (out_resp.count_modes >= mode_count) { + copied = 0; + list_for_each_entry(mode, &output->modes, head) { + if (put_user(mode->mode_id, &out_resp.modes[copied++])) { + retcode = -EFAULT; + goto done; + } + } + } + out_resp.count_modes = mode_count; + +done: + if (copy_to_user(argp, &out_resp, sizeof(out_resp))) + return -EFAULT; + + return retcode; +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 003946bc..e608b462 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -74,8 +74,6 @@ enum drm_mode_status { #define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \ DRM_MODE_TYPE_CRTC_C) -#define DRM_DISPLAY_MODE_LEN 32 - #define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \ .name = nm, .status = 0, .type = (t), .clock = (c), \ .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ @@ -173,6 +171,7 @@ enum subpixel_order { struct drm_framebuffer { struct drm_device *dev; struct list_head head; + int id; /* idr assigned */ unsigned int pitch; unsigned long offset; unsigned int width; @@ -259,6 +258,8 @@ struct drm_crtc { struct drm_device *dev; struct list_head head; + int id; /* idr assigned */ + /* framebuffer the CRTC is currently bound to */ struct drm_framebuffer *fb; @@ -350,6 +351,7 @@ struct drm_output { struct drm_device *dev; struct list_head head; struct drm_crtc *crtc; + int id; /* idr assigned */ unsigned long possible_crtcs; unsigned long possible_clones; bool interlace_allowed; @@ -394,7 +396,7 @@ struct drm_crtc_config_funcs { */ struct drm_crtc_config { spinlock_t config_lock; - struct idr mode_idr; + struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, output, modes - just makes life easier */ /* this is limited to one for now */ int num_fb; struct list_head fb_list; @@ -437,5 +439,9 @@ extern void drm_crtc_mode_destroy(struct drm_device *dev, struct drm_display_mod extern int drm_mode_getresources(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int drm_mode_getcrtc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mode_getoutput(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 9877db13..7d436f8a 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -123,7 +123,9 @@ 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}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETRESOURCES)] = {drm_mode_getresources, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETCRTC)] = {drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETOUTPUT)] = {drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY}, }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/shared-core/drm.h b/shared-core/drm.h index 33194dcc..1af0be38 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -892,6 +892,8 @@ typedef union drm_mm_init_arg{ * Drm mode setting */ +#define DRM_DISPLAY_MODE_LEN 32 + struct drm_mode_modeinfo { unsigned int id; @@ -901,8 +903,8 @@ struct drm_mode_modeinfo { unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan; unsigned int flags; -// int count_flag; -// unsigned int __user *modeFlags; + + char name[DRM_DISPLAY_MODE_LEN]; }; struct drm_mode_card_res { @@ -910,7 +912,11 @@ struct drm_mode_card_res { unsigned int fb_id; int count_crtcs; + unsigned int __user *crtc_id; + int count_outputs; + unsigned int __user *output_id; + int count_modes; struct drm_mode_modeinfo __user *modes; @@ -918,10 +924,10 @@ struct drm_mode_card_res { struct drm_mode_crtc { unsigned int crtc_id; /**< Id */ - unsigned int buffer_id; /**< Id of framebuffer */ + unsigned int fb_id; /**< Id of framebuffer */ int x, y; /**< Position on the frameuffer */ - unsigned int width, height; + unsigned int mode; /**< Current mode used */ int count_outputs; @@ -942,7 +948,7 @@ struct drm_mode_get_output { unsigned int crtc; /**< Id of crtc */ unsigned int connection; - unsigned int width, height; /**< HxW in millimeters */ + unsigned int mm_width, mm_height; /**< HxW in millimeters */ unsigned int subpixel; int count_crtcs; @@ -1028,8 +1034,8 @@ struct drm_mode_get_output { #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) +#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_GETOUTPUT DRM_IOWR(0xA2, struct drm_mode_get_output) /*@}*/ -- cgit v1.2.3