Merge branch 'modesetting-101' of git+ssh://git.freedesktop.org/git/mesa/drm into...
authorJesse Barnes <jbarnes@hobbes.virtuousgeek.org>
Thu, 17 May 2007 17:35:07 +0000 (10:35 -0700)
committerJesse Barnes <jbarnes@hobbes.virtuousgeek.org>
Thu, 17 May 2007 17:35:07 +0000 (10:35 -0700)
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

1  2 
linux-core/drmP.h
linux-core/drm_crtc.c
linux-core/drm_fb.c
linux-core/drm_objects.h
linux-core/intel_display.c
linux-core/intel_drv.h
linux-core/intel_fb.c
shared-core/i915_drv.h
shared-core/i915_init.c

@@@ -661,10 -661,6 +661,10 @@@ struct drm_driver 
        unsigned long (*get_reg_ofs) (struct drm_device * dev);
        void (*set_version) (struct drm_device * dev, drm_set_version_t * sv);
  
-       int (*fb_probe)(struct drm_device *dev, struct drm_framebuffer *fb);
-       int (*fb_remove)(struct drm_device *dev, struct drm_framebuffer *fb);
 +      /* FB routines, if present */
++      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;
  
@@@ -87,6 -87,6 +87,31 @@@ void drm_idr_put(struct drm_device *dev
  }
  
  /**
++ * 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
   *
@@@ -465,51 -465,6 +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 -670,6 +696,7 @@@ struct drm_display_mode *drm_mode_creat
        nmode->mode_id = drm_idr_get(dev, nmode);
        return nmode;
  }
++EXPORT_SYMBOL(drm_mode_create);
  
  /**
   * drm_mode_destroy - remove a mode
@@@ -732,6 -687,6 +714,7 @@@ void drm_mode_destroy(struct drm_devic
  
        kfree(mode);
  }
++EXPORT_SYMBOL(drm_mode_destroy);
  
  /**
   * drm_mode_config_init - initialize DRM mode_configuration structure
@@@ -844,94 -865,50 +893,57 @@@ bool drm_initial_config(drm_device_t *d
        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) {
 +              if (des_mode->hdisplay > fb->width)
                        fb->width = des_mode->hdisplay;
 -                      fb->pitch = fb->width;
 -              }
                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->pitch * fb->height * bytes_per_pixel;
++              size = fb->width * fb->height * bytes_per_pixel;
+               /* FIXME - what about resizeable objects ??? */
 -              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);
 -              printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width,
 -                        fb->height, fbo->offset, fbo);
++              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;
 -              drmfb_probe(dev, output->crtc);
++              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;
  }
@@@ -962,8 -940,12 +975,12 @@@ void drm_mode_config_cleanup(drm_device
                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);
 -              drmfb_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);
@@@ -1522,12 -1566,11 +1601,11 @@@ int drm_mode_addfb(struct inode *inode
                struct drm_crtc *crtc;
                list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                        crtc->fb = fb;
 -                      drmfb_probe(dev, crtc);
+                       
++                      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 -1606,8 +1641,8 @@@ int drm_mode_rmfb(struct inode *inode, 
                return -EINVAL;
        }
  
-       dev->driver->fb_remove(dev, fb);
 -      drmfb_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 -1688,199 +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);
 -              drmfb_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;
+ }
@@@ -81,9 -203,74 +203,74 @@@ static int drmfb_check_var(struct fb_va
  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;
 -      info->fix.line_length = fb->pitch * ((fb->bits_per_pixel + 1) / 8);
+       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;
  }
  
@@@ -131,7 -319,9 +319,9 @@@ int drmfb_probe(struct drm_device *dev
        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;
  
                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;
@@@ -459,6 -459,6 +459,7 @@@ extern int drm_bo_mem_space(drm_buffer_
                            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.
Simple merge
Simple merge
index 267b4fd,0000000..7126c16
mode 100644,000000..100644
--- /dev/null
@@@ -1,358 -1,0 +1,590 @@@
-       struct drm_framebuffer *fb;
 +/*
 + * Copyright Â© 2007 David Airlie
 + *
 + * 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 (including the next
 + * paragraph) 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.
 + *
 + * Authors:
 + *     David Airlie
 + */
 +    /*
 +     *  Modularization
 +     */
 +
 +#include <linux/module.h>
 +#include <linux/kernel.h>
 +#include <linux/errno.h>
 +#include <linux/string.h>
 +#include <linux/mm.h>
 +#include <linux/tty.h>
 +#include <linux/slab.h>
 +#include <linux/delay.h>
 +#include <linux/fb.h>
 +#include <linux/init.h>
 +
 +#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 = par->fb;
-       if (regno > 17)
++      struct drm_crtc *crtc;
 +};
 +
 +static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
 +                         unsigned blue, unsigned transp,
 +                         struct fb_info *info)
 +{
 +      struct intelfb_par *par = info->par;
-       drm_set_desired_modes(dev);
++      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:
 +                      fb->pseudo_palette[regno] = ((red & 0xf800) >>  1) |
 +                              ((green & 0xf800) >>  6) |
 +                              ((blue & 0xf800) >> 11);
 +                      break;
 +              case 16:
 +                      fb->pseudo_palette[regno] = (red & 0xf800) |
 +                              ((green & 0xfc00) >>  5) |
 +                              ((blue  & 0xf800) >> 11);
 +                      break;
 +              case 24:
 +              case 32:
 +                      fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
 +                              (green & 0xff00) |
 +                              ((blue  & 0xff00) >> 8);
 +                      break;
 +              }
 +      }
 +
 +      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
 +
