Merge branch 'modesetting-101' of git+ssh://git.freedesktop.org/git/mesa/drm into origin/modesetting-101

Conflicts:

	linux-core/drm_crtc.c
	linux-core/drm_fb.c

Lots of changes to merge with alanh's latest stuff:
  o fix use of fb->pitch now that it has the right value
  o add new helper for finding the CRTC given an FB
  o fix new fb_probe/fb_remove functions to take a CRTC
  o fixup callers of new FB routines
  o port drm_fb changes to intel_fb
  o check for errors after creating fb buffer object
  o go back to using cfb_imageblit since the accel stubs aren't ready
This commit is contained in:
Jesse Barnes 2007-05-17 10:35:07 -07:00
commit b7bf317f42
17 changed files with 1028 additions and 364 deletions

View file

@ -238,15 +238,10 @@ drmModeFBPtr drmModeGetFB(int fd, uint32_t buf)
return r;
}
#if 0
int drmModeForceProbe(int fd, uint32_t outputId)
{
/* TODO impl/keep? */
}
#endif
/*
* Crtc function.
* Crtc functions
*/
drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
@ -274,9 +269,7 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
r->x = crtc.x;
r->y = crtc.y;
r->mode = crtc.mode;
// r->width = crtc.width;
// r->height = crtc.height;
r->buffer_id = crtc.fb_id;
r->buffer_id = crtc.fb_id;
r->gamma_size = crtc.gamma_size;
r->count_outputs = crtc.count_outputs;
r->count_possibles = crtc.count_possibles;
@ -305,8 +298,8 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
crtc.x = x;
crtc.y = y;
crtc.crtc_id = crtcId;
crtc.fb_id = bufferId;
crtc.crtc_id = crtcId;
crtc.fb_id = bufferId;
crtc.set_outputs = outputs;
crtc.count_outputs = count;
crtc.mode = modeId;
@ -314,22 +307,11 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
}
#if 0
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;
@ -376,37 +358,38 @@ err_allocs:
return 0;
}
#if 0
uint32_t drmModeNewMode(int fd, struct drm_mode_modeinfo *modeInfo)
uint32_t drmModeAddMode(int fd, struct drm_mode_modeinfo *mode_info)
{
/* TODO impl */
if (ioctl(fd, DRM_IOCTL_MODE_ADDMODE, mode_info))
return 0;
return mode_info->id;
}
int drmModeDesMode(int fd, uint32_t modeId)
int drmModeRmMode(int fd, uint32_t mode_id)
{
// return ioctl(fd, DRM_IOCTL_MODE_DESMODE, modeId);
return ioctl(fd, DRM_IOCTL_MODE_RMMODE, mode_id);
}
int drmModeAddMode(int fd, uint32_t outputId, uint32_t modeId)
int drmModeAttachMode(int fd, uint32_t output_id, uint32_t mode_id)
{
drm_mode_outputmode_t res;
struct drm_mode_mode_cmd res;
res.outputId = outputId;
res.modeId = modeId;
res.output_id = output_id;
res.mode_id = mode_id;
// return ioctl(fd, DRM_IOCTL_MODE_ADDMODE, &res);
return ioctl(fd, DRM_IOCTL_MODE_ATTACHMODE, &res);
}
int drmModeDelMode(int fd, uint32_t outputId, uint32_t modeId)
int drmModeDetachMode(int fd, uint32_t output_id, uint32_t mode_id)
{
drm_mode_outputmode_t res;
struct drm_mode_mode_cmd res;
res.outputId = outputId;
res.modeId = modeId;
res.output_id = output_id;
res.mode_id = mode_id;
// return ioctl(fd, DRM_IOCTL_MODE_DELMODE, &res);
return ioctl(fd, DRM_IOCTL_MODE_DETACHMODE, &res);
}
#endif

View file

