drm: Import drm2+i915 work from FreeBSD
authorFrançois Tigeot <ftigeot@wolfpond.org>
Mon, 22 Jul 2013 20:23:54 +0000 (22:23 +0200)
committerFrançois Tigeot <ftigeot@wolfpond.org>
Mon, 22 Jul 2013 20:46:42 +0000 (22:46 +0200)
As of r240917 (2012-09-25): "Reduce delays in several wait loops"

81 files changed:
sys/dev/drm2/drm.h [new file with mode: 0644]
sys/dev/drm2/drmP.h [new file with mode: 0644]
sys/dev/drm2/drm_agpsupport.c [new file with mode: 0644]
sys/dev/drm2/drm_atomic.h [new file with mode: 0644]
sys/dev/drm2/drm_auth.c [new file with mode: 0644]
sys/dev/drm2/drm_bufs.c [new file with mode: 0644]
sys/dev/drm2/drm_context.c [new file with mode: 0644]
sys/dev/drm2/drm_crtc.c [new file with mode: 0644]
sys/dev/drm2/drm_crtc.h [new file with mode: 0644]
sys/dev/drm2/drm_crtc_helper.c [new file with mode: 0644]
sys/dev/drm2/drm_crtc_helper.h [new file with mode: 0644]
sys/dev/drm2/drm_dma.c [new file with mode: 0644]
sys/dev/drm2/drm_dp_helper.h [new file with mode: 0644]
sys/dev/drm2/drm_dp_iic_helper.c [new file with mode: 0644]
sys/dev/drm2/drm_drawable.c [new file with mode: 0644]
sys/dev/drm2/drm_drv.c [new file with mode: 0644]
sys/dev/drm2/drm_edid.c [new file with mode: 0644]
sys/dev/drm2/drm_edid.h [new file with mode: 0644]
sys/dev/drm2/drm_edid_modes.h [new file with mode: 0644]
sys/dev/drm2/drm_fb_helper.c [new file with mode: 0644]
sys/dev/drm2/drm_fb_helper.h [new file with mode: 0644]
sys/dev/drm2/drm_fops.c [new file with mode: 0644]
sys/dev/drm2/drm_fourcc.h [new file with mode: 0644]
sys/dev/drm2/drm_gem.c [new file with mode: 0644]
sys/dev/drm2/drm_gem_names.c [new file with mode: 0644]
sys/dev/drm2/drm_gem_names.h [new file with mode: 0644]
sys/dev/drm2/drm_hashtab.c [new file with mode: 0644]
sys/dev/drm2/drm_hashtab.h [new file with mode: 0644]
sys/dev/drm2/drm_internal.h [new file with mode: 0644]
sys/dev/drm2/drm_ioctl.c [new file with mode: 0644]
sys/dev/drm2/drm_irq.c [new file with mode: 0644]
sys/dev/drm2/drm_linux_list.h [new file with mode: 0644]
sys/dev/drm2/drm_linux_list_sort.c [new file with mode: 0644]
sys/dev/drm2/drm_lock.c [new file with mode: 0644]
sys/dev/drm2/drm_memory.c [new file with mode: 0644]
sys/dev/drm2/drm_mm.c [new file with mode: 0644]
sys/dev/drm2/drm_mm.h [new file with mode: 0644]
sys/dev/drm2/drm_mode.h [new file with mode: 0644]
sys/dev/drm2/drm_modes.c [new file with mode: 0644]
sys/dev/drm2/drm_pci.c [new file with mode: 0644]
sys/dev/drm2/drm_pciids.h [new file with mode: 0644]
sys/dev/drm2/drm_sarea.h [new file with mode: 0644]
sys/dev/drm2/drm_scatter.c [new file with mode: 0644]
sys/dev/drm2/drm_sman.c [new file with mode: 0644]
sys/dev/drm2/drm_sman.h [new file with mode: 0644]
sys/dev/drm2/drm_stub.c [new file with mode: 0644]
sys/dev/drm2/drm_sysctl.c [new file with mode: 0644]
sys/dev/drm2/drm_vm.c [new file with mode: 0644]
sys/dev/drm2/i915/i915_debug.c [new file with mode: 0644]
sys/dev/drm2/i915/i915_dma.c [new file with mode: 0644]
sys/dev/drm2/i915/i915_drm.h [new file with mode: 0644]
sys/dev/drm2/i915/i915_drv.c [new file with mode: 0644]
sys/dev/drm2/i915/i915_drv.h [new file with mode: 0644]
sys/dev/drm2/i915/i915_gem.c [new file with mode: 0644]
sys/dev/drm2/i915/i915_gem_evict.c [new file with mode: 0644]
sys/dev/drm2/i915/i915_gem_execbuffer.c [new file with mode: 0644]
sys/dev/drm2/i915/i915_gem_gtt.c [new file with mode: 0644]
sys/dev/drm2/i915/i915_gem_tiling.c [new file with mode: 0644]
sys/dev/drm2/i915/i915_irq.c [new file with mode: 0644]
sys/dev/drm2/i915/i915_reg.h [new file with mode: 0644]
sys/dev/drm2/i915/i915_suspend.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_bios.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_bios.h [new file with mode: 0644]
sys/dev/drm2/i915/intel_crt.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_display.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_dp.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_drv.h [new file with mode: 0644]
sys/dev/drm2/i915/intel_fb.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_hdmi.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_iic.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_lvds.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_modes.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_opregion.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_overlay.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_panel.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_ringbuffer.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_ringbuffer.h [new file with mode: 0644]
sys/dev/drm2/i915/intel_sdvo.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_sdvo_regs.h [new file with mode: 0644]
sys/dev/drm2/i915/intel_sprite.c [new file with mode: 0644]
sys/dev/drm2/i915/intel_tv.c [new file with mode: 0644]