-       .fb_imageblit = intelfb_imageblit,
 +      return 0;
 +}
 +
++#if 0
 +static void intelfb_copyarea(struct fb_info *info,
 +                           const struct fb_copyarea *region)
 +{
 +        struct intelfb_par *par = info->par;
 +      struct drm_device *dev = par->dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      u32 src_x1, src_y1, dst_x1, dst_y1, dst_x2, dst_y2, offset;
 +      u32 cmd, rop_depth_pitch, src_pitch;
 +      RING_LOCALS;
 +
 +      cmd = XY_SRC_COPY_BLT_CMD;
 +      src_x1 = region->sx;
 +      src_y1 = region->sy;
 +      dst_x1 = region->dx;
 +      dst_y1 = region->dy;
 +      dst_x2 = region->dx + region->width;
 +      dst_y2 = region->dy + region->height;
 +      offset = par->fb->offset;
 +      rop_depth_pitch = BLT_ROP_GXCOPY | par->fb->pitch;
 +      src_pitch = par->fb->pitch;
 +
 +      switch (par->fb->bits_per_pixel) {
 +      case 16:
 +              rop_depth_pitch |= BLT_DEPTH_16_565;
 +              break;
 +      case 32:
 +              rop_depth_pitch |= BLT_DEPTH_32;
 +              cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
 +              break;
 +      }
 +
 +      BEGIN_LP_RING(8);
 +      OUT_RING(cmd);
 +      OUT_RING(rop_depth_pitch);
 +      OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff));
 +      OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff));
 +      OUT_RING(offset);
 +      OUT_RING((src_y1 << 16) | (src_x1 & 0xffff));
 +      OUT_RING(src_pitch);
 +      OUT_RING(offset);
 +      ADVANCE_LP_RING();
 +}
 +
 +#define ROUND_UP_TO(x, y)     (((x) + (y) - 1) / (y) * (y))
 +#define ROUND_DOWN_TO(x, y)   ((x) / (y) * (y))
 +
 +void intelfb_imageblit(struct fb_info *info, const struct fb_image *image)
 +{
 +        struct intelfb_par *par = info->par;
 +      struct drm_device *dev = par->dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      u32 cmd, rop_pitch_depth, tmp;
 +      int nbytes, ndwords, pad;
 +      u32 dst_x1, dst_y1, dst_x2, dst_y2, offset, bg, fg;
 +      int dat, ix, iy, iw;
 +      int i, j;
 +      RING_LOCALS;
 +
 +      /* size in bytes of a padded scanline */
 +      nbytes = ROUND_UP_TO(image->width, 16) / 8;
 +
 +      /* Total bytes of padded scanline data to write out. */
 +      nbytes *= image->height;
 +
 +      /*
 +       * Check if the glyph data exceeds the immediate mode limit.
 +       * It would take a large font (1K pixels) to hit this limit.
 +       */
 +      if (nbytes > 128 || image->depth != 1)
 +              return cfb_imageblit(info, image);
 +
 +      /* Src data is packaged a dword (32-bit) at a time. */
 +      ndwords = ROUND_UP_TO(nbytes, 4) / 4;
 +
 +      /*
 +       * Ring has to be padded to a quad word. But because the command starts
 +         with 7 bytes, pad only if there is an even number of ndwords
 +       */
 +      pad = !(ndwords % 2);
 +
 +      DRM_DEBUG("imageblit %dx%dx%d to (%d,%d)\n", image->width,
 +                image->height, image->depth, image->dx, image->dy);
 +      DRM_DEBUG("nbytes: %d, ndwords: %d, pad: %d\n", nbytes, ndwords, pad);
 +
 +      tmp = (XY_MONO_SRC_COPY_IMM_BLT & 0xff) + ndwords;
 +      cmd = (XY_MONO_SRC_COPY_IMM_BLT & ~0xff) | tmp;
 +      offset = par->fb->offset;
 +      dst_x1 = image->dx;
 +      dst_y1 = image->dy;
 +      dst_x2 = image->dx + image->width;
 +      dst_y2 = image->dy + image->height;
 +      rop_pitch_depth = BLT_ROP_GXCOPY | par->fb->pitch;
 +
 +      switch (par->fb->bits_per_pixel) {
 +      case 8:
 +              rop_pitch_depth |= BLT_DEPTH_8;
 +              fg = image->fg_color;
 +              bg = image->bg_color;
 +              break;
 +      case 16:
 +              rop_pitch_depth |= BLT_DEPTH_16_565;
 +              fg = par->fb->pseudo_palette[image->fg_color];
 +              bg = par->fb->pseudo_palette[image->bg_color];
 +              break;
 +      case 32:
 +              rop_pitch_depth |= BLT_DEPTH_32;
 +              cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
 +              fg = par->fb->pseudo_palette[image->fg_color];
 +              bg = par->fb->pseudo_palette[image->bg_color];
 +              break;
 +      default:
 +              DRM_ERROR("unknown depth %d\n", par->fb->bits_per_pixel);
 +              break;
 +      }
 +      
 +      BEGIN_LP_RING(8 + ndwords);
 +      OUT_RING(cmd);
 +      OUT_RING(rop_pitch_depth);
 +      OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff));
 +      OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff));
 +      OUT_RING(offset);
 +      OUT_RING(bg);
 +      OUT_RING(fg);
 +      ix = iy = 0;
 +      iw = ROUND_UP_TO(image->width, 8) / 8;
 +      while (ndwords--) {
 +              dat = 0;
 +              for (j = 0; j < 2; ++j) {
 +                      for (i = 0; i < 2; ++i) {
 +                              if (ix != iw || i == 0)
 +                                      dat |= image->data[iy*iw + ix++] << (i+j*2)*8;
 +                      }
 +                      if (ix == iw && iy != (image->height - 1)) {
 +                              ix = 0;
 +                              ++iy;
 +                      }
 +              }
 +              OUT_RING(dat);
 +      }
 +      if (pad)
 +              OUT_RING(MI_NOOP);
 +      ADVANCE_LP_RING();
 +}