@ -40,25 +40,17 @@
* In order to use this interface you must include either <stdint.h> or another
* header defining uint32_t, int32_t and uint16_t.
*
* It aims to provide a randr compatible interface for modesettings in the
* It aims to provide a randr1.2 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.
*
* There are some major diffrences to be noted. Unlike the randr1.2 proto you
* need to create the memory object of the framebuffer yourself with the ttm
* buffer object interface. This object needs to be pinned.
*/
typedef struct _drmModeGammaTriple {
uint16_t r, g, b;
} drmModeGammaTriple, *drmModeGammaTriplePtr;
typedef struct _drmModeRes {
@ -130,53 +122,7 @@ typedef struct _drmModeOutput {
} 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 );
@ -189,11 +135,6 @@ extern void drmModeFreeOutput( drmModeOutputPtr ptr );
*/
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.
@ -215,13 +156,9 @@ extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
*/
extern int drmModeRmFB(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.
* Crtc functions
*/
/**
@ -236,19 +173,6 @@ 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
@ -261,24 +185,24 @@ extern drmModeOutputPtr drmModeGetOutput(int fd,
uint32_t outputId);
/**
* Creates a new mode from the given mode info.
* Adds a new mode from the given mode info.
* Name must be unique.
*/
extern uint32_t drmModeNewMode(int fd, struct drm_mode_modeinfo *modeInfo);
extern uint32_t drmModeAddMode(int fd, struct drm_mode_modeinfo *modeInfo);
/**
* Destroys a mode created with CreateMode, must be unused.
* Removes a mode created with AddMode, must be unused.
*/
extern int drmModeDesMode(int fd, uint32_t modeId);
extern int drmModeRmMode(int fd, uint32_t modeId);
/**
* Adds the given mode to an output.
* Attaches the given mode to an output.
*/
extern int drmModeAddMode(int fd, uint32_t outputId, uint32_t modeId);
extern int drmModeAttachMode(int fd, uint32_t outputId, uint32_t modeId);
/**
* Deletes a mode Added with AddOutputMode from the output,
* Detaches a mode from the output
* must be unused, by the given mode.
*/
extern int drmModeDelMode(int fd, uint32_t outputId, uint32_t modeId);
extern int drmModeDetachMode(int fd, uint32_t outputId, uint32_t modeId);

View file

@ -662,8 +662,8 @@ struct drm_driver {
void (*set_version) (struct drm_device * dev, drm_set_version_t * sv);
/* FB routines, if present */
int (*fb_probe)(struct drm_device *dev, struct drm_framebuffer *fb);
int (*fb_remove)(struct drm_device *dev, struct drm_framebuffer *fb);
int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc);
int (*fb_remove)(struct drm_device *dev, struct drm_crtc *crtc);
struct drm_fence_driver *fence_driver;
struct drm_bo_driver *bo_driver;

View file

@ -86,6 +86,31 @@ void drm_idr_put(struct drm_device *dev, int id)
idr_remove(&dev->mode_config.crtc_idr, id);
}
/**
* drm_crtc_from_fb - find the CRTC structure associated with an fb
* @dev: DRM device
* @fb: framebuffer in question
*
* LOCKING:
* Caller must hold mode_config lock.
*
* Find CRTC in the mode_config structure that matches @fb.
*
* RETURNS:
* Pointer to the CRTC or NULL if it wasn't found.
*/
struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev,
struct drm_framebuffer *fb)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->fb == fb)
return crtc;
}
return NULL;
}
/**
* drm_framebuffer_create - create a new framebuffer object
* @dev: DRM device
@ -252,7 +277,7 @@ EXPORT_SYMBOL(drm_crtc_in_use);
* Detailed mode info for a standard 640x480@60Hz monitor
*/
static struct drm_display_mode std_mode[] = {
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
{ DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656,
752, 800, 0, 480, 490, 492, 525, 0,
V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */
};
@ -465,51 +490,7 @@ done:
return ret;
}
/**
* drm_set_desired_modes - set a good mode on every CRTC & output
* @dev: DRM device
*
* LOCKING:
* Caller? (FIXME)
*
* Each CRTC may have a desired mode associated with it. This routine simply
* walks @dev's mode_config and sets the desired mode on every CRTC. Intended
* for use at startup time.
*
* RETURNS:
* True if modes were set, false otherwise.
*/
bool drm_set_desired_modes(struct drm_device *dev)
{
struct drm_crtc *crtc;
struct drm_output *output, *list_output;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
output = NULL;
list_for_each_entry(list_output, &dev->mode_config.output_list,
head) {
if (list_output->crtc == crtc) {
output = list_output;
break;
}
}
/* Skip disabled crtcs */
if (!output) {
DRM_DEBUG("skipping disabled crtc\n");
continue;
}
if (!drm_crtc_set_mode(crtc, crtc->desired_mode,
crtc->desired_x, crtc->desired_y))
return false;
}
drm_disable_unused_functions(dev);
return true;
}
EXPORT_SYMBOL(drm_set_desired_modes);
EXPORT_SYMBOL(drm_crtc_set_mode);
/**
* drm_disable_unused_functions - disable unused objects
@ -715,6 +696,7 @@ struct drm_display_mode *drm_mode_create(struct drm_device *dev)
nmode->mode_id = drm_idr_get(dev, nmode);
return nmode;
}
EXPORT_SYMBOL(drm_mode_create);
/**
* drm_mode_destroy - remove a mode
@ -732,6 +714,7 @@ void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
kfree(mode);
}
EXPORT_SYMBOL(drm_mode_destroy);
/**
* drm_mode_config_init - initialize DRM mode_configuration structure
@ -749,6 +732,7 @@ void drm_mode_config_init(drm_device_t *dev)
INIT_LIST_HEAD(&dev->mode_config.fb_list);
INIT_LIST_HEAD(&dev->mode_config.crtc_list);
INIT_LIST_HEAD(&dev->mode_config.output_list);
INIT_LIST_HEAD(&dev->mode_config.usermode_list);
idr_init(&dev->mode_config.crtc_idr);
}
EXPORT_SYMBOL(drm_mode_config_init);
@ -798,26 +782,94 @@ out_err:
}
/**
* drm_setup_output - setup an output structure
* @output: output to setup
* @crtc: CRTC this output belongs to
* @mode: desired mode for this output
* drm_pick_crtcs - pick crtcs for output devices
* @dev: DRM device
*
* LOCKING:
* None.
*
* Setup @output with the parameters given, with its initial coordinates set
* at the origin.
*/
static void drm_setup_output(struct drm_output *output, struct drm_crtc *crtc,
struct drm_display_mode *mode)
static void drm_pick_crtcs (drm_device_t *dev)
{
output->crtc = crtc;
output->crtc->desired_mode = mode;
output->initial_x = 0;
output->initial_y = 0;
int c, o;
struct drm_output *output, *output_equal;
struct drm_crtc *crtc;
struct drm_display_mode *des_mode = NULL, *modes, *modes_equal;
list_for_each_entry(output, &dev->mode_config.output_list, head) {
output->crtc = NULL;
/* Don't hook up outputs that are disconnected ??
*
* This is debateable. Do we want fixed /dev/fbX or
* dynamic on hotplug (need mode code for that though) ?
*
* If we don't hook up outputs now, then we only create
* /dev/fbX for the output that's enabled, that's good as
* the users console will be on that output.
*
* If we do hook up outputs that are disconnected now, then
* the user may end up having to muck about with the fbcon
* map flags to assign his console to the enabled output. Ugh.
*/
if (output->status != output_status_connected)
continue;
des_mode = NULL;
list_for_each_entry(des_mode, &output->modes, head) {
if (des_mode->flags & DRM_MODE_TYPE_PREFERRED)
break;
}
/* No preferred mode, let's select another which should pick
* the default 640x480 if nothing else is here.
*
*/
if (!des_mode || !(des_mode->flags & DRM_MODE_TYPE_PREFERRED)) {
list_for_each_entry(des_mode, &output->modes, head) {
if (des_mode->flags & DRM_MODE_TYPE_DEFAULT)
break;
}
}
c = -1;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
c++;
if ((output->possible_crtcs & (1 << c)) == 0)
continue;
#if 0 /* should we try and clone ?? - code not tested - FIXME */
o = -1;
list_for_each_entry(output_equal, &dev->mode_config.output_list, head) {
o++;
if (output->id == output_equal->id)
continue;
list_for_each_entry(modes, &output->modes, head) {
list_for_each_entry(modes_equal, &output_equal->modes, head) {
if (drm_mode_equal (modes, modes_equal)) {
if ((output->possible_clones & (1 << o))) {
goto clone;
}
}
}
}
}
clone:
#endif
/* Found a CRTC to attach to, do it ! */
output->crtc = crtc;
output->crtc->desired_mode = des_mode;
output->initial_x = 0;
output->initial_y = 0;
DRM_DEBUG("Desired mode for CRTC %d is %s\n",c,des_mode->name);
break;
}
}
}
/**
* drm_initial_config - setup a sane initial output configuration
* @dev: DRM device
@ -830,108 +882,68 @@ static void drm_setup_output(struct drm_output *output, struct drm_crtc *crtc,
* At the moment, this is a cloned configuration across all heads with
* a new framebuffer object as the backing store.
*
* FIXME: return value and better initial config.
*
* RETURNS:
* Zero if everything went ok, nonzero otherwise.
*/
bool drm_initial_config(drm_device_t *dev, bool can_grow)
{
/* do a hardcoded initial configuration here */
struct drm_crtc *crtc, *vga_crtc = NULL, *tmds_crtc = NULL,
*lvds_crtc = NULL;
struct drm_display_mode *des_mode = NULL;
struct drm_output *output;
struct drm_framebuffer *fb;
drm_buffer_object_t *fbo;
unsigned long size, bytes_per_pixel;
fb = drm_framebuffer_create(dev);
if (!fb) {
DRM_ERROR("failed to allocate fb.\n");
return true;
}
/* bind both CRTCs to this fb */
/* only initialise one crtc to enabled state */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
crtc->fb = fb;
if (!vga_crtc) {
vga_crtc = crtc;
crtc->enabled = 1;
crtc->desired_x = 0;
crtc->desired_y = 0;
} else {
if (!lvds_crtc) {
lvds_crtc = crtc;
crtc->enabled = 1;
crtc->desired_x = 0;
crtc->desired_y = 0;
}
if (!tmds_crtc) {
tmds_crtc = crtc;
crtc->enabled = 1;
crtc->desired_x = 0;
crtc->desired_y = 0;
}
}
}
int ret;
drm_crtc_probe_output_modes(dev, 2048, 2048);
/* hard bind the CRTCS */
drm_pick_crtcs(dev);
/* bind analog output to one crtc */
list_for_each_entry(output, &dev->mode_config.output_list, head) {
struct drm_display_mode *des_mode = NULL;
if (list_empty(&output->modes))
/* can't setup the output if there's no assigned crtc or mode */
if (!output->crtc || !output->crtc->desired_mode)
continue;
/* Get the first preferred moded */
list_for_each_entry(des_mode, &output->modes, head) {
if (des_mode->flags & DRM_MODE_TYPE_PREFERRED)
break;
fb = drm_framebuffer_create(dev);
if (!fb) {
DRM_ERROR("failed to allocate fb.\n");
return true;
}
output->crtc->fb = fb;
des_mode = output->crtc->desired_mode;
if (!des_mode)
continue;
if (!strncmp(output->name, "VGA", 3)) {
DRM_DEBUG("VGA preferred mode: %s\n", des_mode->name);
drm_setup_output(output, vga_crtc, des_mode);
} else if (!strncmp(output->name, "TMDS", 4)) {
DRM_DEBUG("TMDS preferred mode: %s\n", des_mode->name);
drm_setup_output(output, tmds_crtc, des_mode);
} else if (!strncmp(output->name, "LVDS", 3)) {
DRM_DEBUG("LVDS preferred mode: %s\n", des_mode->name);
drm_setup_output(output, lvds_crtc, des_mode);
} else
output->crtc = NULL;
/* FB config is max of above desired resolutions */
/* FIXME: per-output FBs/CRTCs */
if (des_mode->hdisplay > fb->width)
fb->width = des_mode->hdisplay;
if (des_mode->vdisplay > fb->height)
fb->height = des_mode->vdisplay;
}
/* FIXME: multiple depths */
bytes_per_pixel = 4;
fb->bits_per_pixel = bytes_per_pixel * 8;
fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8);
fb->depth = bytes_per_pixel * 8;
size = fb->width * fb->height * bytes_per_pixel;
drm_buffer_object_create(dev, size, drm_bo_type_kernel,
DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE |
DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE,
0, 0, 0,
&fbo);
DRM_DEBUG("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width,
fb->height, fbo->offset, fbo);
fb->offset = fbo->offset;
fb->bo = fbo;
dev->driver->fb_probe(dev, fb);
/* FIXME: multiple depths */
bytes_per_pixel = 4;
fb->bits_per_pixel = 32;
fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8);
fb->depth = 24;
size = fb->width * fb->height * bytes_per_pixel;
/* FIXME - what about resizeable objects ??? */
ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel,
DRM_BO_FLAG_READ |
DRM_BO_FLAG_WRITE |
DRM_BO_FLAG_MEM_PRIV0 |
DRM_BO_FLAG_NO_MOVE,
0, 0, 0,
&fbo);
if (ret) {
printk(KERN_ERR "failed to allocate framebuffer\n");
drm_framebuffer_destroy(fb);
continue;
}
fb->offset = fbo->offset;
fb->bo = fbo;
printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width,
fb->height, fbo->offset, fbo);
dev->driver->fb_probe(dev, output->crtc);
}
drm_disable_unused_functions(dev);
return false;
}
@ -954,6 +966,7 @@ void drm_mode_config_cleanup(drm_device_t *dev)
struct drm_output *output, *ot;
struct drm_crtc *crtc, *ct;
struct drm_framebuffer *fb, *fbt;
struct drm_display_mode *mode, *mt;
list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) {
drm_output_destroy(output);
}
@ -962,8 +975,12 @@ void drm_mode_config_cleanup(drm_device_t *dev)
drm_crtc_destroy(crtc);
}
list_for_each_entry_safe(mode, mt, &dev->mode_config.usermode_list, head) {
drm_mode_destroy(dev, mode);
}
list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
dev->driver->fb_remove(dev, fb);
dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb));
/* If this FB was the kernel one, free it */
if (fb->bo->type == drm_bo_type_kernel) {
mutex_lock(&dev->struct_mutex);
@ -1089,6 +1106,35 @@ void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display
out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
}
/**
* drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode
* @out: drm_display_mode to return to the user
* @in: drm_mode_modeinfo to use
*
* LOCKING:
* None.
*
* Convert a drmo_mode_modeinfo into a drm_display_mode structure to return to
* the caller.
*/
void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modeinfo *in)
{
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->vrefresh = in->vrefresh;
out->flags = in->flags;
strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
}
/**
* drm_mode_getresources - get graphics configuration
@ -1142,6 +1188,8 @@ int drm_mode_getresources(struct inode *inode, struct file *filp,
list_for_each(lh, &output->modes)
mode_count++;
}
list_for_each(lh, &dev->mode_config.usermode_list)
mode_count++;
if (copy_from_user(&card_res, argp, sizeof(card_res)))
return -EFAULT;
@ -1154,6 +1202,8 @@ int drm_mode_getresources(struct inode *inode, struct file *filp,
list_for_each(lh, &output->modes)
mode_count++;
}
list_for_each(lh, &dev->mode_config.usermode_list)
mode_count++;
}
/* handle this in 4 parts */
@ -1210,6 +1260,14 @@ int drm_mode_getresources(struct inode *inode, struct file *filp,
}
}
}
/* add in user modes */
list_for_each_entry(mode, &dev->mode_config.usermode_list, 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;
}
}
}
card_res.count_modes = mode_count;
@ -1311,6 +1369,7 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp,
int mode_count = 0;
int retcode = 0;
int copied = 0;
int i;
if (copy_from_user(&out_resp, argp, sizeof(out_resp)))
return -EFAULT;
@ -1322,6 +1381,10 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp,
list_for_each_entry(mode, &output->modes, head)
mode_count++;
for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++)
if (output->user_mode_ids[i] != 0)
mode_count++;
strncpy(out_resp.name, output->name, DRM_OUTPUT_NAME_LEN);
out_resp.name[DRM_OUTPUT_NAME_LEN-1] = 0;
@ -1343,6 +1406,14 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp,
goto done;
}
}
for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) {
if (output->user_mode_ids[i] != 0)
if (put_user(output->user_mode_ids[i], &out_resp.modes[copied++])) {
retcode = -EFAULT;
goto done;
}
}
}
out_resp.count_modes = mode_count;
@ -1407,9 +1478,13 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp,
if (!mode || (mode->mode_id != crtc_req.mode)) {
struct drm_output *output;
list_for_each_entry(output, &dev->mode_config.output_list, head) {
list_for_each_entry(mode, &output->modes, head) {
drm_mode_debug_printmodeline(dev, mode);
list_for_each_entry(output,
&dev->mode_config.output_list,
head) {
list_for_each_entry(mode, &output->modes,
head) {
drm_mode_debug_printmodeline(dev,
mode);
}
}
@ -1517,17 +1592,20 @@ int drm_mode_addfb(struct inode *inode, struct file *filp,
r.buffer_id = fb->id;
list_add(&fb->filp_head, &priv->fbs);
if (copy_to_user(argp, &r, sizeof(r)))
return -EFAULT;
/* bind the fb to the crtc for now */
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
crtc->fb = fb;
dev->driver->fb_probe(dev, crtc);
}
}
if (copy_to_user(argp, &r, sizeof(r)))
return -EFAULT;
dev->driver->fb_probe(dev, fb);
return 0;
}
@ -1563,7 +1641,8 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp,
return -EINVAL;
}
dev->driver->fb_remove(dev, fb);
dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb));
/* TODO check if we own the buffer */
/* TODO release all crtc connected to the framebuffer */
/* bind the fb to the crtc for now */
@ -1644,8 +1723,199 @@ void drm_fb_release(struct file *filp)
list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
list_del(&fb->filp_head);
dev->driver->fb_remove(dev, fb);
dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb));
drm_framebuffer_destroy(fb);
}
}
/**
* drm_fb_newmode - adds a user defined mode
* @inode: inode from the ioctl
* @filp: file * from the ioctl
* @cmd: cmd from ioctl
* @arg: arg from ioctl
*
* Adds a user specified mode to the kernel.
*
* Called by the user via ioctl.
*
* RETURNS:
* writes new mode id into arg.
* Zero on success, errno on failure.
*/
int drm_mode_addmode(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_modeinfo __user *argp = (void __user *)arg;
struct drm_mode_modeinfo new_mode;
struct drm_display_mode *user_mode;
if (copy_from_user(&new_mode, argp, sizeof(new_mode)))
return -EFAULT;
user_mode = drm_mode_create(dev);
if (!user_mode)
return -ENOMEM;
drm_crtc_convert_umode(user_mode, &new_mode);
user_mode->type |= DRM_MODE_TYPE_USERDEF;
user_mode->output_count = 0;
spin_lock(&dev->mode_config.config_lock);
list_add(&user_mode->head, &dev->mode_config.usermode_list);
spin_unlock(&dev->mode_config.config_lock);
new_mode.id = user_mode->mode_id;
if (copy_to_user(argp, &new_mode, sizeof(new_mode)))
return -EFAULT;
return 0;
}
/**
* drm_fb_rmmode - removes a user defined mode
* @inode: inode from the ioctl
* @filp: file * from the ioctl
* @cmd: cmd from ioctl
* @arg: arg from ioctl
*
* Remove the user defined mode specified by the user.
*
* Called by the user via ioctl
*
* RETURNS:
* Zero on success, errno on failure.
*/
int drm_mode_rmmode(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;
uint32_t id = arg;
struct drm_display_mode *mode, *t;
int retcode = -EINVAL;
mode = idr_find(&dev->mode_config.crtc_idr, id);
if (!mode || (id != mode->mode_id))
return -EINVAL;
if (!(mode->type & DRM_MODE_TYPE_USERDEF))
return -EINVAL;
if (mode->output_count)
return -EINVAL;
spin_lock(&dev->mode_config.config_lock);
list_for_each_entry(t, &dev->mode_config.usermode_list, head) {
if (t == mode) {
list_del(&mode->head);
drm_mode_destroy(dev, mode);
retcode = 0;
break;
}
}
spin_unlock(&dev->mode_config.config_lock);
return retcode;
}
/**
* drm_fb_attachmode - Attach a user mode to an output
* @inode: inode from the ioctl
* @filp: file * from the ioctl
* @cmd: cmd from ioctl
* @arg: arg from ioctl
*
* This attaches a user specified mode to an output.
* Called by the user via ioctl.
*
* RETURNS:
* Zero on success, errno on failure.
*/
int drm_mode_attachmode(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_mode_cmd __user *argp = (void __user *)arg;
struct drm_mode_mode_cmd mode_cmd;
struct drm_output *output;
struct drm_display_mode *mode;
int i;
if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd)))
return -EFAULT;
mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id);
if (!mode || (mode->mode_id != mode_cmd.mode_id))
return -EINVAL;
output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id);
if (!output || (output->id != mode_cmd.output_id))
return -EINVAL;
for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) {
if (output->user_mode_ids[i] == 0) {
output->user_mode_ids[i] = mode->mode_id;
mode->output_count++;
break;
}
}
if (i == DRM_OUTPUT_MAX_UMODES)
return -ENOSPC;
return 0;
}
/**
* drm_fb_detachmode - Detach a user specified mode from an output
* @inode: inode from the ioctl
* @filp: file * from the ioctl
* @cmd: cmd from ioctl
* @arg: arg from ioctl
*
* Called by the user via ioctl.
*
* RETURNS:
* Zero on success, errno on failure.
*/
int drm_mode_detachmode(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_mode_cmd __user *argp = (void __user *)arg;
struct drm_mode_mode_cmd mode_cmd;
struct drm_output *output;
struct drm_display_mode *mode;
int i, found = 0;
if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd)))
return -EFAULT;
mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id);
if (!mode || (mode->mode_id != mode_cmd.mode_id))
return -EINVAL;
output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id);
if (!output || (output->id != mode_cmd.output_id))
return -EINVAL;
for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) {
if (output->user_mode_ids[i] == mode->mode_id) {
output->user_mode_ids[i] = 0;
mode->output_count--;
found = 1;
}
}
if (!found)
return -EINVAL;
return 0;
}

