OSDN Git Service

drm: Fix race that can lockup the kernel
[android-x86/external-libdrm.git] / linux-core / mga_drv.c
index bea65cf..14a0be4 100644 (file)
  *    Gareth Hughes <gareth@valinux.com>
  */
 
-#include <linux/config.h>
-#include "mga.h"
 #include "drmP.h"
+#include "drm.h"
+#include "mga_drm.h"
 #include "mga_drv.h"
 
-#define DRIVER_AUTHOR          "Gareth Hughes, VA Linux Systems Inc."
-
-#define DRIVER_NAME            "mga"
-#define DRIVER_DESC            "Matrox G200/G400"
-#define DRIVER_DATE            "20010321"
-
-#define DRIVER_MAJOR           3
-#define DRIVER_MINOR           0
-#define DRIVER_PATCHLEVEL      2
-
-#define DRIVER_IOCTLS                                                     \
-       [DRM_IOCTL_NR(DRM_IOCTL_DMA)]         = { mga_dma_buffers, 1, 0 }, \
-       [DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)]    = { mga_dma_init,    1, 1 }, \
-       [DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)]   = { mga_dma_flush,   1, 0 }, \
-       [DRM_IOCTL_NR(DRM_IOCTL_MGA_RESET)]   = { mga_dma_reset,   1, 0 }, \
-       [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)]    = { mga_dma_swap,    1, 0 }, \
-       [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)]   = { mga_dma_clear,   1, 0 }, \
-       [DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)]  = { mga_dma_vertex,  1, 0 }, \
-       [DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_dma_indices, 1, 0 }, \
-       [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)]   = { mga_dma_iload,   1, 0 }, \
-       [DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)]    = { mga_dma_blit,    1, 0 },
-
-
-#define __HAVE_COUNTERS         3
-#define __HAVE_COUNTER6         _DRM_STAT_IRQ
-#define __HAVE_COUNTER7         _DRM_STAT_PRIMARY
-#define __HAVE_COUNTER8         _DRM_STAT_SECONDARY
-
-
-#include "drm_agpsupport.h"
-#include "drm_auth.h"
-#include "drm_bufs.h"
-#include "drm_context.h"
-#include "drm_dma.h"
-#include "drm_drawable.h"
-#include "drm_drv.h"
-#include "drm_fops.h"
-#include "drm_init.h"
-#include "drm_ioctl.h"
-#include "drm_lock.h"
-#include "drm_memory.h"
-#include "drm_proc.h"
-#include "drm_vm.h"
-#include "drm_stub.h"
+#include "drm_pciids.h"
+
+static int mga_driver_device_is_agp(struct drm_device * dev);
+
+static struct pci_device_id pciidlist[] = {
+       mga_PCI_IDS
+};
+
+static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static struct drm_driver driver = {
+       .driver_features =
+           DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
+           DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
+       .dev_priv_size = sizeof (drm_mga_buf_priv_t),
+       .load = mga_driver_load,
+       .unload = mga_driver_unload,
+       .lastclose = mga_driver_lastclose,
+       .dma_quiescent = mga_driver_dma_quiescent,
+       .device_is_agp = mga_driver_device_is_agp,
+       .get_vblank_counter = mga_get_vblank_counter,
+       .enable_vblank = mga_enable_vblank,
+       .disable_vblank = mga_disable_vblank,
+       .irq_preinstall = mga_driver_irq_preinstall,
+       .irq_postinstall = mga_driver_irq_postinstall,
+       .irq_uninstall = mga_driver_irq_uninstall,
+       .irq_handler = mga_driver_irq_handler,
+       .reclaim_buffers = drm_core_reclaim_buffers,
+       .get_map_ofs = drm_core_get_map_ofs,
+       .get_reg_ofs = drm_core_get_reg_ofs,
+       .ioctls = mga_ioctls,
+       .dma_ioctl = mga_dma_buffers,
+       .fops = {
+               .owner = THIS_MODULE,
+               .open = drm_open,
+               .release = drm_release,
+               .ioctl = drm_ioctl,
+               .mmap = drm_mmap,
+               .poll = drm_poll,
+               .fasync = drm_fasync,
+#if defined(CONFIG_COMPAT) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
+               .compat_ioctl = mga_compat_ioctl,
+#endif
+               },
+       .pci_driver = {
+               .name = DRIVER_NAME,
+               .id_table = pciidlist,
+               .probe = probe,
+               .remove = __devexit_p(drm_cleanup_pci),
+       },
+
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+       .date = DRIVER_DATE,
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+       .patchlevel = DRIVER_PATCHLEVEL,
+};
+
+static int probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       return drm_get_dev(pdev, ent, &driver);
+}
+
+
+static int __init mga_init(void)
+{
+       driver.num_ioctls = mga_max_ioctl;
+       return drm_init(&driver, pciidlist);
+}
+
+static void __exit mga_exit(void)
+{
+       drm_exit(&driver);
+}
+
+module_init(mga_init);
+module_exit(mga_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
+
+/**
+ * Determine if the device really is AGP or not.
+ *
+ * In addition to the usual tests performed by \c drm_device_is_agp, this
+ * function detects PCI G450 cards that appear to the system exactly like
+ * AGP G450 cards.
+ *
+ * \param dev   The device to be tested.
+ *
+ * \returns
+ * If the device is a PCI G450, zero is returned.  Otherwise 2 is returned.
+ */
+static int mga_driver_device_is_agp(struct drm_device * dev)
+{
+       const struct pci_dev * const pdev = dev->pdev;
+
+
+       /* There are PCI versions of the G450.  These cards have the
+        * same PCI ID as the AGP G450, but have an additional PCI-to-PCI
+        * bridge chip.  We detect these cards, which are not currently
+        * supported by this driver, by looking at the device ID of the
+        * bus the "card" is on.  If vendor is 0x3388 (Hint Corp) and the
+        * device is 0x0021 (HB6 Universal PCI-PCI bridge), we reject the
+        * device.
+        */
+
+       if ((pdev->device == 0x0525) && pdev->bus->self
+           && (pdev->bus->self->vendor == 0x3388)
+           && (pdev->bus->self->device == 0x0021)) {
+               return 0;
+       }
+
+       return 2;
+}