diff --git a/sys/dev/drm2/drm.h b/sys/dev/drm2/drm.h
new file mode 100644 (file)
index 0000000..2de327f
--- /dev/null
@@ -0,0 +1,1214 @@
+/**
+ * \file drm.h
+ * Header for the Direct Rendering Manager
+ *
+ * \author Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ * \par Acknowledgments:
+ * Dec 1999, Richard Henderson <rth@twiddle.net>, move to generic \c cmpxchg.
+ */
+
+/*-
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/drm2/drm.h,v 1.1 2012/05/22 11:07:44 kib Exp $");
+
+/**
+ * \mainpage
+ *
+ * The Direct Rendering Manager (DRM) is a device-independent kernel-level
+ * device driver that provides support for the XFree86 Direct Rendering
+ * Infrastructure (DRI).
+ *
+ * The DRM supports the Direct Rendering Infrastructure (DRI) in four major
+ * ways:
+ *     -# The DRM provides synchronized access to the graphics hardware via
+ *        the use of an optimized two-tiered lock.
+ *     -# The DRM enforces the DRI security policy for access to the graphics
+ *        hardware by only allowing authenticated X11 clients access to
+ *        restricted regions of memory.
+ *     -# The DRM provides a generic DMA engine, complete with multiple
+ *        queues and the ability to detect the need for an OpenGL context
+ *        switch.
+ *     -# The DRM is extensible via the use of small device-specific modules
+ *        that rely extensively on the API exported by the DRM module.
+ *
+ */
+
+#ifndef _DRM_H_
+#define _DRM_H_
+
+#ifndef __user
+#define __user
+#endif
+#ifndef __iomem
+#define __iomem
+#endif
+
+#ifdef __GNUC__
+# define DEPRECATED  __attribute__ ((deprecated))
+#else
+# define DEPRECATED
+#endif
+
+#if defined(__linux__)
+#include <asm/ioctl.h>         /* For _IO* macros */
+#define DRM_IOCTL_NR(n)                _IOC_NR(n)
+#define DRM_IOC_VOID           _IOC_NONE
+#define DRM_IOC_READ           _IOC_READ
+#define DRM_IOC_WRITE          _IOC_WRITE
+#define DRM_IOC_READWRITE      _IOC_READ|_IOC_WRITE
+#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+#include <sys/ioccom.h>
+#define DRM_IOCTL_NR(n)                ((n) & 0xff)
+#define DRM_IOC_VOID           IOC_VOID
+#define DRM_IOC_READ           IOC_OUT
+#define DRM_IOC_WRITE          IOC_IN
+#define DRM_IOC_READWRITE      IOC_INOUT
+#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
+#endif
+
+#ifdef __OpenBSD__
+#define DRM_MAJOR       81
+#endif
+#if defined(__linux__) || defined(__NetBSD__)
+#define DRM_MAJOR       226
+#endif
+#define DRM_MAX_MINOR   15
+
+#define DRM_NAME       "drm"     /**< Name in kernel, /dev, and /proc */
+#define DRM_MIN_ORDER  5         /**< At least 2^5 bytes = 32 bytes */
+#define DRM_MAX_ORDER  22        /**< Up to 2^22 bytes = 4MB */
+#define DRM_RAM_PERCENT 10       /**< How much system ram can we lock? */
+
+#define _DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */
+#define _DRM_LOCK_CONT 0x40000000U /**< Hardware lock is contended */
+#define _DRM_LOCK_IS_HELD(lock)           ((lock) & _DRM_LOCK_HELD)
+#define _DRM_LOCK_IS_CONT(lock)           ((lock) & _DRM_LOCK_CONT)
+#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT))
+
+#if defined(__linux__)
+typedef unsigned int drm_handle_t;
+#else
+#include <sys/types.h>
+typedef unsigned long drm_handle_t;    /**< To mapped regions */
+#endif
+typedef unsigned int drm_context_t;    /**< GLXContext handle */
+typedef unsigned int drm_drawable_t;
+typedef unsigned int drm_magic_t;      /**< Magic for authentication */
+
+/**
+ * Cliprect.
+ *
+ * \warning If you change this structure, make sure you change
+ * XF86DRIClipRectRec in the server as well
+ *
+ * \note KW: Actually it's illegal to change either for
+ * backwards-compatibility reasons.
+ */
+struct drm_clip_rect {
+       unsigned short x1;
+       unsigned short y1;
+       unsigned short x2;
+       unsigned short y2;
+};
+
+/**
+ * Texture region,
+ */
+struct drm_tex_region {
+       unsigned char next;
+       unsigned char prev;
+       unsigned char in_use;
+       unsigned char padding;
+       unsigned int age;
+};
+
+/**
+ * Hardware lock.
+ *
+ * The lock structure is a simple cache-line aligned integer.  To avoid
+ * processor bus contention on a multiprocessor system, there should not be any
+ * other data stored in the same cache line.
+ */
+struct drm_hw_lock {
+       __volatile__ unsigned int lock;         /**< lock variable */
+       char padding[60];                       /**< Pad to cache line */
+};
+
+/* This is beyond ugly, and only works on GCC.  However, it allows me to use
+ * drm.h in places (i.e., in the X-server) where I can't use size_t.  The real
+ * fix is to use uint32_t instead of size_t, but that fix will break existing
+ * LP64 (i.e., PowerPC64, SPARC64, IA-64, Alpha, etc.) systems.  That *will*
+ * eventually happen, though.  I chose 'unsigned long' to be the fallback type
+ * because that works on all the platforms I know about.  Hopefully, the
+ * real fix will happen before that bites us.
+ */
+
+#ifdef __SIZE_TYPE__
+# define DRM_SIZE_T __SIZE_TYPE__
+#else
+# warning "__SIZE_TYPE__ not defined.  Assuming sizeof(size_t) == sizeof(unsigned long)!"
+# define DRM_SIZE_T unsigned long
+#endif
+
+/**
+ * DRM_IOCTL_VERSION ioctl argument type.
+ *
+ * \sa drmGetVersion().
+ */
+struct drm_version {
+       int version_major;        /**< Major version */
+       int version_minor;        /**< Minor version */
+       int version_patchlevel;   /**< Patch level */
+       DRM_SIZE_T name_len;      /**< Length of name buffer */
+       char __user *name;                /**< Name of driver */
+       DRM_SIZE_T date_len;      /**< Length of date buffer */
+       char __user *date;                /**< User-space buffer to hold date */
+       DRM_SIZE_T desc_len;      /**< Length of desc buffer */
+       char __user *desc;                /**< User-space buffer to hold desc */
+};
+
+/**
+ * DRM_IOCTL_GET_UNIQUE ioctl argument type.
+ *
+ * \sa drmGetBusid() and drmSetBusId().
+ */
+struct drm_unique {
+       DRM_SIZE_T unique_len;    /**< Length of unique */
+       char __user *unique;              /**< Unique name for driver instantiation */
+};
+
+#undef DRM_SIZE_T
+
+struct drm_list {
+       int count;                /**< Length of user-space structures */
+       struct drm_version __user *version;
+};
+
+struct drm_block {
+       int unused;
+};
+
+/**
+ * DRM_IOCTL_CONTROL ioctl argument type.
+ *
+ * \sa drmCtlInstHandler() and drmCtlUninstHandler().
+ */
+struct drm_control {
+       enum {
+               DRM_ADD_COMMAND,
+               DRM_RM_COMMAND,
+               DRM_INST_HANDLER,
+               DRM_UNINST_HANDLER
+       } func;
+       int irq;
+};
+
+/**
+ * Type of memory to map.
+ */
+enum drm_map_type {
+       _DRM_FRAME_BUFFER = 0,    /**< WC (no caching), no core dump */
+       _DRM_REGISTERS = 1,       /**< no caching, no core dump */
+       _DRM_SHM = 2,             /**< shared, cached */
+       _DRM_AGP = 3,             /**< AGP/GART */
+       _DRM_SCATTER_GATHER = 4,  /**< Scatter/gather memory for PCI DMA */
+       _DRM_CONSISTENT = 5,      /**< Consistent memory for PCI DMA */
+       _DRM_GEM = 6              /**< GEM */
+};
+
+/**
+ * Memory mapping flags.
+ */
+enum drm_map_flags {
+       _DRM_RESTRICTED = 0x01,      /**< Cannot be mapped to user-virtual */
+       _DRM_READ_ONLY = 0x02,
+       _DRM_LOCKED = 0x04,          /**< shared, cached, locked */
+       _DRM_KERNEL = 0x08,          /**< kernel requires access */
+       _DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */
+       _DRM_CONTAINS_LOCK = 0x20,   /**< SHM page that contains lock */
+       _DRM_REMOVABLE = 0x40,       /**< Removable mapping */
+       _DRM_DRIVER = 0x80           /**< Managed by driver */
+};
+
+struct drm_ctx_priv_map {
+       unsigned int ctx_id;     /**< Context requesting private mapping */
+       void *handle;            /**< Handle of map */
+};
+
+/**
+ * DRM_IOCTL_GET_MAP, DRM_IOCTL_ADD_MAP and DRM_IOCTL_RM_MAP ioctls
+ * argument type.
+ *
+ * \sa drmAddMap().
+ */
+struct drm_map {
+       unsigned long offset;    /**< Requested physical address (0 for SAREA)*/
+       unsigned long size;      /**< Requested physical size (bytes) */
+       enum drm_map_type type;  /**< Type of memory to map */
+       enum drm_map_flags flags;        /**< Flags */
+       void *handle;            /**< User-space: "Handle" to pass to mmap() */
+                                /**< Kernel-space: kernel-virtual address */
+       int mtrr;                /**< MTRR slot used */
+       /*   Private data */
+};
+
+/**
+ * DRM_IOCTL_GET_CLIENT ioctl argument type.
+ */
+struct drm_client {
+       int idx;                /**< Which client desired? */
+       int auth;               /**< Is client authenticated? */
+       unsigned long pid;      /**< Process ID */
+       unsigned long uid;      /**< User ID */
+       unsigned long magic;    /**< Magic */
+       unsigned long iocs;     /**< Ioctl count */
+};
+
+enum drm_stat_type {
+       _DRM_STAT_LOCK,
+       _DRM_STAT_OPENS,
+       _DRM_STAT_CLOSES,
+       _DRM_STAT_IOCTLS,
+       _DRM_STAT_LOCKS,
+       _DRM_STAT_UNLOCKS,
+       _DRM_STAT_VALUE,        /**< Generic value */
+       _DRM_STAT_BYTE,         /**< Generic byte counter (1024bytes/K) */
+       _DRM_STAT_COUNT,        /**< Generic non-byte counter (1000/k) */
+
+       _DRM_STAT_IRQ,          /**< IRQ */
+       _DRM_STAT_PRIMARY,      /**< Primary DMA bytes */
+       _DRM_STAT_SECONDARY,    /**< Secondary DMA bytes */
+       _DRM_STAT_DMA,          /**< DMA */
+       _DRM_STAT_SPECIAL,      /**< Special DMA (e.g., priority or polled) */
+       _DRM_STAT_MISSED        /**< Missed DMA opportunity */
+           /* Add to the *END* of the list */
+};
+
+/**
+ * DRM_IOCTL_GET_STATS ioctl argument type.
+ */
+struct drm_stats {
+       unsigned long count;
+       struct {
+               unsigned long value;
+               enum drm_stat_type type;
+       } data[15];
+};
+
+/**
+ * Hardware locking flags.
+ */
+enum drm_lock_flags {
+       _DRM_LOCK_READY = 0x01,      /**< Wait until hardware is ready for DMA */
+       _DRM_LOCK_QUIESCENT = 0x02,  /**< Wait until hardware quiescent */
+       _DRM_LOCK_FLUSH = 0x04,      /**< Flush this context's DMA queue first */
+       _DRM_LOCK_FLUSH_ALL = 0x08,  /**< Flush all DMA queues first */
+       /* These *HALT* flags aren't supported yet
+          -- they will be used to support the
+          full-screen DGA-like mode. */
+       _DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */
+       _DRM_HALT_CUR_QUEUES = 0x20  /**< Halt all current queues */
+};
+
+/**
+ * DRM_IOCTL_LOCK, DRM_IOCTL_UNLOCK and DRM_IOCTL_FINISH ioctl argument type.
+ *
+ * \sa drmGetLock() and drmUnlock().
+ */
+struct drm_lock {
+       int context;
+       enum drm_lock_flags flags;
+};
+
+/**
+ * DMA flags
+ *
+ * \warning
+ * These values \e must match xf86drm.h.
+ *
+ * \sa drm_dma.
+ */
+enum drm_dma_flags {
+       /* Flags for DMA buffer dispatch */
+       _DRM_DMA_BLOCK = 0x01,        /**<
+                                      * Block until buffer dispatched.
+                                      *
+                                      * \note The buffer may not yet have
+                                      * been processed by the hardware --
+                                      * getting a hardware lock with the
+                                      * hardware quiescent will ensure
+                                      * that the buffer has been
+                                      * processed.
+                                      */
+       _DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */
+       _DRM_DMA_PRIORITY = 0x04,     /**< High priority dispatch */
+
+       /* Flags for DMA buffer request */
+       _DRM_DMA_WAIT = 0x10,         /**< Wait for free buffers */
+       _DRM_DMA_SMALLER_OK = 0x20,   /**< Smaller-than-requested buffers OK */
+       _DRM_DMA_LARGER_OK = 0x40     /**< Larger-than-requested buffers OK */
+};
+
+/**
+ * DRM_IOCTL_ADD_BUFS and DRM_IOCTL_MARK_BUFS ioctl argument type.
+ *
+ * \sa drmAddBufs().
+ */
+struct drm_buf_desc {
+       int count;               /**< Number of buffers of this size */
+       int size;                /**< Size in bytes */
+       int low_mark;            /**< Low water mark */
+       int high_mark;           /**< High water mark */
+       enum {
+               _DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */
+               _DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */
+               _DRM_SG_BUFFER  = 0x04, /**< Scatter/gather memory buffer */
+               _DRM_FB_BUFFER  = 0x08, /**< Buffer is in frame buffer */
+               _DRM_PCI_BUFFER_RO = 0x10 /**< Map PCI DMA buffer read-only */
+       } flags;
+       unsigned long agp_start; /**<
+                                 * Start address of where the AGP buffers are
+                                 * in the AGP aperture
+                                 */
+};
+
+/**
+ * DRM_IOCTL_INFO_BUFS ioctl argument type.
+ */
+struct drm_buf_info {
+       int count;                /**< Number of buffers described in list */
+       struct drm_buf_desc __user *list; /**< List of buffer descriptions */
+};
+
+/**
+ * DRM_IOCTL_FREE_BUFS ioctl argument type.
+ */
+struct drm_buf_free {
+       int count;
+       int __user *list;
+};
+
+/**
+ * Buffer information
+ *
+ * \sa drm_buf_map.
+ */
+struct drm_buf_pub {
+       int idx;                       /**< Index into the master buffer list */
+       int total;                     /**< Buffer size */
+       int used;                      /**< Amount of buffer in use (for DMA) */
+       void __user *address;          /**< Address of buffer */
+};
+
+/**
+ * DRM_IOCTL_MAP_BUFS ioctl argument type.
+ */
+struct drm_buf_map {
+       int count;              /**< Length of the buffer list */
+#if defined(__cplusplus)
+       void __user *c_virtual;
+#else
+       void __user *virtual;           /**< Mmap'd area in user-virtual */
+#endif
+       struct drm_buf_pub __user *list;        /**< Buffer information */
+};
+
+/**
+ * DRM_IOCTL_DMA ioctl argument type.
+ *
+ * Indices here refer to the offset into the buffer list in drm_buf_get.
+ *
+ * \sa drmDMA().
+ */
+struct drm_dma {
+       int context;                      /**< Context handle */
+       int send_count;                   /**< Number of buffers to send */
+       int __user *send_indices;         /**< List of handles to buffers */
+       int __user *send_sizes;           /**< Lengths of data to send */
+       enum drm_dma_flags flags;         /**< Flags */
+       int request_count;                /**< Number of buffers requested */
+       int request_size;                 /**< Desired size for buffers */
+       int __user *request_indices;     /**< Buffer information */
+       int __user *request_sizes;
+       int granted_count;                /**< Number of buffers granted */
+};
+
+enum drm_ctx_flags {
+       _DRM_CONTEXT_PRESERVED = 0x01,
+       _DRM_CONTEXT_2DONLY = 0x02
+};
+
+/**
+ * DRM_IOCTL_ADD_CTX ioctl argument type.
+ *
+ * \sa drmCreateContext() and drmDestroyContext().
+ */
+struct drm_ctx {
+       drm_context_t handle;
+       enum drm_ctx_flags flags;
+};
+
+/**
+ * DRM_IOCTL_RES_CTX ioctl argument type.
+ */
+struct drm_ctx_res {
+       int count;
+       struct drm_ctx __user *contexts;
+};
+
+/**
+ * DRM_IOCTL_ADD_DRAW and DRM_IOCTL_RM_DRAW ioctl argument type.
+ */
+struct drm_draw {
+       drm_drawable_t handle;
+};
+
+/**
+ * DRM_IOCTL_UPDATE_DRAW ioctl argument type.
+ */
+typedef enum {
+       DRM_DRAWABLE_CLIPRECTS,
+} drm_drawable_info_type_t;
+
+struct drm_update_draw {
+       drm_drawable_t handle;
+       unsigned int type;
+       unsigned int num;
+       unsigned long long data;
+};
+
+/**
+ * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type.
+ */
+struct drm_auth {
+       drm_magic_t magic;
+};
+
+/**
+ * DRM_IOCTL_IRQ_BUSID ioctl argument type.
+ *
+ * \sa drmGetInterruptFromBusID().
+ */
+struct drm_irq_busid {
+       int irq;        /**< IRQ number */
+       int busnum;     /**< bus number */
+       int devnum;     /**< device number */
+       int funcnum;    /**< function number */
+};
+
+enum drm_vblank_seq_type {
+       _DRM_VBLANK_ABSOLUTE = 0x0,     /**< Wait for specific vblank sequence number */
+       _DRM_VBLANK_RELATIVE = 0x1,     /**< Wait for given number of vblanks */
+       _DRM_VBLANK_HIGH_CRTC_MASK = 0x0000003e,
+       _DRM_VBLANK_EVENT = 0x4000000,   /**< Send event instead of blocking */
+       _DRM_VBLANK_FLIP = 0x8000000,   /**< Scheduled buffer swap should flip */
+       _DRM_VBLANK_NEXTONMISS = 0x10000000,    /**< If missed, wait for next vblank */
+       _DRM_VBLANK_SECONDARY = 0x20000000,     /**< Secondary display controller */
+       _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
+};
+#define _DRM_VBLANK_HIGH_CRTC_SHIFT 1
+
+#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
+#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_EVENT | _DRM_VBLANK_SIGNAL | \
+                               _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)
+
+struct drm_wait_vblank_request {
+       enum drm_vblank_seq_type type;
+       unsigned int sequence;
+       unsigned long signal;
+};
+
+struct drm_wait_vblank_reply {
+       enum drm_vblank_seq_type type;
+       unsigned int sequence;
+       long tval_sec;
+       long tval_usec;
+};
+
+/**
+ * DRM_IOCTL_WAIT_VBLANK ioctl argument type.
+ *
+ * \sa drmWaitVBlank().
+ */
+union drm_wait_vblank {
+       struct drm_wait_vblank_request request;
+       struct drm_wait_vblank_reply reply;
+};
+
+
+#define _DRM_PRE_MODESET 1
+#define _DRM_POST_MODESET 2
+
+/**
+ * DRM_IOCTL_MODESET_CTL ioctl argument type
+ *
+ * \sa drmModesetCtl().
+ */
+struct drm_modeset_ctl {
+       uint32_t crtc;
+       uint32_t cmd;
+};
+
+/**
+ * DRM_IOCTL_AGP_ENABLE ioctl argument type.
+ *
+ * \sa drmAgpEnable().
+ */
+struct drm_agp_mode {
+       unsigned long mode;     /**< AGP mode */
+};
+
+/**
+ * DRM_IOCTL_AGP_ALLOC and DRM_IOCTL_AGP_FREE ioctls argument type.
+ *
+ * \sa drmAgpAlloc() and drmAgpFree().
+ */
+struct drm_agp_buffer {
+       unsigned long size;     /**< In bytes -- will round to page boundary */
+       unsigned long handle;   /**< Used for binding / unbinding */
+       unsigned long type;     /**< Type of memory to allocate */
+       unsigned long physical; /**< Physical used by i810 */
+};
+
+/**
+ * DRM_IOCTL_AGP_BIND and DRM_IOCTL_AGP_UNBIND ioctls argument type.
+ *
+ * \sa drmAgpBind() and drmAgpUnbind().
+ */
+struct drm_agp_binding {
+       unsigned long handle;   /**< From drm_agp_buffer */
+       unsigned long offset;   /**< In bytes -- will round to page boundary */
+};
+
+/**
+ * DRM_IOCTL_AGP_INFO ioctl argument type.
+ *
+ * \sa drmAgpVersionMajor(), drmAgpVersionMinor(), drmAgpGetMode(),
+ * drmAgpBase(), drmAgpSize(), drmAgpMemoryUsed(), drmAgpMemoryAvail(),
+ * drmAgpVendorId() and drmAgpDeviceId().
+ */
+struct drm_agp_info {
+       int agp_version_major;
+       int agp_version_minor;
+       unsigned long mode;
+       unsigned long aperture_base;   /**< physical address */
+       unsigned long aperture_size;   /**< bytes */
+       unsigned long memory_allowed;  /**< bytes */
+       unsigned long memory_used;
+
+       /** \name PCI information */
+       /*@{ */
+       unsigned short id_vendor;
+       unsigned short id_device;
+       /*@} */
+};
+
+/**
+ * DRM_IOCTL_SG_ALLOC ioctl argument type.
+ */
+struct drm_scatter_gather {
+       unsigned long size;     /**< In bytes -- will round to page boundary */
+       unsigned long handle;   /**< Used for mapping / unmapping */
+};
+
+/**
+ * DRM_IOCTL_SET_VERSION ioctl argument type.
+ */
+struct drm_set_version {
+       int drm_di_major;
+       int drm_di_minor;
+       int drm_dd_major;
+       int drm_dd_minor;
+};
+
+#define DRM_FENCE_FLAG_EMIT                0x00000001
+#define DRM_FENCE_FLAG_SHAREABLE           0x00000002
+/**
+ * On hardware with no interrupt events for operation completion,
+ * indicates that the kernel should sleep while waiting for any blocking
+ * operation to complete rather than spinning.
+ *
+ * Has no effect otherwise.
+ */
+#define DRM_FENCE_FLAG_WAIT_LAZY           0x00000004
+#define DRM_FENCE_FLAG_NO_USER             0x00000010
+
+/* Reserved for driver use */
+#define DRM_FENCE_MASK_DRIVER              0xFF000000
+
+#define DRM_FENCE_TYPE_EXE                 0x00000001
+
+struct drm_fence_arg {
+       unsigned int handle;
+       unsigned int fence_class;
+       unsigned int type;
+       unsigned int flags;
+       unsigned int signaled;
+       unsigned int error;
+       unsigned int sequence;
+       unsigned int pad64;
+       uint64_t expand_pad[2]; /* Future expansion */
+};
+
+/* Buffer permissions, referring to how the GPU uses the buffers.
+ * these translate to fence types used for the buffers.
+ * Typically a texture buffer is read, A destination buffer is write and
+ *  a command (batch-) buffer is exe. Can be or-ed together.
+ */
+
+#define DRM_BO_FLAG_READ        (1ULL << 0)
+#define DRM_BO_FLAG_WRITE       (1ULL << 1)
+#define DRM_BO_FLAG_EXE         (1ULL << 2)
+
+/*
+ * All of the bits related to access mode
+ */
+#define DRM_BO_MASK_ACCESS     (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_EXE)
+/*
+ * Status flags. Can be read to determine the actual state of a buffer.
+ * Can also be set in the buffer mask before validation.
+ */
+
+/*
+ * Mask: Never evict this buffer. Not even with force. This type of buffer is only
+ * available to root and must be manually removed before buffer manager shutdown
+ * or lock.
+ * Flags: Acknowledge
+ */
+#define DRM_BO_FLAG_NO_EVICT    (1ULL << 4)
+
+/*
+ * Mask: Require that the buffer is placed in mappable memory when validated.
+ *       If not set the buffer may or may not be in mappable memory when validated.
+ * Flags: If set, the buffer is in mappable memory.
+ */
+#define DRM_BO_FLAG_MAPPABLE    (1ULL << 5)
+
+/* Mask: The buffer should be shareable with other processes.
+ * Flags: The buffer is shareable with other processes.
+ */
+#define DRM_BO_FLAG_SHAREABLE   (1ULL << 6)
+
+/* Mask: If set, place the buffer in cache-coherent memory if available.
+ *       If clear, never place the buffer in cache coherent memory if validated.
+ * Flags: The buffer is currently in cache-coherent memory.
+ */
+#define DRM_BO_FLAG_CACHED      (1ULL << 7)
+
+/* Mask: Make sure that every time this buffer is validated,
+ *       it ends up on the same location provided that the memory mask is the same.
+ *       The buffer will also not be evicted when claiming space for
+ *       other buffers. Basically a pinned buffer but it may be thrown out as
+ *       part of buffer manager shutdown or locking.
+ * Flags: Acknowledge.
+ */
+#define DRM_BO_FLAG_NO_MOVE     (1ULL << 8)
+
+/* Mask: Make sure the buffer is in cached memory when mapped.  In conjunction
+ * with DRM_BO_FLAG_CACHED it also allows the buffer to be bound into the GART
+ * with unsnooped PTEs instead of snooped, by using chipset-specific cache
+ * flushing at bind time.  A better name might be DRM_BO_FLAG_TT_UNSNOOPED,
+ * as the eviction to local memory (TTM unbind) on map is just a side effect
+ * to prevent aggressive cache prefetch from the GPU disturbing the cache
+ * management that the DRM is doing.
+ *
+ * Flags: Acknowledge.
+ * Buffers allocated with this flag should not be used for suballocators
+ * This type may have issues on CPUs with over-aggressive caching
+ * http://marc.info/?l=linux-kernel&m=102376926732464&w=2
+ */
+#define DRM_BO_FLAG_CACHED_MAPPED    (1ULL << 19)
+
+
+/* Mask: Force DRM_BO_FLAG_CACHED flag strictly also if it is set.
+ * Flags: Acknowledge.
+ */
+#define DRM_BO_FLAG_FORCE_CACHING  (1ULL << 13)
+
+/*
+ * Mask: Force DRM_BO_FLAG_MAPPABLE flag strictly also if it is clear.
+ * Flags: Acknowledge.
+ */
+#define DRM_BO_FLAG_FORCE_MAPPABLE (1ULL << 14)
+#define DRM_BO_FLAG_TILE           (1ULL << 15)
+
+/*
+ * Memory type flags that can be or'ed together in the mask, but only
+ * one appears in flags.
+ */
+
+/* System memory */
+#define DRM_BO_FLAG_MEM_LOCAL  (1ULL << 24)
+/* Translation table memory */
+#define DRM_BO_FLAG_MEM_TT     (1ULL << 25)
+/* Vram memory */
+#define DRM_BO_FLAG_MEM_VRAM   (1ULL << 26)
+/* Up to the driver to define. */
+#define DRM_BO_FLAG_MEM_PRIV0  (1ULL << 27)
+#define DRM_BO_FLAG_MEM_PRIV1  (1ULL << 28)
+#define DRM_BO_FLAG_MEM_PRIV2  (1ULL << 29)
+#define DRM_BO_FLAG_MEM_PRIV3  (1ULL << 30)
+#define DRM_BO_FLAG_MEM_PRIV4  (1ULL << 31)
+/* We can add more of these now with a 64-bit flag type */
+
+/*
+ * This is a mask covering all of the memory type flags; easier to just
+ * use a single constant than a bunch of | values. It covers
+ * DRM_BO_FLAG_MEM_LOCAL through DRM_BO_FLAG_MEM_PRIV4
+ */
+#define DRM_BO_MASK_MEM         0x00000000FF000000ULL
+/*
+ * This adds all of the CPU-mapping options in with the memory
+ * type to label all bits which change how the page gets mapped
+ */
+#define DRM_BO_MASK_MEMTYPE     (DRM_BO_MASK_MEM | \
+                                DRM_BO_FLAG_CACHED_MAPPED | \
+                                DRM_BO_FLAG_CACHED | \
+                                DRM_BO_FLAG_MAPPABLE)
+                                
+/* Driver-private flags */
+#define DRM_BO_MASK_DRIVER      0xFFFF000000000000ULL
+
+/*
+ * Don't block on validate and map. Instead, return EBUSY.
+ */
+#define DRM_BO_HINT_DONT_BLOCK  0x00000002
+/*
+ * Don't place this buffer on the unfenced list. This means
+ * that the buffer will not end up having a fence associated
+ * with it as a result of this operation
+ */
+#define DRM_BO_HINT_DONT_FENCE  0x00000004
+/**
+ * On hardware with no interrupt events for operation completion,
+ * indicates that the kernel should sleep while waiting for any blocking
+ * operation to complete rather than spinning.
+ *
+ * Has no effect otherwise.
+ */
+#define DRM_BO_HINT_WAIT_LAZY   0x00000008
+/*
+ * The client has compute relocations refering to this buffer using the
+ * offset in the presumed_offset field. If that offset ends up matching
+ * where this buffer lands, the kernel is free to skip executing those
+ * relocations
+ */
+#define DRM_BO_HINT_PRESUMED_OFFSET 0x00000010
+
+#define DRM_BO_INIT_MAGIC 0xfe769812
+#define DRM_BO_INIT_MAJOR 1
+#define DRM_BO_INIT_MINOR 0
+#define DRM_BO_INIT_PATCH 0
+
+
+struct drm_bo_info_req {
+       uint64_t mask;
+       uint64_t flags;
+       unsigned int handle;
+       unsigned int hint;
+       unsigned int fence_class;
+       unsigned int desired_tile_stride;
+       unsigned int tile_info;
+       unsigned int pad64;
+       uint64_t presumed_offset;
+};
+
+struct drm_bo_create_req {
+       uint64_t flags;
+       uint64_t size;
+       uint64_t buffer_start;
+       unsigned int hint;
+       unsigned int page_alignment;
+};
+
+
+/*
+ * Reply flags
+ */
+
+#define DRM_BO_REP_BUSY 0x00000001
+
+struct drm_bo_info_rep {
+       uint64_t flags;
+       uint64_t proposed_flags;
+       uint64_t size;
+       uint64_t offset;
+       uint64_t arg_handle;
+       uint64_t buffer_start;
+       unsigned int handle;
+       unsigned int fence_flags;
+       unsigned int rep_flags;
+       unsigned int page_alignment;
+       unsigned int desired_tile_stride;
+       unsigned int hw_tile_stride;
+       unsigned int tile_info;
+       unsigned int pad64;
+       uint64_t expand_pad[4]; /*Future expansion */
+};
+
+struct drm_bo_arg_rep {
+       struct drm_bo_info_rep bo_info;
+       int ret;
+       unsigned int pad64;
+};
+
+struct drm_bo_create_arg {
+       union {
+               struct drm_bo_create_req req;
+               struct drm_bo_info_rep rep;
+       } d;
+};
+
+struct drm_bo_handle_arg {
+       unsigned int handle;
+};
+
+struct drm_bo_reference_info_arg {
+       union {
+               struct drm_bo_handle_arg req;
+               struct drm_bo_info_rep rep;
+       } d;
+};
+
+struct drm_bo_map_wait_idle_arg {
+       union {
+               struct drm_bo_info_req req;
+               struct drm_bo_info_rep rep;
+       } d;
+};
+
+struct drm_bo_op_req {
+       enum {
+               drm_bo_validate,
+               drm_bo_fence,
+               drm_bo_ref_fence,
+       } op;
+       unsigned int arg_handle;
+       struct drm_bo_info_req bo_req;
+};
+
+
+struct drm_bo_op_arg {
+       uint64_t next;
+       union {
+               struct drm_bo_op_req req;
+               struct drm_bo_arg_rep rep;
+       } d;
+       int handled;
+       unsigned int pad64;
+};
+
+
+#define DRM_BO_MEM_LOCAL 0
+#define DRM_BO_MEM_TT 1
+#define DRM_BO_MEM_VRAM 2
+#define DRM_BO_MEM_PRIV0 3
+#define DRM_BO_MEM_PRIV1 4
+#define DRM_BO_MEM_PRIV2 5
+#define DRM_BO_MEM_PRIV3 6
+#define DRM_BO_MEM_PRIV4 7
+
+#define DRM_BO_MEM_TYPES 8 /* For now. */
+
+#define DRM_BO_LOCK_UNLOCK_BM       (1 << 0)
+#define DRM_BO_LOCK_IGNORE_NO_EVICT (1 << 1)
+
+struct drm_bo_version_arg {
+       uint32_t major;
+       uint32_t minor;
+       uint32_t patchlevel;
+};
+
+struct drm_mm_type_arg {
+       unsigned int mem_type;
+       unsigned int lock_flags;
+};
+
+struct drm_mm_init_arg {
+       unsigned int magic;
+       unsigned int major;
+       unsigned int minor;
+       unsigned int mem_type;
+       uint64_t p_offset;
+       uint64_t p_size;
+};
+
+struct drm_mm_info_arg {
+       unsigned int mem_type;
+       uint64_t p_size;
+};
+
+struct drm_gem_close {
+       /** Handle of the object to be closed. */
+       uint32_t handle;
+       uint32_t pad;
+};
+
+struct drm_gem_flink {
+       /** Handle for the object being named */
+       uint32_t handle;
+
+       /** Returned global name */
+       uint32_t name;
+};
+
+struct drm_gem_open {
+       /** Name of object being opened */
+       uint32_t name;
+
+       /** Returned handle for the object */
+       uint32_t handle;
+       
+       /** Returned size of the object */
+       uint64_t size;
+};
+
+struct drm_get_cap {
+       uint64_t capability;
+       uint64_t value;
+};
+
+struct drm_event {
+       uint32_t type;
+       uint32_t length;
+};
+
+#define DRM_EVENT_VBLANK 0x01
+#define DRM_EVENT_FLIP_COMPLETE 0x02
+
+struct drm_event_vblank {
+       struct drm_event base;
+       uint64_t user_data;
+       uint32_t tv_sec;
+       uint32_t tv_usec;
+       uint32_t sequence;
+       uint32_t reserved;
+};
+
+#define DRM_CAP_DUMB_BUFFER 0x1
+#define DRM_CAP_VBLANK_HIGH_CRTC 0x2
+#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
+#define DRM_CAP_DUMB_PREFER_SHADOW 0x4
+
+#include "drm_mode.h"
+
+/**
+ * \name Ioctls Definitions
+ */
+/*@{*/
+
+#define DRM_IOCTL_BASE                 'd'
+#define DRM_IO(nr)                     _IO(DRM_IOCTL_BASE,nr)
+#define DRM_IOR(nr,type)               _IOR(DRM_IOCTL_BASE,nr,type)
+#define DRM_IOW(nr,type)               _IOW(DRM_IOCTL_BASE,nr,type)
+#define DRM_IOWR(nr,type)              _IOWR(DRM_IOCTL_BASE,nr,type)
+
+#define DRM_IOCTL_VERSION              DRM_IOWR(0x00, struct drm_version)
+#define DRM_IOCTL_GET_UNIQUE           DRM_IOWR(0x01, struct drm_unique)
+#define DRM_IOCTL_GET_MAGIC            DRM_IOR( 0x02, struct drm_auth)
+#define DRM_IOCTL_IRQ_BUSID            DRM_IOWR(0x03, struct drm_irq_busid)
+#define DRM_IOCTL_GET_MAP               DRM_IOWR(0x04, struct drm_map)
+#define DRM_IOCTL_GET_CLIENT            DRM_IOWR(0x05, struct drm_client)
+#define DRM_IOCTL_GET_STATS             DRM_IOR( 0x06, struct drm_stats)
+#define DRM_IOCTL_SET_VERSION          DRM_IOWR(0x07, struct drm_set_version)
+#define DRM_IOCTL_MODESET_CTL           DRM_IOW(0x08,  struct drm_modeset_ctl)
+
+#define DRM_IOCTL_GEM_CLOSE            DRM_IOW (0x09, struct drm_gem_close)
+#define DRM_IOCTL_GEM_FLINK            DRM_IOWR(0x0a, struct drm_gem_flink)
+#define DRM_IOCTL_GEM_OPEN             DRM_IOWR(0x0b, struct drm_gem_open)
+
+#define DRM_IOCTL_GET_CAP              DRM_IOWR(0x0c, struct drm_get_cap)
+
+#define DRM_IOCTL_SET_UNIQUE           DRM_IOW( 0x10, struct drm_unique)
+#define DRM_IOCTL_AUTH_MAGIC           DRM_IOW( 0x11, struct drm_auth)
+#define DRM_IOCTL_BLOCK                        DRM_IOWR(0x12, struct drm_block)
+#define DRM_IOCTL_UNBLOCK              DRM_IOWR(0x13, struct drm_block)
+#define DRM_IOCTL_CONTROL              DRM_IOW( 0x14, struct drm_control)
+#define DRM_IOCTL_ADD_MAP              DRM_IOWR(0x15, struct drm_map)
+#define DRM_IOCTL_ADD_BUFS             DRM_IOWR(0x16, struct drm_buf_desc)
+#define DRM_IOCTL_MARK_BUFS            DRM_IOW( 0x17, struct drm_buf_desc)
+#define DRM_IOCTL_INFO_BUFS            DRM_IOWR(0x18, struct drm_buf_info)
+#define DRM_IOCTL_MAP_BUFS             DRM_IOWR(0x19, struct drm_buf_map)
+#define DRM_IOCTL_FREE_BUFS            DRM_IOW( 0x1a, struct drm_buf_free)
+
+#define DRM_IOCTL_RM_MAP               DRM_IOW( 0x1b, struct drm_map)
+
+#define DRM_IOCTL_SET_SAREA_CTX                DRM_IOW( 0x1c, struct drm_ctx_priv_map)
+#define DRM_IOCTL_GET_SAREA_CTX                DRM_IOWR(0x1d, struct drm_ctx_priv_map)
+
+#define DRM_IOCTL_SET_MASTER            DRM_IO(0x1e)
+#define DRM_IOCTL_DROP_MASTER           DRM_IO(0x1f)
+
+#define DRM_IOCTL_ADD_CTX              DRM_IOWR(0x20, struct drm_ctx)
+#define DRM_IOCTL_RM_CTX               DRM_IOWR(0x21, struct drm_ctx)
+#define DRM_IOCTL_MOD_CTX              DRM_IOW( 0x22, struct drm_ctx)
+#define DRM_IOCTL_GET_CTX              DRM_IOWR(0x23, struct drm_ctx)
+#define DRM_IOCTL_SWITCH_CTX           DRM_IOW( 0x24, struct drm_ctx)
+#define DRM_IOCTL_NEW_CTX              DRM_IOW( 0x25, struct drm_ctx)
+#define DRM_IOCTL_RES_CTX              DRM_IOWR(0x26, struct drm_ctx_res)
+#define DRM_IOCTL_ADD_DRAW             DRM_IOWR(0x27, struct drm_draw)
+#define DRM_IOCTL_RM_DRAW              DRM_IOWR(0x28, struct drm_draw)
+#define DRM_IOCTL_DMA                  DRM_IOWR(0x29, struct drm_dma)
+#define DRM_IOCTL_LOCK                 DRM_IOW( 0x2a, struct drm_lock)
+#define DRM_IOCTL_UNLOCK               DRM_IOW( 0x2b, struct drm_lock)
+#define DRM_IOCTL_FINISH               DRM_IOW( 0x2c, struct drm_lock)
+
+#define DRM_IOCTL_GEM_PRIME_OPEN        DRM_IOWR(0x2e, struct drm_gem_open)
+
+#define DRM_IOCTL_AGP_ACQUIRE          DRM_IO(  0x30)
+#define DRM_IOCTL_AGP_RELEASE          DRM_IO(  0x31)
+#define DRM_IOCTL_AGP_ENABLE           DRM_IOW( 0x32, struct drm_agp_mode)
+#define DRM_IOCTL_AGP_INFO             DRM_IOR( 0x33, struct drm_agp_info)
+#define DRM_IOCTL_AGP_ALLOC            DRM_IOWR(0x34, struct drm_agp_buffer)
+#define DRM_IOCTL_AGP_FREE             DRM_IOW( 0x35, struct drm_agp_buffer)
+#define DRM_IOCTL_AGP_BIND             DRM_IOW( 0x36, struct drm_agp_binding)
+#define DRM_IOCTL_AGP_UNBIND           DRM_IOW( 0x37, struct drm_agp_binding)
+
+#define DRM_IOCTL_SG_ALLOC             DRM_IOWR(0x38, struct drm_scatter_gather)
+#define DRM_IOCTL_SG_FREE              DRM_IOW( 0x39, struct drm_scatter_gather)
+
+#define DRM_IOCTL_WAIT_VBLANK          DRM_IOWR(0x3a, union drm_wait_vblank)
+
+#define DRM_IOCTL_UPDATE_DRAW           DRM_IOW(0x3f, struct drm_update_draw)
+
+#define DRM_IOCTL_MODE_GETRESOURCES    DRM_IOWR(0xA0, struct drm_mode_card_res)
+#define DRM_IOCTL_MODE_GETCRTC         DRM_IOWR(0xA1, struct drm_mode_crtc)
+#define DRM_IOCTL_MODE_SETCRTC         DRM_IOWR(0xA2, struct drm_mode_crtc)
+#define DRM_IOCTL_MODE_CURSOR          DRM_IOWR(0xA3, struct drm_mode_cursor)
+#define DRM_IOCTL_MODE_GETGAMMA                DRM_IOWR(0xA4, struct drm_mode_crtc_lut)
+#define DRM_IOCTL_MODE_SETGAMMA                DRM_IOWR(0xA5, struct drm_mode_crtc_lut)
+#define DRM_IOCTL_MODE_GETENCODER      DRM_IOWR(0xA6, struct drm_mode_get_encoder)
+#define DRM_IOCTL_MODE_GETCONNECTOR    DRM_IOWR(0xA7, struct drm_mode_get_connector)
+#define DRM_IOCTL_MODE_ATTACHMODE      DRM_IOWR(0xA8, struct drm_mode_mode_cmd)
+#define DRM_IOCTL_MODE_DETACHMODE      DRM_IOWR(0xA9, struct drm_mode_mode_cmd)
+
+#define DRM_IOCTL_MODE_GETPROPERTY     DRM_IOWR(0xAA, struct drm_mode_get_property)
+#define DRM_IOCTL_MODE_SETPROPERTY     DRM_IOWR(0xAB, struct drm_mode_connector_set_property)
+#define DRM_IOCTL_MODE_GETPROPBLOB     DRM_IOWR(0xAC, struct drm_mode_get_blob)
+#define DRM_IOCTL_MODE_GETFB           DRM_IOWR(0xAD, struct drm_mode_fb_cmd)
+#define DRM_IOCTL_MODE_ADDFB           DRM_IOWR(0xAE, struct drm_mode_fb_cmd)
+#define DRM_IOCTL_MODE_RMFB            DRM_IOWR(0xAF, unsigned int)
+#define DRM_IOCTL_MODE_PAGE_FLIP       DRM_IOWR(0xB0, struct drm_mode_crtc_page_flip)
+#define DRM_IOCTL_MODE_DIRTYFB         DRM_IOWR(0xB1, struct drm_mode_fb_dirty_cmd)
+
+#define DRM_IOCTL_MODE_CREATE_DUMB     DRM_IOWR(0xB2, struct drm_mode_create_dumb)
+#define DRM_IOCTL_MODE_MAP_DUMB                DRM_IOWR(0xB3, struct drm_mode_map_dumb)
+#define DRM_IOCTL_MODE_DESTROY_DUMB    DRM_IOWR(0xB4, struct drm_mode_destroy_dumb)
+#define DRM_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xB5, struct drm_mode_get_plane_res)
+#define DRM_IOCTL_MODE_GETPLANE                DRM_IOWR(0xB6, struct drm_mode_get_plane)
+#define DRM_IOCTL_MODE_SETPLANE                DRM_IOWR(0xB7, struct drm_mode_set_plane)
+#define DRM_IOCTL_MODE_ADDFB2          DRM_IOWR(0xB8, struct drm_mode_fb_cmd2)
+
+#define DRM_IOCTL_MM_INIT               DRM_IOWR(0xc0, struct drm_mm_init_arg)
+#define DRM_IOCTL_MM_TAKEDOWN           DRM_IOWR(0xc1, struct drm_mm_type_arg)
+#define DRM_IOCTL_MM_LOCK               DRM_IOWR(0xc2, struct drm_mm_type_arg)
+#define DRM_IOCTL_MM_UNLOCK             DRM_IOWR(0xc3, struct drm_mm_type_arg)
+
+#define DRM_IOCTL_FENCE_CREATE          DRM_IOWR(0xc4, struct drm_fence_arg)
+#define DRM_IOCTL_FENCE_REFERENCE       DRM_IOWR(0xc6, struct drm_fence_arg)
+#define DRM_IOCTL_FENCE_UNREFERENCE     DRM_IOWR(0xc7, struct drm_fence_arg)
+#define DRM_IOCTL_FENCE_SIGNALED        DRM_IOWR(0xc8, struct drm_fence_arg)
+#define DRM_IOCTL_FENCE_FLUSH           DRM_IOWR(0xc9, struct drm_fence_arg)
+#define DRM_IOCTL_FENCE_WAIT            DRM_IOWR(0xca, struct drm_fence_arg)
+#define DRM_IOCTL_FENCE_EMIT            DRM_IOWR(0xcb, struct drm_fence_arg)
+#define DRM_IOCTL_FENCE_BUFFERS         DRM_IOWR(0xcc, struct drm_fence_arg)
+
+#define DRM_IOCTL_BO_CREATE             DRM_IOWR(0xcd, struct drm_bo_create_arg)
+#define DRM_IOCTL_BO_MAP                DRM_IOWR(0xcf, struct drm_bo_map_wait_idle_arg)
+#define DRM_IOCTL_BO_UNMAP              DRM_IOWR(0xd0, struct drm_bo_handle_arg)
+#define DRM_IOCTL_BO_REFERENCE          DRM_IOWR(0xd1, struct drm_bo_reference_info_arg)
+#define DRM_IOCTL_BO_UNREFERENCE        DRM_IOWR(0xd2, struct drm_bo_handle_arg)
+#define DRM_IOCTL_BO_SETSTATUS          DRM_IOWR(0xd3, struct drm_bo_map_wait_idle_arg)
+#define DRM_IOCTL_BO_INFO               DRM_IOWR(0xd4, struct drm_bo_reference_info_arg)
+#define DRM_IOCTL_BO_WAIT_IDLE          DRM_IOWR(0xd5, struct drm_bo_map_wait_idle_arg)
+#define DRM_IOCTL_BO_VERSION          DRM_IOR(0xd6, struct drm_bo_version_arg)
+#define DRM_IOCTL_MM_INFO               DRM_IOWR(0xd7, struct drm_mm_info_arg)
+
+/*@}*/
+
+/**
+ * Device specific ioctls should only be in their respective headers
+ * The device specific ioctl range is from 0x40 to 0x99.
+ * Generic IOCTLS restart at 0xA0.
+ *
+ * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and
+ * drmCommandReadWrite().
+ */
+#define DRM_COMMAND_BASE                0x40
+#define DRM_COMMAND_END                 0xA0
+
+/* typedef area */
+#ifndef __KERNEL__
+typedef struct drm_clip_rect drm_clip_rect_t;
+typedef struct drm_tex_region drm_tex_region_t;
+typedef struct drm_hw_lock drm_hw_lock_t;
+typedef struct drm_version drm_version_t;
+typedef struct drm_unique drm_unique_t;
+typedef struct drm_list drm_list_t;
+typedef struct drm_block drm_block_t;
+typedef struct drm_control drm_control_t;
+typedef enum drm_map_type drm_map_type_t;
+typedef enum drm_map_flags drm_map_flags_t;
+typedef struct drm_ctx_priv_map drm_ctx_priv_map_t;
+typedef struct drm_map drm_map_t;
+typedef struct drm_client drm_client_t;
+typedef enum drm_stat_type drm_stat_type_t;
+typedef struct drm_stats drm_stats_t;
+typedef enum drm_lock_flags drm_lock_flags_t;
+typedef struct drm_lock drm_lock_t;
+typedef enum drm_dma_flags drm_dma_flags_t;
+typedef struct drm_buf_desc drm_buf_desc_t;
+typedef struct drm_buf_info drm_buf_info_t;
+typedef struct drm_buf_free drm_buf_free_t;
+typedef struct drm_buf_pub drm_buf_pub_t;
+typedef struct drm_buf_map drm_buf_map_t;
+typedef struct drm_dma drm_dma_t;
+typedef union drm_wait_vblank drm_wait_vblank_t;
+typedef struct drm_agp_mode drm_agp_mode_t;
+typedef enum drm_ctx_flags drm_ctx_flags_t;
+typedef struct drm_ctx drm_ctx_t;
+typedef struct drm_ctx_res drm_ctx_res_t;
+typedef struct drm_draw drm_draw_t;
+typedef struct drm_update_draw drm_update_draw_t;
+typedef struct drm_auth drm_auth_t;
+typedef struct drm_irq_busid drm_irq_busid_t;
+typedef enum drm_vblank_seq_type drm_vblank_seq_type_t;
+typedef struct drm_agp_buffer drm_agp_buffer_t;
+typedef struct drm_agp_binding drm_agp_binding_t;
+typedef struct drm_agp_info drm_agp_info_t;
+typedef struct drm_scatter_gather drm_scatter_gather_t;
+typedef struct drm_set_version drm_set_version_t;
+
+typedef struct drm_fence_arg drm_fence_arg_t;
+typedef struct drm_mm_type_arg drm_mm_type_arg_t;
+typedef struct drm_mm_init_arg drm_mm_init_arg_t;
+typedef enum drm_bo_type drm_bo_type_t;
+#endif
+
+#endif
diff --git a/sys/dev/drm2/drmP.h b/sys/dev/drm2/drmP.h
new file mode 100644 (file)
index 0000000..feed09b
--- /dev/null
@@ -0,0 +1,1400 @@
+/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
+ */
+/*-
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/drm2/drmP.h,v 1.1 2012/05/22 11:07:44 kib Exp $");
+
+#ifndef _DRM_P_H_
+#define _DRM_P_H_
+
+#if defined(_KERNEL) || defined(__KERNEL__)
+
+struct drm_device;
+struct drm_file;
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/sglist.h>
+#include <sys/stat.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/fcntl.h>
+#include <sys/uio.h>
+#include <sys/filio.h>
+#include <sys/selinfo.h>
+#include <sys/sysctl.h>
+#include <sys/bus.h>
+#include <sys/queue.h>
+#include <sys/signalvar.h>
+#include <sys/poll.h>
+#include <sys/sbuf.h>
+#include <sys/taskqueue.h>
+#include <sys/tree.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_param.h>
+#include <vm/vm_phys.h>
+#include <machine/param.h>
+#include <machine/pmap.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#if defined(__i386__) || defined(__amd64__)
+#include <machine/specialreg.h>
+#endif
+#include <machine/sysarch.h>
+#include <sys/endian.h>
+#include <sys/mman.h>
+#include <sys/rman.h>
+#include <sys/memrange.h>
+#include <dev/agp/agpvar.h>
+#include <sys/agpio.h>
+#include <sys/mutex.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <sys/selinfo.h>
+#include <sys/bus.h>
+
+#include <dev/drm2/drm.h>
+#include <dev/drm2/drm_atomic.h>
+#include <dev/drm2/drm_internal.h>
+#include <dev/drm2/drm_linux_list.h>
+#include <dev/drm2/drm_gem_names.h>
+#include <dev/drm2/drm_mm.h>
+#include <dev/drm2/drm_hashtab.h>
+
+#include "opt_drm.h"
+#ifdef DRM_DEBUG
+#undef DRM_DEBUG
+#define DRM_DEBUG_DEFAULT_ON 1
+#endif /* DRM_DEBUG */
+
+#define        DRM_DEBUGBITS_DEBUG             0x1
+#define        DRM_DEBUGBITS_KMS               0x2
+#define        DRM_DEBUGBITS_FAILED_IOCTL      0x4
+
+#undef DRM_LINUX
+#define DRM_LINUX 0
+
+/* driver capabilities and requirements mask */
+#define DRIVER_USE_AGP     0x1
+#define DRIVER_REQUIRE_AGP 0x2
+#define DRIVER_USE_MTRR    0x4
+#define DRIVER_PCI_DMA     0x8
+#define DRIVER_SG          0x10
+#define DRIVER_HAVE_DMA    0x20
+#define DRIVER_HAVE_IRQ    0x40
+#define DRIVER_IRQ_SHARED  0x80
+#define DRIVER_IRQ_VBL     0x100
+#define DRIVER_DMA_QUEUE   0x200
+#define DRIVER_FB_DMA      0x400
+#define DRIVER_IRQ_VBL2    0x800
+#define DRIVER_GEM         0x1000
+#define DRIVER_MODESET     0x2000
+#define DRIVER_USE_PLATFORM_DEVICE  0x4000
+#define        DRIVER_LOCKLESS_IRQ 0x8000
+
+
+#define DRM_HASH_SIZE        16 /* Size of key hash table                */
+#define DRM_KERNEL_CONTEXT    0         /* Change drm_resctx if changed          */
+#define DRM_RESERVED_CONTEXTS 1         /* Change drm_resctx if changed          */
+
+#define        DRM_GEM_MAPPING_MASK    (3ULL << 62)
+#define        DRM_GEM_MAPPING_KEY     (2ULL << 62) /* Non-canonical address form */
+#define        DRM_GEM_MAX_IDX         0x3fffff
+#define        DRM_GEM_MAPPING_IDX(o)  (((o) >> 40) & DRM_GEM_MAX_IDX)
+#define        DRM_GEM_MAPPING_OFF(i)  (((uint64_t)(i)) << 40)
+#define        DRM_GEM_MAPPING_MAPOFF(o) \
+    ((o) & ~(DRM_GEM_MAPPING_OFF(DRM_GEM_MAX_IDX) | DRM_GEM_MAPPING_KEY))
+
+MALLOC_DECLARE(DRM_MEM_DMA);
+MALLOC_DECLARE(DRM_MEM_SAREA);
+MALLOC_DECLARE(DRM_MEM_DRIVER);
+MALLOC_DECLARE(DRM_MEM_MAGIC);
+MALLOC_DECLARE(DRM_MEM_IOCTLS);
+MALLOC_DECLARE(DRM_MEM_MAPS);
+MALLOC_DECLARE(DRM_MEM_BUFS);
+MALLOC_DECLARE(DRM_MEM_SEGS);
+MALLOC_DECLARE(DRM_MEM_PAGES);
+MALLOC_DECLARE(DRM_MEM_FILES);
+MALLOC_DECLARE(DRM_MEM_QUEUES);
+MALLOC_DECLARE(DRM_MEM_CMDS);
+MALLOC_DECLARE(DRM_MEM_MAPPINGS);
+MALLOC_DECLARE(DRM_MEM_BUFLISTS);
+MALLOC_DECLARE(DRM_MEM_AGPLISTS);
+MALLOC_DECLARE(DRM_MEM_CTXBITMAP);
+MALLOC_DECLARE(DRM_MEM_SGLISTS);
+MALLOC_DECLARE(DRM_MEM_DRAWABLE);
+MALLOC_DECLARE(DRM_MEM_MM);
+MALLOC_DECLARE(DRM_MEM_HASHTAB);
+MALLOC_DECLARE(DRM_MEM_KMS);
+
+SYSCTL_DECL(_hw_drm);
+
+#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
+
+                               /* Internal types and structures */
+#define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define DRM_MIN(a,b) ((a)<(b)?(a):(b))
+#define DRM_MAX(a,b) ((a)>(b)?(a):(b))
+
+#define DRM_IF_VERSION(maj, min) (maj << 16 | min)
+
+#define __OS_HAS_AGP   1
+
+#define DRM_DEV_MODE   (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
+#define DRM_DEV_UID    0
+#define DRM_DEV_GID    0
+
+#define wait_queue_head_t      atomic_t
+#define DRM_WAKEUP(w)          wakeup((void *)w)
+#define DRM_WAKEUP_INT(w)      wakeup(w)
+#define DRM_INIT_WAITQUEUE(queue) do {(void)(queue);} while (0)
+
+#define DRM_CURPROC            curthread
+#define DRM_STRUCTPROC         struct thread
+#define DRM_SPINTYPE           struct mtx
+#define DRM_SPININIT(l,name)   mtx_init(l, name, NULL, MTX_DEF)
+#define DRM_SPINUNINIT(l)      mtx_destroy(l)
+#define DRM_SPINLOCK(l)                mtx_lock(l)
+#define DRM_SPINUNLOCK(u)      mtx_unlock(u)
+#define DRM_SPINLOCK_IRQSAVE(l, irqflags) do {         \
+       mtx_lock(l);                                    \
+       (void)irqflags;                                 \
+} while (0)
+#define DRM_SPINUNLOCK_IRQRESTORE(u, irqflags) mtx_unlock(u)
+#define DRM_SPINLOCK_ASSERT(l) mtx_assert(l, MA_OWNED)
+#define DRM_CURRENTPID         curthread->td_proc->p_pid
+#define DRM_LOCK(dev)          sx_xlock(&(dev)->dev_struct_lock)
+#define DRM_UNLOCK(dev)        sx_xunlock(&(dev)->dev_struct_lock)
+#define        DRM_LOCK_SLEEP(dev, chan, flags, msg, timeout)                  \
+    (sx_sleep((chan), &(dev)->dev_struct_lock, (flags), (msg), (timeout)))
+#if defined(INVARIANTS)
+#define        DRM_LOCK_ASSERT(dev)    sx_assert(&(dev)->dev_struct_lock, SA_XLOCKED)
+#define        DRM_UNLOCK_ASSERT(dev)  sx_assert(&(dev)->dev_struct_lock, SA_UNLOCKED)
+#else
+#define        DRM_LOCK_ASSERT(d)
+#define        DRM_UNLOCK_ASSERT(d)
+#endif
+
+#define DRM_SYSCTL_HANDLER_ARGS        (SYSCTL_HANDLER_ARGS)
+
+#define DRM_IRQ_ARGS           void *arg
+typedef void                   irqreturn_t;
+#define IRQ_HANDLED            /* nothing */
+#define IRQ_NONE               /* nothing */
+
+#define unlikely(x)            __builtin_expect(!!(x), 0)
+#define container_of(ptr, type, member) ({                     \
+       __typeof( ((type *)0)->member ) *__mptr = (ptr);        \
+       (type *)( (char *)__mptr - offsetof(type,member) );})
+
+enum {
+       DRM_IS_NOT_AGP,
+       DRM_IS_AGP,
+       DRM_MIGHT_BE_AGP
+};
+#define DRM_AGP_MEM            struct agp_memory_info
+
+#define drm_get_device_from_kdev(_kdev) (_kdev->si_drv1)
+
+#define PAGE_ALIGN(addr) round_page(addr)
+/* DRM_SUSER returns true if the user is superuser */
+#define DRM_SUSER(p)           (priv_check(p, PRIV_DRIVER) == 0)
+#define DRM_AGP_FIND_DEVICE()  agp_find_device()
+#define DRM_MTRR_WC            MDF_WRITECOMBINE
+#define jiffies                        ticks
+#define        jiffies_to_msecs(x)     (((int64_t)(x)) * 1000 / hz)
+#define        msecs_to_jiffies(x)     (((int64_t)(x)) * hz / 1000)
+#define        time_after(a,b)         ((long)(b) - (long)(a) < 0)
+#define        time_after_eq(a,b)      ((long)(b) - (long)(a) <= 0)
+#define drm_msleep(x, msg)     pause((msg), ((int64_t)(x)) * hz / 1000)
+
+typedef vm_paddr_t dma_addr_t;
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+typedef int64_t s64;
+typedef int32_t s32;
+typedef int16_t s16;
+typedef int8_t s8;
+
+/* DRM_READMEMORYBARRIER() prevents reordering of reads.
+ * DRM_WRITEMEMORYBARRIER() prevents reordering of writes.
+ * DRM_MEMORYBARRIER() prevents reordering of reads and writes.
+ */
+#define DRM_READMEMORYBARRIER()                rmb()
+#define DRM_WRITEMEMORYBARRIER()       wmb()
+#define DRM_MEMORYBARRIER()            mb()
+
+#define DRM_READ8(map, offset)                                         \
+       *(volatile u_int8_t *)(((vm_offset_t)(map)->virtual) +          \
+           (vm_offset_t)(offset))
+#define DRM_READ16(map, offset)                                                \
+       le16toh(*(volatile u_int16_t *)(((vm_offset_t)(map)->virtual) + \
+           (vm_offset_t)(offset)))
+#define DRM_READ32(map, offset)                                                \
+       le32toh(*(volatile u_int32_t *)(((vm_offset_t)(map)->virtual) + \
+           (vm_offset_t)(offset)))
+#define DRM_READ64(map, offset)                                                \
+       le64toh(*(volatile u_int64_t *)(((vm_offset_t)(map)->virtual) + \
+           (vm_offset_t)(offset)))
+#define DRM_WRITE8(map, offset, val)                                   \
+       *(volatile u_int8_t *)(((vm_offset_t)(map)->virtual) +          \
+           (vm_offset_t)(offset)) = val
+#define DRM_WRITE16(map, offset, val)                                  \
+       *(volatile u_int16_t *)(((vm_offset_t)(map)->virtual) +         \
+           (vm_offset_t)(offset)) = htole16(val)
+#define DRM_WRITE32(map, offset, val)                                  \
+       *(volatile u_int32_t *)(((vm_offset_t)(map)->virtual) +         \
+           (vm_offset_t)(offset)) = htole32(val)
+#define DRM_WRITE64(map, offset, val)                                  \
+       *(volatile u_int64_t *)(((vm_offset_t)(map)->virtual) +         \
+           (vm_offset_t)(offset)) = htole64(val)
+
+#define DRM_VERIFYAREA_READ( uaddr, size )             \
+       (!useracc(__DECONST(caddr_t, uaddr), size, VM_PROT_READ))
+
+#define DRM_COPY_TO_USER(user, kern, size) \
+       copyout(kern, user, size)
+#define DRM_COPY_FROM_USER(kern, user, size) \
+       copyin(user, kern, size)
+#define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3)         \
+       copyin(arg2, arg1, arg3)
+#define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3)   \
+       copyout(arg2, arg1, arg3)
+#define DRM_GET_USER_UNCHECKED(val, uaddr)             \
+       ((val) = fuword32(uaddr), 0)
+
+#define cpu_to_le32(x) htole32(x)
+#define le32_to_cpu(x) le32toh(x)
+
+#define DRM_HZ                 hz
+#define DRM_UDELAY(udelay)     DELAY(udelay)
+#define DRM_TIME_SLICE         (hz/20)  /* Time slice for GLXContexts    */
+
+#define DRM_GET_PRIV_SAREA(_dev, _ctx, _map) do {      \
+       (_map) = (_dev)->context_sareas[_ctx];          \
+} while(0)
+
+#define LOCK_TEST_WITH_RETURN(dev, file_priv)                          \
+do {                                                                   \
+       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||              \
+            dev->lock.file_priv != file_priv) {                        \
+               DRM_ERROR("%s called without lock held\n",              \
+                          __FUNCTION__);                               \
+               return EINVAL;                                          \
+       }                                                               \
+} while (0)
+
+/* Returns -errno to shared code */
+#define DRM_WAIT_ON( ret, queue, timeout, condition )          \
+for ( ret = 0 ; !ret && !(condition) ; ) {                     \
+       DRM_UNLOCK(dev);                                                \
+       mtx_lock(&dev->irq_lock);                               \
+       if (!(condition))                                       \
+           ret = -mtx_sleep(&(queue), &dev->irq_lock,          \
+               PCATCH, "drmwtq", (timeout));                   \
+       mtx_unlock(&dev->irq_lock);                             \
+       DRM_LOCK(dev);                                          \
+}
+
+#define DRM_ERROR(fmt, ...) \
+       printf("error: [" DRM_NAME ":pid%d:%s] *ERROR* " fmt,           \
+           DRM_CURRENTPID, __func__ , ##__VA_ARGS__)
+
+#define DRM_INFO(fmt, ...)  printf("info: [" DRM_NAME "] " fmt , ##__VA_ARGS__)
+
+#define DRM_DEBUG(fmt, ...) do {                                       \
+       if ((drm_debug_flag & DRM_DEBUGBITS_DEBUG) != 0)                \
+               printf("[" DRM_NAME ":pid%d:%s] " fmt, DRM_CURRENTPID,  \
+                       __func__ , ##__VA_ARGS__);                      \
+} while (0)
+
+#define DRM_DEBUG_KMS(fmt, ...) do {                                   \
+       if ((drm_debug_flag & DRM_DEBUGBITS_KMS) != 0)                  \
+               printf("[" DRM_NAME ":KMS:pid%d:%s] " fmt, DRM_CURRENTPID,\
+                       __func__ , ##__VA_ARGS__);                      \
+} while (0)
+
+#define DRM_DEBUG_DRIVER(fmt, ...) do {                                        \
+       if ((drm_debug_flag & DRM_DEBUGBITS_KMS) != 0)                  \
+               printf("[" DRM_NAME ":KMS:pid%d:%s] " fmt, DRM_CURRENTPID,\
+                       __func__ , ##__VA_ARGS__);                      \
+} while (0)
+
+typedef struct drm_pci_id_list
+{
+       int vendor;
+       int device;
+       long driver_private;
+       char *name;
+} drm_pci_id_list_t;
+
+struct drm_msi_blacklist_entry
+{
+       int vendor;
+       int device;
+};
+
+#define DRM_AUTH       0x1
+#define DRM_MASTER     0x2
+#define DRM_ROOT_ONLY  0x4
+#define DRM_CONTROL_ALLOW 0x8
+#define DRM_UNLOCKED   0x10
+
+typedef struct drm_ioctl_desc {
+       unsigned long cmd;
+       int (*func)(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv);
+       int flags;
+} drm_ioctl_desc_t;
+/**
+ * Creates a driver or general drm_ioctl_desc array entry for the given
+ * ioctl, for use by drm_ioctl().
+ */
+#define DRM_IOCTL_DEF(ioctl, func, flags) \
+       [DRM_IOCTL_NR(ioctl)] = {ioctl, func, flags}
+
+typedef struct drm_magic_entry {
+       drm_magic_t            magic;
+       struct drm_file        *priv;
+       struct drm_magic_entry *next;
+} drm_magic_entry_t;
+
+typedef struct drm_magic_head {
+       struct drm_magic_entry *head;
+       struct drm_magic_entry *tail;
+} drm_magic_head_t;
+
+typedef struct drm_buf {
+       int               idx;         /* Index into master buflist          */
+       int               total;       /* Buffer size                        */
+       int               order;       /* log-base-2(total)                  */
+       int               used;        /* Amount of buffer in use (for DMA)  */
+       unsigned long     offset;      /* Byte offset (used internally)      */
+       void              *address;    /* Address of buffer                  */
+       unsigned long     bus_address; /* Bus address of buffer              */
+       struct drm_buf    *next;       /* Kernel-only: used for free list    */
+       __volatile__ int  pending;     /* On hardware DMA queue              */
+       struct drm_file   *file_priv;  /* Unique identifier of holding process */
+       int               context;     /* Kernel queue for this buffer       */
+       enum {
+               DRM_LIST_NONE    = 0,
+               DRM_LIST_FREE    = 1,
+               DRM_LIST_WAIT    = 2,
+               DRM_LIST_PEND    = 3,
+               DRM_LIST_PRIO    = 4,
+               DRM_LIST_RECLAIM = 5
+       }                 list;        /* Which list we're on                */
+
+       int               dev_priv_size; /* Size of buffer private stoarge   */
+       void              *dev_private;  /* Per-buffer private storage       */
+} drm_buf_t;
+
+typedef struct drm_freelist {
+       int               initialized; /* Freelist in use                  */
+       atomic_t          count;       /* Number of free buffers           */
+       drm_buf_t         *next;       /* End pointer                      */
+
+       int               low_mark;    /* Low water mark                   */
+       int               high_mark;   /* High water mark                  */
+} drm_freelist_t;
+
+typedef struct drm_dma_handle {
+       void *vaddr;
+       bus_addr_t busaddr;
+       bus_dma_tag_t tag;
+       bus_dmamap_t map;
+} drm_dma_handle_t;
+
+typedef struct drm_buf_entry {
+       int               buf_size;
+       int               buf_count;
+       drm_buf_t         *buflist;
+       int               seg_count;
+       drm_dma_handle_t  **seglist;
+       int               page_order;
+
+       drm_freelist_t    freelist;
+} drm_buf_entry_t;
+
+/* Event queued up for userspace to read */
+struct drm_pending_event {
+       struct drm_event *event;
+       struct list_head link;
+       struct drm_file *file_priv;
+       pid_t pid; /* pid of requester, no guarantee it's valid by the time
+                     we deliver the event, for tracing only */
+       void (*destroy)(struct drm_pending_event *event);
+};
+
+typedef TAILQ_HEAD(drm_file_list, drm_file) drm_file_list_t;
+struct drm_file {
+       TAILQ_ENTRY(drm_file) link;
+       struct drm_device *dev;
+       int               authenticated;
+       int               master;
+       pid_t             pid;
+       uid_t             uid;
+       drm_magic_t       magic;
+       unsigned long     ioctl_count;
+
+       void             *driver_priv;
+       struct drm_gem_names object_names;
+
+       int               is_master;
+       struct drm_master *masterp;
+
+       struct list_head  fbs;
+
+       struct list_head  event_list;
+       int               event_space;
+       struct selinfo    event_poll;
+};
+
+typedef struct drm_lock_data {
+       struct drm_hw_lock      *hw_lock;       /* Hardware lock                   */
+       struct drm_file   *file_priv;   /* Unique identifier of holding process (NULL is kernel)*/
+       int               lock_queue;   /* Queue of blocked processes      */
+       unsigned long     lock_time;    /* Time of last lock in jiffies    */
+} drm_lock_data_t;
+
+/* This structure, in the struct drm_device, is always initialized while the
+ * device
+ * is open.  dev->dma_lock protects the incrementing of dev->buf_use, which
+ * when set marks that no further bufs may be allocated until device teardown
+ * occurs (when the last open of the device has closed).  The high/low
+ * watermarks of bufs are only touched by the X Server, and thus not
+ * concurrently accessed, so no locking is needed.
+ */
+typedef struct drm_device_dma {
+       drm_buf_entry_t   bufs[DRM_MAX_ORDER+1];
+       int               buf_count;
+       drm_buf_t         **buflist;    /* Vector of pointers info bufs    */
+       int               seg_count;
+       int               page_count;
+       unsigned long     *pagelist;
+       unsigned long     byte_count;
+       enum {
+               _DRM_DMA_USE_AGP = 0x01,
+               _DRM_DMA_USE_SG  = 0x02
+       } flags;
+} drm_device_dma_t;
+
+typedef struct drm_agp_mem {
+       void               *handle;
+       unsigned long      bound; /* address */
+       int                pages;
+       struct drm_agp_mem *prev;
+       struct drm_agp_mem *next;
+} drm_agp_mem_t;
+
+typedef struct drm_agp_head {
+       device_t           agpdev;
+       struct agp_info    info;
+       const char         *chipset;
+       drm_agp_mem_t      *memory;
+       unsigned long      mode;
+       int                enabled;
+       int                acquired;
+       unsigned long      base;
+       int                mtrr;
+       int                cant_use_aperture;
+       unsigned long      page_mask;
+} drm_agp_head_t;
+
+typedef struct drm_sg_mem {
+       vm_offset_t vaddr;
+       vm_paddr_t *busaddr;
+       vm_pindex_t pages;
+} drm_sg_mem_t;
+
+#define DRM_MAP_HANDLE_BITS    (sizeof(void *) == 4 ? 4 : 24)
+#define DRM_MAP_HANDLE_SHIFT   (sizeof(void *) * 8 - DRM_MAP_HANDLE_BITS)
+typedef TAILQ_HEAD(drm_map_list, drm_local_map) drm_map_list_t;
+
+typedef struct drm_local_map {
+       unsigned long offset;     /* Physical address (0 for SAREA)       */
+       unsigned long size;       /* Physical size (bytes)                */
+       enum drm_map_type type;   /* Type of memory mapped                */
+       enum drm_map_flags flags; /* Flags                                */
+       void *handle;             /* User-space: "Handle" to pass to mmap */
+                                 /* Kernel-space: kernel-virtual address */
+       int mtrr;                 /* Boolean: MTRR used                   */
+                                 /* Private data                         */
+       int rid;                  /* PCI resource ID for bus_space        */
+       void *virtual;            /* Kernel-space: kernel-virtual address */
+       struct resource *bsr;
+       bus_space_tag_t bst;
+       bus_space_handle_t bsh;
+       drm_dma_handle_t *dmah;
+       TAILQ_ENTRY(drm_local_map) link;
+} drm_local_map_t;
+
+struct drm_vblank_info {
+       wait_queue_head_t queue;        /* vblank wait queue */
+       atomic_t count;                 /* number of VBLANK interrupts */
+                                       /* (driver must alloc the right number of counters) */
+       atomic_t refcount;              /* number of users of vblank interrupts */
+       u32 last;                       /* protected by dev->vbl_lock, used */
+                                       /* for wraparound handling */
+       int enabled;                    /* so we don't call enable more than */
+                                       /* once per disable */
+       int inmodeset;                  /* Display driver is setting mode */
+};
+
+/* Size of ringbuffer for vblank timestamps. Just double-buffer
+ * in initial implementation.
+ */
+#define DRM_VBLANKTIME_RBSIZE 2
+
+/* Flags and return codes for get_vblank_timestamp() driver function. */
+#define DRM_CALLED_FROM_VBLIRQ 1
+#define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0)
+#define DRM_VBLANKTIME_INVBL             (1 << 1)
+
+/* get_scanout_position() return flags */
+#define DRM_SCANOUTPOS_VALID        (1 << 0)
+#define DRM_SCANOUTPOS_INVBL        (1 << 1)
+#define DRM_SCANOUTPOS_ACCURATE     (1 << 2)
+
+/* location of GART table */
+#define DRM_ATI_GART_MAIN 1
+#define DRM_ATI_GART_FB   2
+
+#define DRM_ATI_GART_PCI  1
+#define DRM_ATI_GART_PCIE 2
+#define DRM_ATI_GART_IGP  3
+
+struct drm_ati_pcigart_info {
+       int gart_table_location;
+       int gart_reg_if;
+       void *addr;
+       dma_addr_t bus_addr;
+       dma_addr_t table_mask;
+       dma_addr_t member_mask;
+       struct drm_dma_handle *table_handle;
+       drm_local_map_t mapping;
+       int table_size;
+       struct drm_dma_handle *dmah; /* handle for ATI PCIGART table */
+};
+
+typedef vm_paddr_t resource_size_t;
+
+/**
+ * GEM specific mm private for tracking GEM objects
+ */
+struct drm_gem_mm {
+       struct drm_open_hash offset_hash; /**< User token hash table for maps */
+       struct unrhdr *idxunr;
+};
+
+struct drm_gem_object {
+       /** Reference count of this object */
+       u_int refcount;
+
+       /** Handle count of this object. Each handle also holds a reference */
+       u_int handle_count; /* number of handles on this object */
+
+       /** Related drm device */
+       struct drm_device *dev;
+
+       /** File representing the shmem storage: filp in Linux parlance */
+       vm_object_t vm_obj;
+
+       bool on_map;
+       struct drm_hash_item map_list;
+
+       /**
+        * Size of the object, in bytes.  Immutable over the object's
+        * lifetime.
+        */
+       size_t size;
+
+       /**
+        * Global name for this object, starts at 1. 0 means unnamed.
+        * Access is covered by the object_name_lock in the related drm_device
+        */
+       int name;
+
+       /**
+        * Memory domains. These monitor which caches contain read/write data
+        * related to the object. When transitioning from one set of domains
+        * to another, the driver is called to ensure that caches are suitably
+        * flushed and invalidated
+        */
+       uint32_t read_domains;
+       uint32_t write_domain;
+
+       /**
+        * While validating an exec operation, the
+        * new read/write domain values are computed here.
+        * They will be transferred to the above values
+        * at the point that any cache flushing occurs
+        */
+       uint32_t pending_read_domains;
+       uint32_t pending_write_domain;
+
+       void *driver_private;
+};
+
+#include "drm_crtc.h"
+
+#ifndef DMA_BIT_MASK
+#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : (1ULL<<(n)) - 1)
+#endif
+
+#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
+
+struct drm_driver_info {
+       int     (*load)(struct drm_device *, unsigned long flags);
+       int     (*firstopen)(struct drm_device *);
+       int     (*open)(struct drm_device *, struct drm_file *);
+       void    (*preclose)(struct drm_device *, struct drm_file *file_priv);
+       void    (*postclose)(struct drm_device *, struct drm_file *);
+       void    (*lastclose)(struct drm_device *);
+       int     (*unload)(struct drm_device *);
+       void    (*reclaim_buffers_locked)(struct drm_device *,
+                                         struct drm_file *file_priv);
+       int     (*dma_ioctl)(struct drm_device *dev, void *data,
+                            struct drm_file *file_priv);
+       void    (*dma_ready)(struct drm_device *);
+       int     (*dma_quiescent)(struct drm_device *);
+       int     (*dma_flush_block_and_flush)(struct drm_device *, int context,
+                                            enum drm_lock_flags flags);
+       int     (*dma_flush_unblock)(struct drm_device *, int context,
+                                    enum drm_lock_flags flags);
+       int     (*context_ctor)(struct drm_device *dev, int context);
+       int     (*context_dtor)(struct drm_device *dev, int context);
+       int     (*kernel_context_switch)(struct drm_device *dev, int old,
+                                        int new);
+       int     (*kernel_context_switch_unlock)(struct drm_device *dev);
+       void    (*irq_preinstall)(struct drm_device *dev);
+       int     (*irq_postinstall)(struct drm_device *dev);
+       void    (*irq_uninstall)(struct drm_device *dev);
+       void    (*irq_handler)(DRM_IRQ_ARGS);
+
+       u32     (*get_vblank_counter)(struct drm_device *dev, int crtc);
+       int     (*enable_vblank)(struct drm_device *dev, int crtc);
+       void    (*disable_vblank)(struct drm_device *dev, int crtc);
+       int     (*get_scanout_position)(struct drm_device *dev, int crtc,
+                   int *vpos, int *hpos);
+
+       int     (*get_vblank_timestamp)(struct drm_device *dev, int crtc,
+                   int *max_error, struct timeval *vblank_time,
+                   unsigned flags);
+
+       int     (*gem_init_object)(struct drm_gem_object *obj);
+       void    (*gem_free_object)(struct drm_gem_object *obj);
+
+       struct cdev_pager_ops *gem_pager_ops;
+
+       int     (*dumb_create)(struct drm_file *file_priv,
+                   struct drm_device *dev, struct drm_mode_create_dumb *args);
+       int     (*dumb_map_offset)(struct drm_file *file_priv,
+                   struct drm_device *dev, uint32_t handle, uint64_t *offset);
+       int     (*dumb_destroy)(struct drm_file *file_priv,
+                   struct drm_device *dev, uint32_t handle);
+
+       int     (*sysctl_init)(struct drm_device *dev,
+                   struct sysctl_ctx_list *ctx, struct sysctl_oid *top);
+       void    (*sysctl_cleanup)(struct drm_device *dev);
+
+       drm_pci_id_list_t *id_entry;    /* PCI ID, name, and chipset private */
+
+       /**
+        * Called by \c drm_device_is_agp.  Typically used to determine if a
+        * card is really attached to AGP or not.
+        *
+        * \param dev  DRM device handle
+        *
+        * \returns 
+        * One of three values is returned depending on whether or not the
+        * card is absolutely \b not AGP (return of 0), absolutely \b is AGP
+        * (return of 1), or may or may not be AGP (return of 2).
+        */
+       int     (*device_is_agp) (struct drm_device * dev);
+
+       drm_ioctl_desc_t *ioctls;
+       int     max_ioctl;
+
+       int     buf_priv_size;
+
+       int     major;
+       int     minor;
+       int     patchlevel;
+       const char *name;               /* Simple driver name              */
+       const char *desc;               /* Longer driver name              */
+       const char *date;               /* Date of last major changes.     */
+
+       u32 driver_features;
+};
+
+/**
+ * DRM minor structure. This structure represents a drm minor number.
+ */
+struct drm_minor {
+       int index;                      /**< Minor device number */
+       int type;                       /**< Control or render */
+       device_t kdev;                  /**< OS device */
+       struct drm_device *dev;
+
+       struct drm_master *master; /* currently active master for this node */
+       struct list_head master_list;
+       struct drm_mode_group mode_group;
+};
+
+/* mode specified on the command line */
+struct drm_cmdline_mode {
+       bool specified;
+       bool refresh_specified;
+       bool bpp_specified;
+       int xres, yres;
+       int bpp;
+       int refresh;
+       bool rb;
+       bool interlace;
+       bool cvt;
+       bool margins;
+       enum drm_connector_force force;
+};
+
+struct drm_pending_vblank_event {
+       struct drm_pending_event base;
+       int pipe;
+       struct drm_event_vblank event;
+};
+
+/* Length for the array of resource pointers for drm_get_resource_*. */
+#define DRM_MAX_PCI_RESOURCE   6
+
+/** 
+ * DRM device functions structure
+ */
+struct drm_device {
+       struct drm_driver_info *driver;
+       drm_pci_id_list_t *id_entry;    /* PCI ID, name, and chipset private */
+
+       u_int16_t pci_device;           /* PCI device id */
+       u_int16_t pci_vendor;           /* PCI vendor id */
+
+       char              *unique;      /* Unique identifier: e.g., busid  */
+       int               unique_len;   /* Length of unique field          */
+       device_t          device;       /* Device instance from newbus     */
+       struct cdev       *devnode;     /* Device number for mknod         */
+       int               if_version;   /* Highest interface version set */
+
+       int               flags;        /* Flags to open(2)                */
+
+                               /* Locks */
+       struct mtx        dma_lock;     /* protects dev->dma */
+       struct mtx        irq_lock;     /* protects irq condition checks */
+       struct mtx        dev_lock;     /* protects everything else */
+       struct sx         dev_struct_lock;
+       DRM_SPINTYPE      drw_lock;
+
+                               /* Usage Counters */
+       int               open_count;   /* Outstanding files open          */
+       int               buf_use;      /* Buffers in use -- cannot alloc  */
+
+                               /* Performance counters */
+       unsigned long     counters;
+       enum drm_stat_type      types[15];
+       atomic_t          counts[15];
+
+                               /* Authentication */
+       drm_file_list_t   files;
+       drm_magic_head_t  magiclist[DRM_HASH_SIZE];
+
+       /* Linked list of mappable regions. Protected by dev_lock */
+       drm_map_list_t    maplist;
+       struct unrhdr     *map_unrhdr;
+
+       drm_local_map_t   **context_sareas;
+       int               max_context;
+
+       drm_lock_data_t   lock;         /* Information on hardware lock    */
+
+                               /* DMA queues (contexts) */
+       drm_device_dma_t  *dma;         /* Optional pointer for DMA support */
+
+                               /* Context support */
+       int               irq;          /* Interrupt used by board         */
+       int               irq_enabled;  /* True if the irq handler is enabled */
+       int               msi_enabled;  /* MSI enabled */
+       int               irqrid;       /* Interrupt used by board */
+       struct resource   *irqr;        /* Resource for interrupt used by board    */
+       void              *irqh;        /* Handle from bus_setup_intr      */
+
+       /* Storage of resource pointers for drm_get_resource_* */
+       struct resource   *pcir[DRM_MAX_PCI_RESOURCE];
+       int               pcirid[DRM_MAX_PCI_RESOURCE];
+
+       int               pci_domain;
+       int               pci_bus;
+       int               pci_slot;
+       int               pci_func;
+
+       atomic_t          context_flag; /* Context swapping flag           */
+       int               last_context; /* Last current context            */
+
+       int               num_crtcs;
+
+       struct sigio      *buf_sigio;   /* Processes waiting for SIGIO     */
+
+                               /* Sysctl support */
+       struct drm_sysctl_info *sysctl;
+       int               sysctl_node_idx;
+
+       drm_agp_head_t    *agp;
+       drm_sg_mem_t      *sg;  /* Scatter gather memory */
+       atomic_t          *ctx_bitmap;
+       void              *dev_private;
+       unsigned int      agp_buffer_token;
+       drm_local_map_t   *agp_buffer_map;
+
+       struct drm_minor *control;              /**< Control node for card */
+       struct drm_minor *primary;              /**< render type primary screen head */
+
+       struct unrhdr     *drw_unrhdr;
+       /* RB tree of drawable infos */
+       RB_HEAD(drawable_tree, bsd_drm_drawable_info) drw_head;
+
+       int vblank_disable_allowed;
+
+       atomic_t *_vblank_count;        /**< number of VBLANK interrupts (driver must alloc the right number of counters) */
+       struct timeval *_vblank_time;   /**< timestamp of current vblank_count (drivers must alloc right number of fields) */
+       struct mtx vblank_time_lock;    /**< Protects vblank count and time updates during vblank enable/disable */
+       struct mtx vbl_lock;
+       atomic_t *vblank_refcount;      /* number of users of vblank interruptsper crtc */
+       u32 *last_vblank;               /* protected by dev->vbl_lock, used */
+                                       /* for wraparound handling */
+       int *vblank_enabled;            /* so we don't call enable more than
+                                          once per disable */
+       int *vblank_inmodeset;          /* Display driver is setting mode */
+       u32 *last_vblank_wait;          /* Last vblank seqno waited per CRTC */
+       struct callout vblank_disable_callout;
+
+       u32 max_vblank_count;           /**< size of vblank counter register */
+
+       struct list_head vblank_event_list;
+       struct mtx       event_lock;
+
+        struct drm_mode_config mode_config;    /**< Current mode config */
+
+       /* GEM part */
+       struct sx         object_name_lock;
+       struct drm_gem_names object_names;
+       void             *mm_private;
+
+       void *sysctl_private;
+       char busid_str[128];
+       int modesetting;
+};
+
+static __inline__ int drm_core_check_feature(struct drm_device *dev,
+                                            int feature)
+{
+       return ((dev->driver->driver_features & feature) ? 1 : 0);
+}
+
+#if __OS_HAS_AGP
+static inline int drm_core_has_AGP(struct drm_device *dev)
+{
+       return drm_core_check_feature(dev, DRIVER_USE_AGP);
+}
+#else
+#define drm_core_has_AGP(dev) (0)
+#endif
+
+enum dmi_field {
+        DMI_NONE,
+        DMI_BIOS_VENDOR,
+        DMI_BIOS_VERSION,
+        DMI_BIOS_DATE,
+        DMI_SYS_VENDOR,
+        DMI_PRODUCT_NAME,
+        DMI_PRODUCT_VERSION,
+        DMI_PRODUCT_SERIAL,
+        DMI_PRODUCT_UUID,
+        DMI_BOARD_VENDOR,
+        DMI_BOARD_NAME,
+        DMI_BOARD_VERSION,
+        DMI_BOARD_SERIAL,
+        DMI_BOARD_ASSET_TAG,
+        DMI_CHASSIS_VENDOR,
+        DMI_CHASSIS_TYPE,
+        DMI_CHASSIS_VERSION,
+        DMI_CHASSIS_SERIAL,
+        DMI_CHASSIS_ASSET_TAG,
+        DMI_STRING_MAX,
+};
+
+struct dmi_strmatch {
+       unsigned char slot;
+       char substr[79];
+};
+
+struct dmi_system_id {
+        int (*callback)(const struct dmi_system_id *);
+        const char *ident;
+        struct dmi_strmatch matches[4];
+};
+#define        DMI_MATCH(a, b) {(a), (b)}
+bool dmi_check_system(const struct dmi_system_id *);
+
+extern int     drm_debug_flag;
+extern int     drm_notyet_flag;
+extern unsigned int drm_vblank_offdelay;
+extern unsigned int drm_timestamp_precision;
+
+/* Device setup support (drm_drv.c) */
+int    drm_probe(device_t kdev, drm_pci_id_list_t *idlist);
+int    drm_attach(device_t kdev, drm_pci_id_list_t *idlist);
+int    drm_create_cdevs(device_t kdev);
+void   drm_close(void *data);
+int    drm_detach(device_t kdev);
+d_ioctl_t drm_ioctl;
+d_open_t drm_open;
+d_read_t drm_read;
+d_poll_t drm_poll;
+d_mmap_t drm_mmap;
+extern drm_local_map_t *drm_getsarea(struct drm_device *dev);
+
+void drm_event_wakeup(struct drm_pending_event *e);
+
+int drm_add_busid_modesetting(struct drm_device *dev,
+    struct sysctl_ctx_list *ctx, struct sysctl_oid *top);
+
+/* File operations helpers (drm_fops.c) */
+extern int             drm_open_helper(struct cdev *kdev, int flags, int fmt,
+                                        DRM_STRUCTPROC *p,
+                                       struct drm_device *dev);
+
+/* Memory management support (drm_memory.c) */
+void   drm_mem_init(void);
+void   drm_mem_uninit(void);
+void   *drm_ioremap_wc(struct drm_device *dev, drm_local_map_t *map);
+void   *drm_ioremap(struct drm_device *dev, drm_local_map_t *map);
+void   drm_ioremapfree(drm_local_map_t *map);
+int    drm_mtrr_add(unsigned long offset, size_t size, int flags);
+int    drm_mtrr_del(int handle, unsigned long offset, size_t size, int flags);
+
+int    drm_context_switch(struct drm_device *dev, int old, int new);
+int    drm_context_switch_complete(struct drm_device *dev, int new);
+
+int    drm_ctxbitmap_init(struct drm_device *dev);
+void   drm_ctxbitmap_cleanup(struct drm_device *dev);
+void   drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle);
+int    drm_ctxbitmap_next(struct drm_device *dev);
+
+/* Locking IOCTL support (drm_lock.c) */
+int    drm_lock_take(struct drm_lock_data *lock_data,
+                     unsigned int context);
+int    drm_lock_transfer(struct drm_lock_data *lock_data,
+                         unsigned int context);
+int    drm_lock_free(struct drm_lock_data *lock_data,
+                     unsigned int context);
+
+/* Buffer management support (drm_bufs.c) */
+unsigned long drm_get_resource_start(struct drm_device *dev,
+                                    unsigned int resource);
+unsigned long drm_get_resource_len(struct drm_device *dev,
+                                  unsigned int resource);
+void   drm_rmmap(struct drm_device *dev, drm_local_map_t *map);
+int    drm_order(unsigned long size);
+int    drm_addmap(struct drm_device *dev, unsigned long offset,
+                  unsigned long size,
+                  enum drm_map_type type, enum drm_map_flags flags,
+                  drm_local_map_t **map_ptr);
+int    drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request);
+int    drm_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request);
+int    drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request);
+
+/* DMA support (drm_dma.c) */
+int    drm_dma_setup(struct drm_device *dev);
+void   drm_dma_takedown(struct drm_device *dev);
+void   drm_free_buffer(struct drm_device *dev, drm_buf_t *buf);
+void   drm_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv);
+#define drm_core_reclaim_buffers drm_reclaim_buffers
+
+/* IRQ support (drm_irq.c) */
+int    drm_irq_install(struct drm_device *dev);
+int    drm_irq_uninstall(struct drm_device *dev);
+irqreturn_t drm_irq_handler(DRM_IRQ_ARGS);
+void   drm_driver_irq_preinstall(struct drm_device *dev);
+void   drm_driver_irq_postinstall(struct drm_device *dev);
+void   drm_driver_irq_uninstall(struct drm_device *dev);
+
+void   drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
+void   drm_vblank_post_modeset(struct drm_device *dev, int crtc);
+int    drm_modeset_ctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+
+extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
+extern int drm_wait_vblank(struct drm_device *dev, void *data,
+                          struct drm_file *filp);
+extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
+extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
+extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
+                                    struct timeval *vblanktime);
+extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
+void drm_handle_vblank_events(struct drm_device *dev, int crtc);
+extern int drm_vblank_get(struct drm_device *dev, int crtc);
+extern void drm_vblank_put(struct drm_device *dev, int crtc);
+extern void drm_vblank_off(struct drm_device *dev, int crtc);
+extern void drm_vblank_cleanup(struct drm_device *dev);
+extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
+                                    struct timeval *tvblank, unsigned flags);
+extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
+                                                int crtc, int *max_error,
+                                                struct timeval *vblank_time,
+                                                unsigned flags,
+                                                struct drm_crtc *refcrtc);
+extern void drm_calc_timestamping_constants(struct drm_crtc *crtc);
+
+struct timeval ns_to_timeval(const int64_t nsec);
+int64_t timeval_to_ns(const struct timeval *tv);
+
+/* AGP/PCI Express/GART support (drm_agpsupport.c) */
+int    drm_device_is_agp(struct drm_device *dev);
+int    drm_device_is_pcie(struct drm_device *dev);
+drm_agp_head_t *drm_agp_init(void);
+int    drm_agp_acquire(struct drm_device *dev);
+int    drm_agp_release(struct drm_device *dev);
+int    drm_agp_info(struct drm_device * dev, struct drm_agp_info *info);
+int    drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode);
+void   *drm_agp_allocate_memory(size_t pages, u32 type);
+int    drm_agp_free_memory(void *handle);
+int    drm_agp_bind_memory(void *handle, off_t start);
+int    drm_agp_unbind_memory(void *handle);
+int    drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request);
+int    drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request);
+int    drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request);
+int    drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request);
+
+/* Scatter Gather Support (drm_scatter.c) */
+void   drm_sg_cleanup(drm_sg_mem_t *entry);
+int    drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request);
+
+/* sysctl support (drm_sysctl.h) */
+extern int             drm_sysctl_init(struct drm_device *dev);
+extern int             drm_sysctl_cleanup(struct drm_device *dev);
+
+/* ATI PCIGART support (ati_pcigart.c) */
+int    drm_ati_pcigart_init(struct drm_device *dev,
+                               struct drm_ati_pcigart_info *gart_info);
+int    drm_ati_pcigart_cleanup(struct drm_device *dev,
+                               struct drm_ati_pcigart_info *gart_info);
+
+/* Cache management (drm_memory.c) */
+void   drm_clflush_pages(vm_page_t *pages, unsigned long num_pages);
+
+/* Locking IOCTL support (drm_drv.c) */
+int    drm_lock(struct drm_device *dev, void *data,
+                struct drm_file *file_priv);
+int    drm_unlock(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv);
+int    drm_version(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv);
+int    drm_setversion(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv);
+
+/* Misc. IOCTL support (drm_ioctl.c) */
+int    drm_irq_by_busid(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+int    drm_getunique(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+int    drm_setunique(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+int    drm_getmap(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv);
+int    drm_getclient(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+int    drm_getstats(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv);
+int    drm_getcap(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv);
+int    drm_noop(struct drm_device *dev, void *data,
+                struct drm_file *file_priv);
+
+/* Context IOCTL support (drm_context.c) */
+int    drm_resctx(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv);
+int    drm_addctx(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv);
+int    drm_modctx(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv);
+int    drm_getctx(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv);
+int    drm_switchctx(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+int    drm_newctx(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv);
+int    drm_rmctx(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv);
+int    drm_setsareactx(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int    drm_getsareactx(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+
+/* Drawable IOCTL support (drm_drawable.c) */
+int    drm_adddraw(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv);
+int    drm_rmdraw(struct drm_device *dev, void *data,
+                  struct drm_file *file_priv);
+int    drm_update_draw(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev,
+                                               int handle);
+
+/* Drawable support (drm_drawable.c) */
+void drm_drawable_free_all(struct drm_device *dev);
+
+/* Authentication IOCTL support (drm_auth.c) */
+int    drm_getmagic(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv);
+int    drm_authmagic(struct drm_device *dev, void *data,
+                     struct drm_file *file_priv);
+
+/* Buffer management support (drm_bufs.c) */
+int    drm_addmap_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+int    drm_rmmap_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int    drm_addbufs(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv);
+int    drm_infobufs(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv);
+int    drm_markbufs(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv);
+int    drm_freebufs(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv);
+int    drm_mapbufs(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv);
+
+/* DMA support (drm_dma.c) */
+int    drm_dma(struct drm_device *dev, void *data, struct drm_file *file_priv);
+
+/* IRQ support (drm_irq.c) */
+int    drm_control(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv);
+
+/* AGP/GART support (drm_agpsupport.c) */
+int    drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv);
+int    drm_agp_release_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv);
+int    drm_agp_enable_ioctl(struct drm_device *dev, void *data,
+                            struct drm_file *file_priv);
+int    drm_agp_info_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
+int    drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
+                           struct drm_file *file_priv);
+int    drm_agp_free_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
+int    drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
+                            struct drm_file *file_priv);
+int    drm_agp_bind_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
+
+                               /* Stub support (drm_stub.h) */
+extern int drm_setmaster_ioctl(struct drm_device *dev, void *data,
+                              struct drm_file *file_priv);
+extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv);
+
+/* Scatter Gather Support (drm_scatter.c) */
+int    drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
+int    drm_sg_free(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv);
+
+/* consistent PCI memory functions (drm_pci.c) */
+drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size,
+                               size_t align, dma_addr_t maxaddr);
+void   drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah);
+
+/* Graphics Execution Manager library functions (drm_gem.c) */
+int drm_gem_init(struct drm_device *dev);
+void drm_gem_destroy(struct drm_device *dev);
+
+int drm_gem_close_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int drm_gem_flink_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int drm_gem_open_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv);
+int drm_gem_handle_create(struct drm_file *file_priv,
+                         struct drm_gem_object *obj,
+                         u32 *handlep);
+int drm_gem_handle_delete(struct drm_file *file_priv, uint32_t handle);
+void drm_gem_object_handle_reference(struct drm_gem_object *obj);
+void drm_gem_object_handle_unreference(struct drm_gem_object *obj);
+void drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj);
+void drm_gem_object_handle_free(struct drm_gem_object *obj);
+void drm_gem_object_reference(struct drm_gem_object *obj);
+void drm_gem_object_unreference(struct drm_gem_object *obj);
+void drm_gem_object_unreference_unlocked(struct drm_gem_object *obj);
+void drm_gem_object_release(struct drm_gem_object *obj);
+void drm_gem_object_free(struct drm_gem_object *obj);
+int drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj,
+    size_t size);
+int drm_gem_private_object_init(struct drm_device *dev,
+    struct drm_gem_object *obj, size_t size);
+struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev,
+    size_t size);
+struct drm_gem_object *drm_gem_object_lookup(struct drm_device *dev,
+    struct drm_file *file_priv, uint32_t handle);
+
+void drm_gem_open(struct drm_device *dev, struct drm_file *file_priv);
+void drm_gem_release(struct drm_device *dev, struct drm_file *file_priv);
+
+int drm_gem_create_mmap_offset(struct drm_gem_object *obj);
+void drm_gem_free_mmap_offset(struct drm_gem_object *obj);
+int drm_gem_mmap_single(struct cdev *kdev, vm_ooffset_t *offset, vm_size_t size,
+    struct vm_object **obj_res, int nprot);
+void drm_gem_pager_dtr(void *obj);
+
+void drm_device_lock_mtx(struct drm_device *dev);
+void drm_device_unlock_mtx(struct drm_device *dev);
+int drm_device_sleep_mtx(struct drm_device *dev, void *chan, int flags,
+    const char *msg, int timeout);
+void drm_device_assert_mtx_locked(struct drm_device *dev);
+void drm_device_assert_mtx_unlocked(struct drm_device *dev);
+
+void drm_device_lock_struct(struct drm_device *dev);
+void drm_device_unlock_struct(struct drm_device *dev);
+int drm_device_sleep_struct(struct drm_device *dev, void *chan, int flags,
+    const char *msg, int timeout);
+void drm_device_assert_struct_locked(struct drm_device *dev);
+void drm_device_assert_struct_unlocked(struct drm_device *dev);
+
+void drm_compat_locking_init(struct drm_device *dev);
+void drm_sleep_locking_init(struct drm_device *dev);
+
+/* drm_modes.c */
+bool drm_mode_parse_command_line_for_connector(const char *mode_option,
+    struct drm_connector *connector, struct drm_cmdline_mode *mode);
+struct drm_display_mode *drm_mode_create_from_cmdline_mode(
+    struct drm_device *dev, struct drm_cmdline_mode *cmd);
+
+/* drm_edid.c */
+u8 *drm_find_cea_extension(struct edid *edid);
+
+/* Inline replacements for drm_alloc and friends */
+static __inline__ void *
+drm_alloc(size_t size, struct malloc_type *area)
+{
+       return malloc(size, area, M_NOWAIT);
+}
+
+static __inline__ void *
+drm_calloc(size_t nmemb, size_t size, struct malloc_type *area)
+{
+       return malloc(size * nmemb, area, M_NOWAIT | M_ZERO);
+}
+
+static __inline__ void *
+drm_realloc(void *oldpt, size_t oldsize, size_t size,
+    struct malloc_type *area)
+{
+       return reallocf(oldpt, size, area, M_NOWAIT);
+}
+
+static __inline__ void
+drm_free(void *pt, size_t size, struct malloc_type *area)
+{
+       free(pt, area);
+}
+
+/* Inline replacements for DRM_IOREMAP macros */
+static __inline__ void
+drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev)
+{
+       map->virtual = drm_ioremap_wc(dev, map);
+}
+static __inline__ void
+drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev)
+{
+       map->virtual = drm_ioremap(dev, map);
+}
+static __inline__ void
+drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev)
+{
+       if ( map->virtual && map->size )
+               drm_ioremapfree(map);
+}
+
+static __inline__ struct drm_local_map *
+drm_core_findmap(struct drm_device *dev, unsigned long offset)
+{
+       drm_local_map_t *map;
+
+       DRM_LOCK_ASSERT(dev);
+       TAILQ_FOREACH(map, &dev->maplist, link) {
+               if (offset == (unsigned long)map->handle)
+                       return map;
+       }
+       return NULL;
+}
+
+static __inline__ void drm_core_dropmap(struct drm_map *map)
+{
+}
+
+#define KIB_NOTYET()                                                   \
+do {                                                                   \
+       if (drm_debug_flag && drm_notyet_flag)                          \
+               printf("NOTYET: %s at %s:%d\n", __func__, __FILE__, __LINE__); \
+} while (0)
+
+#define        KTR_DRM         KTR_DEV
+#define        KTR_DRM_REG     KTR_SPARE3
+
+#endif /* __KERNEL__ */
+#endif /* _DRM_P_H_ */
diff --git a/sys/dev/drm2/drm_agpsupport.c b/sys/dev/drm2/drm_agpsupport.c
new file mode 100644 (file)
index 0000000..ef6d52f
--- /dev/null
@@ -0,0 +1,434 @@
+/*-
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ *
+ * Author:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/drm2/drm_agpsupport.c,v 1.1 2012/05/22 11:07:44 kib Exp $");
+
+/** @file drm_agpsupport.c
+ * Support code for tying the kernel AGP support to DRM drivers and
+ * the DRM's AGP ioctls.
+ */
+
+#include <dev/drm2/drmP.h>
+
+#include <dev/agp/agpreg.h>
+#include <dev/pci/pcireg.h>
+
+/* Returns 1 if AGP or 0 if not. */
+static int
+drm_device_find_capability(struct drm_device *dev, int cap)
+{
+
+       return (pci_find_cap(dev->device, cap, NULL) == 0);
+}
+
+int drm_device_is_agp(struct drm_device *dev)
+{
+       if (dev->driver->device_is_agp != NULL) {
+               int ret;
+
+               /* device_is_agp returns a tristate, 0 = not AGP, 1 = definitely
+                * AGP, 2 = fall back to PCI capability
+                */
+               ret = (*dev->driver->device_is_agp)(dev);
+               if (ret != DRM_MIGHT_BE_AGP)
+                       return ret;
+       }
+
+       return (drm_device_find_capability(dev, PCIY_AGP));
+}
+
+int drm_device_is_pcie(struct drm_device *dev)
+{
+       return (drm_device_find_capability(dev, PCIY_EXPRESS));
+}
+
+int drm_agp_info(struct drm_device * dev, struct drm_agp_info *info)
+{
+       struct agp_info *kern;
+
+       if (!dev->agp || !dev->agp->acquired)
+               return EINVAL;
+
+       kern                   = &dev->agp->info;
+       agp_get_info(dev->agp->agpdev, kern);
+       info->agp_version_major = 1;
+       info->agp_version_minor = 0;
+       info->mode              = kern->ai_mode;
+       info->aperture_base     = kern->ai_aperture_base;
+       info->aperture_size     = kern->ai_aperture_size;
+       info->memory_allowed    = kern->ai_memory_allowed;
+       info->memory_used       = kern->ai_memory_used;
+       info->id_vendor         = kern->ai_devid & 0xffff;
+       info->id_device         = kern->ai_devid >> 16;
+
+       return 0;
+}
+
+int drm_agp_info_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
+{
+       int err;
+       struct drm_agp_info info;
+
+       err = drm_agp_info(dev, &info);
+       if (err != 0)
+               return err;
+
+       *(struct drm_agp_info *) data = info;
+       return 0;
+}
+
+int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
+{
+
+       return drm_agp_acquire(dev);
+}
+
+int drm_agp_acquire(struct drm_device *dev)
+{
+       int retcode;
+
+       if (!dev->agp || dev->agp->acquired)
+               return EINVAL;
+
+       retcode = agp_acquire(dev->agp->agpdev);
+       if (retcode)
+               return retcode;
+
+       dev->agp->acquired = 1;
+       return 0;
+}
+
+int drm_agp_release_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
+{
+
+       return drm_agp_release(dev);
+}
+
+int drm_agp_release(struct drm_device * dev)
+{
+       if (!dev->agp || !dev->agp->acquired)
+               return EINVAL;
+       agp_release(dev->agp->agpdev);
+       dev->agp->acquired = 0;
+       return 0;
+}
+
+int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode)
+{
+
+       if (!dev->agp || !dev->agp->acquired)
+               return EINVAL;
+       
+       dev->agp->mode    = mode.mode;
+       agp_enable(dev->agp->agpdev, mode.mode);
+       dev->agp->enabled = 1;
+       return 0;
+}
+
+int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
+{
+       struct drm_agp_mode mode;
+
+       mode = *(struct drm_agp_mode *) data;
+
+       return drm_agp_enable(dev, mode);
+}
+
+int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
+{
+       drm_agp_mem_t    *entry;
+       void             *handle;
+       unsigned long    pages;
+       u_int32_t        type;
+       struct agp_memory_info info;
+
+       if (!dev->agp || !dev->agp->acquired)
+               return EINVAL;
+
+       entry = malloc(sizeof(*entry), DRM_MEM_AGPLISTS, M_NOWAIT | M_ZERO);
+       if (entry == NULL)
+               return ENOMEM;
+
+       pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
+       type = (u_int32_t) request->type;
+
+       DRM_UNLOCK(dev);
+       handle = drm_agp_allocate_memory(pages, type);
+       DRM_LOCK(dev);
+       if (handle == NULL) {
+               free(entry, DRM_MEM_AGPLISTS);
+               return ENOMEM;
+       }
+       
+       entry->handle    = handle;
+       entry->bound     = 0;
+       entry->pages     = pages;
+       entry->prev      = NULL;
+       entry->next      = dev->agp->memory;
+       if (dev->agp->memory)
+               dev->agp->memory->prev = entry;
+       dev->agp->memory = entry;
+
+       agp_memory_info(dev->agp->agpdev, entry->handle, &info);
+
+       request->handle   = (unsigned long) entry->handle;
+        request->physical = info.ami_physical;
+
+       return 0;
+}
+
+int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+       struct drm_agp_buffer request;
+       int retcode;
+
+       request = *(struct drm_agp_buffer *) data;
+
+       DRM_LOCK(dev);
+       retcode = drm_agp_alloc(dev, &request);
+       DRM_UNLOCK(dev);
+
+       *(struct drm_agp_buffer *) data = request;
+
+       return retcode;
+}
+
+static drm_agp_mem_t * drm_agp_lookup_entry(struct drm_device *dev,
+                                           void *handle)
+{
+       drm_agp_mem_t *entry;
+
+       for (entry = dev->agp->memory; entry; entry = entry->next) {
+               if (entry->handle == handle) return entry;
+       }
+       return NULL;
+}
+
+int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
+{
+       drm_agp_mem_t     *entry;
+       int retcode;
+
+       if (!dev->agp || !dev->agp->acquired)
+               return EINVAL;
+
+       entry = drm_agp_lookup_entry(dev, (void *)request->handle);
+       if (entry == NULL || !entry->bound)
+               return EINVAL;
+
+       DRM_UNLOCK(dev);
+       retcode = drm_agp_unbind_memory(entry->handle);
+       DRM_LOCK(dev);
+
+       if (retcode == 0)
+               entry->bound = 0;
+
+       return retcode;
+}
+
+int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
+{
+       struct drm_agp_binding request;
+       int retcode;
+
+       request = *(struct drm_agp_binding *) data;
+
+       DRM_LOCK(dev);
+       retcode = drm_agp_unbind(dev, &request);
+       DRM_UNLOCK(dev);
+
+       return retcode;
+}
+
+int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
+{
+       drm_agp_mem_t     *entry;
+       int               retcode;
+       int               page;
+       
+       if (!dev->agp || !dev->agp->acquired)
+               return EINVAL;
+
+       DRM_DEBUG("agp_bind, page_size=%x\n", (int)PAGE_SIZE);
+
+       entry = drm_agp_lookup_entry(dev, (void *)request->handle);
+       if (entry == NULL || entry->bound)
+               return EINVAL;
+
+       page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE;
+
+       DRM_UNLOCK(dev);
+       retcode = drm_agp_bind_memory(entry->handle, page);
+       DRM_LOCK(dev);
+       if (retcode == 0)
+               entry->bound = dev->agp->base + (page << PAGE_SHIFT);
+
+       return retcode;
+}
+
+int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
+{
+       struct drm_agp_binding request;
+       int retcode;
+
+       request = *(struct drm_agp_binding *) data;
+
+       DRM_LOCK(dev);
+       retcode = drm_agp_bind(dev, &request);
+       DRM_UNLOCK(dev);
+
+       return retcode;
+}
+
+int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
+{
+       drm_agp_mem_t    *entry;
+       
+       if (!dev->agp || !dev->agp->acquired)
+               return EINVAL;
+
+       entry = drm_agp_lookup_entry(dev, (void*)request->handle);
+       if (entry == NULL)
+               return EINVAL;
+   
+       if (entry->prev)
+               entry->prev->next = entry->next;
+       else
+               dev->agp->memory  = entry->next;
+       if (entry->next)
+               entry->next->prev = entry->prev;
+
+       DRM_UNLOCK(dev);
+       if (entry->bound)
+               drm_agp_unbind_memory(entry->handle);
+       drm_agp_free_memory(entry->handle);
+       DRM_LOCK(dev);
+
+       free(entry, DRM_MEM_AGPLISTS);
+
+       return 0;
+
+}
+
+int drm_agp_free_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
+{
+       struct drm_agp_buffer request;
+       int retcode;
+
+       request = *(struct drm_agp_buffer *) data;
+
+       DRM_LOCK(dev);
+       retcode = drm_agp_free(dev, &request);
+       DRM_UNLOCK(dev);
+
+       return retcode;
+}
+
+drm_agp_head_t *drm_agp_init(void)
+{
+       device_t agpdev;
+       drm_agp_head_t *head   = NULL;
+       int      agp_available = 1;
+   
+       agpdev = DRM_AGP_FIND_DEVICE();
+       if (!agpdev)
+               agp_available = 0;
+
+       DRM_DEBUG("agp_available = %d\n", agp_available);
+
+       if (agp_available) {
+               head = malloc(sizeof(*head), DRM_MEM_AGPLISTS,
+                   M_NOWAIT | M_ZERO);
+               if (head == NULL)
+                       return NULL;
+               head->agpdev = agpdev;
+               agp_get_info(agpdev, &head->info);
+               head->base = head->info.ai_aperture_base;
+               head->memory = NULL;
+               DRM_INFO("AGP at 0x%08lx %dMB\n",
+                        (long)head->info.ai_aperture_base,
+                        (int)(head->info.ai_aperture_size >> 20));
+       }
+       return head;
+}
+
+void *drm_agp_allocate_memory(size_t pages, u32 type)
+{
+       device_t agpdev;
+
+       agpdev = DRM_AGP_FIND_DEVICE();
+       if (!agpdev)
+               return NULL;
+
+       return agp_alloc_memory(agpdev, type, pages << AGP_PAGE_SHIFT);
+}
+
+int drm_agp_free_memory(void *handle)
+{
+       device_t agpdev;
+
+       agpdev = DRM_AGP_FIND_DEVICE();
+       if (!agpdev || !handle)
+               return 0;
+
+       agp_free_memory(agpdev, handle);
+       return 1;
+}
+
+int drm_agp_bind_memory(void *handle, off_t start)
+{
+       device_t agpdev;
+
+       agpdev = DRM_AGP_FIND_DEVICE();
+       if (!agpdev || !handle)
+               return EINVAL;
+
+       return agp_bind_memory(agpdev, handle, start * PAGE_SIZE);
+}
+
+int drm_agp_unbind_memory(void *handle)
+{
+       device_t agpdev;
+
+       agpdev = DRM_AGP_FIND_DEVICE();
+       if (!agpdev || !handle)
+               return EINVAL;
+
+       return agp_unbind_memory(agpdev, handle);
+}
diff --git a/sys/dev/drm2/drm_atomic.h b/sys/dev/drm2/drm_atomic.h
new file mode 100644 (file)
index 0000000..fc60246
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+ * \file drm_atomic.h
+ * Atomic operations used in the DRM which may or may not be provided by the OS.
+ * 
+ * \author Eric Anholt <anholt@FreeBSD.org>
+ */
+
+/*-
+ * Copyright 2004 Eric Anholt
+ * All Rights Reserved.
+ *
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/drm2/drm_atomic.h,v 1.1 2012/05/22 11:07:44 kib Exp $");
+
+/* Many of these implementations are rather fake, but good enough. */
+
+typedef u_int32_t atomic_t;
+
+#define atomic_set(p, v)       (*(p) = (v))
+#define atomic_read(p)         (*(p))
+#define atomic_inc(p)          atomic_add_int(p, 1)
+#define atomic_dec(p)          atomic_subtract_int(p, 1)
+#define atomic_add(n, p)       atomic_add_int(p, n)
+#define atomic_sub(n, p)       atomic_subtract_int(p, n)
+
+static __inline atomic_t
+test_and_set_bit(int b, volatile void *p)
+{
+       int s = splhigh();
+       unsigned int m = 1<<b;
+       unsigned int r = *(volatile int *)p & m;
+       *(volatile int *)p |= m;
+       splx(s);
+       return r;
+}
+
+static __inline void
+clear_bit(int b, volatile void *p)
+{
+       atomic_clear_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f));
+}
+
+static __inline void
+set_bit(int b, volatile void *p)
+{
+       atomic_set_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f));
+}
+
+static __inline int
+test_bit(int b, volatile void *p)
+{
+       return ((volatile int *)p)[b >> 5] & (1 << (b & 0x1f));
+}
+
+static __inline int
+find_first_zero_bit(volatile void *p, int max)
+{
+       int b;
+       volatile int *ptr = (volatile int *)p;
+
+       for (b = 0; b < max; b += 32) {
+               if (ptr[b >> 5] != ~0) {
+                       for (;;) {
+                               if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0)
+                                       return b;
+                               b++;
+                       }
+               }
+       }
+       return max;
+}
+
+#define        BITS_TO_LONGS(x) (howmany((x), NBBY * sizeof(long)))
diff --git a/sys/dev/drm2/drm_auth.c b/sys/dev/drm2/drm_auth.c
new file mode 100644 (file)
index 0000000..5dd1248
--- /dev/null
@@ -0,0 +1,190 @@
+/*-
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/drm2/drm_auth.c,v 1.1 2012/05/22 11:07:44 kib Exp $");
+
+/** @file drm_auth.c
+ * Implementation of the get/authmagic ioctls implementing the authentication
+ * scheme between the master and clients.
+ */
+
+#include <dev/drm2/drmP.h>
+
+static int drm_hash_magic(drm_magic_t magic)
+{
+       return magic & (DRM_HASH_SIZE-1);
+}
+
+/**
+ * Returns the file private associated with the given magic number.
+ */
+static struct drm_file *drm_find_file(struct drm_device *dev, drm_magic_t magic)
+{
+       drm_magic_entry_t *pt;
+       int hash = drm_hash_magic(magic);
+
+       DRM_LOCK_ASSERT(dev);
+
+       for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
+               if (pt->magic == magic) {
+                       return pt->priv;
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * Inserts the given magic number into the hash table of used magic number
+ * lists.
+ */
+static int drm_add_magic(struct drm_device *dev, struct drm_file *priv,
+                        drm_magic_t magic)
+{
+       int               hash;
+       drm_magic_entry_t *entry;
+
+       DRM_DEBUG("%d\n", magic);
+
+       DRM_LOCK_ASSERT(dev);
+
+       hash = drm_hash_magic(magic);
+       entry = malloc(sizeof(*entry), DRM_MEM_MAGIC, M_ZERO | M_NOWAIT);
+       if (!entry)
+               return ENOMEM;
+       entry->magic = magic;
+       entry->priv  = priv;
+       entry->next  = NULL;
+
+       if (dev->magiclist[hash].tail) {
+               dev->magiclist[hash].tail->next = entry;
+               dev->magiclist[hash].tail       = entry;
+       } else {
+               dev->magiclist[hash].head       = entry;
+               dev->magiclist[hash].tail       = entry;
+       }
+
+       return 0;
+}
+
+/**
+ * Removes the given magic number from the hash table of used magic number
+ * lists.
+ */
+static int drm_remove_magic(struct drm_device *dev, drm_magic_t magic)
+{
+       drm_magic_entry_t *prev = NULL;
+       drm_magic_entry_t *pt;
+       int               hash;
+
+       DRM_LOCK_ASSERT(dev);
+
+       DRM_DEBUG("%d\n", magic);
+       hash = drm_hash_magic(magic);
+
+       for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
+               if (pt->magic == magic) {
+                       if (dev->magiclist[hash].head == pt) {
+                               dev->magiclist[hash].head = pt->next;
+                       }
+                       if (dev->magiclist[hash].tail == pt) {
+                               dev->magiclist[hash].tail = prev;
+                       }
+                       if (prev) {
+                               prev->next = pt->next;
+                       }
+                       free(pt, DRM_MEM_MAGIC);
+                       return 0;
+               }
+       }
+
+       return EINVAL;
+}
+
+/**
+ * Called by the client, this returns a unique magic number to be authorized
+ * by the master.
+ *
+ * The master may use its own knowledge of the client (such as the X
+ * connection that the magic is passed over) to determine if the magic number
+ * should be authenticated.
+ */
+int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       static drm_magic_t sequence = 0;
+       struct drm_auth *auth = data;
+
+       /* Find unique magic */
+       if (file_priv->magic) {
+               auth->magic = file_priv->magic;
+       } else {
+               DRM_LOCK(dev);
+               do {
+                       int old = sequence;
+
+                       auth->magic = old+1;
+
+                       if (!atomic_cmpset_int(&sequence, old, auth->magic))
+                               continue;
+               } while (drm_find_file(dev, auth->magic));
+               file_priv->magic = auth->magic;
+               drm_add_magic(dev, file_priv, auth->magic);
+               DRM_UNLOCK(dev);
+       }
+
+       DRM_DEBUG("%u\n", auth->magic);
+
+       return 0;
+}
+
+/**
+ * Marks the client associated with the given magic number as authenticated.
+ */
+int drm_authmagic(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
+{
+       struct drm_auth *auth = data;
+       struct drm_file *priv;
+
+       DRM_DEBUG("%u\n", auth->magic);
+
+       DRM_LOCK(dev);
+       priv = drm_find_file(dev, auth->magic);
+       if (priv != NULL) {
+               priv->authenticated = 1;
+               drm_remove_magic(dev, auth->magic);
+               DRM_UNLOCK(dev);
+               return 0;
+       } else {
+               DRM_UNLOCK(dev);
+               return EINVAL;
+       }
+}
diff --git a/sys/dev/drm2/drm_bufs.c b/sys/dev/drm2/drm_bufs.c
new file mode 100644 (file)
index 0000000..160fbde
--- /dev/null
@@ -0,0 +1,1130 @@
+/*-
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/drm2/drm_bufs.c,v 1.1 2012/05/22 11:07:44 kib Exp $");
+
+/** @file drm_bufs.c
+ * Implementation of the ioctls for setup of DRM mappings and DMA buffers.
+ */
+
+#include <dev/pci/pcireg.h>
+
+#include <dev/drm2/drmP.h>
+
+/* Allocation of PCI memory resources (framebuffer, registers, etc.) for
+ * drm_get_resource_*.  Note that they are not RF_ACTIVE, so there's no virtual
+ * address for accessing them.  Cleaned up at unload.
+ */
+static int drm_alloc_resource(struct drm_device *dev, int resource)
+{
+       struct resource *res;
+       int rid;
+
+       DRM_LOCK_ASSERT(dev);
+
+       if (resource >= DRM_MAX_PCI_RESOURCE) {
+               DRM_ERROR("Resource %d too large\n", resource);
+               return 1;
+       }
+
+       if (dev->pcir[resource] != NULL) {
+               return 0;
+       }
+
+       DRM_UNLOCK(dev);
+       rid = PCIR_BAR(resource);
+       res = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &rid,
+           RF_SHAREABLE);
+       DRM_LOCK(dev);
+       if (res == NULL) {
+               DRM_ERROR("Couldn't find resource 0x%x\n", resource);
+               return 1;
+       }
+
+       if (dev->pcir[resource] == NULL) {
+               dev->pcirid[resource] = rid;
+               dev->pcir[resource] = res;
+       }
+
+       return 0;
+}
+
+unsigned long drm_get_resource_start(struct drm_device *dev,
+                                    unsigned int resource)
+{
+       if (drm_alloc_resource(dev, resource) != 0)
+               return 0;
+
+       return rman_get_start(dev->pcir[resource]);
+}
+
+unsigned long drm_get_resource_len(struct drm_device *dev,
+                                  unsigned int resource)
+{
+       if (drm_alloc_resource(dev, resource) != 0)
+               return 0;
+
+       return rman_get_size(dev->pcir[resource]);
+}
+
+int drm_addmap(struct drm_device * dev, unsigned long offset,
+              unsigned long size,
+    enum drm_map_type type, enum drm_map_flags flags, drm_local_map_t **map_ptr)
+{
+       drm_local_map_t *map;
+       int align;
+       /*drm_agp_mem_t *entry;
+       int valid;*/
+
+       /* Only allow shared memory to be removable since we only keep enough
+        * book keeping information about shared memory to allow for removal
+        * when processes fork.
+        */
+       if ((flags & _DRM_REMOVABLE) && type != _DRM_SHM) {
+               DRM_ERROR("Requested removable map for non-DRM_SHM\n");
+               return EINVAL;
+       }
+       if ((offset & PAGE_MASK) || (size & PAGE_MASK)) {
+               DRM_ERROR("offset/size not page aligned: 0x%lx/0x%lx\n",
+                   offset, size);
+               return EINVAL;
+       }
+       if (offset + size < offset) {
+               DRM_ERROR("offset and size wrap around: 0x%lx/0x%lx\n",
+                   offset, size);
+               return EINVAL;
+       }
+
+       DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", offset,
+           size, type);
+
+       /* Check if this is just another version of a kernel-allocated map, and
+        * just hand that back if so.
+        */
+       if (type == _DRM_REGISTERS || type == _DRM_FRAME_BUFFER ||
+           type == _DRM_SHM) {
+               TAILQ_FOREACH(map, &dev->maplist, link) {
+                       if (map->type == type && (map->offset == offset ||
+                           (map->type == _DRM_SHM &&
+                           map->flags == _DRM_CONTAINS_LOCK))) {
+                               map->size = size;
+                               DRM_DEBUG("Found kernel map %d\n", type);
+                               goto done;
+                       }
+               }
+       }
+       DRM_UNLOCK(dev);
+
+       /* Allocate a new map structure, fill it in, and do any type-specific
+        * initialization necessary.
+        */
+       map = malloc(sizeof(*map), DRM_MEM_MAPS, M_ZERO | M_NOWAIT);
+       if (!map) {
+               DRM_LOCK(dev);
+               return ENOMEM;
+       }
+
+       map->offset = offset;
+       map->size = size;
+       map->type = type;
+       map->flags = flags;
+       map->handle = (void *)((unsigned long)alloc_unr(dev->map_unrhdr) <<
+           DRM_MAP_HANDLE_SHIFT);
+
+       switch (map->type) {
+       case _DRM_REGISTERS:
+               map->virtual = drm_ioremap(dev, map);
+               if (!(map->flags & _DRM_WRITE_COMBINING))
+                       break;
+               /* FALLTHROUGH */
+       case _DRM_FRAME_BUFFER:
+               if (drm_mtrr_add(map->offset, map->size, DRM_MTRR_WC) == 0)
+                       map->mtrr = 1;
+               break;
+       case _DRM_SHM:
+               map->virtual = malloc(map->size, DRM_MEM_MAPS, M_NOWAIT);
+               DRM_DEBUG("%lu %d %p\n",
+                   map->size, drm_order(map->size), map->virtual);
+               if (!map->virtual) {
+                       free(map, DRM_MEM_MAPS);
+                       DRM_LOCK(dev);
+                       return ENOMEM;
+               }
+               map->offset = (unsigned long)map->virtual;
+               if (map->flags & _DRM_CONTAINS_LOCK) {
+                       /* Prevent a 2nd X Server from creating a 2nd lock */
+                       DRM_LOCK(dev);
+                       if (dev->lock.hw_lock != NULL) {
+                               DRM_UNLOCK(dev);
+                               free(map->virtual, DRM_MEM_MAPS);
+                               free(map, DRM_MEM_MAPS);
+                               return EBUSY;
+                       }
+                       dev->lock.hw_lock = map->virtual; /* Pointer to lock */
+                       DRM_UNLOCK(dev);
+               }
+               break;
+       case _DRM_AGP:
+               /*valid = 0;*/
+               /* In some cases (i810 driver), user space may have already
+                * added the AGP base itself, because dev->agp->base previously
+                * only got set during AGP enable.  So, only add the base
+                * address if the map's offset isn't already within the
+                * aperture.
+                */
+               if (map->offset < dev->agp->base ||
+                   map->offset > dev->agp->base +
+                   dev->agp->info.ai_aperture_size - 1) {
+                       map->offset += dev->agp->base;
+               }
+               map->mtrr   = dev->agp->mtrr; /* for getmap */
+               /*for (entry = dev->agp->memory; entry; entry = entry->next) {
+                       if ((map->offset >= entry->bound) &&
+                           (map->offset + map->size <=
+                           entry->bound + entry->pages * PAGE_SIZE)) {
+                               valid = 1;
+                               break;
+                       }
+               }
+               if (!valid) {
+                       free(map, DRM_MEM_MAPS);
+                       DRM_LOCK(dev);
+                       return EACCES;
+               }*/
+               break;
+       case _DRM_SCATTER_GATHER:
+               if (!dev->sg) {
+                       free(map, DRM_MEM_MAPS);
+                       DRM_LOCK(dev);
+                       return EINVAL;
+               }
+               map->virtual = (void *)(dev->sg->vaddr + offset);
+               map->offset = dev->sg->vaddr + offset;
+               break;
+       case _DRM_CONSISTENT:
+               /* Unfortunately, we don't get any alignment specification from
+                * the caller, so we have to guess.  drm_pci_alloc requires
+                * a power-of-two alignment, so try to align the bus address of
+                * the map to it size if possible, otherwise just assume
+                * PAGE_SIZE alignment.
+                */
+               align = map->size;
+               if ((align & (align - 1)) != 0)
+                       align = PAGE_SIZE;
+               map->dmah = drm_pci_alloc(dev, map->size, align, 0xfffffffful);
+               if (map->dmah == NULL) {
+                       free(map, DRM_MEM_MAPS);
+                       DRM_LOCK(dev);
+                       return ENOMEM;
+               }
+               map->virtual = map->dmah->vaddr;
+               map->offset = map->dmah->busaddr;
+               break;
+       default:
+               DRM_ERROR("Bad map type %d\n", map->type);
+               free(map, DRM_MEM_MAPS);
+               DRM_LOCK(dev);
+               return EINVAL;
+       }
+
+       DRM_LOCK(dev);
+       TAILQ_INSERT_TAIL(&dev->maplist, map, link);
+
+done:
+       /* Jumped to, with lock held, when a kernel map is found. */
+
+       DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset,
+           map->size);
+
+       *map_ptr = map;
+
+       return 0;
+}
+
+int drm_addmap_ioctl(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv)
+{
+       struct drm_map *request = data;
+       drm_local_map_t *map;
+       int err;
+
+       if (!(dev->flags & (FREAD|FWRITE)))
+               return EACCES; /* Require read/write */
+
+       if (!DRM_SUSER(DRM_CURPROC) && request->type != _DRM_AGP)
+               return EACCES;
+
+       DRM_LOCK(dev);
+       err = drm_addmap(dev, request->offset, request->size, request->type,
+           request->flags, &map);
+       DRM_UNLOCK(dev);
+       if (err != 0)
+               return err;
+
+       request->offset = map->offset;
+       request->size = map->size;
+       request->type = map->type;
+       request->flags = map->flags;
+       request->mtrr   = map->mtrr;
+       request->handle = (void *)map->handle;
+
+       return 0;
+}
+
+void drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
+{
+       DRM_LOCK_ASSERT(dev);
+
+       if (map == NULL)
+               return;
+
+       TAILQ_REMOVE(&dev->maplist, map, link);
+
+       switch (map->type) {
+       case _DRM_REGISTERS:
+               if (map->bsr == NULL)
+                       drm_ioremapfree(map);
+               /* FALLTHROUGH */
+       case _DRM_FRAME_BUFFER:
+               if (map->mtrr) {
+                       int __unused retcode;
+                       
+                       retcode = drm_mtrr_del(0, map->offset, map->size,
+                           DRM_MTRR_WC);
+                       DRM_DEBUG("mtrr_del = %d\n", retcode);
+               }
+               break;
+       case _DRM_SHM:
+               free(map->virtual, DRM_MEM_MAPS);
+               break;
+       case _DRM_AGP:
+       case _DRM_SCATTER_GATHER:
+               break;
+       case _DRM_CONSISTENT:
+               drm_pci_free(dev, map->dmah);
+               break;
+       default:
+               DRM_ERROR("Bad map type %d\n", map->type);
+               break;
+       }
+
+       if (map->bsr != NULL) {
+               bus_release_resource(dev->device, SYS_RES_MEMORY, map->rid,
+                   map->bsr);
+       }
+
+       DRM_UNLOCK(dev);
+       if (map->handle)
+               free_unr(dev->map_unrhdr, (unsigned long)map->handle >>
+                   DRM_MAP_HANDLE_SHIFT);
+       DRM_LOCK(dev);
+
+       free(map, DRM_MEM_MAPS);
+}
+
+/* Remove a map private from list and deallocate resources if the mapping
+ * isn't in use.
+ */
+
+int drm_rmmap_ioctl(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
+{
+       drm_local_map_t *map;
+       struct drm_map *request = data;
+
+       DRM_LOCK(dev);
+       TAILQ_FOREACH(map, &dev->maplist, link) {
+               if (map->handle == request->handle &&
+                   map->flags & _DRM_REMOVABLE)
+                       break;
+       }
+
+       /* No match found. */
+       if (map == NULL) {
+               DRM_UNLOCK(dev);
+               return EINVAL;
+       }
+
+       drm_rmmap(dev, map);
+
+       DRM_UNLOCK(dev);
+
+       return 0;
+}
+
+
+static void drm_cleanup_buf_error(struct drm_device *dev,
+                                 drm_buf_entry_t *entry)
+{
+       int i;
+
+       if (entry->seg_count) {
+               for (i = 0; i < entry->seg_count; i++) {
+                       drm_pci_free(dev, entry->seglist[i]);
+               }
+               free(entry->seglist, DRM_MEM_SEGS);
+
+               entry->seg_count = 0;
+       }
+
+       if (entry->buf_count) {
+               for (i = 0; i < entry->buf_count; i++) {
+                       free(entry->buflist[i].dev_private, DRM_MEM_BUFS);
+               }
+               free(entry->buflist, DRM_MEM_BUFS);
+
+               entry->buf_count = 0;
+       }
+}
+
+static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request)
+{
+       drm_device_dma_t *dma = dev->dma;
+       drm_buf_entry_t *entry;
+       /*drm_agp_mem_t *agp_entry;
+       int valid*/
+       drm_buf_t *buf;
+       unsigned long offset;
+       unsigned long agp_offset;
+       int count;
+       int order;
+       int size;
+       int alignment;
+       int page_order;
+       int total;
+       int byte_count;
+       int i;
+       drm_buf_t **temp_buflist;
+
+       count = request->count;
+       order = drm_order(request->size);
+       size = 1 << order;
+
+       alignment  = (request->flags & _DRM_PAGE_ALIGN)
+           ? round_page(size) : size;
+       page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+       total = PAGE_SIZE << page_order;
+
+       byte_count = 0;
+       agp_offset = dev->agp->base + request->agp_start;
+
+       DRM_DEBUG("count:      %d\n",  count);
+       DRM_DEBUG("order:      %d\n",  order);
+       DRM_DEBUG("size:       %d\n",  size);
+       DRM_DEBUG("agp_offset: 0x%lx\n", agp_offset);
+       DRM_DEBUG("alignment:  %d\n",  alignment);
+       DRM_DEBUG("page_order: %d\n",  page_order);
+       DRM_DEBUG("total:      %d\n",  total);
+
+       /* Make sure buffers are located in AGP memory that we own */
+       /* Breaks MGA due to drm_alloc_agp not setting up entries for the
+        * memory.  Safe to ignore for now because these ioctls are still
+        * root-only.
+        */
+       /*valid = 0;
+       for (agp_entry = dev->agp->memory; agp_entry;
+           agp_entry = agp_entry->next) {
+               if ((agp_offset >= agp_entry->bound) &&
+                   (agp_offset + total * count <=
+                   agp_entry->bound + agp_entry->pages * PAGE_SIZE)) {
+                       valid = 1;
+                       break;
+               }
+       }
+       if (!valid) {
+               DRM_DEBUG("zone invalid\n");
+               return EINVAL;
+       }*/
+
+       entry = &dma->bufs[order];
+
+       entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
+           M_NOWAIT | M_ZERO);
+       if (!entry->buflist) {
+               return ENOMEM;
+       }
+
+       entry->buf_size = size;
+       entry->page_order = page_order;
+
+       offset = 0;
+
+       while (entry->buf_count < count) {
+               buf          = &entry->buflist[entry->buf_count];
+               buf->idx     = dma->buf_count + entry->buf_count;
+               buf->total   = alignment;
+               buf->order   = order;
+               buf->used    = 0;
+
+               buf->offset  = (dma->byte_count + offset);
+               buf->bus_address = agp_offset + offset;
+               buf->address = (void *)(agp_offset + offset);
+               buf->next    = NULL;
+               buf->pending = 0;
+               buf->file_priv = NULL;
+
+               buf->dev_priv_size = dev->driver->buf_priv_size;
+               buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS,
+                   M_NOWAIT | M_ZERO);
+               if (buf->dev_private == NULL) {
+                       /* Set count correctly so we free the proper amount. */
+                       entry->buf_count = count;
+                       drm_cleanup_buf_error(dev, entry);
+                       return ENOMEM;
+               }
+
+               offset += alignment;
+               entry->buf_count++;
+               byte_count += PAGE_SIZE << page_order;
+       }
+
+       DRM_DEBUG("byte_count: %d\n", byte_count);
+
+       temp_buflist = realloc(dma->buflist,
+           (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist),
+           DRM_MEM_BUFS, M_NOWAIT);
+       if (temp_buflist == NULL) {
+               /* Free the entry because it isn't valid */
+               drm_cleanup_buf_error(dev, entry);
+               return ENOMEM;
+       }
+       dma->buflist = temp_buflist;
+
+       for (i = 0; i < entry->buf_count; i++) {
+               dma->buflist[i + dma->buf_count] = &entry->buflist[i];
+       }
+
+       dma->buf_count += entry->buf_count;
+       dma->byte_count += byte_count;
+
+       DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
+       DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
+
+       request->count = entry->buf_count;
+       request->size = size;
+
+       dma->flags = _DRM_DMA_USE_AGP;
+
+       return 0;
+}
+
+static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request)
+{
+       drm_device_dma_t *dma = dev->dma;
+       int count;
+       int order;
+       int size;
+       int total;
+       int page_order;
+       drm_buf_entry_t *entry;
+       drm_buf_t *buf;
+       int alignment;
+       unsigned long offset;
+       int i;
+       int byte_count;
+       int page_count;
+       unsigned long *temp_pagelist;
+       drm_buf_t **temp_buflist;
+
+       count = request->count;
+       order = drm_order(request->size);
+       size = 1 << order;
+
+       DRM_DEBUG("count=%d, size=%d (%d), order=%d\n",
+           request->count, request->size, size, order);
+
+       alignment = (request->flags & _DRM_PAGE_ALIGN)
+           ? round_page(size) : size;
+       page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+       total = PAGE_SIZE << page_order;
+
+       entry = &dma->bufs[order];
+
+       entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
+           M_NOWAIT | M_ZERO);
+       entry->seglist = malloc(count * sizeof(*entry->seglist), DRM_MEM_SEGS,
+           M_NOWAIT | M_ZERO);
+
+       /* Keep the original pagelist until we know all the allocations
+        * have succeeded
+        */
+       temp_pagelist = malloc((dma->page_count + (count << page_order)) *
+           sizeof(*dma->pagelist), DRM_MEM_PAGES, M_NOWAIT);
+
+       if (entry->buflist == NULL || entry->seglist == NULL || 
+           temp_pagelist == NULL) {
+               free(temp_pagelist, DRM_MEM_PAGES);
+               free(entry->seglist, DRM_MEM_SEGS);
+               free(entry->buflist, DRM_MEM_BUFS);
+               return ENOMEM;
+       }
+
+       memcpy(temp_pagelist, dma->pagelist, dma->page_count * 
+           sizeof(*dma->pagelist));
+
+       DRM_DEBUG("pagelist: %d entries\n",
+           dma->page_count + (count << page_order));
+
+       entry->buf_size = size;
+       entry->page_order = page_order;
+       byte_count = 0;
+       page_count = 0;
+
+       while (entry->buf_count < count) {
+               DRM_SPINUNLOCK(&dev->dma_lock);
+               drm_dma_handle_t *dmah = drm_pci_alloc(dev, size, alignment,
+                   0xfffffffful);
+               DRM_SPINLOCK(&dev->dma_lock);
+               if (dmah == NULL) {
+                       /* Set count correctly so we free the proper amount. */
+                       entry->buf_count = count;
+                       entry->seg_count = count;
+                       drm_cleanup_buf_error(dev, entry);
+                       free(temp_pagelist, DRM_MEM_PAGES);
+                       return ENOMEM;
+               }
+
+               entry->seglist[entry->seg_count++] = dmah;
+               for (i = 0; i < (1 << page_order); i++) {
+                       DRM_DEBUG("page %d @ %p\n",
+                           dma->page_count + page_count,
+                           (char *)dmah->vaddr + PAGE_SIZE * i);
+                       temp_pagelist[dma->page_count + page_count++] = 
+                           (long)dmah->vaddr + PAGE_SIZE * i;
+               }
+               for (offset = 0;
+                   offset + size <= total && entry->buf_count < count;
+                   offset += alignment, ++entry->buf_count) {
+                       buf          = &entry->buflist[entry->buf_count];
+                       buf->idx     = dma->buf_count + entry->buf_count;
+                       buf->total   = alignment;
+                       buf->order   = order;
+                       buf->used    = 0;
+                       buf->offset  = (dma->byte_count + byte_count + offset);
+                       buf->address = ((char *)dmah->vaddr + offset);
+                       buf->bus_address = dmah->busaddr + offset;
+                       buf->next    = NULL;
+                       buf->pending = 0;
+                       buf->file_priv = NULL;
+
+                       buf->dev_priv_size = dev->driver->buf_priv_size;
+                       buf->dev_private = malloc(buf->dev_priv_size,
+                           DRM_MEM_BUFS, M_NOWAIT | M_ZERO);
+                       if (buf->dev_private == NULL) {
+                               /* Set count correctly so we free the proper amount. */
+                               entry->buf_count = count;
+                               entry->seg_count = count;
+                               drm_cleanup_buf_error(dev, entry);
+                               free(temp_pagelist, DRM_MEM_PAGES);
+                               return ENOMEM;
+                       }
+
+                       DRM_DEBUG("buffer %d @ %p\n",
+                           entry->buf_count, buf->address);
+               }
+               byte_count += PAGE_SIZE << page_order;
+       }
+
+       temp_buflist = realloc(dma->buflist,
+           (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist),
+           DRM_MEM_BUFS, M_NOWAIT);
+       if (temp_buflist == NULL) {
+               /* Free the entry because it isn't valid */
+               drm_cleanup_buf_error(dev, entry);
+               free(temp_pagelist, DRM_MEM_PAGES);
+               return ENOMEM;
+       }
+       dma->buflist = temp_buflist;
+
+       for (i = 0; i < entry->buf_count; i++) {
+               dma->buflist[i + dma->buf_count] = &entry->buflist[i];
+       }
+
+       /* No allocations failed, so now we can replace the orginal pagelist
+        * with the new one.
+        */
+       free(dma->pagelist, DRM_MEM_PAGES);
+       dma->pagelist = temp_pagelist;
+
+       dma->buf_count += entry->buf_count;
+       dma->seg_count += entry->seg_count;
+       dma->page_count += entry->seg_count << page_order;
+       dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
+
+       request->count = entry->buf_count;
+       request->size = size;
+
+       return 0;
+
+}
+
+static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request)
+{
+       drm_device_dma_t *dma = dev->dma;
+       drm_buf_entry_t *entry;
+       drm_buf_t *buf;
+       unsigned long offset;
+       unsigned long agp_offset;
+       int count;
+       int order;
+       int size;
+       int alignment;
+       int page_order;
+       int total;
+       int byte_count;
+       int i;
+       drm_buf_t **temp_buflist;
+
+       count = request->count;
+       order = drm_order(request->size);
+       size = 1 << order;
+
+       alignment  = (request->flags & _DRM_PAGE_ALIGN)
+           ? round_page(size) : size;
+       page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+       total = PAGE_SIZE << page_order;
+
+       byte_count = 0;
+       agp_offset = request->agp_start;
+
+       DRM_DEBUG("count:      %d\n",  count);
+       DRM_DEBUG("order:      %d\n",  order);
+       DRM_DEBUG("size:       %d\n",  size);
+       DRM_DEBUG("agp_offset: %ld\n", agp_offset);
+       DRM_DEBUG("alignment:  %d\n",  alignment);
+       DRM_DEBUG("page_order: %d\n",  page_order);
+       DRM_DEBUG("total:      %d\n",  total);
+
+       entry = &dma->bufs[order];
+
+       entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
+           M_NOWAIT | M_ZERO);
+       if (entry->buflist == NULL)
+               return ENOMEM;
+
+       entry->buf_size = size;
+       entry->page_order = page_order;
+
+       offset = 0;
+
+       while (entry->buf_count < count) {
+               buf          = &entry->buflist[entry->buf_count];
+               buf->idx     = dma->buf_count + entry->buf_count;
+               buf->total   = alignment;
+               buf->order   = order;
+               buf->used    = 0;
+
+               buf->offset  = (dma->byte_count + offset);
+               buf->bus_address = agp_offset + offset;
+               buf->address = (void *)(agp_offset + offset + dev->sg->vaddr);
+               buf->next    = NULL;
+               buf->pending = 0;
+               buf->file_priv = NULL;
+
+               buf->dev_priv_size = dev->driver->buf_priv_size;
+               buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS,
+                   M_NOWAIT | M_ZERO);
+               if (buf->dev_private == NULL) {
+                       /* Set count correctly so we free the proper amount. */
+                       entry->buf_count = count;
+                       drm_cleanup_buf_error(dev, entry);
+                       return ENOMEM;
+               }
+
+               DRM_DEBUG("buffer %d @ %p\n",
+                   entry->buf_count, buf->address);
+
+               offset += alignment;
+               entry->buf_count++;
+               byte_count += PAGE_SIZE << page_order;
+       }
+
+       DRM_DEBUG("byte_count: %d\n", byte_count);
+
+       temp_buflist = realloc(dma->buflist,
+           (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist),
+           DRM_MEM_BUFS, M_NOWAIT);
+       if (temp_buflist == NULL) {
+               /* Free the entry because it isn't valid */
+               drm_cleanup_buf_error(dev, entry);
+               return ENOMEM;
+       }
+       dma->buflist = temp_buflist;
+
+       for (i = 0; i < entry->buf_count; i++) {
+               dma->buflist[i + dma->buf_count] = &entry->buflist[i];
+       }
+
+       dma->buf_count += entry->buf_count;
+       dma->byte_count += byte_count;
+
+       DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
+       DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
+
+       request->count = entry->buf_count;
+       request->size = size;
+
+       dma->flags = _DRM_DMA_USE_SG;
+
+       return 0;
+}
+
+int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request)
+{
+       int order, ret;
+
+       if (request->count < 0 || request->count > 4096)
+               return EINVAL;
+       
+       order = drm_order(request->size);
+       if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
+               return EINVAL;
+
+       DRM_SPINLOCK(&dev->dma_lock);
+
+       /* No more allocations after first buffer-using ioctl. */
+       if (dev->buf_use != 0) {
+               DRM_SPINUNLOCK(&dev->dma_lock);
+               return EBUSY;
+       }
+       /* No more than one allocation per order */
+       if (dev->dma->bufs[order].buf_count != 0) {
+               DRM_SPINUNLOCK(&dev->dma_lock);
+               return ENOMEM;
+       }
+
+       ret = drm_do_addbufs_agp(dev, request);
+
+       DRM_SPINUNLOCK(&dev->dma_lock);
+
+       return ret;
+}
+
+int drm_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request)
+{
+       int order, ret;
+
+       if (!DRM_SUSER(DRM_CURPROC))
+               return EACCES;
+
+       if (request->count < 0 || request->count > 4096)
+               return EINVAL;
+
+       order = drm_order(request->size);
+       if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
+               return EINVAL;
+
+       DRM_SPINLOCK(&dev->dma_lock);
+
+       /* No more allocations after first buffer-using ioctl. */
+       if (dev->buf_use != 0) {
+               DRM_SPINUNLOCK(&dev->dma_lock);
+               return EBUSY;
+       }
+       /* No more than one allocation per order */
+       if (dev->dma->bufs[order].buf_count != 0) {
+               DRM_SPINUNLOCK(&dev->dma_lock);
+               return ENOMEM;
+       }
+
+       ret = drm_do_addbufs_sg(dev, request);
+
+       DRM_SPINUNLOCK(&dev->dma_lock);
+
+       return ret;
+}
+
+int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request)
+{
+       int order, ret;
+
+       if (!DRM_SUSER(DRM_CURPROC))
+               return EACCES;
+
+       if (request->count < 0 || request->count > 4096)
+               return EINVAL;
+
+       order = drm_order(request->size);
+       if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
+               return EINVAL;
+
+       DRM_SPINLOCK(&dev->dma_lock);
+
+       /* No more allocations after first buffer-using ioctl. */
+       if (dev->buf_use != 0) {
+               DRM_SPINUNLOCK(&dev->dma_lock);
+               return EBUSY;
+       }
+       /* No more than one allocation per order */
+       if (dev->dma->bufs[order].buf_count != 0) {
+               DRM_SPINUNLOCK(&dev->dma_lock);
+               return ENOMEM;
+       }
+
+       ret = drm_do_addbufs_pci(dev, request);
+
+       DRM_SPINUNLOCK(&dev->dma_lock);
+
+       return ret;
+}
+
+int drm_addbufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       struct drm_buf_desc *request = data;
+       int err;
+
+       if (request->flags & _DRM_AGP_BUFFER)
+               err = drm_addbufs_agp(dev, request);
+       else if (request->flags & _DRM_SG_BUFFER)
+               err = drm_addbufs_sg(dev, request);
+       else
+               err = drm_addbufs_pci(dev, request);
+
+       return err;
+}
+
+int drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       drm_device_dma_t *dma = dev->dma;
+       struct drm_buf_info *request = data;
+       int i;
+       int count;
+       int retcode = 0;
+
+       DRM_SPINLOCK(&dev->dma_lock);
+       ++dev->buf_use;         /* Can't allocate more after this call */
+       DRM_SPINUNLOCK(&dev->dma_lock);
+
+       for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
+               if (dma->bufs[i].buf_count)
+                       ++count;
+       }
+
+       DRM_DEBUG("count = %d\n", count);
+
+       if (request->count >= count) {
+               for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
+                       if (dma->bufs[i].buf_count) {
+                               struct drm_buf_desc from;
+
+                               from.count = dma->bufs[i].buf_count;
+                               from.size = dma->bufs[i].buf_size;
+                               from.low_mark = dma->bufs[i].freelist.low_mark;
+                               from.high_mark = dma->bufs[i].freelist.high_mark;
+
+                               if (DRM_COPY_TO_USER(&request->list[count], &from,
+                                   sizeof(struct drm_buf_desc)) != 0) {
+                                       retcode = EFAULT;
+                                       break;
+                               }
+
+                               DRM_DEBUG("%d %d %d %d %d\n",
+                                   i, dma->bufs[i].buf_count,
+                                   dma->bufs[i].buf_size,
+                                   dma->bufs[i].freelist.low_mark,
+                                   dma->bufs[i].freelist.high_mark);
+                               ++count;
+                       }
+               }
+       }
+       request->count = count;
+
+       return retcode;
+}
+
+int drm_markbufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       drm_device_dma_t *dma = dev->dma;
+       struct drm_buf_desc *request = data;
+       int order;
+
+       DRM_DEBUG("%d, %d, %d\n",
+                 request->size, request->low_mark, request->high_mark);
+       
+
+       order = drm_order(request->size);       
+       if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ||
+           request->low_mark < 0 || request->high_mark < 0) {
+               return EINVAL;
+       }
+
+       DRM_SPINLOCK(&dev->dma_lock);
+       if (request->low_mark > dma->bufs[order].buf_count ||
+           request->high_mark > dma->bufs[order].buf_count) {
+               DRM_SPINUNLOCK(&dev->dma_lock);
+               return EINVAL;
+       }
+
+       dma->bufs[order].freelist.low_mark  = request->low_mark;
+       dma->bufs[order].freelist.high_mark = request->high_mark;
+       DRM_SPINUNLOCK(&dev->dma_lock);
+
+       return 0;
+}
+
+int drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       drm_device_dma_t *dma = dev->dma;
+       struct drm_buf_free *request = data;
+       int i;
+       int idx;
+       drm_buf_t *buf;
+       int retcode = 0;
+
+       DRM_DEBUG("%d\n", request->count);
+       
+       DRM_SPINLOCK(&dev->dma_lock);
+       for (i = 0; i < request->count; i++) {
+               if (DRM_COPY_FROM_USER(&idx, &request->list[i], sizeof(idx))) {
+                       retcode = EFAULT;
+                       break;
+               }
+               if (idx < 0 || idx >= dma->buf_count) {
+                       DRM_ERROR("Index %d (of %d max)\n",
+                           idx, dma->buf_count - 1);
+                       retcode = EINVAL;
+                       break;
+               }
+               buf = dma->buflist[idx];
+               if (buf->file_priv != file_priv) {
+                       DRM_ERROR("Process %d freeing buffer not owned\n",
+                           DRM_CURRENTPID);
+                       retcode = EINVAL;
+                       break;
+               }
+               drm_free_buffer(dev, buf);
+       }
+       DRM_SPINUNLOCK(&dev->dma_lock);
+
+       return retcode;
+}
+
+int drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       drm_device_dma_t *dma = dev->dma;
+       int retcode = 0;
+       const int zero = 0;
+       vm_offset_t address;
+       struct vmspace *vms;
+       vm_ooffset_t foff;
+       vm_size_t size;
+       vm_offset_t vaddr;
+       struct drm_buf_map *request = data;
+       int i;
+
+       vms = DRM_CURPROC->td_proc->p_vmspace;
+
+       DRM_SPINLOCK(&dev->dma_lock);
+       dev->buf_use++;         /* Can't allocate more after this call */
+       DRM_SPINUNLOCK(&dev->dma_lock);
+
+       if (request->count < dma->buf_count)
+               goto done;
+
+       if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) ||
+           (drm_core_check_feature(dev, DRIVER_SG) &&
+           (dma->flags & _DRM_DMA_USE_SG))) {
+               drm_local_map_t *map = dev->agp_buffer_map;
+
+               if (map == NULL) {
+                       retcode = EINVAL;
+                       goto done;
+               }
+               size = round_page(map->size);
+               foff = (unsigned long)map->handle;
+       } else {
+               size = round_page(dma->byte_count),
+               foff = 0;
+       }
+
+       vaddr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ);
+#if __FreeBSD_version >= 600023
+       retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE,
+           VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, OBJT_DEVICE,
+           dev->devnode, foff);
+#else
+       retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE,
+           VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC,
+           SLIST_FIRST(&dev->devnode->si_hlist), foff);
+#endif
+       if (retcode)
+               goto done;
+
+       request->virtual = (void *)vaddr;
+
+       for (i = 0; i < dma->buf_count; i++) {
+               if (DRM_COPY_TO_USER(&request->list[i].idx,
+                   &dma->buflist[i]->idx, sizeof(request->list[0].idx))) {
+                       retcode = EFAULT;
+                       goto done;
+               }
+               if (DRM_COPY_TO_USER(&request->list[i].total,
+                   &dma->buflist[i]->total, sizeof(request->list[0].total))) {
+                       retcode = EFAULT;
+                       goto done;
+               }
+               if (DRM_COPY_TO_USER(&request->list[i].used, &zero,
+                   sizeof(zero))) {
+                       retcode = EFAULT;
+                       goto done;
+               }
+               address = vaddr + dma->buflist[i]->offset; /* *** */
+               if (DRM_COPY_TO_USER(&request->list[i].address, &address,
+                   sizeof(address))) {
+                       retcode = EFAULT;
+                       goto done;
+               }
+       }
+
+ done:
+       request->count = dma->buf_count;
+
+       DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode);
+
+       return retcode;
+}
+
+/*
+ * Compute order.  Can be made faster.
+ */
+int drm_order(unsigned long size)
+{
+       int order;
+
+       if (size == 0)
+               return 0;
+
+       order = flsl(size) - 1;
+       if (size & ~(1ul << order))
+               ++order;
+
+       return order;
+}
diff --git a/sys/dev/drm2/drm_context.c b/sys/dev/drm2/drm_context.c
new file mode 100644 (file)
index 0000000..79def2a
--- /dev/null
@@ -0,0 +1,312 @@
+/*-
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/drm2/drm_context.c,v 1.1 2012/05/22 11:07:44 kib Exp $");
+
+/** @file drm_context.c
+ * Implementation of the context management ioctls.
+ */
+
+#include <dev/drm2/drmP.h>
+
+/* ================================================================
+ * Context bitmap support
+ */
+
+void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle)
+{
+       if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP || 
+           dev->ctx_bitmap == NULL) {
+               DRM_ERROR("Attempt to free invalid context handle: %d\n",
+                  ctx_handle);
+               return;
+       }
+
+       DRM_LOCK(dev);
+       clear_bit(ctx_handle, dev->ctx_bitmap);
+       dev->context_sareas[ctx_handle] = NULL;
+       DRM_UNLOCK(dev);
+       return;
+}
+
+int drm_ctxbitmap_next(struct drm_device *dev)
+{
+       int bit;
+
+       if (dev->ctx_bitmap == NULL)
+               return -1;
+
+       DRM_LOCK(dev);
+       bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
+       if (bit >= DRM_MAX_CTXBITMAP) {
+               DRM_UNLOCK(dev);
+               return -1;
+       }
+
+       set_bit(bit, dev->ctx_bitmap);
+       DRM_DEBUG("bit : %d\n", bit);
+       if ((bit+1) > dev->max_context) {
+               drm_local_map_t **ctx_sareas;
+               int max_ctx = (bit+1);
+
+               ctx_sareas = realloc(dev->context_sareas,
+                   max_ctx * sizeof(*dev->context_sareas),
+                   DRM_MEM_SAREA, M_NOWAIT);
+               if (ctx_sareas == NULL) {
+                       clear_bit(bit, dev->ctx_bitmap);
+                       DRM_DEBUG("failed to allocate bit : %d\n", bit);
+                       DRM_UNLOCK(dev);
+                       return -1;
+               }
+               dev->max_context = max_ctx;
+               dev->context_sareas = ctx_sareas;
+               dev->context_sareas[bit] = NULL;
+       }
+       DRM_UNLOCK(dev);
+       return bit;
+}
+
+int drm_ctxbitmap_init(struct drm_device *dev)
+{
+       int i;
+       int temp;
+
+       DRM_LOCK(dev);
+       dev->ctx_bitmap = malloc(PAGE_SIZE, DRM_MEM_CTXBITMAP,
+           M_NOWAIT | M_ZERO);
+       if (dev->ctx_bitmap == NULL) {
+               DRM_UNLOCK(dev);
+               return ENOMEM;
+       }
+       dev->context_sareas = NULL;
+       dev->max_context = -1;
+       DRM_UNLOCK(dev);
+
+       for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+               temp = drm_ctxbitmap_next(dev);
+               DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
+       }
+
+       return 0;
+}
+
+void drm_ctxbitmap_cleanup(struct drm_device *dev)
+{
+       DRM_LOCK(dev);
+       if (dev->context_sareas != NULL)
+               free(dev->context_sareas, DRM_MEM_SAREA);
+       free(dev->ctx_bitmap, DRM_MEM_CTXBITMAP);
+       DRM_UNLOCK(dev);
+}
+
+/* ================================================================
+ * Per Context SAREA Support
+ */
+
+int drm_getsareactx(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
+{
+       struct drm_ctx_priv_map *request = data;
+       drm_local_map_t *map;
+
+       DRM_LOCK(dev);
+       if (dev->max_context < 0 ||
+           request->ctx_id >= (unsigned) dev->max_context) {
+               DRM_UNLOCK(dev);
+               return EINVAL;
+       }
+
+       map = dev->context_sareas[request->ctx_id];
+       DRM_UNLOCK(dev);
+
+       request->handle = (void *)map->handle;
+
+       return 0;
+}
+
+int drm_setsareactx(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
+{
+       struct drm_ctx_priv_map *request = data;
+       drm_local_map_t *map = NULL;
+
+       DRM_LOCK(dev);
+       TAILQ_FOREACH(map, &dev->maplist, link) {
+               if (map->handle == request->handle) {
+                       if (dev->max_context < 0)
+                               goto bad;
+                       if (request->ctx_id >= (unsigned) dev->max_context)
+                               goto bad;
+                       dev->context_sareas[request->ctx_id] = map;
+                       DRM_UNLOCK(dev);
+                       return 0;
+               }
+       }
+
+bad:
+       DRM_UNLOCK(dev);
+       return EINVAL;
+}
+
+/* ================================================================
+ * The actual DRM context handling routines
+ */
+
+int drm_context_switch(struct drm_device *dev, int old, int new)
+{
+       if (test_and_set_bit(0, &dev->context_flag)) {
+               DRM_ERROR("Reentering -- FIXME\n");
+               return EBUSY;
+       }
+
+       DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+       if (new == dev->last_context) {
+               clear_bit(0, &dev->context_flag);
+               return 0;
+       }
+
+       return 0;
+}
+
+int drm_context_switch_complete(struct drm_device *dev, int new)
+{
+       dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
+
+       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+               DRM_ERROR("Lock isn't held after context switch\n");
+       }
+
+       /* If a context switch is ever initiated
+          when the kernel holds the lock, release
+          that lock here. */
+       clear_bit(0, &dev->context_flag);
+
+       return 0;
+}
+
+int drm_resctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       struct drm_ctx_res *res = data;
+       struct drm_ctx ctx;
+       int i;
+
+       if (res->count >= DRM_RESERVED_CONTEXTS) {
+               bzero(&ctx, sizeof(ctx));
+               for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+                       ctx.handle = i;
+                       if (DRM_COPY_TO_USER(&res->contexts[i],
+                           &ctx, sizeof(ctx)))
+                               return EFAULT;
+               }
+       }
+       res->count = DRM_RESERVED_CONTEXTS;
+
+       return 0;
+}
+
+int drm_addctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       struct drm_ctx *ctx = data;
+
+       ctx->handle = drm_ctxbitmap_next(dev);
+       if (ctx->handle == DRM_KERNEL_CONTEXT) {
+               /* Skip kernel's context and get a new one. */
+               ctx->handle = drm_ctxbitmap_next(dev);
+       }
+       DRM_DEBUG("%d\n", ctx->handle);
+       if (ctx->handle == -1) {
+               DRM_DEBUG("Not enough free contexts.\n");
+               /* Should this return -EBUSY instead? */
+               return ENOMEM;
+       }
+
+       if (dev->driver->context_ctor && ctx->handle != DRM_KERNEL_CONTEXT) {
+               DRM_LOCK(dev);
+               dev->driver->context_ctor(dev, ctx->handle);
+               DRM_UNLOCK(dev);
+       }
+
+       return 0;
+}
+
+int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       /* This does nothing */
+       return 0;
+}
+
+int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       struct drm_ctx *ctx = data;
+
+       /* This is 0, because we don't handle any context flags */
+       ctx->flags = 0;
+
+       return 0;
+}
+
+int drm_switchctx(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
+{
+       struct drm_ctx *ctx = data;
+
+       DRM_DEBUG("%d\n", ctx->handle);
+       return drm_context_switch(dev, dev->last_context, ctx->handle);
+}
+
+int drm_newctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       struct drm_ctx *ctx = data;
+
+       DRM_DEBUG("%d\n", ctx->handle);
+       drm_context_switch_complete(dev, ctx->handle);
+
+       return 0;
+}
+
+int drm_rmctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       struct drm_ctx *ctx = data;
+
+       DRM_DEBUG("%d\n", ctx->handle);
+       if (ctx->handle != DRM_KERNEL_CONTEXT) {
+               if (dev->driver->context_dtor) {
+                       DRM_LOCK(dev);
+                       dev->driver->context_dtor(dev, ctx->handle);
+                       DRM_UNLOCK(dev);
+               }
+
+               drm_ctxbitmap_free(dev, ctx->handle);
+       }
+
+       return 0;
+}
diff --git a/sys/dev/drm2/drm_crtc.c b/sys/dev/drm2/drm_crtc.c
new file mode 100644 (file)
index 0000000..fa0f939
--- /dev/null
@@ -0,0 +1,3413 @@
+/*
+ * Copyright (c) 2006-2008 Intel Corporation
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
+ * Copyright (c) 2008 Red Hat Inc.
+ *
+ * DRM core CRTC related functions
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * Authors:
+ *      Keith Packard
+ *     Eric Anholt <eric@anholt.net>
+ *      Dave Airlie <airlied@linux.ie>
+ *      Jesse Barnes <jesse.barnes@intel.com>
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/drm2/drm_crtc.c,v 1.1 2012/05/22 11:07:44 kib Exp $");
+
+#include <dev/drm2/drm.h>
+#include <dev/drm2/drmP.h>
+#include <dev/drm2/drm_crtc.h>
+#include <dev/drm2/drm_edid.h>
+#include <dev/drm2/drm_fourcc.h>
+#include <sys/limits.h>
+
+/* Avoid boilerplate.  I'm tired of typing. */
+#define DRM_ENUM_NAME_FN(fnname, list)                         \
+       char *fnname(int val)                                   \
+       {                                                       \
+               int i;                                          \
+               for (i = 0; i < DRM_ARRAY_SIZE(list); i++) {    \
+                       if (list[i].type == val)                \
+                               return list[i].name;            \
+               }                                               \
+               return "(unknown)";                             \
+       }
+
+/*
+ * Global properties
+ */
+static struct drm_prop_enum_list drm_dpms_enum_list[] =
+{      { DRM_MODE_DPMS_ON, "On" },
+       { DRM_MODE_DPMS_STANDBY, "Standby" },
+       { DRM_MODE_DPMS_SUSPEND, "Suspend" },
+       { DRM_MODE_DPMS_OFF, "Off" }
+};
+
+DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
+
+/*
+ * Optional properties
+ */
+static struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
+{
+       { DRM_MODE_SCALE_NONE, "None" },
+       { DRM_MODE_SCALE_FULLSCREEN, "Full" },
+       { DRM_MODE_SCALE_CENTER, "Center" },
+       { DRM_MODE_SCALE_ASPECT, "Full aspect" },
+};
+
+static struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
+{
+       { DRM_MODE_DITHERING_OFF, "Off" },
+       { DRM_MODE_DITHERING_ON, "On" },
+       { DRM_MODE_DITHERING_AUTO, "Automatic" },
+};
+
+/*
+ * Non-global properties, but "required" for certain connectors.
+ */
+static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
+{
+       { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
+       { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
+};
+
+DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
+
+static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
+{
+       { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
+       { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
+};
+
+DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
+                drm_dvi_i_subconnector_enum_list)
+
+static struct drm_prop_enum_list drm_tv_select_enum_list[] =
+{
+       { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_SCART,     "SCART"     }, /* TV-out */
+};
+
+DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
+
+static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
+{
+       { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_SCART,     "SCART"     }, /* TV-out */
+};
+
+DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
+                drm_tv_subconnector_enum_list)
+
+static struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
+       { DRM_MODE_DIRTY_OFF,      "Off"      },
+       { DRM_MODE_DIRTY_ON,       "On"       },
+       { DRM_MODE_DIRTY_ANNOTATE, "Annotate" },
+};
+
+DRM_ENUM_NAME_FN(drm_get_dirty_info_name,
+                drm_dirty_info_enum_list)
+
+struct drm_conn_prop_enum_list {
+       int type;
+       char *name;
+       int count;
+};
+
+/*
+ * Connector and encoder types.
+ */
+static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
+{      { DRM_MODE_CONNECTOR_Unknown, "Unknown", 0 },
+       { DRM_MODE_CONNECTOR_VGA, "VGA", 0 },
+       { DRM_MODE_CONNECTOR_DVII, "DVI-I", 0 },
+       { DRM_MODE_CONNECTOR_DVID, "DVI-D", 0 },
+       { DRM_MODE_CONNECTOR_DVIA, "DVI-A", 0 },
+       { DRM_MODE_CONNECTOR_Composite, "Composite", 0 },
+       { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 },
+       { DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 },
+       { DRM_MODE_CONNECTOR_Component, "Component", 0 },
+       { DRM_MODE_CONNECTOR_9PinDIN, "DIN", 0 },
+       { DRM_MODE_CONNECTOR_DisplayPort, "DP", 0 },
+       { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A", 0 },
+       { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 },
+       { DRM_MODE_CONNECTOR_TV, "TV", 0 },
+       { DRM_MODE_CONNECTOR_eDP, "eDP", 0 },
+};
+
+static struct drm_prop_enum_list drm_encoder_enum_list[] =
+{      { DRM_MODE_ENCODER_NONE, "None" },
+       { DRM_MODE_ENCODER_DAC, "DAC" },
+       { DRM_MODE_ENCODER_TMDS, "TMDS" },
+       { DRM_MODE_ENCODER_LVDS, "LVDS" },
+       { DRM_MODE_ENCODER_TVDAC, "TV" },
+};
+
+char *drm_get_encoder_name(struct drm_encoder *encoder)
+{
+       static char buf[32];
+
+       snprintf(buf, 32, "%s-%d",
+                drm_encoder_enum_list[encoder->encoder_type].name,
+                encoder->base.id);
+       return buf;
+}
+
+char *drm_get_connector_name(struct drm_connector *connector)
+{
+       static char buf[32];
+
+       snprintf(buf, 32, "%s-%d",
+                drm_connector_enum_list[connector->connector_type].name,
+                connector->connector_type_id);
+       return buf;
+}
+
+char *drm_get_connector_status_name(enum drm_connector_status status)
+{
+       if (status == connector_status_connected)
+               return "connected";
+       else if (status == connector_status_disconnected)
+               return "disconnected";
+       else
+               return "unknown";
+}
+
+/**
+ * drm_mode_object_get - allocate a new identifier
+ * @dev: DRM device
+ * @ptr: object pointer, used to generate unique ID
+ * @type: object type
+ *
+ * LOCKING:
+ *
+ * Create a unique identifier based on @ptr in @dev's identifier space.  Used
+ * for tracking modes, CRTCs and connectors.
+ *
+ * RETURNS:
+ * New unique (relative to other objects in @dev) integer identifier for the
+ * object.
+ */
+static int drm_mode_object_get(struct drm_device *dev,
+                              struct drm_mode_object *obj, uint32_t obj_type)
+{
+       int new_id;
+       int ret;
+
+       new_id = 0;
+       ret = drm_gem_name_create(&dev->mode_config.crtc_names, obj, &new_id);
+       if (ret != 0)
+               return (ret);
+
+       obj->id = new_id;
+       obj->type = obj_type;
+       return 0;
+}
+
+/**
+ * drm_mode_object_put - free an identifer
+ * @dev: DRM device
+ * @id: ID to free
+ *
+ * LOCKING:
+ * Caller must hold DRM mode_config lock.
+ *
+ * Free @id from @dev's unique identifier pool.
+ */
+static void drm_mode_object_put(struct drm_device *dev,
+                               struct drm_mode_object *object)
+{
+
+       drm_gem_names_remove(&dev->mode_config.crtc_names, object->id);
+}
+
+struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
+               uint32_t id, uint32_t type)
+{
+       struct drm_mode_object *obj;
+
+       obj = drm_gem_name_ref(&dev->mode_config.crtc_names, id, NULL);
+       if (!obj || (obj->type != type) || (obj->id != id))
+               obj = NULL;
+
+       return obj;
+}
+
+/**
+ * drm_framebuffer_init - initialize a framebuffer
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Allocates an ID for the framebuffer's parent mode object, sets its mode
+ * functions & device file and adds it to the master fd list.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure.
+ */
+int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
+                        const struct drm_framebuffer_funcs *funcs)
+{
+       int ret;
+
+       DRM_MODE_CONFIG_ASSERT_LOCKED(dev);
+
+       ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
+       if (ret)
+               return ret;
+
+       fb->dev = dev;
+       fb->funcs = funcs;
+       dev->mode_config.num_fb++;
+       list_add(&fb->head, &dev->mode_config.fb_list);
+
+       return 0;
+}
+
+/**
+ * drm_framebuffer_cleanup - remove a framebuffer object
+ * @fb: framebuffer to remove
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Scans all the CRTCs in @dev's mode_config.  If they're using @fb, removes
+ * it, setting it to NULL.
+ */
+void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
+{
+       struct drm_device *dev = fb->dev;
+       struct drm_crtc *crtc;
+       struct drm_plane *plane;
+       struct drm_mode_set set;
+       int ret;
+
+       DRM_MODE_CONFIG_ASSERT_LOCKED(dev);
+
+       /* remove from any CRTC */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (crtc->fb == fb) {
+                       /* should turn off the crtc */
+                       memset(&set, 0, sizeof(struct drm_mode_set));
+                       set.crtc = crtc;
+                       set.fb = NULL;
+                       ret = crtc->funcs->set_config(&set);
+                       if (ret)
+                               DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
+               }
+       }
+
+       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+               if (plane->fb == fb) {
+                       /* should turn off the crtc */
+                       ret = plane->funcs->disable_plane(plane);
+                       if (ret)
+                               DRM_ERROR("failed to disable plane with busy fb\n");
+                       /* disconnect the plane from the fb and crtc: */
+                       plane->fb = NULL;
+                       plane->crtc = NULL;
+               }
+       }
+
+       drm_mode_object_put(dev, &fb->base);
+       list_del(&fb->head);
+       dev->mode_config.num_fb--;
+}
+
+/**
+ * drm_crtc_init - Initialise a new CRTC object
+ * @dev: DRM device
+ * @crtc: CRTC object to init
+ * @funcs: callbacks for the new CRTC
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Inits a new object created as base part of an driver crtc object.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure.
+ */
+int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+                  const struct drm_crtc_funcs *funcs)
+{
+       int ret;
+
+       crtc->dev = dev;
+       crtc->funcs = funcs;
+
+       sx_xlock(&dev->mode_config.mutex);
+       ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
+       if (ret)
+               goto out;
+
+       list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
+       dev->mode_config.num_crtc++;
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+
+       return ret;
+}
+
+/**
+ * drm_crtc_cleanup - Cleans up the core crtc usage.
+ * @crtc: CRTC to cleanup
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Cleanup @crtc. Removes from drm modesetting space
+ * does NOT free object, caller does that.
+ */
+void drm_crtc_cleanup(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+
+       DRM_MODE_CONFIG_ASSERT_LOCKED(dev);
+
+       if (crtc->gamma_store) {
+               free(crtc->gamma_store, DRM_MEM_KMS);
+               crtc->gamma_store = NULL;
+       }
+
+       drm_mode_object_put(dev, &crtc->base);
+       list_del(&crtc->head);
+       dev->mode_config.num_crtc--;
+}
+
+/**
+ * drm_mode_probed_add - add a mode to a connector's probed mode list
+ * @connector: connector the new mode
+ * @mode: mode data
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Add @mode to @connector's mode list for later use.
+ */
+void drm_mode_probed_add(struct drm_connector *connector,
+                        struct drm_display_mode *mode)
+{
+
+       DRM_MODE_CONFIG_ASSERT_LOCKED(connector->dev);
+
+       list_add(&mode->head, &connector->probed_modes);
+}
+
+/**
+ * drm_mode_remove - remove and free a mode
+ * @connector: connector list to modify
+ * @mode: mode to remove
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Remove @mode from @connector's mode list, then free it.
+ */
+void drm_mode_remove(struct drm_connector *connector,
+                    struct drm_display_mode *mode)
+{
+
+       DRM_MODE_CONFIG_ASSERT_LOCKED(connector->dev);
+
+       list_del(&mode->head);
+       drm_mode_destroy(connector->dev, mode);
+}
+
+/**
+ * drm_connector_init - Init a preallocated connector
+ * @dev: DRM device
+ * @connector: the connector to init
+ * @funcs: callbacks for this connector
+ * @name: user visible name of the connector
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Initialises a preallocated connector. Connectors should be
+ * subclassed as part of driver connector objects.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure.
+ */
+int drm_connector_init(struct drm_device *dev,
+                      struct drm_connector *connector,
+                      const struct drm_connector_funcs *funcs,
+                      int connector_type)
+{
+       int ret;
+
+       sx_xlock(&dev->mode_config.mutex);
+
+       ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
+       if (ret)
+               goto out;
+
+       connector->dev = dev;
+       connector->funcs = funcs;
+       connector->connector_type = connector_type;
+       connector->connector_type_id =
+               ++drm_connector_enum_list[connector_type].count; /* TODO */
+       INIT_LIST_HEAD(&connector->user_modes);
+       INIT_LIST_HEAD(&connector->probed_modes);
+       INIT_LIST_HEAD(&connector->modes);
+       connector->edid_blob_ptr = NULL;
+
+       list_add_tail(&connector->head, &dev->mode_config.connector_list);
+       dev->mode_config.num_connector++;
+
+       drm_connector_attach_property(connector,
+                                     dev->mode_config.edid_property, 0);
+
+       drm_connector_attach_property(connector,
+                                     dev->mode_config.dpms_property, 0);
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+
+       return ret;
+}
+
+/**
+ * drm_connector_cleanup - cleans up an initialised connector
+ * @connector: connector to cleanup
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Cleans up the connector but doesn't free the object.
+ */
+void drm_connector_cleanup(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_display_mode *mode, *t;
+
+       list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
+               drm_mode_remove(connector, mode);
+
+       list_for_each_entry_safe(mode, t, &connector->modes, head)
+               drm_mode_remove(connector, mode);
+
+       list_for_each_entry_safe(mode, t, &connector->user_modes, head)
+               drm_mode_remove(connector, mode);
+
+       sx_xlock(&dev->mode_config.mutex);
+       drm_mode_object_put(dev, &connector->base);
+       list_del(&connector->head);
+       dev->mode_config.num_connector--;
+       sx_xunlock(&dev->mode_config.mutex);
+}
+
+int drm_encoder_init(struct drm_device *dev,
+                    struct drm_encoder *encoder,
+                    const struct drm_encoder_funcs *funcs,
+                    int encoder_type)
+{
+       int ret;
+
+       sx_xlock(&dev->mode_config.mutex);
+
+       ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
+       if (ret)
+               goto out;
+
+       encoder->dev = dev;
+       encoder->encoder_type = encoder_type;
+       encoder->funcs = funcs;
+
+       list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
+       dev->mode_config.num_encoder++;
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+
+       return ret;
+}
+
+void drm_encoder_cleanup(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+
+       sx_xlock(&dev->mode_config.mutex);
+       drm_mode_object_put(dev, &encoder->base);
+       list_del(&encoder->head);
+       dev->mode_config.num_encoder--;
+       sx_xunlock(&dev->mode_config.mutex);
+}
+
+int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
+                  unsigned long possible_crtcs,
+                  const struct drm_plane_funcs *funcs,
+                  const uint32_t *formats, uint32_t format_count,
+                  bool priv)
+{
+       int ret;
+
+       sx_xlock(&dev->mode_config.mutex);
+
+       ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
+       if (ret)
+               goto out;
+
+       plane->dev = dev;
+       plane->funcs = funcs;
+       plane->format_types = malloc(sizeof(uint32_t) * format_count,
+           DRM_MEM_KMS, M_WAITOK);
+
+       memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
+       plane->format_count = format_count;
+       plane->possible_crtcs = possible_crtcs;
+
+       /* private planes are not exposed to userspace, but depending on
+        * display hardware, might be convenient to allow sharing programming
+        * for the scanout engine with the crtc implementation.
+        */
+       if (!priv) {
+               list_add_tail(&plane->head, &dev->mode_config.plane_list);
+               dev->mode_config.num_plane++;
+       } else {
+               INIT_LIST_HEAD(&plane->head);
+       }
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+
+       return ret;
+}
+
+void drm_plane_cleanup(struct drm_plane *plane)
+{
+       struct drm_device *dev = plane->dev;
+
+       sx_xlock(&dev->mode_config.mutex);
+       free(plane->format_types, DRM_MEM_KMS);
+       drm_mode_object_put(dev, &plane->base);
+       /* if not added to a list, it must be a private plane */
+       if (!list_empty(&plane->head)) {
+               list_del(&plane->head);
+               dev->mode_config.num_plane--;
+       }
+       sx_xunlock(&dev->mode_config.mutex);
+}
+
+/**
+ * drm_mode_create - create a new display mode
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller must hold DRM mode_config lock.
+ *
+ * Create a new drm_display_mode, give it an ID, and return it.
+ *
+ * RETURNS:
+ * Pointer to new mode on success, NULL on error.
+ */
+struct drm_display_mode *drm_mode_create(struct drm_device *dev)
+{
+       struct drm_display_mode *nmode;
+
+       nmode = malloc(sizeof(struct drm_display_mode), DRM_MEM_KMS,
+           M_WAITOK | M_ZERO);
+
+       if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
+               free(nmode, DRM_MEM_KMS);
+               return (NULL);
+       }
+       return nmode;
+}
+
+/**
+ * drm_mode_destroy - remove a mode
+ * @dev: DRM device
+ * @mode: mode to remove
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Free @mode's unique identifier, then free it.
+ */
+void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
+{
+       if (!mode)
+               return;
+
+       drm_mode_object_put(dev, &mode->base);
+
+       free(mode, DRM_MEM_KMS);
+}
+
+static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
+{
+       struct drm_property *edid;
+       struct drm_property *dpms;
+
+       /*
+        * Standard properties (apply to all connectors)
+        */
+       edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
+                                  DRM_MODE_PROP_IMMUTABLE,
+                                  "EDID", 0);
+       dev->mode_config.edid_property = edid;
+
+       dpms = drm_property_create_enum(dev, 0,
+                                  "DPMS", drm_dpms_enum_list,
+                                   DRM_ARRAY_SIZE(drm_dpms_enum_list));
+       dev->mode_config.dpms_property = dpms;
+
+       return 0;
+}
+
+/**
+ * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
+ * @dev: DRM device
+ *
+ * Called by a driver the first time a DVI-I connector is made.
+ */
+int drm_mode_create_dvi_i_properties(struct drm_device *dev)
+{
+       struct drm_property *dvi_i_selector;
+       struct drm_property *dvi_i_subconnector;
+
+       if (dev->mode_config.dvi_i_select_subconnector_property)
+               return 0;
+
+       dvi_i_selector =
+               drm_property_create_enum(dev, 0,
+                                   "select subconnector",
+                                   drm_dvi_i_select_enum_list,
+                                   DRM_ARRAY_SIZE(drm_dvi_i_select_enum_list));
+       dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
+
+       dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+                                   "subconnector",
+                                   drm_dvi_i_subconnector_enum_list,
+                                   DRM_ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
+       dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
+
+       return 0;
+}
+
+/**
+ * drm_create_tv_properties - create TV specific connector properties
+ * @dev: DRM device
+ * @num_modes: number of different TV formats (modes) supported
+ * @modes: array of pointers to strings containing name of each format
+ *
+ * Called by a driver's TV initialization routine, this function creates
+ * the TV specific connector properties for a given device.  Caller is
+ * responsible for allocating a list of format names and passing them to
+ * this routine.
+ */
+int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
+                                 char *modes[])
+{
+       struct drm_property *tv_selector;
+       struct drm_property *tv_subconnector;
+       int i;
+
+       if (dev->mode_config.tv_select_subconnector_property)
+               return 0;
+
+       /*
+        * Basic connector properties
+        */
+       tv_selector = drm_property_create_enum(dev, 0,
+                                         "select subconnector",
+                                         drm_tv_select_enum_list,
+                                         DRM_ARRAY_SIZE(drm_tv_select_enum_list));
+       dev->mode_config.tv_select_subconnector_property = tv_selector;
+
+       tv_subconnector =
+               drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+                                   "subconnector",
+                                   drm_tv_subconnector_enum_list,
+                                   DRM_ARRAY_SIZE(drm_tv_subconnector_enum_list));
+       dev->mode_config.tv_subconnector_property = tv_subconnector;
+
+       /*
+        * Other, TV specific properties: margins & TV modes.
+        */
+       dev->mode_config.tv_left_margin_property =
+               drm_property_create_range(dev, 0, "left margin", 0, 100);
+
+       dev->mode_config.tv_right_margin_property =
+               drm_property_create_range(dev, 0, "right margin", 0, 100);
+
+       dev->mode_config.tv_top_margin_property =
+               drm_property_create_range(dev, 0, "top margin", 0, 100);
+
+       dev->mode_config.tv_bottom_margin_property =
+               drm_property_create_range(dev, 0, "bottom margin", 0, 100);
+
+       dev->mode_config.tv_mode_property =
+               drm_property_create(dev, DRM_MODE_PROP_ENUM,
+                                   "mode", num_modes);
+       for (i = 0; i < num_modes; i++)
+               drm_property_add_enum(dev->mode_config.tv_mode_property, i,
+                                     i, modes[i]);
+
+       dev->mode_config.tv_brightness_property =
+               drm_property_create_range(dev, 0, "brightness", 0, 100);
+
+       dev->mode_config.tv_contrast_property =
+               drm_property_create_range(dev, 0, "contrast", 0, 100);
+
+       dev->mode_config.tv_flicker_reduction_property =
+               drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
+
+       dev->mode_config.tv_overscan_property =
+               drm_property_create_range(dev, 0, "overscan", 0, 100);
+
+       dev->mode_config.tv_saturation_property =
+               drm_property_create_range(dev, 0, "saturation", 0, 100);
+
+       dev->mode_config.tv_hue_property =
+               drm_property_create_range(dev, 0, "hue", 0, 100);
+
+       return 0;
+}
+
+/**
+ * drm_mode_create_scaling_mode_property - create scaling mode property
+ * @dev: DRM device
+ *
+ * Called by a driver the first time it's needed, must be attached to desired
+ * connectors.
+ */
+int drm_mode_create_scaling_mode_property(struct drm_device *dev)
+{
+       struct drm_property *scaling_mode;
+
+       if (dev->mode_config.scaling_mode_property)
+               return 0;
+
+       scaling_mode =
+               drm_property_create_enum(dev, 0, "scaling mode",
+                               drm_scaling_mode_enum_list,
+                                   DRM_ARRAY_SIZE(drm_scaling_mode_enum_list));
+
+       dev->mode_config.scaling_mode_property = scaling_mode;
+
+       return 0;
+}
+
+/**
+ * drm_mode_create_dithering_property - create dithering property
+ * @dev: DRM device
+ *
+ * Called by a driver the first time it's needed, must be attached to desired
+ * connectors.
+ */
+int drm_mode_create_dithering_property(struct drm_device *dev)
+{
+       struct drm_property *dithering_mode;
+
+       if (dev->mode_config.dithering_mode_property)
+               return 0;
+
+       dithering_mode =
+               drm_property_create_enum(dev, 0, "dithering",
+                               drm_dithering_mode_enum_list,
+                                   DRM_ARRAY_SIZE(drm_dithering_mode_enum_list));
+       dev->mode_config.dithering_mode_property = dithering_mode;
+
+       return 0;
+}
+
+/**
+ * drm_mode_create_dirty_property - create dirty property
+ * @dev: DRM device
+ *
+ * Called by a driver the first time it's needed, must be attached to desired
+ * connectors.
+ */
+int drm_mode_create_dirty_info_property(struct drm_device *dev)
+{
+       struct drm_property *dirty_info;
+
+       if (dev->mode_config.dirty_info_property)
+               return 0;
+
+       dirty_info =
+               drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+                                   "dirty",
+                                   drm_dirty_info_enum_list,
+                                   DRM_ARRAY_SIZE(drm_dirty_info_enum_list));
+       dev->mode_config.dirty_info_property = dirty_info;
+
+       return 0;
+}
+
+/**
+ * drm_mode_config_init - initialize DRM mode_configuration structure
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * None, should happen single threaded at init time.
+ *
+ * Initialize @dev's mode_config structure, used for tracking the graphics
+ * configuration of @dev.
+ */
+void drm_mode_config_init(struct drm_device *dev)
+{
+       sx_init(&dev->mode_config.mutex, "kmslk");
+       INIT_LIST_HEAD(&dev->mode_config.fb_list);
+       INIT_LIST_HEAD(&dev->mode_config.crtc_list);
+       INIT_LIST_HEAD(&dev->mode_config.connector_list);
+       INIT_LIST_HEAD(&dev->mode_config.encoder_list);
+       INIT_LIST_HEAD(&dev->mode_config.property_list);
+       INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
+       INIT_LIST_HEAD(&dev->mode_config.plane_list);
+       drm_gem_names_init(&dev->mode_config.crtc_names);
+
+       sx_xlock(&dev->mode_config.mutex);
+       drm_mode_create_standard_connector_properties(dev);
+       sx_xunlock(&dev->mode_config.mutex);
+
+       /* Just to be sure */
+       dev->mode_config.num_fb = 0;
+       dev->mode_config.num_connector = 0;
+       dev->mode_config.num_crtc = 0;
+       dev->mode_config.num_encoder = 0;
+}
+
+static int
+drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
+{
+       uint32_t total_objects = 0;
+
+       total_objects += dev->mode_config.num_crtc;
+       total_objects += dev->mode_config.num_connector;
+       total_objects += dev->mode_config.num_encoder;
+
+       group->id_list = malloc(total_objects * sizeof(uint32_t),
+           DRM_MEM_KMS, M_WAITOK | M_ZERO);
+
+       group->num_crtcs = 0;
+       group->num_connectors = 0;
+       group->num_encoders = 0;
+       return 0;
+}
+
+int drm_mode_group_init_legacy_group(struct drm_device *dev,
+                                    struct drm_mode_group *group)
+{
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+       int ret;
+
+       if ((ret = drm_mode_group_init(dev, group)))
+               return ret;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+               group->id_list[group->num_crtcs++] = crtc->base.id;
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               group->id_list[group->num_crtcs + group->num_encoders++] =
+               encoder->base.id;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               group->id_list[group->num_crtcs + group->num_encoders +
+                              group->num_connectors++] = connector->base.id;
+
+       return 0;
+}
+
+/**
+ * drm_mode_config_cleanup - free up DRM mode_config info
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Free up all the connectors and CRTCs associated with this DRM device, then
+ * free up the framebuffers and associated buffer objects.
+ *
+ * FIXME: cleanup any dangling user buffer objects too
+ */
+void drm_mode_config_cleanup(struct drm_device *dev)
+{
+       struct drm_connector *connector, *ot;
+       struct drm_crtc *crtc, *ct;
+       struct drm_encoder *encoder, *enct;
+       struct drm_framebuffer *fb, *fbt;
+       struct drm_property *property, *pt;
+       struct drm_plane *plane, *plt;
+
+       list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
+                                head) {
+               encoder->funcs->destroy(encoder);
+       }
+
+       list_for_each_entry_safe(connector, ot,
+                                &dev->mode_config.connector_list, head) {
+               connector->funcs->destroy(connector);
+       }
+
+       list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
+                                head) {
+               drm_property_destroy(dev, property);
+       }
+
+       list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
+               fb->funcs->destroy(fb);
+       }
+
+       list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
+               crtc->funcs->destroy(crtc);
+       }
+
+       list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
+                                head) {
+               plane->funcs->destroy(plane);
+       }
+       drm_gem_names_fini(&dev->mode_config.crtc_names);
+}
+
+/**
+ * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
+ * @out: drm_mode_modeinfo struct to return to the user
+ * @in: drm_display_mode to use
+ *
+ * LOCKING:
+ * None.
+ *
+ * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
+ * the user.
+ */
+static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
+                                     const struct drm_display_mode *in)
+{
+       if (in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
+           in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
+           in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
+           in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
+           in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX)
+               printf("timing values too large for mode info\n");
+
+       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;
+       out->type = in->type;
+       strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
+       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 drm_mode_modeinfo into a drm_display_mode structure to return to
+ * the caller.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+static int drm_crtc_convert_umode(struct drm_display_mode *out,
+                                 const struct drm_mode_modeinfo *in)
+{
+       if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
+               return ERANGE;
+
+       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;
+       out->type = in->type;
+       strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
+       out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
+
+       return 0;
+}
+
+/**
+ * drm_mode_getresources - get graphics configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Construct a set of configuration description structures and return
+ * them to the user, including CRTC, connector and framebuffer configuration.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getresources(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
+{
+       struct drm_mode_card_res *card_res = data;
+       struct list_head *lh;
+       struct drm_framebuffer *fb;
+       struct drm_connector *connector;
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       int ret = 0;
+       int connector_count = 0;
+       int crtc_count = 0;
+       int fb_count = 0;
+       int encoder_count = 0;
+       int copied = 0, i;
+       uint32_t __user *fb_id;
+       uint32_t __user *crtc_id;
+       uint32_t __user *connector_id;
+       uint32_t __user *encoder_id;
+       struct drm_mode_group *mode_group;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       sx_xlock(&dev->mode_config.mutex);
+
+       /*
+        * For the non-control nodes we need to limit the list of resources
+        * by IDs in the group list for this node
+        */
+       list_for_each(lh, &file_priv->fbs)
+               fb_count++;
+
+#if 1
+       mode_group = NULL; /* XXXKIB */
+       if (1 || file_priv->master) {
+#else
+       mode_group = &file_priv->masterp->minor->mode_group;
+       if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) {
+#endif
+
+               list_for_each(lh, &dev->mode_config.crtc_list)
+                       crtc_count++;
+
+               list_for_each(lh, &dev->mode_config.connector_list)
+                       connector_count++;
+
+               list_for_each(lh, &dev->mode_config.encoder_list)
+                       encoder_count++;
+       } else {
+
+               crtc_count = mode_group->num_crtcs;
+               connector_count = mode_group->num_connectors;
+               encoder_count = mode_group->num_encoders;
+       }
+
+       card_res->max_height = dev->mode_config.max_height;
+       card_res->min_height = dev->mode_config.min_height;
+       card_res->max_width = dev->mode_config.max_width;
+       card_res->min_width = dev->mode_config.min_width;
+
+       /* handle this in 4 parts */
+       /* FBs */
+       if (card_res->count_fbs >= fb_count) {
+               copied = 0;
+               fb_id = (uint32_t *)(uintptr_t)card_res->fb_id_ptr;
+               list_for_each_entry(fb, &file_priv->fbs, filp_head) {
+                       if (copyout(&fb->base.id, fb_id + copied,
+                           sizeof(uint32_t))) {
+                               ret = EFAULT;
+                               goto out;
+                       }
+                       copied++;
+               }
+       }
+       card_res->count_fbs = fb_count;
+
+       /* CRTCs */
+       if (card_res->count_crtcs >= crtc_count) {
+               copied = 0;
+               crtc_id = (uint32_t *)(uintptr_t)card_res->crtc_id_ptr;
+#if 1
+               if (1 || file_priv->master) {
+#else
+               if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) {
+#endif
+                       list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+                                           head) {
+                               DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
+                               if (copyout(&crtc->base.id, crtc_id +
+                                   copied, sizeof(uint32_t))) {
+                                       ret = EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               } else {
+                       for (i = 0; i < mode_group->num_crtcs; i++) {
+                               if (copyout(&mode_group->id_list[i],
+                                   crtc_id + copied, sizeof(uint32_t))) {
+                                       ret = EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               }
+       }
+       card_res->count_crtcs = crtc_count;
+
+       /* Encoders */
+       if (card_res->count_encoders >= encoder_count) {
+               copied = 0;
+               encoder_id = (uint32_t *)(uintptr_t)card_res->encoder_id_ptr;
+#if 1
+               if (file_priv->master) {
+#else
+               if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) {
+#endif
+                       list_for_each_entry(encoder,
+                                           &dev->mode_config.encoder_list,
+                                           head) {
+                               DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id,
+                                               drm_get_encoder_name(encoder));
+                               if (copyout(&encoder->base.id, encoder_id +
+                                   copied, sizeof(uint32_t))) {
+                                       ret = EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               } else {
+                       for (i = mode_group->num_crtcs;
+                           i < mode_group->num_crtcs + mode_group->num_encoders;
+                            i++) {
+                               if (copyout(&mode_group->id_list[i],
+                                   encoder_id + copied, sizeof(uint32_t))) {
+                                       ret = EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+
+               }
+       }
+       card_res->count_encoders = encoder_count;
+
+       /* Connectors */
+       if (card_res->count_connectors >= connector_count) {
+               copied = 0;
+               connector_id = (uint32_t *)(uintptr_t)card_res->connector_id_ptr;
+#if 1
+               if (file_priv->master) {
+#else
+               if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) {
+#endif
+                       list_for_each_entry(connector,
+                                           &dev->mode_config.connector_list,
+                                           head) {
+                               DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                                       connector->base.id,
+                                       drm_get_connector_name(connector));
+                               if (copyout(&connector->base.id,
+                                   connector_id + copied, sizeof(uint32_t))) {
+                                       ret = EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               } else {
+                       int start = mode_group->num_crtcs +
+                               mode_group->num_encoders;
+                       for (i = start; i < start + mode_group->num_connectors; i++) {
+                               if (copyout(&mode_group->id_list[i],
+                                   connector_id + copied, sizeof(uint32_t))) {
+                                       ret = EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               }
+       }
+       card_res->count_connectors = connector_count;
+
+       DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs,
+                 card_res->count_connectors, card_res->count_encoders);
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_getcrtc - get CRTC configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Construct a CRTC configuration structure to return to the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getcrtc(struct drm_device *dev,
+                    void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_crtc *crtc_resp = data;
+       struct drm_crtc *crtc;
+       struct drm_mode_object *obj;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       sx_xlock(&dev->mode_config.mutex);
+
+       obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
+                                  DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               ret = (EINVAL);
+               goto out;
+       }
+       crtc = obj_to_crtc(obj);
+
+       crtc_resp->x = crtc->x;
+       crtc_resp->y = crtc->y;
+       crtc_resp->gamma_size = crtc->gamma_size;
+       if (crtc->fb)
+               crtc_resp->fb_id = crtc->fb->base.id;
+       else
+               crtc_resp->fb_id = 0;
+
+       if (crtc->enabled) {
+
+               drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
+               crtc_resp->mode_valid = 1;
+
+       } else {
+               crtc_resp->mode_valid = 0;
+       }
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_getconnector - get connector configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Construct a connector configuration structure to return to the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getconnector(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
+{
+       struct drm_mode_get_connector *out_resp = data;
+       struct drm_mode_object *obj;
+       struct drm_connector *connector;
+       struct drm_display_mode *mode;
+       int mode_count = 0;
+       int props_count = 0;
+       int encoders_count = 0;
+       int ret = 0;
+       int copied = 0;
+       int i;
+       struct drm_mode_modeinfo u_mode;
+       struct drm_mode_modeinfo __user *mode_ptr;
+       uint32_t *prop_ptr;
+       uint64_t *prop_values;
+       uint32_t *encoder_ptr;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
+
+       sx_xlock(&dev->mode_config.mutex);
+
+       obj = drm_mode_object_find(dev, out_resp->connector_id,
+                                  DRM_MODE_OBJECT_CONNECTOR);
+       if (!obj) {
+               ret = EINVAL;
+               goto out;
+       }
+       connector = obj_to_connector(obj);
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
+               if (connector->property_ids[i] != 0) {
+                       props_count++;
+               }
+       }
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] != 0) {
+                       encoders_count++;
+               }
+       }
+
+       if (out_resp->count_modes == 0) {
+               connector->funcs->fill_modes(connector,
+                                            dev->mode_config.max_width,
+                                            dev->mode_config.max_height);
+       }
+
+       /* delayed so we get modes regardless of pre-fill_modes state */
+       list_for_each_entry(mode, &connector->modes, head)
+               mode_count++;
+
+       out_resp->connector_id = connector->base.id;
+       out_resp->connector_type = connector->connector_type;
+       out_resp->connector_type_id = connector->connector_type_id;
+       out_resp->mm_width = connector->display_info.width_mm;
+       out_resp->mm_height = connector->display_info.height_mm;
+       out_resp->subpixel = connector->display_info.subpixel_order;
+       out_resp->connection = connector->status;
+       if (connector->encoder)
+               out_resp->encoder_id = connector->encoder->base.id;
+       else
+               out_resp->encoder_id = 0;
+
+       /*
+        * This ioctl is called twice, once to determine how much space is
+        * needed, and the 2nd time to fill it.
+        */
+       if ((out_resp->count_modes >= mode_count) && mode_count) {
+               copied = 0;
+               mode_ptr = (struct drm_mode_modeinfo *)(uintptr_t)out_resp->modes_ptr;
+               list_for_each_entry(mode, &connector->modes, head) {
+                       drm_crtc_convert_to_umode(&u_mode, mode);
+                       if (copyout(&u_mode, mode_ptr + copied,
+                           sizeof(u_mode))) {
+                               ret = EFAULT;
+                               goto out;
+                       }
+                       copied++;
+               }
+       }
+       out_resp->count_modes = mode_count;
+
+       if ((out_resp->count_props >= props_count) && props_count) {
+               copied = 0;
+               prop_ptr = (uint32_t *)(uintptr_t)(out_resp->props_ptr);
+               prop_values = (uint64_t *)(uintptr_t)(out_resp->prop_values_ptr);
+               for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
+                       if (connector->property_ids[i] != 0) {
+                               if (copyout(&connector->property_ids[i],
+                                   prop_ptr + copied, sizeof(uint32_t))) {
+                                       ret = EFAULT;
+                                       goto out;
+                               }
+
+                               if (copyout(&connector->property_values[i],
+                                   prop_values + copied, sizeof(uint64_t))) {
+                                       ret = EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               }
+       }
+       out_resp->count_props = props_count;
+
+       if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
+               copied = 0;
+               encoder_ptr = (uint32_t *)(uintptr_t)(out_resp->encoders_ptr);
+               for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+                       if (connector->encoder_ids[i] != 0) {
+                               if (copyout(&connector->encoder_ids[i],
+                                   encoder_ptr + copied, sizeof(uint32_t))) {
+                                       ret = EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               }
+       }
+       out_resp->count_encoders = encoders_count;
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+int drm_mode_getencoder(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+       struct drm_mode_get_encoder *enc_resp = data;
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       sx_xlock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, enc_resp->encoder_id,
+                                  DRM_MODE_OBJECT_ENCODER);
+       if (!obj) {
+               ret = EINVAL;
+               goto out;
+       }
+       encoder = obj_to_encoder(obj);
+
+       if (encoder->crtc)
+               enc_resp->crtc_id = encoder->crtc->base.id;
+       else
+               enc_resp->crtc_id = 0;
+       enc_resp->encoder_type = encoder->encoder_type;
+       enc_resp->encoder_id = encoder->base.id;
+       enc_resp->possible_crtcs = encoder->possible_crtcs;
+       enc_resp->possible_clones = encoder->possible_clones;
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_getplane_res - get plane info
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Return an plane count and set of IDs.
+ */
+int drm_mode_getplane_res(struct drm_device *dev, void *data,
+                           struct drm_file *file_priv)
+{
+       struct drm_mode_get_plane_res *plane_resp = data;
+       struct drm_mode_config *config;
+       struct drm_plane *plane;
+       uint32_t *plane_ptr;
+       int copied = 0, ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       sx_xlock(&dev->mode_config.mutex);
+       config = &dev->mode_config;
+
+       /*
+        * This ioctl is called twice, once to determine how much space is
+        * needed, and the 2nd time to fill it.
+        */
+       if (config->num_plane &&
+           (plane_resp->count_planes >= config->num_plane)) {
+               plane_ptr = (uint32_t *)(unsigned long)plane_resp->plane_id_ptr;
+
+               list_for_each_entry(plane, &config->plane_list, head) {
+                       if (copyout(&plane->base.id, plane_ptr + copied,
+                           sizeof(uint32_t))) {
+                               ret = EFAULT;
+                               goto out;
+                       }
+                       copied++;
+               }
+       }
+       plane_resp->count_planes = config->num_plane;
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_getplane - get plane info
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Return plane info, including formats supported, gamma size, any
+ * current fb, etc.
+ */
+int drm_mode_getplane(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+       struct drm_mode_get_plane *plane_resp = data;
+       struct drm_mode_object *obj;
+       struct drm_plane *plane;
+       uint32_t *format_ptr;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       sx_xlock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, plane_resp->plane_id,
+                                  DRM_MODE_OBJECT_PLANE);
+       if (!obj) {
+               ret = ENOENT;
+               goto out;
+       }
+       plane = obj_to_plane(obj);
+
+       if (plane->crtc)
+               plane_resp->crtc_id = plane->crtc->base.id;
+       else
+               plane_resp->crtc_id = 0;
+
+       if (plane->fb)
+               plane_resp->fb_id = plane->fb->base.id;
+       else
+               plane_resp->fb_id = 0;
+
+       plane_resp->plane_id = plane->base.id;
+       plane_resp->possible_crtcs = plane->possible_crtcs;
+       plane_resp->gamma_size = plane->gamma_size;
+
+       /*
+        * This ioctl is called twice, once to determine how much space is
+        * needed, and the 2nd time to fill it.
+        */
+       if (plane->format_count &&
+           (plane_resp->count_format_types >= plane->format_count)) {
+               format_ptr = (uint32_t *)(unsigned long)plane_resp->format_type_ptr;
+               if (copyout(format_ptr,
+                                plane->format_types,
+                                sizeof(uint32_t) * plane->format_count)) {
+                       ret = EFAULT;
+                       goto out;
+               }
+       }
+       plane_resp->count_format_types = plane->format_count;
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_setplane - set up or tear down an plane
+ * @dev: DRM device
+ * @data: ioctl data*
+ * @file_prive: DRM file info
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Set plane info, including placement, fb, scaling, and other factors.
+ * Or pass a NULL fb to disable.
+ */
+int drm_mode_setplane(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+       struct drm_mode_set_plane *plane_req = data;
+       struct drm_mode_object *obj;
+       struct drm_plane *plane;
+       struct drm_crtc *crtc;
+       struct drm_framebuffer *fb;
+       int ret = 0;
+       unsigned int fb_width, fb_height;
+       int i;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       sx_xlock(&dev->mode_config.mutex);
+
+       /*
+        * First, find the plane, crtc, and fb objects.  If not available,
+        * we don't bother to call the driver.
+        */
+       obj = drm_mode_object_find(dev, plane_req->plane_id,
+                                  DRM_MODE_OBJECT_PLANE);
+       if (!obj) {
+               DRM_DEBUG_KMS("Unknown plane ID %d\n",
+                             plane_req->plane_id);
+               ret = ENOENT;
+               goto out;
+       }
+       plane = obj_to_plane(obj);
+
+       /* No fb means shut it down */
+       if (!plane_req->fb_id) {
+               plane->funcs->disable_plane(plane);
+               plane->crtc = NULL;
+               plane->fb = NULL;
+               goto out;
+       }
+
+       obj = drm_mode_object_find(dev, plane_req->crtc_id,
+                                  DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               DRM_DEBUG_KMS("Unknown crtc ID %d\n",
+                             plane_req->crtc_id);
+               ret = ENOENT;
+               goto out;
+       }
+       crtc = obj_to_crtc(obj);
+
+       obj = drm_mode_object_find(dev, plane_req->fb_id,
+                                  DRM_MODE_OBJECT_FB);
+       if (!obj) {
+               DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
+                             plane_req->fb_id);
+               ret = ENOENT;
+               goto out;
+       }
+       fb = obj_to_fb(obj);
+
+       /* Check whether this plane supports the fb pixel format. */
+       for (i = 0; i < plane->format_count; i++)
+               if (fb->pixel_format == plane->format_types[i])
+                       break;
+       if (i == plane->format_count) {
+               DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format);
+               ret = EINVAL;
+               goto out;
+       }
+
+       fb_width = fb->width << 16;
+       fb_height = fb->height << 16;
+
+       /* Make sure source coordinates are inside the fb. */
+       if (plane_req->src_w > fb_width ||
+           plane_req->src_x > fb_width - plane_req->src_w ||
+           plane_req->src_h > fb_height ||
+           plane_req->src_y > fb_height - plane_req->src_h) {
+               DRM_DEBUG_KMS("Invalid source coordinates "
+                             "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
+                             plane_req->src_w >> 16,
+                             ((plane_req->src_w & 0xffff) * 15625) >> 10,
+                             plane_req->src_h >> 16,
+                             ((plane_req->src_h & 0xffff) * 15625) >> 10,
+                             plane_req->src_x >> 16,
+                             ((plane_req->src_x & 0xffff) * 15625) >> 10,
+                             plane_req->src_y >> 16,
+                             ((plane_req->src_y & 0xffff) * 15625) >> 10);
+               ret = ENOSPC;
+               goto out;
+       }
+
+       /* Give drivers some help against integer overflows */
+       if (plane_req->crtc_w > INT_MAX ||
+           plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
+           plane_req->crtc_h > INT_MAX ||
+           plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
+               DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
+                             plane_req->crtc_w, plane_req->crtc_h,
+                             plane_req->crtc_x, plane_req->crtc_y);
+               ret = ERANGE;
+               goto out;
+       }
+
+       ret = -plane->funcs->update_plane(plane, crtc, fb,
+                                        plane_req->crtc_x, plane_req->crtc_y,
+                                        plane_req->crtc_w, plane_req->crtc_h,
+                                        plane_req->src_x, plane_req->src_y,
+                                        plane_req->src_w, plane_req->src_h);
+       if (!ret) {
+               plane->crtc = crtc;
+               plane->fb = fb;
+       }
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+
+       return ret;
+}
+
+/**
+ * drm_mode_setcrtc - set CRTC configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Build a new CRTC configuration based on user request.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_setcrtc(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv)
+{
+       struct drm_mode_config *config = &dev->mode_config;
+       struct drm_mode_crtc *crtc_req = data;
+       struct drm_mode_object *obj;
+       struct drm_crtc *crtc;
+       struct drm_connector **connector_set = NULL, *connector;
+       struct drm_framebuffer *fb = NULL;
+       struct drm_display_mode *mode = NULL;
+       struct drm_mode_set set;
+       uint32_t *set_connectors_ptr;
+       int ret = 0;
+       int i;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       /* For some reason crtc x/y offsets are signed internally. */
+       if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
+               return (ERANGE);
+
+       sx_xlock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, crtc_req->crtc_id,
+                                  DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
+               ret = EINVAL;
+               goto out;
+       }
+       crtc = obj_to_crtc(obj);
+       DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
+
+       if (crtc_req->mode_valid) {
+               /* If we have a mode we need a framebuffer. */
+               /* If we pass -1, set the mode with the currently bound fb */
+               if (crtc_req->fb_id == -1) {
+                       if (!crtc->fb) {
+                               DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       fb = crtc->fb;
+               } else {
+                       obj = drm_mode_object_find(dev, crtc_req->fb_id,
+                                                  DRM_MODE_OBJECT_FB);
+                       if (!obj) {
+                               DRM_DEBUG_KMS("Unknown FB ID%d\n",
+                                               crtc_req->fb_id);
+                               ret = EINVAL;
+                               goto out;
+                       }
+                       fb = obj_to_fb(obj);
+               }
+
+               mode = drm_mode_create(dev);
+               if (!mode) {
+                       ret = ENOMEM;
+                       goto out;
+               }
+
+               ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
+               if (ret) {
+                       DRM_DEBUG_KMS("Invalid mode\n");
+                       goto out;
+               }
+
+               drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+
+               if (mode->hdisplay > fb->width ||
+                   mode->vdisplay > fb->height ||
+                   crtc_req->x > fb->width - mode->hdisplay ||
+                   crtc_req->y > fb->height - mode->vdisplay) {
+                       DRM_DEBUG_KMS("Invalid CRTC viewport %ux%u+%u+%u for fb size %ux%u.\n",
+                                     mode->hdisplay, mode->vdisplay,
+                                     crtc_req->x, crtc_req->y,
+                                     fb->width, fb->height);
+                       ret = ENOSPC;
+                       goto out;
+               }
+       }
+
+       if (crtc_req->count_connectors == 0 && mode) {
+               DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
+               ret = EINVAL;
+               goto out;
+       }
+
+       if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
+               DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
+                         crtc_req->count_connectors);
+               ret = EINVAL;
+               goto out;
+       }
+
+       if (crtc_req->count_connectors > 0) {
+               u32 out_id;
+
+               /* Avoid unbounded kernel memory allocation */
+               if (crtc_req->count_connectors > config->num_connector) {
+                       ret = EINVAL;
+                       goto out;
+               }
+
+               connector_set = malloc(crtc_req->count_connectors *
+                   sizeof(struct drm_connector *), DRM_MEM_KMS, M_WAITOK);
+
+               for (i = 0; i < crtc_req->count_connectors; i++) {
+                       set_connectors_ptr = (uint32_t *)(uintptr_t)crtc_req->set_connectors_ptr;
+                       if (copyin(&set_connectors_ptr[i], &out_id, sizeof(uint32_t))) {
+                               ret = EFAULT;
+                               goto out;
+                       }
+
+                       obj = drm_mode_object_find(dev, out_id,
+                                                  DRM_MODE_OBJECT_CONNECTOR);
+                       if (!obj) {
+                               DRM_DEBUG_KMS("Connector id %d unknown\n",
+                                               out_id);
+                               ret = EINVAL;
+                               goto out;
+                       }
+                       connector = obj_to_connector(obj);
+                       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                                       connector->base.id,
+                                       drm_get_connector_name(connector));
+
+                       connector_set[i] = connector;
+               }
+       }
+
+       set.crtc = crtc;
+       set.x = crtc_req->x;
+       set.y = crtc_req->y;
+       set.mode = mode;
+       set.connectors = connector_set;
+       set.num_connectors = crtc_req->count_connectors;
+       set.fb = fb;
+       ret = crtc->funcs->set_config(&set);
+
+out:
+       free(connector_set, DRM_MEM_KMS);
+       drm_mode_destroy(dev, mode);
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+int drm_mode_cursor_ioctl(struct drm_device *dev,
+                       void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_cursor *req = data;
+       struct drm_mode_object *obj;
+       struct drm_crtc *crtc;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       if (!req->flags)
+               return (EINVAL);
+
+       sx_xlock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
+               ret = EINVAL;
+               goto out;
+       }
+       crtc = obj_to_crtc(obj);
+
+       if (req->flags & DRM_MODE_CURSOR_BO) {
+               if (!crtc->funcs->cursor_set) {
+                       ret = ENXIO;
+                       goto out;
+               }
+               /* Turns off the cursor if handle is 0 */
+               ret = -crtc->funcs->cursor_set(crtc, file_priv, req->handle,
+                                             req->width, req->height);
+       }
+
+       if (req->flags & DRM_MODE_CURSOR_MOVE) {
+               if (crtc->funcs->cursor_move) {
+                       ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
+               } else {
+                       ret = EFAULT;
+                       goto out;
+               }
+       }
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/* Original addfb only supported RGB formats, so figure out which one */
+uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
+{
+       uint32_t fmt;
+
+       switch (bpp) {
+       case 8:
+               fmt = DRM_FORMAT_RGB332;
+               break;
+       case 16:
+               if (depth == 15)
+                       fmt = DRM_FORMAT_XRGB1555;
+               else
+                       fmt = DRM_FORMAT_RGB565;
+               break;
+       case 24:
+               fmt = DRM_FORMAT_RGB888;
+               break;
+       case 32:
+               if (depth == 24)
+                       fmt = DRM_FORMAT_XRGB8888;
+               else if (depth == 30)
+                       fmt = DRM_FORMAT_XRGB2101010;
+               else
+                       fmt = DRM_FORMAT_ARGB8888;
+               break;
+       default:
+               DRM_ERROR("bad bpp, assuming RGB24 pixel format\n");
+               fmt = DRM_FORMAT_XRGB8888;
+               break;
+       }
+
+       return fmt;
+}
+
+/**
+ * drm_mode_addfb - add an FB to the graphics configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Add a new FB to the specified CRTC, given a user request.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_addfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_fb_cmd *or = data;
+       struct drm_mode_fb_cmd2 r = {};
+       struct drm_mode_config *config = &dev->mode_config;
+       struct drm_framebuffer *fb;
+       int ret = 0;
+
+       /* Use new struct with format internally */
+       r.fb_id = or->fb_id;
+       r.width = or->width;
+       r.height = or->height;
+       r.pitches[0] = or->pitch;
+       r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
+       r.handles[0] = or->handle;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       if ((config->min_width > r.width) || (r.width > config->max_width))
+               return (EINVAL);
+       if ((config->min_height > r.height) || (r.height > config->max_height))
+               return (EINVAL);
+
+       sx_xlock(&dev->mode_config.mutex);
+
+       ret = -dev->mode_config.funcs->fb_create(dev, file_priv, &r, &fb);
+       if (ret != 0) {
+               DRM_ERROR("could not create framebuffer, error %d\n", ret);
+               goto out;
+       }
+
+       or->fb_id = fb->base.id;
+       list_add(&fb->filp_head, &file_priv->fbs);
+       DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+static int format_check(struct drm_mode_fb_cmd2 *r)
+{
+       uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN;
+
+       switch (format) {
+       case DRM_FORMAT_C8:
+       case DRM_FORMAT_RGB332:
+       case DRM_FORMAT_BGR233:
+       case DRM_FORMAT_XRGB4444:
+       case DRM_FORMAT_XBGR4444:
+       case DRM_FORMAT_RGBX4444:
+       case DRM_FORMAT_BGRX4444:
+       case DRM_FORMAT_ARGB4444:
+       case DRM_FORMAT_ABGR4444:
+       case DRM_FORMAT_RGBA4444:
+       case DRM_FORMAT_BGRA4444:
+       case DRM_FORMAT_XRGB1555:
+       case DRM_FORMAT_XBGR1555:
+       case DRM_FORMAT_RGBX5551:
+       case DRM_FORMAT_BGRX5551:
+       case DRM_FORMAT_ARGB1555:
+       case DRM_FORMAT_ABGR1555:
+       case DRM_FORMAT_RGBA5551:
+       case DRM_FORMAT_BGRA5551:
+       case DRM_FORMAT_RGB565:
+       case DRM_FORMAT_BGR565:
+       case DRM_FORMAT_RGB888:
+       case DRM_FORMAT_BGR888:
+       case DRM_FORMAT_XRGB8888:
+       case DRM_FORMAT_XBGR8888:
+       case DRM_FORMAT_RGBX8888:
+       case DRM_FORMAT_BGRX8888:
+       case DRM_FORMAT_ARGB8888:
+       case DRM_FORMAT_ABGR8888:
+       case DRM_FORMAT_RGBA8888:
+       case DRM_FORMAT_BGRA8888:
+       case DRM_FORMAT_XRGB2101010:
+       case DRM_FORMAT_XBGR2101010:
+       case DRM_FORMAT_RGBX1010102:
+       case DRM_FORMAT_BGRX1010102:
+       case DRM_FORMAT_ARGB2101010:
+       case DRM_FORMAT_ABGR2101010:
+       case DRM_FORMAT_RGBA1010102:
+       case DRM_FORMAT_BGRA1010102:
+       case DRM_FORMAT_YUYV:
+       case DRM_FORMAT_YVYU:
+       case DRM_FORMAT_UYVY:
+       case DRM_FORMAT_VYUY:
+       case DRM_FORMAT_AYUV:
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+       case DRM_FORMAT_NV16:
+       case DRM_FORMAT_NV61:
+       case DRM_FORMAT_YUV410:
+       case DRM_FORMAT_YVU410:
+       case DRM_FORMAT_YUV411:
+       case DRM_FORMAT_YVU411:
+       case DRM_FORMAT_YUV420:
+       case DRM_FORMAT_YVU420:
+       case DRM_FORMAT_YUV422:
+       case DRM_FORMAT_YVU422:
+       case DRM_FORMAT_YUV444:
+       case DRM_FORMAT_YVU444:
+               return 0;
+       default:
+               return (EINVAL);
+       }
+}
+
+/**
+ * drm_mode_addfb2 - add an FB to the graphics configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Add a new FB to the specified CRTC, given a user request with format.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_addfb2(struct drm_device *dev,
+                   void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_fb_cmd2 *r = data;
+       struct drm_mode_config *config = &dev->mode_config;
+       struct drm_framebuffer *fb;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       if ((config->min_width > r->width) || (r->width > config->max_width)) {
+               DRM_ERROR("bad framebuffer width %d, should be >= %d && <= %d\n",
+                         r->width, config->min_width, config->max_width);
+               return (EINVAL);
+       }
+       if ((config->min_height > r->height) || (r->height > config->max_height)) {
+               DRM_ERROR("bad framebuffer height %d, should be >= %d && <= %d\n",
+                         r->height, config->min_height, config->max_height);
+               return (EINVAL);
+       }
+
+       ret = format_check(r);
+       if (ret) {
+               DRM_ERROR("bad framebuffer format 0x%08x\n", r->pixel_format);
+               return ret;
+       }
+
+       sx_xlock(&dev->mode_config.mutex);
+
+       /* TODO check buffer is sufficiently large */
+       /* TODO setup destructor callback */
+
+       ret = -dev->mode_config.funcs->fb_create(dev, file_priv, r, &fb);
+       if (ret != 0) {
+               DRM_ERROR("could not create framebuffer, error %d\n", ret);
+               goto out;
+       }
+
+       r->fb_id = fb->base.id;
+       list_add(&fb->filp_head, &file_priv->fbs);
+       DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return (ret);
+}
+
+/**
+ * drm_mode_rmfb - remove an FB from the configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Remove the FB specified by the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_rmfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_object *obj;
+       struct drm_framebuffer *fb = NULL;
+       struct drm_framebuffer *fbl = NULL;
+       uint32_t *id = data;
+       int ret = 0;
+       int found = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       sx_xlock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
+       /* TODO check that we really get a framebuffer back. */
+       if (!obj) {
+               ret = EINVAL;
+               goto out;
+       }
+       fb = obj_to_fb(obj);
+
+       list_for_each_entry(fbl, &file_priv->fbs, filp_head)
+               if (fb == fbl)
+                       found = 1;
+
+       if (!found) {
+               ret = EINVAL;
+               goto out;
+       }
+
+       /* TODO release all crtc connected to the framebuffer */
+       /* TODO unhock the destructor from the buffer object */
+
+       list_del(&fb->filp_head);
+       fb->funcs->destroy(fb);
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_getfb - get FB info
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Lookup the FB given its ID and return info about it.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_fb_cmd *r = data;
+       struct drm_mode_object *obj;
+       struct drm_framebuffer *fb;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       sx_xlock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
+       if (!obj) {
+               ret = EINVAL;
+               goto out;
+       }
+       fb = obj_to_fb(obj);
+
+       r->height = fb->height;
+       r->width = fb->width;
+       r->depth = fb->depth;
+       r->bpp = fb->bits_per_pixel;
+       r->pitch = fb->pitches[0];
+       fb->funcs->create_handle(fb, file_priv, &r->handle);
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
+                          void *data, struct drm_file *file_priv)
+{
+       struct drm_clip_rect __user *clips_ptr;
+       struct drm_clip_rect *clips = NULL;
+       struct drm_mode_fb_dirty_cmd *r = data;
+       struct drm_mode_object *obj;
+       struct drm_framebuffer *fb;
+       unsigned flags;
+       int num_clips;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return (EINVAL);
+
+       sx_xlock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
+       if (!obj) {
+               ret = EINVAL;
+               goto out_err1;
+       }
+       fb = obj_to_fb(obj);
+
+       num_clips = r->num_clips;
+       clips_ptr = (struct drm_clip_rect *)(unsigned long)r->clips_ptr;
+
+       if (!num_clips != !clips_ptr) {
+               ret = EINVAL;
+               goto out_err1;
+       }
+
+       flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags;
+
+       /* If userspace annotates copy, clips must come in pairs */
+       if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) {
+               ret = EINVAL;
+               goto out_err1;
+       }
+
+       if (num_clips && clips_ptr) {
+               if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) {
+                       ret = EINVAL;
+                       goto out_err1;
+               }
+               clips = malloc(num_clips * sizeof(*clips), DRM_MEM_KMS,
+                   M_WAITOK | M_ZERO);
+
+               ret = copyin(clips_ptr, clips, num_clips * sizeof(*clips));
+               if (ret)
+                       goto out_err2;
+       }
+
+       if (fb->funcs->dirty) {
+               ret = -fb->funcs->dirty(fb, file_priv, flags, r->color,
+                                      clips, num_clips);
+       } else {
+               ret = ENOSYS;
+               goto out_err2;
+       }
+
+out_err2:
+       free(clips, DRM_MEM_KMS);
+out_err1:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+
+/**
+ * drm_fb_release - remove and free the FBs on this file
+ * @filp: file * from the ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Destroy all the FBs associated with @filp.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+void drm_fb_release(struct drm_file *priv)
+{
+#if 1
+       struct drm_device *dev = priv->dev;
+#else
+       struct drm_device *dev = priv->minor->dev;
+#endif
+       struct drm_framebuffer *fb, *tfb;
+
+       sx_xlock(&dev->mode_config.mutex);
+       list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
+               list_del(&fb->filp_head);
+               fb->funcs->destroy(fb);
+       }
+       sx_xunlock(&dev->mode_config.mutex);
+}
+
+/**
+ * drm_mode_attachmode - add a mode to the user mode list
+ * @dev: DRM device
+ * @connector: connector to add the mode to
+ * @mode: mode to add
+ *
+ * Add @mode to @connector's user mode list.
+ */
+static void drm_mode_attachmode(struct drm_device *dev,
+                               struct drm_connector *connector,
+                               struct drm_display_mode *mode)
+{
+       list_add_tail(&mode->head, &connector->user_modes);
+}
+
+int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc,
+                            const struct drm_display_mode *mode)
+{
+       struct drm_connector *connector;
+       int ret = 0;
+       struct drm_display_mode *dup_mode, *next;
+       DRM_LIST_HEAD(list);
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (!connector->encoder)
+                       continue;
+               if (connector->encoder->crtc == crtc) {
+                       dup_mode = drm_mode_duplicate(dev, mode);
+                       if (!dup_mode) {
+                               ret = ENOMEM;
+                               goto out;
+                       }
+                       list_add_tail(&dup_mode->head, &list);
+               }
+       }
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (!connector->encoder)
+                       continue;
+               if (connector->encoder->crtc == crtc)
+                       list_move_tail(list.next, &connector->user_modes);
+       }
+
+       MPASS(!list_empty(&list));
+
+ out:
+       list_for_each_entry_safe(dup_mode, next, &list, head)
+               drm_mode_destroy(dev, dup_mode);
+
+       return ret;
+}
+
+static int drm_mode_detachmode(struct drm_device *dev,
+                              struct drm_connector *connector,
+                              struct drm_display_mode *mode)
+{
+       int found = 0;
+       int ret = 0;
+       struct drm_display_mode *match_mode, *t;
+
+       list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) {
+               if (drm_mode_equal(match_mode, mode)) {
+                       list_del(&match_mode->head);
+                       drm_mode_destroy(dev, match_mode);
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found)
+               ret = -EINVAL;
+
+       return ret;
+}
+
+int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode)
+{
+       struct drm_connector *connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               drm_mode_detachmode(dev, connector, mode);
+       }
+       return 0;
+}
+
+/**
+ * drm_fb_attachmode - Attach a user mode to an connector
+ * @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 connector.
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_attachmode_ioctl(struct drm_device *dev,
+                             void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_mode_cmd *mode_cmd = data;
+       struct drm_connector *connector;
+       struct drm_display_mode *mode;
+       struct drm_mode_object *obj;
+       struct drm_mode_modeinfo *umode = &mode_cmd->mode;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       sx_xlock(&dev->mode_config.mutex);
+
+       obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out;
+       }
+       connector = obj_to_connector(obj);
+
+       mode = drm_mode_create(dev);
+       if (!mode) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = drm_crtc_convert_umode(mode, umode);
+       if (ret) {
+               DRM_DEBUG_KMS("Invalid mode\n");
+               drm_mode_destroy(dev, mode);
+               goto out;
+       }
+
+       drm_mode_attachmode(dev, connector, mode);
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+
+/**
+ * drm_fb_detachmode - Detach a user specified mode from an connector
+ * @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_ioctl(struct drm_device *dev,
+                             void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_object *obj;
+       struct drm_mode_mode_cmd *mode_cmd = data;
+       struct drm_connector *connector;
+       struct drm_display_mode mode;
+       struct drm_mode_modeinfo *umode = &mode_cmd->mode;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       sx_xlock(&dev->mode_config.mutex);
+
+       obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out;
+       }
+       connector = obj_to_connector(obj);
+
+       ret = drm_crtc_convert_umode(&mode, umode);
+       if (ret) {
+               DRM_DEBUG_KMS("Invalid mode\n");
+               goto out;
+       }
+
+       ret = drm_mode_detachmode(dev, connector, &mode);
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+struct drm_property *drm_property_create(struct drm_device *dev, int flags,
+                                        const char *name, int num_values)
+{
+       struct drm_property *property = NULL;
+       int ret;
+
+       property = malloc(sizeof(struct drm_property), DRM_MEM_KMS,
+           M_WAITOK | M_ZERO);
+
+       if (num_values) {
+               property->values = malloc(sizeof(uint64_t)*num_values, DRM_MEM_KMS,
+                   M_WAITOK | M_ZERO);
+       }
+
+       ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
+       if (ret)
+               goto fail;
+       property->flags = flags;
+       property->num_values = num_values;
+       INIT_LIST_HEAD(&property->enum_blob_list);
+
+       if (name) {
+               strncpy(property->name, name, DRM_PROP_NAME_LEN);
+               property->name[DRM_PROP_NAME_LEN-1] = '\0';
+       }
+
+       list_add_tail(&property->head, &dev->mode_config.property_list);
+       return property;
+
+fail:
+       free(property->values, DRM_MEM_KMS);
+       free(property, DRM_MEM_KMS);
+       return (NULL);
+}
+
+struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
+                                        const char *name,
+                                        const struct drm_prop_enum_list *props,
+                                        int num_values)
+{
+       struct drm_property *property;
+       int i, ret;
+
+       flags |= DRM_MODE_PROP_ENUM;
+
+       property = drm_property_create(dev, flags, name, num_values);
+       if (!property)
+               return NULL;
+
+       for (i = 0; i < num_values; i++) {
+               ret = drm_property_add_enum(property, i,
+                                     props[i].type,
+                                     props[i].name);
+               if (ret) {
+                       drm_property_destroy(dev, property);
+                       return NULL;
+               }
+       }
+
+       return property;
+}
+
+struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
+                                        const char *name,
+                                        uint64_t min, uint64_t max)
+{
+       struct drm_property *property;
+
+       flags |= DRM_MODE_PROP_RANGE;
+
+       property = drm_property_create(dev, flags, name, 2);
+       if (!property)
+               return NULL;
+
+       property->values[0] = min;
+       property->values[1] = max;
+
+       return property;
+}
+
+int drm_property_add_enum(struct drm_property *property, int index,
+                         uint64_t value, const char *name)
+{
+       struct drm_property_enum *prop_enum;
+
+       if (!(property->flags & DRM_MODE_PROP_ENUM))
+               return -EINVAL;
+
+       if (!list_empty(&property->enum_blob_list)) {
+               list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
+                       if (prop_enum->value == value) {
+                               strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
+                               prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
+                               return 0;
+                       }
+               }
+       }
+
+       prop_enum = malloc(sizeof(struct drm_property_enum), DRM_MEM_KMS,
+           M_WAITOK | M_ZERO);
+
+       strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
+       prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
+       prop_enum->value = value;
+
+       property->values[index] = value;
+       list_add_tail(&prop_enum->head, &property->enum_blob_list);
+       return 0;
+}
+
+void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
+{
+       struct drm_property_enum *prop_enum, *pt;
+
+       list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
+               list_del(&prop_enum->head);
+               free(prop_enum, DRM_MEM_KMS);
+       }
+
+       if (property->num_values)
+               free(property->values, DRM_MEM_KMS);
+       drm_mode_object_put(dev, &property->base);
+       list_del(&property->head);
+       free(property, DRM_MEM_KMS);
+}
+
+int drm_connector_attach_property(struct drm_connector *connector,
+                              struct drm_property *property, uint64_t init_val)
+{
+       int i;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
+               if (connector->property_ids[i] == 0) {
+                       connector->property_ids[i] = property->base.id;
+                       connector->property_values[i] = init_val;
+                       break;
+               }
+       }
+
+       if (i == DRM_CONNECTOR_MAX_PROPERTY)
+               return -EINVAL;
+       return 0;
+}
+
+int drm_connector_property_set_value(struct drm_connector *connector,
+                                 struct drm_property *property, uint64_t value)
+{
+       int i;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
+               if (connector->property_ids[i] == property->base.id) {
+                       connector->property_values[i] = value;
+                       break;
+               }
+       }
+
+       if (i == DRM_CONNECTOR_MAX_PROPERTY)
+               return -EINVAL;
+       return 0;
+}
+
+int drm_connector_property_get_value(struct drm_connector *connector,
+                                 struct drm_property *property, uint64_t *val)
+{
+       int i;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
+               if (connector->property_ids[i] == property->base.id) {
+                       *val = connector->property_values[i];
+                       break;
+               }
+       }
+
+       if (i == DRM_CONNECTOR_MAX_PROPERTY)
+               return -EINVAL;
+       return 0;
+}
+
+int drm_mode_getproperty_ioctl(struct drm_device *dev,
+                              void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_object *obj;
+       struct drm_mode_get_property *out_resp = data;
+       struct drm_property *property;
+       int enum_count = 0;
+       int blob_count = 0;
+       int value_count = 0;
+       int ret = 0, i;
+       int copied;
+       struct drm_property_enum *prop_enum;
+       struct drm_mode_property_enum __user *enum_ptr;
+       struct drm_property_blob *prop_blob;
+       uint32_t *blob_id_ptr;
+       uint64_t *values_ptr;
+       uint32_t *blob_length_ptr;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       sx_xlock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
+       if (!obj) {
+               ret = -EINVAL;
+               goto done;
+       }
+       property = obj_to_property(obj);
+
+       if (property->flags & DRM_MODE_PROP_ENUM) {
+               list_for_each_entry(prop_enum, &property->enum_blob_list, head)
+                       enum_count++;
+       } else if (property->flags & DRM_MODE_PROP_BLOB) {
+               list_for_each_entry(prop_blob, &property->enum_blob_list, head)
+                       blob_count++;
+       }
+
+       value_count = property->num_values;
+
+       strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
+       out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
+       out_resp->flags = property->flags;
+
+       if ((out_resp->count_values >= value_count) && value_count) {
+               values_ptr = (uint64_t *)(uintptr_t)out_resp->values_ptr;
+               for (i = 0; i < value_count; i++) {
+                       if (copyout(&property->values[i], values_ptr + i, sizeof(uint64_t))) {
+                               ret = -EFAULT;
+                               goto done;
+                       }
+               }
+       }
+       out_resp->count_values = value_count;
+
+       if (property->flags & DRM_MODE_PROP_ENUM) {
+               if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
+                       copied = 0;
+                       enum_ptr = (struct drm_mode_property_enum *)(uintptr_t)out_resp->enum_blob_ptr;
+                       list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
+
+                               if (copyout(&prop_enum->value, &enum_ptr[copied].value, sizeof(uint64_t))) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+
+                               if (copyout(&prop_enum->name,
+                                   &enum_ptr[copied].name,DRM_PROP_NAME_LEN)) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+                               copied++;
+                       }
+               }
+               out_resp->count_enum_blobs = enum_count;
+       }
+
+       if (property->flags & DRM_MODE_PROP_BLOB) {
+               if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
+                       copied = 0;
+                       blob_id_ptr = (uint32_t *)(uintptr_t)out_resp->enum_blob_ptr;
+                       blob_length_ptr = (uint32_t *)(uintptr_t)out_resp->values_ptr;
+
+                       list_for_each_entry(prop_blob, &property->enum_blob_list, head) {
+                               if (copyout(&prop_blob->base.id,
+                                   blob_id_ptr + copied, sizeof(uint32_t))) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+
+                               if (copyout(&prop_blob->length,
+                                   blob_length_ptr + copied, sizeof(uint32_t))) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+
+                               copied++;
+                       }
+               }
+               out_resp->count_enum_blobs = blob_count;
+       }
+done:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
+                                                         void *data)
+{
+       struct drm_property_blob *blob;
+       int ret;
+
+       if (!length || !data)
+               return NULL;
+
+       blob = malloc(sizeof(struct drm_property_blob) + length, DRM_MEM_KMS,
+           M_WAITOK | M_ZERO);
+
+       ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
+       if (ret) {
+               free(blob, DRM_MEM_KMS);
+               return (NULL);
+       }
+
+       blob->length = length;
+
+       memcpy(blob->data, data, length);
+
+       list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
+       return blob;
+}
+
+static void drm_property_destroy_blob(struct drm_device *dev,
+                              struct drm_property_blob *blob)
+{
+       drm_mode_object_put(dev, &blob->base);
+       list_del(&blob->head);
+       free(blob, DRM_MEM_KMS);
+}
+
+int drm_mode_getblob_ioctl(struct drm_device *dev,
+                          void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_object *obj;
+       struct drm_mode_get_blob *out_resp = data;
+       struct drm_property_blob *blob;
+       int ret = 0;
+       void *blob_ptr;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       sx_xlock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
+       if (!obj) {
+               ret = -EINVAL;
+               goto done;
+       }
+       blob = obj_to_blob(obj);
+
+       if (out_resp->length == blob->length) {
+               blob_ptr = (void *)(unsigned long)out_resp->data;
+               if (copyout(blob->data, blob_ptr, blob->length)){
+                       ret = -EFAULT;
+                       goto done;
+               }
+       }
+       out_resp->length = blob->length;
+
+done:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+int drm_mode_connector_update_edid_property(struct drm_connector *connector,
+                                           struct edid *edid)
+{
+       struct drm_device *dev = connector->dev;
+       int ret = 0, size;
+
+       if (connector->edid_blob_ptr)
+               drm_property_destroy_blob(dev, connector->edid_blob_ptr);
+
+       /* Delete edid, when there is none. */
+       if (!edid) {
+               connector->edid_blob_ptr = NULL;
+               ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, 0);
+               return ret;
+       }
+
+       size = EDID_LENGTH * (1 + edid->extensions);
+       connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
+                                                           size, edid);
+
+       ret = drm_connector_property_set_value(connector,
+                                              dev->mode_config.edid_property,
+                                              connector->edid_blob_ptr->base.id);
+
+       return ret;
+}
+
+int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
+                                      void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_connector_set_property *out_resp = data;
+       struct drm_mode_object *obj;
+       struct drm_property *property;
+       struct drm_connector *connector;
+       int ret = -EINVAL;
+       int i;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       sx_xlock(&dev->mode_config.mutex);
+
+       obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR);
+       if (!obj) {
+               goto out;
+       }
+       connector = obj_to_connector(obj);
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
+               if (connector->property_ids[i] == out_resp->prop_id)
+                       break;
+       }
+
+       if (i == DRM_CONNECTOR_MAX_PROPERTY) {
+               goto out;
+       }
+
+       obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
+       if (!obj) {
+               goto out;
+       }
+       property = obj_to_property(obj);
+
+       if (property->flags & DRM_MODE_PROP_IMMUTABLE)
+               goto out;
+
+       if (property->flags & DRM_MODE_PROP_RANGE) {
+               if (out_resp->value < property->values[0])
+                       goto out;
+
+               if (out_resp->value > property->values[1])
+                       goto out;
+       } else {
+               int found = 0;
+               for (i = 0; i < property->num_values; i++) {
+                       if (property->values[i] == out_resp->value) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found) {
+                       goto out;
+               }
+       }
+
+       /* Do DPMS ourselves */
+       if (property == connector->dev->mode_config.dpms_property) {
+               if (connector->funcs->dpms)
+                       (*connector->funcs->dpms)(connector, (int) out_resp->value);
+               ret = 0;
+       } else if (connector->funcs->set_property)
+               ret = connector->funcs->set_property(connector, property, out_resp->value);
+
+       /* store the property value if successful */
+       if (!ret)
+               drm_connector_property_set_value(connector, property, out_resp->value);
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+int drm_mode_connector_attach_encoder(struct drm_connector *connector,
+                                     struct drm_encoder *encoder)
+{
+       int i;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0) {
+                       connector->encoder_ids[i] = encoder->base.id;
+                       return 0;
+               }
+       }
+       return -ENOMEM;
+}
+
+void drm_mode_connector_detach_encoder(struct drm_connector *connector,
+                                   struct drm_encoder *encoder)
+{
+       int i;
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == encoder->base.id) {
+                       connector->encoder_ids[i] = 0;
+                       if (connector->encoder == encoder)
+                               connector->encoder = NULL;
+                       break;
+               }
+       }
+}
+
+int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
+                                 int gamma_size)
+{
+       crtc->gamma_size = gamma_size;
+
+       crtc->gamma_store = malloc(gamma_size * sizeof(uint16_t) * 3,
+           DRM_MEM_KMS, M_WAITOK | M_ZERO);
+
+       return 0;
+}
+
+int drm_mode_gamma_set_ioctl(struct drm_device *dev,
+                            void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_crtc_lut *crtc_lut = data;
+       struct drm_mode_object *obj;
+       struct drm_crtc *crtc;
+       void *r_base, *g_base, *b_base;
+       int size;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       sx_xlock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out;
+       }
+       crtc = obj_to_crtc(obj);
+
+       /* memcpy into gamma store */
+       if (crtc_lut->gamma_size != crtc->gamma_size) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       size = crtc_lut->gamma_size * (sizeof(uint16_t));
+       r_base = crtc->gamma_store;
+       if (copyin((void *)(uintptr_t)crtc_lut->red, r_base, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       g_base = (char *)r_base + size;
+       if (copyin((void *)(uintptr_t)crtc_lut->green, g_base, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       b_base = (char *)g_base + size;
+       if (copyin((void *)(uintptr_t)crtc_lut->blue, b_base, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+
+}
+
+int drm_mode_gamma_get_ioctl(struct drm_device *dev,
+                            void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_crtc_lut *crtc_lut = data;
+       struct drm_mode_object *obj;
+       struct drm_crtc *crtc;
+       void *r_base, *g_base, *b_base;
+       int size;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       sx_xlock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out;
+       }
+       crtc = obj_to_crtc(obj);
+
+       /* memcpy into gamma store */
+       if (crtc_lut->gamma_size != crtc->gamma_size) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       size = crtc_lut->gamma_size * (sizeof(uint16_t));
+       r_base = crtc->gamma_store;
+       if (copyout(r_base, (void *)(uintptr_t)crtc_lut->red, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       g_base = (char *)r_base + size;
+       if (copyout(g_base, (void *)(uintptr_t)crtc_lut->green, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       b_base = (char *)g_base + size;
+       if (copyout(b_base, (void *)(uintptr_t)crtc_lut->blue, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+static void
+drm_kms_free(void *arg)
+{
+
+       free(arg, DRM_MEM_KMS);
+}
+
+int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+       struct drm_mode_crtc_page_flip *page_flip = data;
+       struct drm_mode_object *obj;
+       struct drm_crtc *crtc;
+       struct drm_framebuffer *fb;
+       struct drm_pending_vblank_event *e = NULL;
+       int ret = EINVAL;
+
+       if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
+           page_flip->reserved != 0)
+               return (EINVAL);
+
+       sx_xlock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
+       if (!obj)
+               goto out;
+       crtc = obj_to_crtc(obj);
+
+       if (crtc->fb == NULL) {
+               /* The framebuffer is currently unbound, presumably
+                * due to a hotplug event, that userspace has not
+                * yet discovered.
+                */
+               ret = EBUSY;
+               goto out;
+       }
+
+       if (crtc->funcs->page_flip == NULL)
+               goto out;
+
+       obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB);
+       if (!obj)
+               goto out;
+       fb = obj_to_fb(obj);
+
+       if (crtc->mode.hdisplay > fb->width ||
+           crtc->mode.vdisplay > fb->height ||
+           crtc->x > fb->width - crtc->mode.hdisplay ||
+           crtc->y > fb->height - crtc->mode.vdisplay) {
+               DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d.\n",
+                             fb->width, fb->height,
+                             crtc->mode.hdisplay, crtc->mode.vdisplay,
+                             crtc->x, crtc->y);
+               ret = ENOSPC;
+               goto out;
+       }
+
+       if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
+               ret = ENOMEM;
+               mtx_lock(&dev->event_lock);
+               if (file_priv->event_space < sizeof e->event) {
+                       mtx_unlock(&dev->event_lock);
+                       goto out;
+               }
+               file_priv->event_space -= sizeof e->event;
+               mtx_unlock(&dev->event_lock);
+
+               e = malloc(sizeof *e, DRM_MEM_KMS, M_WAITOK | M_ZERO);
+
+               e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
+               e->event.base.length = sizeof e->event;
+               e->event.user_data = page_flip->user_data;
+               e->base.event = &e->event.base;
+               e->base.file_priv = file_priv;
+               e->base.destroy =
+                       (void (*) (struct drm_pending_event *))drm_kms_free;
+       }
+
+       ret = -crtc->funcs->page_flip(crtc, fb, e);
+       if (ret != 0) {
+               if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
+                       mtx_lock(&dev->event_lock);
+                       file_priv->event_space += sizeof e->event;
+                       mtx_unlock(&dev->event_lock);
+                       free(e, DRM_MEM_KMS);
+               }
+       }
+
+out:
+       sx_xunlock(&dev->mode_config.mutex);
+       CTR3(KTR_DRM, "page_flip_ioctl %d %d %d", curproc->p_pid,
+           page_flip->crtc_id, ret);
+       return (ret);
+}
+
+void drm_mode_config_reset(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+               if (crtc->funcs->reset)
+                       crtc->funcs->reset(crtc);
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               if (encoder->funcs->reset)
+                       encoder->funcs->reset(encoder);
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               if (connector->funcs->reset)
+                       connector->funcs->reset(connector);
+}
+
+int drm_mode_create_dumb_ioctl(struct drm_device *dev,
+                              void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_create_dumb *args = data;
+
+       if (!dev->driver->dumb_create)
+               return -ENOTSUP;
+       return dev->driver->dumb_create(file_priv, dev, args);
+}
+
+int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
+                            void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_map_dumb *args = data;
+
+       /* call driver ioctl to get mmap offset */
+       if (!dev->driver->dumb_map_offset)
+               return -ENOTSUP;
+
+       return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset);
+}
+
+int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
+                               void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_destroy_dumb *args = data;
+
+       if (!dev->driver->dumb_destroy)
+               return -ENOTSUP;
+
+       return dev->driver->dumb_destroy(file_priv, dev, args->handle);
+}
+
+/*
+ * Just need to support RGB formats here for compat with code that doesn't
+ * use pixel formats directly yet.
+ */
+void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
+                         int *bpp)
+{
+       switch (format) {
+       case DRM_FORMAT_RGB332:
+       case DRM_FORMAT_BGR233:
+               *depth = 8;
+               *bpp = 8;
+               break;
+       case DRM_FORMAT_XRGB1555:
+       case DRM_FORMAT_XBGR1555:
+       case DRM_FORMAT_RGBX5551:
+       case DRM_FORMAT_BGRX5551:
+       case DRM_FORMAT_ARGB1555:
+       case DRM_FORMAT_ABGR1555:
+       case DRM_FORMAT_RGBA5551:
+       case DRM_FORMAT_BGRA5551:
+               *depth = 15;
+               *bpp = 16;
+               break;
+       case DRM_FORMAT_RGB565:
+       case DRM_FORMAT_BGR565:
+               *depth = 16;
+               *bpp = 16;
+               break;
+       case DRM_FORMAT_RGB888:
+       case DRM_FORMAT_BGR888:
+               *depth = 24;
+               *bpp = 24;
+               break;
+       case DRM_FORMAT_XRGB8888:
+       case DRM_FORMAT_XBGR8888:
+       case DRM_FORMAT_RGBX8888:
+       case DRM_FORMAT_BGRX8888:
+               *depth = 24;
+               *bpp = 32;
+               break;
+       case DRM_FORMAT_XRGB2101010:
+       case DRM_FORMAT_XBGR2101010:
+       case DRM_FORMAT_RGBX1010102:
+       case DRM_FORMAT_BGRX1010102:
+       case DRM_FORMAT_ARGB2101010:
+       case DRM_FORMAT_ABGR2101010:
+       case DRM_FORMAT_RGBA1010102:
+       case DRM_FORMAT_BGRA1010102:
+               *depth = 30;
+               *bpp = 32;
+               break;
+       case DRM_FORMAT_ARGB8888:
+       case DRM_FORMAT_ABGR8888:
+       case DRM_FORMAT_RGBA8888:
+       case DRM_FORMAT_BGRA8888:
+               *depth = 32;
+               *bpp = 32;
+               break;
+       default:
+               DRM_DEBUG_KMS("unsupported pixel format\n");
+               *depth = 0;
+               *bpp = 0;
+               break;
+       }
+}
diff --git a/sys/dev/drm2/drm_crtc.h b/sys/dev/drm2/drm_crtc.h
new file mode 100644 (file)
index 0000000..97158ab
--- /dev/null
@@ -0,0 +1,935 @@
+/*
+ * Copyright © 2006 Keith Packard
+ * Copyright © 2007-2008 Dave Airlie
+ * Copyright © 2007-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * $FreeBSD: src/sys/dev/drm2/drm_crtc.h,v 1.1 2012/05/22 11:07:44 kib Exp $
+ */
+#ifndef __DRM_CRTC_H__
+#define __DRM_CRTC_H__
+
+#include <dev/drm2/drm_gem_names.h>
+#include <dev/drm2/drm_fourcc.h>
+
+struct drm_device;
+struct drm_mode_set;
+struct drm_framebuffer;
+struct i2c_adapter;
+
+#define DRM_MODE_OBJECT_CRTC 0xcccccccc
+#define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0
+#define DRM_MODE_OBJECT_ENCODER 0xe0e0e0e0
+#define DRM_MODE_OBJECT_MODE 0xdededede
+#define DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0
+#define DRM_MODE_OBJECT_FB 0xfbfbfbfb
+#define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb
+#define DRM_MODE_OBJECT_PLANE 0xeeeeeeee
+
+struct drm_mode_object {
+       uint32_t id;
+       uint32_t type;
+};
+
+/*
+ * Note on terminology:  here, for brevity and convenience, we refer to connector
+ * control chips as 'CRTCs'.  They can control any type of connector, VGA, LVDS,
+ * DVI, etc.  And 'screen' refers to the whole of the visible display, which
+ * may span multiple monitors (and therefore multiple CRTC and connector
+ * structures).
+ */
+
+enum drm_mode_status {
+    MODE_OK    = 0,    /* Mode OK */
+    MODE_HSYNC,                /* hsync out of range */
+    MODE_VSYNC,                /* vsync out of range */
+    MODE_H_ILLEGAL,    /* mode has illegal horizontal timings */
+    MODE_V_ILLEGAL,    /* mode has illegal horizontal timings */
+    MODE_BAD_WIDTH,    /* requires an unsupported linepitch */
+    MODE_NOMODE,       /* no mode with a maching name */
+    MODE_NO_INTERLACE, /* interlaced mode not supported */
+    MODE_NO_DBLESCAN,  /* doublescan mode not supported */
+    MODE_NO_VSCAN,     /* multiscan mode not supported */
+    MODE_MEM,          /* insufficient video memory */
+    MODE_VIRTUAL_X,    /* mode width too large for specified virtual size */
+    MODE_VIRTUAL_Y,    /* mode height too large for specified virtual size */
+    MODE_MEM_VIRT,     /* insufficient video memory given virtual size */
+    MODE_NOCLOCK,      /* no fixed clock available */
+    MODE_CLOCK_HIGH,   /* clock required is too high */
+    MODE_CLOCK_LOW,    /* clock required is too low */
+    MODE_CLOCK_RANGE,  /* clock/mode isn't in a ClockRange */
+    MODE_BAD_HVALUE,   /* horizontal timing was out of range */
+    MODE_BAD_VVALUE,   /* vertical timing was out of range */
+    MODE_BAD_VSCAN,    /* VScan value out of range */
+    MODE_HSYNC_NARROW, /* horizontal sync too narrow */
+    MODE_HSYNC_WIDE,   /* horizontal sync too wide */
+    MODE_HBLANK_NARROW,        /* horizontal blanking too narrow */
+    MODE_HBLANK_WIDE,  /* horizontal blanking too wide */
+    MODE_VSYNC_NARROW, /* vertical sync too narrow */
+    MODE_VSYNC_WIDE,   /* vertical sync too wide */
+    MODE_VBLANK_NARROW,        /* vertical blanking too narrow */
+    MODE_VBLANK_WIDE,  /* vertical blanking too wide */
+    MODE_PANEL,         /* exceeds panel dimensions */
+    MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */
+    MODE_ONE_WIDTH,     /* only one width is supported */
+    MODE_ONE_HEIGHT,    /* only one height is supported */
+    MODE_ONE_SIZE,      /* only one resolution is supported */
+    MODE_NO_REDUCED,    /* monitor doesn't accept reduced blanking */
+    MODE_UNVERIFIED = -3, /* mode needs to reverified */
+    MODE_BAD = -2,     /* unspecified reason */
+    MODE_ERROR = -1    /* error condition */
+};
+
+#define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \
+                                   DRM_MODE_TYPE_CRTC_C)
+
+#define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \
+       .name = nm, .status = 0, .type = (t), .clock = (c), \
+       .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \
+       .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \
+       .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \
+       .vscan = (vs), .flags = (f), .vrefresh = 0
+
+#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */
+
+struct drm_display_mode {
+       /* Header */
+       struct list_head head;
+       struct drm_mode_object base;
+
+       char name[DRM_DISPLAY_MODE_LEN];
+
+       int connector_count;
+       enum drm_mode_status status;
+       int type;
+
+       /* Proposed mode values */
+       int clock;              /* in kHz */
+       int hdisplay;
+       int hsync_start;
+       int hsync_end;
+       int htotal;
+       int hskew;
+       int vdisplay;
+       int vsync_start;
+       int vsync_end;
+       int vtotal;
+       int vscan;
+       unsigned int flags;
+
+       /* Addressable image size (may be 0 for projectors, etc.) */
+       int width_mm;
+       int height_mm;
+
+       /* Actual mode we give to hw */
+       int clock_index;
+       int synth_clock;
+       int crtc_hdisplay;
+       int crtc_hblank_start;
+       int crtc_hblank_end;
+       int crtc_hsync_start;
+       int crtc_hsync_end;
+       int crtc_htotal;
+       int crtc_hskew;
+       int crtc_vdisplay;
+       int crtc_vblank_start;
+       int crtc_vblank_end;
+       int crtc_vsync_start;
+       int crtc_vsync_end;
+       int crtc_vtotal;
+       int crtc_hadjusted;
+       int crtc_vadjusted;
+
+       /* Driver private mode info */
+       int private_size;
+       int *private;
+       int private_flags;
+
+       int vrefresh;           /* in Hz */
+       int hsync;              /* in kHz */
+};
+
+enum drm_connector_status {
+       connector_status_connected = 1,
+       connector_status_disconnected = 2,
+       connector_status_unknown = 3,
+};
+
+enum subpixel_order {
+       SubPixelUnknown = 0,
+       SubPixelHorizontalRGB,
+       SubPixelHorizontalBGR,
+       SubPixelVerticalRGB,
+       SubPixelVerticalBGR,
+       SubPixelNone,
+};
+
+#define DRM_COLOR_FORMAT_RGB444                (1<<0)
+#define DRM_COLOR_FORMAT_YCRCB444      (1<<1)
+#define DRM_COLOR_FORMAT_YCRCB422      (1<<2)
+/*
+ * Describes a given display (e.g. CRT or flat panel) and its limitations.
+ */
+struct drm_display_info {
+       char name[DRM_DISPLAY_INFO_LEN];
+
+       /* Physical size */
+        unsigned int width_mm;
+       unsigned int height_mm;
+
+       /* Clock limits FIXME: storage format */
+       unsigned int min_vfreq, max_vfreq;
+       unsigned int min_hfreq, max_hfreq;
+       unsigned int pixel_clock;
+       unsigned int bpc;
+
+       enum subpixel_order subpixel_order;
+       u32 color_formats;
+
+       u8 cea_rev;
+
+       char *raw_edid; /* if any */
+};
+
+struct drm_framebuffer_funcs {
+       void (*destroy)(struct drm_framebuffer *framebuffer);
+       int (*create_handle)(struct drm_framebuffer *fb,
+                            struct drm_file *file_priv,
+                            unsigned int *handle);
+       /**
+        * Optinal callback for the dirty fb ioctl.
+        *
+        * Userspace can notify the driver via this callback
+        * that a area of the framebuffer has changed and should
+        * be flushed to the display hardware.
+        *
+        * See documentation in drm_mode.h for the struct
+        * drm_mode_fb_dirty_cmd for more information as all
+        * the semantics and arguments have a one to one mapping
+        * on this function.
+        */
+       int (*dirty)(struct drm_framebuffer *framebuffer,
+                    struct drm_file *file_priv, unsigned flags,
+                    unsigned color, struct drm_clip_rect *clips,
+                    unsigned num_clips);
+};
+
+struct drm_framebuffer {
+       struct drm_device *dev;
+       struct list_head head;
+       struct drm_mode_object base;
+       const struct drm_framebuffer_funcs *funcs;
+       unsigned int pitches[4];
+       unsigned int offsets[4];
+       unsigned int width;
+       unsigned int height;
+       /* depth can be 15 or 16 */
+       unsigned int depth;
+       int bits_per_pixel;
+       int flags;
+       uint32_t pixel_format; /* fourcc format */
+       struct list_head filp_head;
+       /* if you are using the helper */
+       void *helper_private;
+};
+
+struct drm_property_blob {
+       struct drm_mode_object base;
+       struct list_head head;
+       unsigned int length;
+       unsigned char data[];
+};
+
+struct drm_property_enum {
+       uint64_t value;
+       struct list_head head;
+       char name[DRM_PROP_NAME_LEN];
+};
+
+struct drm_property {
+       struct list_head head;
+       struct drm_mode_object base;
+       uint32_t flags;
+       char name[DRM_PROP_NAME_LEN];
+       uint32_t num_values;
+       uint64_t *values;
+
+       struct list_head enum_blob_list;
+};
+
+struct drm_crtc;
+struct drm_connector;
+struct drm_encoder;
+struct drm_pending_vblank_event;
+struct drm_plane;
+
+/**
+ * drm_crtc_funcs - control CRTCs for a given device
+ * @reset: reset CRTC after state has been invalidate (e.g. resume)
+ * @dpms: control display power levels
+ * @save: save CRTC state
+ * @resore: restore CRTC state
+ * @lock: lock the CRTC
+ * @unlock: unlock the CRTC
+ * @shadow_allocate: allocate shadow pixmap
+ * @shadow_create: create shadow pixmap for rotation support
+ * @shadow_destroy: free shadow pixmap
+ * @mode_fixup: fixup proposed mode
+ * @mode_set: set the desired mode on the CRTC
+ * @gamma_set: specify color ramp for CRTC
+ * @destroy: deinit and free object.
+ *
+ * The drm_crtc_funcs structure is the central CRTC management structure
+ * in the DRM.  Each CRTC controls one or more connectors (note that the name
+ * CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc.
+ * connectors, not just CRTs).
+ *
+ * Each driver is responsible for filling out this structure at startup time,
+ * in addition to providing other modesetting features, like i2c and DDC
+ * bus accessors.
+ */
+struct drm_crtc_funcs {
+       /* Save CRTC state */
+       void (*save)(struct drm_crtc *crtc); /* suspend? */
+       /* Restore CRTC state */
+       void (*restore)(struct drm_crtc *crtc); /* resume? */
+       /* Reset CRTC state */
+       void (*reset)(struct drm_crtc *crtc);
+
+       /* cursor controls */
+       int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv,
+                         uint32_t handle, uint32_t width, uint32_t height);
+       int (*cursor_move)(struct drm_crtc *crtc, int x, int y);
+
+       /* Set gamma on the CRTC */
+       void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
+                         uint32_t start, uint32_t size);
+       /* Object destroy routine */
+       void (*destroy)(struct drm_crtc *crtc);
+
+       int (*set_config)(struct drm_mode_set *set);
+
+       /*
+        * Flip to the given framebuffer.  This implements the page
+        * flip ioctl descibed in drm_mode.h, specifically, the
+        * implementation must return immediately and block all
+        * rendering to the current fb until the flip has completed.
+        * If userspace set the event flag in the ioctl, the event
+        * argument will point to an event to send back when the flip
+        * completes, otherwise it will be NULL.
+        */
+       int (*page_flip)(struct drm_crtc *crtc,
+                        struct drm_framebuffer *fb,
+                        struct drm_pending_vblank_event *event);
+};
+
+/**
+ * drm_crtc - central CRTC control structure
+ * @enabled: is this CRTC enabled?
+ * @x: x position on screen
+ * @y: y position on screen
+ * @funcs: CRTC control functions
+ *
+ * Each CRTC may have one or more connectors associated with it.  This structure
+ * allows the CRTC to be controlled.
+ */
+struct drm_crtc {
+       struct drm_device *dev;
+       struct list_head head;
+
+       struct drm_mode_object base;
+
+       /* framebuffer the connector is currently bound to */
+       struct drm_framebuffer *fb;
+
+       bool enabled;
+
+       /* Requested mode from modesetting. */
+       struct drm_display_mode mode;
+
+       /* Programmed mode in hw, after adjustments for encoders,
+        * crtc, panel scaling etc. Needed for timestamping etc.
+        */
+       struct drm_display_mode hwmode;
+
+       int x, y;
+       const struct drm_crtc_funcs *funcs;
+
+       /* CRTC gamma size for reporting to userspace */
+       uint32_t gamma_size;
+       uint16_t *gamma_store;
+
+       /* Constants needed for precise vblank and swap timestamping. */
+       int64_t framedur_ns, linedur_ns, pixeldur_ns;
+
+       /* if you are using the helper */
+       void *helper_private;
+};
+
+
+/**
+ * drm_connector_funcs - control connectors on a given device
+ * @dpms: set power state (see drm_crtc_funcs above)
+ * @save: save connector state
+ * @restore: restore connector state
+ * @reset: reset connector after state has been invalidate (e.g. resume)
+ * @mode_valid: is this mode valid on the given connector?
+ * @mode_fixup: try to fixup proposed mode for this connector
+ * @mode_set: set this mode
+ * @detect: is this connector active?
+ * @get_modes: get mode list for this connector
+ * @set_property: property for this connector may need update
+ * @destroy: make object go away
+ * @force: notify the driver the connector is forced on
+ *
+ * Each CRTC may have one or more connectors attached to it.  The functions
+ * below allow the core DRM code to control connectors, enumerate available modes,
+ * etc.
+ */
+struct drm_connector_funcs {
+       void (*dpms)(struct drm_connector *connector, int mode);
+       void (*save)(struct drm_connector *connector);
+       void (*restore)(struct drm_connector *connector);
+       void (*reset)(struct drm_connector *connector);
+
+       /* Check to see if anything is attached to the connector.
+        * @force is set to false whilst polling, true when checking the
+        * connector due to user request. @force can be used by the driver
+        * to avoid expensive, destructive operations during automated
+        * probing.
+        */
+       enum drm_connector_status (*detect)(struct drm_connector *connector,
+                                           bool force);
+       int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
+       int (*set_property)(struct drm_connector *connector, struct drm_property *property,
+                            uint64_t val);
+       void (*destroy)(struct drm_connector *connector);
+       void (*force)(struct drm_connector *connector);
+};
+
+struct drm_encoder_funcs {
+       void (*reset)(struct drm_encoder *encoder);
+       void (*destroy)(struct drm_encoder *encoder);
+};
+
+#define DRM_CONNECTOR_MAX_UMODES 16
+#define DRM_CONNECTOR_MAX_PROPERTY 16
+#define DRM_CONNECTOR_LEN 32
+#define DRM_CONNECTOR_MAX_ENCODER 2
+
+/**
+ * drm_encoder - central DRM encoder structure
+ */
+struct drm_encoder {
+       struct drm_device *dev;
+       struct list_head head;
+
+       struct drm_mode_object base;
+       int encoder_type;
+       uint32_t possible_crtcs;
+       uint32_t possible_clones;
+
+       struct drm_crtc *crtc;
+       const struct drm_encoder_funcs *funcs;
+       void *helper_private;
+};
+
+enum drm_connector_force {
+       DRM_FORCE_UNSPECIFIED,
+       DRM_FORCE_OFF,
+       DRM_FORCE_ON,         /* force on analog part normally */
+       DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */
+};
+
+/* should we poll this connector for connects and disconnects */
+/* hot plug detectable */
+#define DRM_CONNECTOR_POLL_HPD (1 << 0)
+/* poll for connections */
+#define DRM_CONNECTOR_POLL_CONNECT (1 << 1)
+/* can cleanly poll for disconnections without flickering the screen */
+/* DACs should rarely do this without a lot of testing */
+#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2)
+
+#define MAX_ELD_BYTES  128
+
+/**
+ * drm_connector - central DRM connector control structure
+ * @crtc: CRTC this connector is currently connected to, NULL if none
+ * @interlace_allowed: can this connector handle interlaced modes?
+ * @doublescan_allowed: can this connector handle doublescan?
+ * @available_modes: modes available on this connector (from get_modes() + user)
+ * @initial_x: initial x position for this connector
+ * @initial_y: initial y position for this connector
+ * @status: connector connected?
+ * @funcs: connector control functions
+ *
+ * Each connector may be connected to one or more CRTCs, or may be clonable by
+ * another connector if they can share a CRTC.  Each connector also has a specific
+ * position in the broader display (referred to as a 'screen' though it could
+ * span multiple monitors).
+ */
+struct drm_connector {
+       struct drm_device *dev;
+       /* struct device kdev; XXXKIB */
+       struct device_attribute *attr;
+       struct list_head head;
+
+       struct drm_mode_object base;
+
+       int connector_type;
+       int connector_type_id;
+       bool interlace_allowed;
+       bool doublescan_allowed;
+       struct list_head modes; /* list of modes on this connector */
+
+       int initial_x, initial_y;
+       enum drm_connector_status status;
+
+       /* these are modes added by probing with DDC or the BIOS */
+       struct list_head probed_modes;
+
+       struct drm_display_info display_info;
+       const struct drm_connector_funcs *funcs;
+
+       struct list_head user_modes;
+       struct drm_property_blob *edid_blob_ptr;
+       u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY];
+       uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY];
+
+       uint8_t polled; /* DRM_CONNECTOR_POLL_* */
+
+       /* requested DPMS state */
+       int dpms;
+
+       void *helper_private;
+
+       /* forced on connector */
+       enum drm_connector_force force;
+       uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
+       uint32_t force_encoder_id;
+       struct drm_encoder *encoder; /* currently active encoder */
+
+       /* EDID bits */
+       uint8_t eld[MAX_ELD_BYTES];
+       bool dvi_dual;
+       int max_tmds_clock;     /* in MHz */
+       bool latency_present[2];
+       int video_latency[2];   /* [0]: progressive, [1]: interlaced */
+       int audio_latency[2];
+
+       int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
+};
+
+/**
+ * drm_plane_funcs - driver plane control functions
+ * @update_plane: update the plane configuration
+ * @disable_plane: shut down the plane
+ * @destroy: clean up plane resources
+ */
+struct drm_plane_funcs {
+       int (*update_plane)(struct drm_plane *plane,
+                           struct drm_crtc *crtc, struct drm_framebuffer *fb,
+                           int crtc_x, int crtc_y,
+                           unsigned int crtc_w, unsigned int crtc_h,
+                           uint32_t src_x, uint32_t src_y,
+                           uint32_t src_w, uint32_t src_h);
+       int (*disable_plane)(struct drm_plane *plane);
+       void (*destroy)(struct drm_plane *plane);
+};
+
+/**
+ * drm_plane - central DRM plane control structure
+ * @dev: DRM device this plane belongs to
+ * @head: for list management
+ * @base: base mode object
+ * @possible_crtcs: pipes this plane can be bound to
+ * @format_types: array of formats supported by this plane
+ * @format_count: number of formats supported
+ * @crtc: currently bound CRTC
+ * @fb: currently bound fb
+ * @gamma_size: size of gamma table
+ * @gamma_store: gamma correction table
+ * @enabled: enabled flag
+ * @funcs: helper functions
+ * @helper_private: storage for drver layer
+ */
+struct drm_plane {
+       struct drm_device *dev;
+       struct list_head head;
+
+       struct drm_mode_object base;
+
+       uint32_t possible_crtcs;
+       uint32_t *format_types;
+       uint32_t format_count;
+
+       struct drm_crtc *crtc;
+       struct drm_framebuffer *fb;
+
+       /* CRTC gamma size for reporting to userspace */
+       uint32_t gamma_size;
+       uint16_t *gamma_store;
+
+       bool enabled;
+
+       const struct drm_plane_funcs *funcs;
+       void *helper_private;
+};
+
+/**
+ * struct drm_mode_set
+ *
+ * Represents a single crtc the connectors that it drives with what mode
+ * and from which framebuffer it scans out from.
+ *
+ * This is used to set modes.
+ */
+struct drm_mode_set {
+       struct list_head head;
+
+       struct drm_framebuffer *fb;
+       struct drm_crtc *crtc;
+       struct drm_display_mode *mode;
+
+       uint32_t x;
+       uint32_t y;
+
+       struct drm_connector **connectors;
+       size_t num_connectors;
+};
+
+/**
+ * struct drm_mode_config_funcs - configure CRTCs for a given screen layout
+ */
+struct drm_mode_config_funcs {
+       int (*fb_create)(struct drm_device *dev,
+           struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd,
+           struct drm_framebuffer **res);
+       void (*output_poll_changed)(struct drm_device *dev);
+};
+
+struct drm_mode_group {
+       uint32_t num_crtcs;
+       uint32_t num_encoders;
+       uint32_t num_connectors;
+
+       /* list of object IDs for this group */
+       uint32_t *id_list;
+};
+
+/**
+ * drm_mode_config - Mode configuration control structure
+ *
+ */
+struct drm_mode_config {
+       struct sx mutex; /* protects configuration (mode lists etc.) */
+       struct drm_gem_names crtc_names; /* use this idr for all IDs, fb, crtc, connector, modes */
+       /* this is limited to one for now */
+       int num_fb;
+       struct list_head fb_list;
+       int num_connector;
+       struct list_head connector_list;
+       int num_encoder;
+       struct list_head encoder_list;
+       int num_plane;
+       struct list_head plane_list;
+
+       int num_crtc;
+       struct list_head crtc_list;
+
+       struct list_head property_list;
+
+       int min_width, min_height;
+       int max_width, max_height;
+       struct drm_mode_config_funcs *funcs;
+       resource_size_t fb_base;
+
+       /* output poll support */
+       bool poll_enabled;
+       struct timeout_task output_poll_task;
+
+       /* pointers to standard properties */
+       struct list_head property_blob_list;
+       struct drm_property *edid_property;
+       struct drm_property *dpms_property;
+
+       /* DVI-I properties */
+       struct drm_property *dvi_i_subconnector_property;
+       struct drm_property *dvi_i_select_subconnector_property;
+
+       /* TV properties */
+       struct drm_property *tv_subconnector_property;
+       struct drm_property *tv_select_subconnector_property;
+       struct drm_property *tv_mode_property;
+       struct drm_property *tv_left_margin_property;
+       struct drm_property *tv_right_margin_property;
+       struct drm_property *tv_top_margin_property;
+       struct drm_property *tv_bottom_margin_property;
+       struct drm_property *tv_brightness_property;
+       struct drm_property *tv_contrast_property;