View file

@ -87,6 +87,7 @@ struct drm_display_mode {
struct list_head head;
char name[DRM_DISPLAY_MODE_LEN];
int mode_id;
int output_count;
enum drm_mode_status status;
int type;
@ -293,8 +294,8 @@ struct drm_crtc_funcs {
void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode, int x, int y);
/* Set gamma on the CRTC */
void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
int size);
void (*gamma_set)(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
int regno);
/* Driver cleanup routine */
void (*cleanup)(struct drm_crtc *crtc);
};
@ -319,7 +320,7 @@ struct drm_crtc {
int id; /* idr assigned */
/* framebuffer the CRTC is currently bound to */
/* framebuffer the output is currently bound to */
struct drm_framebuffer *fb;
bool enabled;
@ -382,6 +383,7 @@ struct drm_output_funcs {
void (*cleanup)(struct drm_output *output);
};
#define DRM_OUTPUT_MAX_UMODES 16
#define DRM_OUTPUT_LEN 32
/**
* drm_output - central DRM output control structure
@ -417,6 +419,7 @@ struct drm_output {
bool doublescan_allowed;
spinlock_t modes_lock; /* protects modes and probed_modes lists */
struct list_head modes; /* list of modes on this output */
/*
OptionInfoPtr options;
XF86ConfMonitorPtr conf_monitor;
@ -434,7 +437,9 @@ struct drm_output {
char name[DRM_OUTPUT_LEN];
const struct drm_output_funcs *funcs;
void *driver_private;
/* RROutputPtr randr_output? */
u32 user_mode_ids[DRM_OUTPUT_MAX_UMODES];
};
/**
@ -467,6 +472,7 @@ struct drm_mode_config {
int num_crtc;
struct list_head crtc_list;
struct list_head usermode_list;
int min_width, min_height;
int max_width, max_height;
/* DamagePtr rotationDamage? */
@ -480,6 +486,7 @@ struct drm_output *drm_output_create(struct drm_device *dev,
const char *name);
extern void drm_output_destroy(struct drm_output *output);
extern bool drm_output_rename(struct drm_output *output, const char *name);
extern void drm_fb_release(struct file *filp);
extern int drm_add_edid_modes(struct drm_output *output,
struct i2c_adapter *adapter);
@ -492,6 +499,7 @@ extern void drm_mode_debug_printmodeline(struct drm_device *dev,
extern void drm_mode_config_init(struct drm_device *dev);
extern void drm_mode_config_cleanup(struct drm_device *dev);
extern void drm_mode_set_name(struct drm_display_mode *mode);
extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2);
extern void drm_disable_unused_functions(struct drm_device *dev);
extern struct drm_display_mode *drm_mode_create(struct drm_device *dev);
@ -507,12 +515,13 @@ extern void drm_mode_sort(struct list_head *mode_list);
extern int drm_mode_vrefresh(struct drm_display_mode *mode);
extern void drm_mode_set_crtcinfo(struct drm_display_mode *p,
int adjust_flags);
extern void drm_mode_output_list_update(struct drm_output *output);
extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev);
extern bool drm_initial_config(struct drm_device *dev, bool cangrow);
extern void drm_framebuffer_set_object(struct drm_device *dev,
unsigned long handle);
extern bool drm_set_desired_modes(struct drm_device *dev);
extern int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb);
extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
/* IOCTLs */
@ -531,5 +540,14 @@ extern int drm_mode_rmfb(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_mode_getfb(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_mode_addmode(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_mode_rmmode(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_mode_attachmode(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_mode_detachmode(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
#endif /* __DRM_CRTC_H__ */

View file

@ -130,6 +130,10 @@ static drm_ioctl_desc_t drm_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_MODE_ADDFB)] = {drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_RMFB)] = {drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_GETFB)] = {drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_ADDMODE)] = {drm_mode_addmode, DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_RMMODE)] = {drm_mode_rmmode, DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_ATTACHMODE)] = {drm_mode_attachmode, DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_DETACHMODE)] = {drm_mode_detachmode, DRM_MASTER|DRM_ROOT_ONLY},
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )

View file

@ -39,9 +39,11 @@
#include <linux/init.h>
#include "drmP.h"
#include "drm_crtc.h"
struct drmfb_par {
struct drm_device *dev;
struct drm_framebuffer *fb;
struct drm_crtc *crtc;
};
static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green,
@ -49,11 +51,20 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green,
struct fb_info *info)
{
struct drmfb_par *par = info->par;
struct drm_framebuffer *fb = par->fb;
if (regno > 17)
struct drm_framebuffer *fb = par->crtc->fb;
struct drm_crtc *crtc = par->crtc;
if (regno > 255)
return 1;
if (regno < 16) {
if (fb->depth == 8) {
if (crtc->funcs->gamma_set) {
crtc->funcs->gamma_set(crtc, red, green, blue, regno);
}
return 0;
}
if (regno < 16) {
switch (fb->depth) {
case 15:
fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
@ -72,8 +83,119 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green,
((blue & 0xff00) >> 8);
break;
}
}
return 0;
}
static int drmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct drmfb_par *par = info->par;
struct drm_device *dev = par->dev;
struct drm_framebuffer *fb = par->crtc->fb;
struct drm_display_mode *drm_mode;
struct drm_output *output;
int depth;
if (!var->pixclock)
return -EINVAL;
/* Need to resize the fb object !!! */
if (var->xres > fb->width || var->yres > fb->height) {
DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height);
DRM_ERROR("Need resizing code.\n");
return -EINVAL;
}
switch (var->bits_per_pixel) {
case 16:
depth = (var->green.length == 6) ? 16 : 15;
break;
case 32:
depth = (var->transp.length > 0) ? 32 : 24;
break;
default:
depth = var->bits_per_pixel;
break;
}
switch (depth) {
case 8:
var->red.offset = 0;
var->green.offset = 0;
var->blue.offset = 0;
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
var->transp.length = 0;
var->transp.offset = 0;
break;
case 15:
var->red.offset = 10;
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 5;
var->blue.length = 5;
var->transp.length = 1;
var->transp.offset = 15;
break;
case 16:
var->red.offset = 11;
var->green.offset = 6;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 6;
var->blue.length = 5;
var->transp.length = 0;
var->transp.offset = 0;
break;
case 24:
var->red.offset = 16;
var->green.offset = 8;
var->blue.offset = 0;
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
var->transp.length = 0;
var->transp.offset = 0;
break;
case 32:
var->red.offset = 16;
var->green.offset = 8;
var->blue.offset = 0;
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
var->transp.length = 8;
var->transp.offset = 24;
break;
default:
return -EINVAL;
}
#if 0
/* Here we walk the output mode list and look for modes. If we haven't
* got it, then bail. Not very nice, so this is disabled.
* In the set_par code, we create our mode based on the incoming
* parameters. Nicer, but may not be desired by some.
*/
list_for_each_entry(output, &dev->mode_config.output_list, head) {
if (output->crtc == par->crtc)
break;
}
list_for_each_entry(drm_mode, &output->modes, head) {
if (drm_mode->hdisplay == var->xres &&
drm_mode->vdisplay == var->yres &&
drm_mode->clock != 0)
break;
}
if (!drm_mode)
return -EINVAL;
#endif
return 0;
}
@ -81,9 +203,74 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green,
static int drmfb_set_par(struct fb_info *info)
{
struct drmfb_par *par = info->par;
struct drm_framebuffer *fb = par->crtc->fb;
struct drm_device *dev = par->dev;
struct drm_display_mode *drm_mode;
struct fb_var_screeninfo *var = &info->var;
struct drm_output *output;
switch (var->bits_per_pixel) {
case 16:
fb->depth = (var->green.length == 6) ? 16 : 15;
break;
case 32:
fb->depth = (var->transp.length > 0) ? 32 : 24;
break;
default:
fb->depth = var->bits_per_pixel;
break;
}
fb->bits_per_pixel = var->bits_per_pixel;
info->fix.line_length = fb->pitch;
info->fix.smem_len = info->fix.line_length * fb->height;
info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
info->screen_size = info->fix.smem_len; /* ??? */
/* Should we walk the output's modelist or just create our own ???
* For now, we create and destroy a mode based on the incoming
* parameters. But there's commented out code below which scans
* the output list too.
*/
#if 0
list_for_each_entry(output, &dev->mode_config.output_list, head) {
if (output->crtc == par->crtc)
break;
}
list_for_each_entry(drm_mode, &output->modes, head) {
if (drm_mode->hdisplay == var->xres &&
drm_mode->vdisplay == var->yres &&
drm_mode->clock != 0)
break;
}
#else
drm_mode = drm_mode_create(dev);
drm_mode->hdisplay = var->xres;
drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
drm_mode->vdisplay = var->yres;
drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
drm_mode->clock = PICOS2KHZ(var->pixclock);
drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
drm_mode_set_name(drm_mode);
#endif
if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0))
return -EINVAL;
/* Have to destroy our created mode if we're not searching the mode
* list for it.
*/
#if 1
drm_mode_destroy(dev, drm_mode);
#endif
drm_set_desired_modes(dev);
return 0;
}
@ -94,6 +281,7 @@ static struct fb_ops drmfb_ops = {
// .fb_write = drmfb_write,
// .fb_release = drmfb_release,
// .fb_ioctl = drmfb_ioctl,
.fb_check_var = drmfb_check_var,
.fb_set_par = drmfb_set_par,
.fb_setcolreg = drmfb_setcolreg,
.fb_fillrect = cfb_fillrect,
@ -101,11 +289,13 @@ static struct fb_ops drmfb_ops = {
.fb_imageblit = cfb_imageblit,
};
int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
{
struct fb_info *info;
struct drm_framebuffer *fb = crtc->fb;
struct drmfb_par *par;
struct device *device = &dev->pdev->dev;
struct drm_display_mode *mode = crtc->desired_mode;
int ret;
info = framebuffer_alloc(sizeof(struct drmfb_par), device);
@ -118,20 +308,20 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
par = info->par;
par->dev = dev;
par->fb = fb;
par->crtc = crtc;
info->fbops = &drmfb_ops;
strcpy(info->fix.id, "drmfb");
info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
info->fix.smem_len = fb->bo->mem.size;
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_DIRECTCOLOR;
info->fix.visual = FB_VISUAL_TRUECOLOR;
info->fix.accel = FB_ACCEL_NONE;
info->fix.type_aux = 0;
info->fix.mmio_start = 0;
info->fix.mmio_len = 0;
info->fix.line_length = fb->pitch * ((fb->bits_per_pixel + 1) / 8);
info->fix.line_length = fb->pitch;
info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
info->fix.smem_len = info->fix.line_length * fb->height;
info->flags = FBINFO_DEFAULT;
@ -140,11 +330,9 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
DRM_ERROR("error mapping fb: %d\n", ret);
info->screen_base = fb->virtual_base;
info->screen_size = fb->bo->mem.size;
info->screen_size = info->fix.smem_len; /* ??? */
info->pseudo_palette = fb->pseudo_palette;
info->var.xres = fb->width;
info->var.xres_virtual = fb->pitch;
info->var.yres = fb->height;
info->var.xres_virtual = fb->width;
info->var.yres_virtual = fb->height;
info->var.bits_per_pixel = fb->bits_per_pixel;
info->var.xoffset = 0;
@ -154,24 +342,69 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
info->var.width = -1;
info->var.vmode = FB_VMODE_NONINTERLACED;
info->var.xres = mode->hdisplay;
info->var.right_margin = mode->hsync_start - mode->hdisplay;
info->var.hsync_len = mode->hsync_end - mode->hsync_start;
info->var.left_margin = mode->htotal - mode->hsync_end;
info->var.yres = mode->vdisplay;
info->var.lower_margin = mode->vsync_start - mode->vdisplay;
info->var.vsync_len = mode->vsync_end - mode->vsync_start;
info->var.upper_margin = mode->vtotal - mode->vsync_end;
info->var.pixclock = 10000000 / mode->htotal * 1000 /
mode->vtotal * 100;
/* avoid overflow */
info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
DRM_DEBUG("fb depth is %d\n", fb->depth);
switch(fb->depth) {
case 8:
case 15:
case 16:
info->var.red.offset = 0;
info->var.green.offset = 0;
info->var.blue.offset = 0;
info->var.red.length = 8; /* 8bit DAC */
info->var.green.length = 8;
info->var.blue.length = 8;
info->var.transp.offset = 0;
info->var.transp.length = 0;
break;
case 15:
info->var.red.offset = 10;
info->var.green.offset = 5;
info->var.blue.offset = 0;
info->var.red.length = info->var.green.length =
info->var.blue.length = 5;
info->var.transp.offset = 15;
info->var.transp.length = 1;
break;
case 16:
info->var.red.offset = 11;
info->var.green.offset = 5;
info->var.blue.offset = 0;
info->var.red.length = 5;
info->var.green.length = 6;
info->var.blue.length = 5;
info->var.transp.offset = 0;
info->var.transp.length = 0;
break;
default:
case 24:
info->var.red.offset = 16;
info->var.green.offset = 8;
info->var.blue.offset = 0;
info->var.red.length = info->var.green.length =
info->var.blue.length = 8;
info->var.transp.offset = 0;
info->var.transp.length = 0;
break;
case 32:
info->var.red.offset = 16;
info->var.green.offset = 8;
info->var.blue.offset = 0;
info->var.red.length = info->var.green.length =
info->var.blue.length = 8;
if (fb->depth == 32) {
info->var.transp.offset = 24;
info->var.transp.length = 8;
}
info->var.transp.offset = 24;
info->var.transp.length = 8;
break;
default:
break;
}

View file

@ -533,7 +533,7 @@ void drm_mode_sort(struct list_head *mode_list)
*/
void drm_mode_output_list_update(struct drm_output *output)
{
struct drm_display_mode *mode, *t;
struct drm_display_mode *mode;
struct drm_display_mode *pmode, *pt;
int found_it;
list_for_each_entry_safe(pmode, pt, &output->probed_modes,

View file

@ -459,6 +459,7 @@ extern int drm_bo_mem_space(drm_buffer_object_t * bo,
drm_bo_mem_reg_t * mem, int no_wait);
extern int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_mem_flags,
int no_wait, int move_unfenced);
extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type);
/*
* Buffer object memory move helpers.

View file

@ -787,6 +787,9 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
else
dpll |= PLL_REF_INPUT_DREFCLK;
/* setup pipeconf */
pipeconf = I915_READ(pipeconf_reg);
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;
@ -814,7 +817,6 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
else
dspcntr |= DISPPLANE_SEL_PIPE_B;
pipeconf = I915_READ(pipeconf_reg);
if (pipe == 0 && !IS_I965G(dev)) {
/* Enable pixel doubling when the dot clock is > 90% of the (display)
* core speed.
@ -955,19 +957,14 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
}
/** Sets the color ramps on behalf of RandR */
static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, int size)
static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno)
{
struct intel_crtc *intel_crtc = crtc->driver_private;
int i;
for (i = 0; i < 256; i++) {
intel_crtc->lut_r[i] = red[i] >> 8;
intel_crtc->lut_g[i] = green[i] >> 8;
intel_crtc->lut_b[i] = blue[i] >> 8;
}
intel_crtc_load_lut(crtc);
intel_crtc->lut_r[regno] = red >> 8;
intel_crtc->lut_g[regno] = green >> 8;
intel_crtc->lut_b[regno] = blue >> 8;
}
/* Returns the clock of the currently programmed mode of the given pipe. */
@ -1176,7 +1173,8 @@ static void intel_setup_outputs(drm_device_t *dev)
(1 << INTEL_OUTPUT_SDVO));
break;
case INTEL_OUTPUT_ANALOG:
crtc_mask = ((1 << 0));
crtc_mask = ((1 << 0)|
(1 << 1));
clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
(1 << INTEL_OUTPUT_DVO) |
(1 << INTEL_OUTPUT_SDVO));
@ -1223,7 +1221,6 @@ void intel_modeset_init(drm_device_t *dev)
intel_setup_outputs(dev);
//drm_initial_config(dev, false);
//drm_set_desired_modes(dev);
}
void intel_modeset_cleanup(drm_device_t *dev)