++#endif
 +
 +static struct fb_ops intelfb_ops = {
 +      .owner = THIS_MODULE,
 +      //      .fb_open = intelfb_open,
 +      //      .fb_read = intelfb_read,
 +      //      .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,
- int intelfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
++      .fb_imageblit = cfb_imageblit, //intelfb_imageblit,
 +};
 +
-       par->fb = 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);
 +      if (!info){
 +              return -EINVAL;
 +      }
 +
 +      fb->fbdev = info;
 +              
 +      par = info->par;
 +
 +      par->dev = dev;
-       info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
-       info->fix.smem_len = fb->bo->mem.size;
++      par->crtc = crtc;
 +
 +      info->fbops = &intelfb_ops;
 +
 +      strcpy(info->fix.id, "intelfb");
-       info->fix.visual = FB_VISUAL_DIRECTCOLOR;
 +      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->screen_size = fb->bo->mem.size;
 +      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;
 +
 +      ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base);
 +      if (ret)
 +              DRM_ERROR("error mapping fb: %d\n", ret);
 +
 +      info->screen_base = fb->virtual_base;
-       info->var.xres = fb->width;
++      info->screen_size = info->fix.smem_len; /* FIXME */
 +      info->pseudo_palette = fb->pseudo_palette;
-       info->var.yres = fb->height;
 +      info->var.xres_virtual = fb->width;
-       case 15:
 +      info->var.yres_virtual = fb->height;
 +      info->var.bits_per_pixel = fb->bits_per_pixel;
 +      info->var.xoffset = 0;
 +      info->var.yoffset = 0;
 +      info->var.activate = FB_ACTIVATE_NOW;
 +      info->var.height = -1;
 +      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;
 +      info->pixmap.flags = FB_PIXMAP_SYSTEM;
 +      info->pixmap.scan_align = 1;
 +
 +      DRM_DEBUG("fb depth is %d\n", fb->depth);
 +      DRM_DEBUG("   pitch is %d\n", fb->pitch);
 +      switch(fb->depth) {
 +      case 8:
-               break;
-       default:
++                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:
-               if (fb->depth == 32) {
-                       info->var.transp.offset = 24;
-                       info->var.transp.length = 8;
-               }
++                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;
- int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
++              info->var.transp.offset = 24;
++              info->var.transp.length = 8;
++              break;
++      default:
 +              break;
 +      }
 +
 +      if (register_framebuffer(info) < 0)
 +              return -EINVAL;
 +
 +      printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
 +             info->fix.id);
 +      return 0;
 +}
 +EXPORT_SYMBOL(intelfb_probe);
 +
++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) {
 +              unregister_framebuffer(info);
 +              framebuffer_release(info);
 +              drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base);
 +      }
 +      return 0;
 +}
 +EXPORT_SYMBOL(intelfb_remove);
 +MODULE_LICENSE("GPL");
Simple merge
@@@ -272,7 -265,7 +272,7 @@@ int i915_driver_unload(drm_device_t *de
        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);