#include <linux/list.h>
#include "drmP.h"
#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->mode_config.crtc_idr, GFP_KERNEL) == 0) {
DRM_ERROR("Ran out memory getting a mode number\n");
return 0;
}
spin_lock(&dev->mode_config.config_lock);
ret = idr_get_new_above(&dev->mode_config.crtc_idr, ptr, 1, &new_id);
if (ret == -EAGAIN) {
spin_unlock(&dev->mode_config.config_lock);
goto again;
}
spin_unlock(&dev->mode_config.config_lock);
return new_id;
}
void drm_mode_idr_put(struct drm_device *dev, int id)
{
idr_remove(&dev->mode_config.crtc_idr, id);
}
struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev)
{
struct drm_framebuffer *fb;
spin_lock(&dev->mode_config.config_lock);
/* Limit to single framebuffer for now */
if (dev->mode_config.num_fb > 1) {
DRM_ERROR("Attempt to add multiple framebuffers failed\n");
return NULL;
}
spin_unlock(&dev->mode_config.config_lock);
fb = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL);
if (!fb) {
return NULL;
}
fb->id = drm_mode_idr_get(dev, fb);
fb->dev = dev;
spin_lock(&dev->mode_config.config_lock);
dev->mode_config.num_fb++;
list_add(&fb->head, &dev->mode_config.fb_list);
spin_unlock(&dev->mode_config.config_lock);
return fb;
}
void drm_framebuffer_destroy(struct drm_framebuffer *fb)
{
drm_device_t *dev = fb->dev;
spin_lock(&dev->mode_config.config_lock);
drm_mode_idr_put(dev, fb->id);
list_del(&fb->head);
dev->mode_config.num_fb--;
spin_unlock(&dev->mode_config.config_lock);
kfree(fb);
}
struct drm_crtc *drm_crtc_create(drm_device_t *dev,
const struct drm_crtc_funcs *funcs)
{
struct drm_crtc *crtc;
crtc = kzalloc(sizeof(struct drm_crtc), GFP_KERNEL);
if (!crtc)
return NULL;
crtc->dev = dev;
crtc->funcs = funcs;
crtc->id = drm_mode_idr_get(dev, crtc);
spin_lock(&dev->mode_config.config_lock);
list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
dev->mode_config.num_crtc++;
spin_unlock(&dev->mode_config.config_lock);
return crtc;
}
EXPORT_SYMBOL(drm_crtc_create);
void drm_crtc_destroy(struct drm_crtc *crtc)
{
drm_device_t *dev = crtc->dev;
if (crtc->funcs->cleanup)
(*crtc->funcs->cleanup)(crtc);
spin_lock(&dev->mode_config.config_lock);
drm_mode_idr_put(dev, crtc->id);
list_del(&crtc->head);
dev->mode_config.num_crtc--;
spin_unlock(&dev->mode_config.config_lock);
kfree(crtc);
}
EXPORT_SYMBOL(drm_crtc_destroy);
bool drm_crtc_in_use(struct drm_crtc *crtc)
{
struct drm_output *output;
drm_device_t *dev = crtc->dev;
/* FIXME: Locking around list access? */
list_for_each_entry(output, &dev->mode_config.output_list, head)
if (output->crtc == crtc)
return true;
return false;
}
EXPORT_SYMBOL(drm_crtc_in_use);
void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY)
{
struct drm_output *output;
struct drm_display_mode *mode, *t;
int ret;
//if (maxX == 0 || maxY == 0)
// TODO
list_for_each_entry(output, &dev->mode_config.output_list, head) {
list_for_each_entry_safe(mode, t, &output->modes, head)
drm_mode_remove(output, mode);
output->status = (*output->funcs->detect)(output);
if (output->status == output_status_disconnected) {
/* TODO set EDID to NULL */
continue;
}
ret = (*output->funcs->get_modes)(output);
if (ret) {
/* move the modes over to the main mode list */
drm_mode_list_concat(&output->probed_modes,
&output->modes);
}
if (maxX && maxY)
drm_mode_validate_size(dev, &output->modes, maxX,
maxY, 0);
|