View file

@ -72,7 +72,7 @@ extern void intel_crtc_load_lut(struct drm_crtc *crtc);
extern void intel_output_prepare (struct drm_output *output);
extern void intel_output_commit (struct drm_output *output);
extern struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev,
struct drm_crtc *crtc);
struct drm_crtc *crtc);
extern void intel_wait_for_vblank(drm_device_t *dev);
extern struct drm_crtc *intel_get_crtc_from_pipe(drm_device_t *dev, int pipe);

View file

@ -40,12 +40,13 @@
#include "drmP.h"
#include "drm.h"
#include "drm_crtc.h"
#include "i915_drm.h"
#include "i915_drv.h"
struct intelfb_par {
struct drm_device *dev;
struct drm_framebuffer *fb;
struct drm_crtc *crtc;
};
static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
@ -53,10 +54,18 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
struct fb_info *info)
{
struct intelfb_par *par = info->par;
struct drm_framebuffer *fb = par->fb;
if (regno > 17)
struct drm_framebuffer *fb = par->crtc->fb;
struct drm_crtc *crtc = par->crtc;
if (regno > 255)
return 1;
if (fb->depth == 8) {
if (crtc->funcs->gamma_set)
crtc->funcs->gamma_set(crtc, red, green, blue, regno);
return 0;
}
if (regno < 16) {
switch (fb->depth) {
case 15:
@ -81,16 +90,194 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 0;
}
static int intelfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct intelfb_par *par = info->par;
struct drm_device *dev = par->dev;
struct drm_framebuffer *fb = par->crtc->fb;
struct drm_display_mode *drm_mode;
struct drm_output *output;
int depth;
if (!var->pixclock)
return -EINVAL;
/* Need to resize the fb object !!! */
if (var->xres > fb->width || var->yres > fb->height) {
DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height);
DRM_ERROR("Need resizing code.\n");
return -EINVAL;
}
switch (var->bits_per_pixel) {
case 16:
depth = (var->green.length == 6) ? 16 : 15;
break;
case 32:
depth = (var->transp.length > 0) ? 32 : 24;
break;
default:
depth = var->bits_per_pixel;
break;
}
switch (depth) {
case 8:
var->red.offset = 0;
var->green.offset = 0;
var->blue.offset = 0;
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
var->transp.length = 0;
var->transp.offset = 0;
break;
case 15:
var->red.offset = 10;
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 5;
var->blue.length = 5;
var->transp.length = 1;
var->transp.offset = 15;
break;
case 16:
var->red.offset = 11;
var->green.offset = 6;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 6;
var->blue.length = 5;
var->transp.length = 0;
var->transp.offset = 0;
break;
case 24:
var->red.offset = 16;
var->green.offset = 8;
var->blue.offset = 0;
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
var->transp.length = 0;
var->transp.offset = 0;
break;
case 32:
var->red.offset = 16;
var->green.offset = 8;
var->blue.offset = 0;
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
var->transp.length = 8;
var->transp.offset = 24;
break;
default:
return -EINVAL;
}
#if 0
/* Here we walk the output mode list and look for modes. If we haven't
* got it, then bail. Not very nice, so this is disabled.
* In the set_par code, we create our mode based on the incoming
* parameters. Nicer, but may not be desired by some.
*/
list_for_each_entry(output, &dev->mode_config.output_list, head) {
if (output->crtc == par->crtc)
break;
}
list_for_each_entry(drm_mode, &output->modes, head) {
if (drm_mode->hdisplay == var->xres &&
drm_mode->vdisplay == var->yres &&
drm_mode->clock != 0)
break;
}
if (!drm_mode)
return -EINVAL;
#endif
return 0;
}
/* this will let fbcon do the mode init */
static int intelfb_set_par(struct fb_info *info)
{
struct intelfb_par *par = info->par;
struct drm_framebuffer *fb = par->crtc->fb;
struct drm_device *dev = par->dev;
struct drm_display_mode *drm_mode;
struct fb_var_screeninfo *var = &info->var;
struct drm_output *output;
switch (var->bits_per_pixel) {
case 16:
fb->depth = (var->green.length == 6) ? 16 : 15;
break;
case 32:
fb->depth = (var->transp.length > 0) ? 32 : 24;
break;
default:
fb->depth = var->bits_per_pixel;
break;
}
fb->bits_per_pixel = var->bits_per_pixel;
info->fix.line_length = fb->pitch;
info->fix.smem_len = info->fix.line_length * fb->height;
info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
info->screen_size = info->fix.smem_len; /* ??? */
/* Should we walk the output's modelist or just create our own ???
* For now, we create and destroy a mode based on the incoming
* parameters. But there's commented out code below which scans
* the output list too.
*/
#if 0
list_for_each_entry(output, &dev->mode_config.output_list, head) {
if (output->crtc == par->crtc)
break;
}
list_for_each_entry(drm_mode, &output->modes, head) {
if (drm_mode->hdisplay == var->xres &&
drm_mode->vdisplay == var->yres &&
drm_mode->clock != 0)
break;
}
#else
drm_mode = drm_mode_create(dev);
drm_mode->hdisplay = var->xres;
drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
drm_mode->vdisplay = var->yres;
drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
drm_mode->clock = PICOS2KHZ(var->pixclock);
drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
drm_mode_set_name(drm_mode);
#endif
if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0))
return -EINVAL;
/* Have to destroy our created mode if we're not searching the mode
* list for it.
*/
#if 1
drm_mode_destroy(dev, drm_mode);
#endif
drm_set_desired_modes(dev);
return 0;
}
#if 0
static void intelfb_copyarea(struct fb_info *info,
const struct fb_copyarea *region)
{
@ -234,6 +421,7 @@ void intelfb_imageblit(struct fb_info *info, const struct fb_image *image)
OUT_RING(MI_NOOP);
ADVANCE_LP_RING();
}
#endif
static struct fb_ops intelfb_ops = {
.owner = THIS_MODULE,
@ -242,18 +430,21 @@ static struct fb_ops intelfb_ops = {
// .fb_write = intelfb_write,
// .fb_release = intelfb_release,
// .fb_ioctl = intelfb_ioctl,
.fb_check_var = intelfb_check_var,
.fb_set_par = intelfb_set_par,
.fb_setcolreg = intelfb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea, //intelfb_copyarea,
.fb_imageblit = intelfb_imageblit,
.fb_imageblit = cfb_imageblit, //intelfb_imageblit,
};
int intelfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
{
struct fb_info *info;
struct intelfb_par *par;
struct device *device = &dev->pdev->dev;
struct drm_framebuffer *fb = crtc->fb;
struct drm_display_mode *mode = crtc->desired_mode;
int ret;
info = framebuffer_alloc(sizeof(struct intelfb_par), device);
@ -266,24 +457,24 @@ int intelfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
par = info->par;
par->dev = dev;
par->fb = fb;
par->crtc = crtc;
info->fbops = &intelfb_ops;
strcpy(info->fix.id, "intelfb");
info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
info->fix.smem_len = fb->bo->mem.size;
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_TRUECOLOR;
info->fix.type_aux = 0;
info->fix.xpanstep = 8;
info->fix.ypanstep = 1;
info->fix.ywrapstep = 0;
info->fix.visual = FB_VISUAL_DIRECTCOLOR;
info->fix.accel = FB_ACCEL_I830;
info->fix.type_aux = 0;
info->fix.mmio_start = 0;
info->fix.mmio_len = 0;
info->fix.line_length = fb->pitch;
info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
info->fix.smem_len = info->fix.line_length * fb->height;
info->flags = FBINFO_DEFAULT;
@ -292,11 +483,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
DRM_ERROR("error mapping fb: %d\n", ret);
info->screen_base = fb->virtual_base;
info->screen_size = fb->bo->mem.size;
info->screen_size = info->fix.smem_len; /* FIXME */
info->pseudo_palette = fb->pseudo_palette;
info->var.xres = fb->width;
info->var.xres_virtual = fb->width;
info->var.yres = fb->height;
info->var.yres_virtual = fb->height;
info->var.bits_per_pixel = fb->bits_per_pixel;
info->var.xoffset = 0;
@ -306,6 +495,17 @@ int intelfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
info->var.width = -1;
info->var.vmode = FB_VMODE_NONINTERLACED;
info->var.xres = mode->hdisplay;
info->var.right_margin = mode->hsync_start - mode->hdisplay;
info->var.hsync_len = mode->hsync_end - mode->hsync_start;
info->var.left_margin = mode->htotal - mode->hsync_end;
info->var.yres = mode->vdisplay;
info->var.lower_margin = mode->vsync_start - mode->vdisplay;
info->var.vsync_len = mode->vsync_end - mode->vsync_start;
info->var.upper_margin = mode->vtotal - mode->vsync_end;
info->var.pixclock = 10000000 / mode->htotal * 1000 /
mode->vtotal * 100000 / mode->vrefresh;
info->pixmap.size = 64*1024;
info->pixmap.buf_align = 8;
info->pixmap.access_align = 32;
@ -316,21 +516,52 @@ int intelfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
DRM_DEBUG(" pitch is %d\n", fb->pitch);
switch(fb->depth) {
case 8:
case 15:
info->var.red.offset = 0;
info->var.green.offset = 0;
info->var.blue.offset = 0;
info->var.red.length = 8; /* 8bit DAC */
info->var.green.length = 8;
info->var.blue.length = 8;
info->var.transp.offset = 0;
info->var.transp.length = 0;
break;
case 15:
info->var.red.offset = 10;
info->var.green.offset = 5;
info->var.blue.offset = 0;
info->var.red.length = info->var.green.length =
info->var.blue.length = 5;
info->var.transp.offset = 15;
info->var.transp.length = 1;
break;
case 16:
break;
default:
info->var.red.offset = 11;
info->var.green.offset = 5;
info->var.blue.offset = 0;
info->var.red.length = 5;
info->var.green.length = 6;
info->var.blue.length = 5;
info->var.transp.offset = 0;
break;
case 24:
info->var.red.offset = 16;
info->var.green.offset = 8;
info->var.blue.offset = 0;
info->var.red.length = info->var.green.length =
info->var.blue.length = 8;
info->var.transp.offset = 0;
info->var.transp.length = 0;
break;
case 32:
info->var.red.offset = 16;
info->var.green.offset = 8;
info->var.blue.offset = 0;
info->var.red.length = info->var.green.length =
info->var.blue.length = 8;
if (fb->depth == 32) {
info->var.transp.offset = 24;
info->var.transp.length = 8;
}
info->var.transp.offset = 24;
info->var.transp.length = 8;
break;
default:
break;
}
@ -343,8 +574,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
}
EXPORT_SYMBOL(intelfb_probe);
int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc)
{
struct drm_framebuffer *fb = crtc->fb;
struct fb_info *info = fb->fbdev;
if (info) {

View file

@ -164,6 +164,13 @@ static bool intel_lvds_mode_fixup(struct drm_output *output,
struct intel_crtc *intel_crtc = output->crtc->driver_private;
struct drm_output *tmp_output;
/* Should never happen!! */
if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
printk(KERN_ERR "Can't support LVDS on pipe A\n");
return false;
}
/* Should never happen!! */
list_for_each_entry(tmp_output, &dev->mode_config.output_list, head) {
if (tmp_output != output && tmp_output->crtc == output->crtc) {
printk(KERN_ERR "Can't enable LVDS and another "
@ -172,11 +179,6 @@ static bool intel_lvds_mode_fixup(struct drm_output *output,
}
}
if (intel_crtc->pipe == 0) {
printk(KERN_ERR "Can't support LVDS on pipe A\n");
return false;
}
/*
* If we have timings from the BIOS for the panel, put them in
* to the adjusted mode. The CRTC will be set up for this mode,

View file

@ -525,7 +525,6 @@ static bool intel_sdvo_get_preferred_input_timing(struct drm_output *output,
static int intel_sdvo_get_clock_rate_mult(struct drm_output *output)
{
struct intel_output *intel_output = output->driver_private;
u8 response, status;
intel_sdvo_write_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0);
@ -895,8 +894,6 @@ static enum drm_output_status intel_sdvo_detect(struct drm_output *output)
static int intel_sdvo_get_modes(struct drm_output *output)
{
struct drm_display_mode *modes;
/* set the bus switch and get the modes */
intel_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2);
intel_ddc_get_modes(output);
@ -1013,26 +1010,18 @@ void intel_sdvo_init(drm_device_t *dev, int output_device)
memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs));
/* TODO, CVBS, SVID, YPRPB & SCART outputs.
* drm_initial_config probably wants tweaking too to support the
* above. But has fixed VGA, TMDS and LVDS checking code. That should
* be dealt with.
*/
/* TODO, CVBS, SVID, YPRPB & SCART outputs. */
if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
{
sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0;
output->subpixel_order = SubPixelHorizontalRGB;
/* drm_initial_config wants this name, but should be RGB */
/* Use this for now.... */
name_prefix="VGA";
name_prefix="RGB";
}
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
{
sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1;
output->subpixel_order = SubPixelHorizontalRGB;
/* drm_initial_config wants this name, but should be RGB */
/* Use this for now.... */
name_prefix="VGA";
name_prefix="RGB";
}
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
{

View file

@ -978,6 +978,11 @@ struct drm_mode_fb_cmd {
unsigned int depth;
};
struct drm_mode_mode_cmd {
unsigned int output_id;
unsigned int mode_id;
};
/**
* \name Ioctls Definitions
*/
@ -1055,7 +1060,12 @@ struct drm_mode_fb_cmd {
#define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA3, struct drm_mode_crtc)
#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xA4, struct drm_mode_fb_cmd)
#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int)
#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd)
#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd)
#define DRM_IOCTL_MODE_ADDMODE DRM_IOWR(0xA7, struct drm_mode_modeinfo)
#define DRM_IOCTL_MODE_RMMODE DRM_IOWR(0xA8, unsigned int)
#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd)
#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd)
/*@}*/
/**

View file

@ -221,6 +221,7 @@ extern void i915_emit_breadcrumb(drm_device_t *dev);
extern void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync);
extern int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush);
extern int i915_driver_firstopen(struct drm_device *dev);
extern int i915_dma_cleanup(drm_device_t * dev);
/* i915_irq.c */
extern int i915_irq_emit(DRM_IOCTL_ARGS);

View file

@ -202,7 +202,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags)
/* FIXME: need wrapper with PCI mem checks */
ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem,
&dev_priv->ring.virtual_start);
(void **) &dev_priv->ring.virtual_start);
if (ret)
DRM_ERROR("error mapping ring buffer: %d\n", ret);
@ -272,7 +272,7 @@ int i915_driver_unload(drm_device_t *dev)
drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem,
dev_priv->ring.virtual_start);
DRM_DEBUG("usage is %d\n", dev_priv->ring_buffer->usage);
DRM_DEBUG("usage is %d\n", atomic_read(&dev_priv->ring_buffer->usage));
mutex_lock(&dev->struct_mutex);
drm_bo_usage_deref_locked(dev_priv->ring_buffer);
mutex_unlock(&dev->struct_mutex);