summaryrefslogtreecommitdiff
path: root/linux-core/xgi_drv.c
diff options
context:
space:
mode:
authorIan Romanick <idr@us.ibm.com>2007-06-26 13:10:30 -0700
committerIan Romanick <idr@us.ibm.com>2007-06-26 13:10:30 -0700
commit434657a2582362367ba2a94f827511252001368f (patch)
tree13ed8f198b68953d33e8f7998aff7e7a5fc57c3e /linux-core/xgi_drv.c
parent7af9d670371de868f0642148fe2d594bc9a7dea3 (diff)
dos2unix and Lindent
Diffstat (limited to 'linux-core/xgi_drv.c')
-rw-r--r--linux-core/xgi_drv.c3174
1 files changed, 1564 insertions, 1610 deletions
diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c
index 5e80d417..0c37d00e 100644
--- a/linux-core/xgi_drv.c
+++ b/linux-core/xgi_drv.c
@@ -1,1610 +1,1564 @@
-
-/****************************************************************************
- * Copyright (C) 2003-2006 by XGI Technology, Taiwan.
- * *
- * 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 on 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
- * NON-INFRINGEMENT. IN NO EVENT SHALL XGI 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 "xgi_types.h"
-#include "xgi_linux.h"
-#include "xgi_drv.h"
-#include "xgi_regs.h"
-#include "xgi_pcie.h"
-#include "xgi_misc.h"
-#include "xgi_cmdlist.h"
-
-/* for debug */
-static int xgi_temp = 1;
-/*
- * global parameters
- */
-static struct xgi_dev {
- u16 vendor;
- u16 device;
- const char *name;
-} xgidev_list[] = {
- {PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XP5, "XP5"},
- {PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XG47, "XG47"},
- {0, 0, NULL}
-};
-
-int xgi_major = XGI_DEV_MAJOR; /* xgi reserved major device number. */
-
-static int xgi_num_devices = 0;
-
-xgi_info_t xgi_devices[XGI_MAX_DEVICES];
-
-#if defined(XGI_PM_SUPPORT_APM)
-static struct pm_dev *apm_xgi_dev[XGI_MAX_DEVICES] = { 0 };
-#endif
-
-/* add one for the control device */
-xgi_info_t xgi_ctl_device;
-wait_queue_head_t xgi_ctl_waitqueue;
-
-#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_xgi;
-#endif
-
-#ifdef CONFIG_DEVFS_FS
-devfs_handle_t xgi_devfs_handles[XGI_MAX_DEVICES];
-#endif
-
-struct list_head xgi_mempid_list;
-
-/* xgi_ functions.. do not take a state device parameter */
-static int xgi_post_vbios(xgi_ioctl_post_vbios_t *info);
-static void xgi_proc_create(void);
-static void xgi_proc_remove_all(struct proc_dir_entry *);
-static void xgi_proc_remove(void);
-
-/* xgi_kern_ functions, interfaces used by linux kernel */
-int xgi_kern_probe(struct pci_dev *, const struct pci_device_id *);
-
-unsigned int xgi_kern_poll(struct file *, poll_table *);
-int xgi_kern_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
-int xgi_kern_mmap(struct file *, struct vm_area_struct *);
-int xgi_kern_open(struct inode *, struct file *);
-int xgi_kern_release(struct inode *inode, struct file *filp);
-
-void xgi_kern_vma_open(struct vm_area_struct *vma);
-void xgi_kern_vma_release(struct vm_area_struct *vma);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1))
-struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type);
-#else
-struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma,
- unsigned long address, int write_access);
-#endif
-
-int xgi_kern_read_card_info(char *, char **, off_t off, int, int *, void *);
-int xgi_kern_read_status(char *, char **, off_t off, int, int *, void *);
-int xgi_kern_read_pcie_info(char *, char **, off_t off, int, int *, void *);
-int xgi_kern_read_version(char *, char **, off_t off, int, int *, void *);
-
-int xgi_kern_ctl_open(struct inode *, struct file *);
-int xgi_kern_ctl_close(struct inode *, struct file *);
-unsigned int xgi_kern_ctl_poll(struct file *, poll_table *);
-
-void xgi_kern_isr_bh(unsigned long);
-irqreturn_t xgi_kern_isr(int, void *, struct pt_regs *);
-
-static void xgi_lock_init(xgi_info_t *info);
-
-#if defined(XGI_PM_SUPPORT_ACPI)
-int xgi_kern_acpi_standby(struct pci_dev *, u32);
-int xgi_kern_acpi_resume(struct pci_dev *);
-#endif
-
-/*
- * verify access to pci config space wasn't disabled behind our back
- * unfortunately, XFree86 enables/disables memory access in pci config space at
- * various times (such as restoring initial pci config space settings during vt
- * switches or when doing mulicard). As a result, all of our register accesses
- * are garbage at this point. add a check to see if access was disabled and
- * reenable any such access.
- */
-#define XGI_CHECK_PCI_CONFIG(xgi) \
- xgi_check_pci_config(xgi, __LINE__)
-
-static inline void xgi_check_pci_config(xgi_info_t *info, int line)
-{
- unsigned short cmd, flag = 0;
-
- // don't do this on the control device, only the actual devices
- if (info->flags & XGI_FLAG_CONTROL)
- return;
-
- pci_read_config_word(info->dev, PCI_COMMAND, &cmd);
- if (!(cmd & PCI_COMMAND_MASTER))
- {
- XGI_INFO("restoring bus mastering! (%d)\n", line);
- cmd |= PCI_COMMAND_MASTER;
- flag = 1;
- }
-
- if (!(cmd & PCI_COMMAND_MEMORY))
- {
- XGI_INFO("restoring MEM access! (%d)\n", line);
- cmd |= PCI_COMMAND_MEMORY;
- flag = 1;
- }
-
- if (flag)
- pci_write_config_word(info->dev, PCI_COMMAND, cmd);
-}
-
-static int xgi_post_vbios(xgi_ioctl_post_vbios_t *info)
-{
- return 1;
-}
-
-/*
- * struct pci_device_id {
- * unsigned int vendor, device; // Vendor and device ID or PCI_ANY_ID
- * unsigned int subvendor, subdevice; // Subsystem ID's or PCI_ANY_ID
- * unsigned int class, class_mask; // (class,subclass,prog-if) triplet
- * unsigned long driver_data; // Data private to the driver
- * };
- */
-
-static struct pci_device_id xgi_dev_table[] = {
- {
- .vendor = PCI_VENDOR_ID_XGI,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .class = (PCI_CLASS_DISPLAY_VGA << 8),
- .class_mask = ~0,
- },
- { }
-};
-
-/*
- * #define MODULE_DEVICE_TABLE(type,name) \
- * MODULE_GENERIC_TABLE(type##_device,name)
- */
- MODULE_DEVICE_TABLE(pci, xgi_dev_table);
-
-/*
- * struct pci_driver {
- * struct list_head node;
- * char *name;
- * const struct pci_device_id *id_table; // NULL if wants all devices
- * int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); // New device inserted
- * void (*remove)(struct pci_dev *dev); // Device removed (NULL if not a hot-plug capable driver)
- * int (*save_state)(struct pci_dev *dev, u32 state); // Save Device Context
- * int (*suspend)(struct pci_dev *dev, u32 state); // Device suspended
- * int (*resume)(struct pci_dev *dev); // Device woken up
- * int (*enable_wake)(struct pci_dev *dev, u32 state, int enable); // Enable wake event
- * };
- */
-static struct pci_driver xgi_pci_driver = {
- .name = "xgi",
- .id_table = xgi_dev_table,
- .probe = xgi_kern_probe,
-#if defined(XGI_SUPPORT_ACPI)
- .suspend = xgi_kern_acpi_standby,
- .resume = xgi_kern_acpi_resume,
-#endif
-};
-
-/*
- * find xgi devices and set initial state
- */
-int xgi_kern_probe(struct pci_dev *dev, const struct pci_device_id *id_table)
-{
- xgi_info_t *info;
-
- if ((dev->vendor != PCI_VENDOR_ID_XGI)
- || (dev->class != (PCI_CLASS_DISPLAY_VGA << 8)))
- {
- return -1;
- }
-
- if (xgi_num_devices == XGI_MAX_DEVICES)
- {
- XGI_INFO("maximum device number (%d) reached!\n", xgi_num_devices);
- return -1;
- }
-
- /* enable io, mem, and bus-mastering in pci config space */
- if (pci_enable_device(dev) != 0)
- {
- XGI_INFO("pci_enable_device failed, aborting\n");
- return -1;
- }
-
- XGI_INFO("maximum device number (%d) reached \n", xgi_num_devices);
-
- pci_set_master(dev);
-
- info = &xgi_devices[xgi_num_devices];
- info->dev = dev;
- info->vendor_id = dev->vendor;
- info->device_id = dev->device;
- info->bus = dev->bus->number;
- info->slot = PCI_SLOT((dev)->devfn);
-
- xgi_lock_init(info);
-
- info->mmio.base = XGI_PCI_RESOURCE_START(dev, 1);
- info->mmio.size = XGI_PCI_RESOURCE_SIZE(dev, 1);
-
- /* check IO region */
- if (!request_mem_region(info->mmio.base, info->mmio.size, "xgi"))
- {
- XGI_ERROR("cannot reserve MMIO memory\n");
- goto error_disable_dev;
- }
-
- XGI_INFO("info->mmio.base: 0x%lx \n", info->mmio.base);
- XGI_INFO("info->mmio.size: 0x%lx \n", info->mmio.size);
-
- info->mmio.vbase = (unsigned char *)ioremap_nocache(info->mmio.base,
- info->mmio.size);
- if (!info->mmio.vbase)
- {
- release_mem_region(info->mmio.base, info->mmio.size);
- XGI_ERROR("info->mmio.vbase failed\n");
- goto error_disable_dev;
- }
- xgi_enable_mmio(info);
-
- //xgi_enable_ge(info);
-
- XGI_INFO("info->mmio.vbase: 0x%p \n", info->mmio.vbase);
-
- info->fb.base = XGI_PCI_RESOURCE_START(dev, 0);
- info->fb.size = XGI_PCI_RESOURCE_SIZE(dev, 0);
-
- XGI_INFO("info->fb.base: 0x%lx \n", info->fb.base);
- XGI_INFO("info->fb.size: 0x%lx \n", info->fb.size);
-
- info->fb.size = bIn3cf(0x54) * 8 * 1024 * 1024;
- XGI_INFO("info->fb.size: 0x%lx \n", info->fb.size);
-
- /* check frame buffer region
- if (!request_mem_region(info->fb.base, info->fb.size, "xgi"))
- {
- release_mem_region(info->mmio.base, info->mmio.size);
- XGI_ERROR("cannot reserve frame buffer memory\n");
- goto error_disable_dev;
- }
-
-
- info->fb.vbase = (unsigned char *)ioremap_nocache(info->fb.base,
- info->fb.size);
-
- if (!info->fb.vbase)
- {
- release_mem_region(info->mmio.base, info->mmio.size);
- release_mem_region(info->fb.base, info->fb.size);
- XGI_ERROR("info->fb.vbase failed\n");
- goto error_disable_dev;
- }
- */
- info->fb.vbase = NULL;
- XGI_INFO("info->fb.vbase: 0x%p \n", info->fb.vbase);
-
- info->irq = dev->irq;
-
- /* check common error condition */
- if (info->irq == 0)
- {
- XGI_ERROR("Can't find an IRQ for your XGI card! \n");
- goto error_zero_dev;
- }
- XGI_INFO("info->irq: %lx \n", info->irq);
-
- //xgi_enable_dvi_interrupt(info);
-
- /* sanity check the IO apertures */
- if ((info->mmio.base == 0) || (info->mmio.size == 0)
- || (info->fb.base == 0) || (info->fb.size == 0))
- {
- XGI_ERROR("The IO regions for your XGI card are invalid.\n");
-
- if ((info->mmio.base == 0) || (info->mmio.size == 0))
- {
- XGI_ERROR("mmio appears to be wrong: 0x%lx 0x%lx\n",
- info->mmio.base,
- info->mmio.size);
- }
-
- if ((info->fb.base == 0) || (info->fb.size == 0))
- {
- XGI_ERROR("frame buffer appears to be wrong: 0x%lx 0x%lx\n",
- info->fb.base,
- info->fb.size);
- }
-
- goto error_zero_dev;
- }
-
- //xgi_num_devices++;
-
- return 0;
-
-error_zero_dev:
- release_mem_region(info->fb.base, info->fb.size);
- release_mem_region(info->mmio.base, info->mmio.size);
-
-error_disable_dev:
- pci_disable_device(dev);
- return -1;
-
-}
-
-/*
- * vma operations...
- * this is only called when the vmas are duplicated. this
- * appears to only happen when the process is cloned to create
- * a new process, and not when the process is threaded.
- *
- * increment the usage count for the physical pages, so when
- * this clone unmaps the mappings, the pages are not
- * deallocated under the original process.
- */
-struct vm_operations_struct xgi_vm_ops = {
- .open = xgi_kern_vma_open,
- .close = xgi_kern_vma_release,
- .nopage = xgi_kern_vma_nopage,
-};
-
-void xgi_kern_vma_open(struct vm_area_struct *vma)
-{
- XGI_INFO("VM: vma_open for 0x%lx - 0x%lx, offset 0x%lx\n",
- vma->vm_start,
- vma->vm_end,
- XGI_VMA_OFFSET(vma));
-
- if (XGI_VMA_PRIVATE(vma))
- {
- xgi_pcie_block_t *block = (xgi_pcie_block_t *)XGI_VMA_PRIVATE(vma);
- XGI_ATOMIC_INC(block->use_count);
- }
-}
-
-void xgi_kern_vma_release(struct vm_area_struct *vma)
-{
- XGI_INFO("VM: vma_release for 0x%lx - 0x%lx, offset 0x%lx\n",
- vma->vm_start,
- vma->vm_end,
- XGI_VMA_OFFSET(vma));
-
- if (XGI_VMA_PRIVATE(vma))
- {
- xgi_pcie_block_t *block = (xgi_pcie_block_t *)XGI_VMA_PRIVATE(vma);
- XGI_ATOMIC_DEC(block->use_count);
-
- /*
- * if use_count is down to 0, the kernel virtual mapping was freed
- * but the underlying physical pages were not, we need to clear the
- * bit and free the physical pages.
- */
- if (XGI_ATOMIC_READ(block->use_count) == 0)
- {
- // Need TO Finish
- XGI_VMA_PRIVATE(vma) = NULL;
- }
- }
-}
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1))
-struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
-{
- xgi_pcie_block_t *block = (xgi_pcie_block_t *)XGI_VMA_PRIVATE(vma);
- struct page *page = NOPAGE_SIGBUS;
- unsigned long offset = 0;
- unsigned long page_addr = 0;
-/*
- XGI_INFO("VM: mmap([0x%lx-0x%lx] off=0x%lx) address: 0x%lx \n",
- vma->vm_start,
- vma->vm_end,
- XGI_VMA_OFFSET(vma),
- address);
-*/
- offset = (address - vma->vm_start) + XGI_VMA_OFFSET(vma);
-
- offset = offset - block->bus_addr;
-
- offset >>= PAGE_SHIFT;
-
- page_addr = block->page_table[offset].virt_addr;
-
- if (xgi_temp)
- {
- XGI_INFO("block->bus_addr: 0x%lx block->hw_addr: 0x%lx"
- "block->page_count: 0x%lx block->page_order: 0x%lx"
- "block->page_table[0x%lx].virt_addr: 0x%lx\n",
- block->bus_addr, block->hw_addr,
- block->page_count, block->page_order,
- offset,
- block->page_table[offset].virt_addr);
- xgi_temp = 0;
- }
-
- if (!page_addr) goto out; /* hole or end-of-file */
- page = virt_to_page(page_addr);
-
- /* got it, now increment the count */
- get_page(page);
-out:
- return page;
-
-}
-#else
-struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma,
- unsigned long address, int write_access)
-{
- xgi_pcie_block_t *block = (xgi_pcie_block_t *)XGI_VMA_PRIVATE(vma);
- struct page *page = NOPAGE_SIGBUS;
- unsigned long offset = 0;
- unsigned long page_addr = 0;
-/*
- XGI_INFO("VM: mmap([0x%lx-0x%lx] off=0x%lx) address: 0x%lx \n",
- vma->vm_start,
- vma->vm_end,
- XGI_VMA_OFFSET(vma),
- address);
-*/
- offset = (address - vma->vm_start) + XGI_VMA_OFFSET(vma);
-
- offset = offset - block->bus_addr;
-
- offset >>= PAGE_SHIFT;
-
- page_addr = block->page_table[offset].virt_addr;
-
- if (xgi_temp)
- {
- XGI_INFO("block->bus_addr: 0x%lx block->hw_addr: 0x%lx"
- "block->page_count: 0x%lx block->page_order: 0x%lx"
- "block->page_table[0x%lx].virt_addr: 0x%lx\n",
- block->bus_addr, block->hw_addr,
- block->page_count, block->page_order,
- offset,
- block->page_table[offset].virt_addr);
- xgi_temp = 0;
- }
-
- if (!page_addr) goto out; /* hole or end-of-file */
- page = virt_to_page(page_addr);
-
- /* got it, now increment the count */
- get_page(page);
-out:
- return page;
-}
-#endif
-
-#if 0
-static struct file_operations xgi_fops = {
- /* owner: THIS_MODULE, */
- poll: xgi_kern_poll,
- ioctl: xgi_kern_ioctl,
- mmap: xgi_kern_mmap,
- open: xgi_kern_open,
- release: xgi_kern_release,
-};
-#endif
-
-static struct file_operations xgi_fops = {
- .owner = THIS_MODULE,
- .poll = xgi_kern_poll,
- .ioctl = xgi_kern_ioctl,
- .mmap = xgi_kern_mmap,
- .open = xgi_kern_open,
- .release = xgi_kern_release,
-};
-
-static xgi_file_private_t * xgi_alloc_file_private(void)
-{
- xgi_file_private_t *fp;
-
- XGI_KMALLOC(fp, sizeof(xgi_file_private_t));
- if (!fp)
- return NULL;
-
- memset(fp, 0, sizeof(xgi_file_private_t));
-
- /* initialize this file's event queue */
- init_waitqueue_head(&fp->wait_queue);
-
- xgi_init_lock(fp->fp_lock);
-
- return fp;
-}
-
-static void xgi_free_file_private(xgi_file_private_t *fp)
-{
- if (fp == NULL)
- return;
-
- XGI_KFREE(fp, sizeof(xgi_file_private_t));
-}
-
-int xgi_kern_open(struct inode *inode, struct file *filp)
-{
- xgi_info_t *info = NULL;
- int dev_num;
- int result = 0, status;
-
- /*
- * the type and num values are only valid if we are not using devfs.
- * However, since we use them to retrieve the device pointer, we
- * don't need them with devfs as filp->private_data is already
- * initialized
- */
- filp->private_data = xgi_alloc_file_private();
- if (filp->private_data == NULL)
- return -ENOMEM;
-
- XGI_INFO("filp->private_data %p\n", filp->private_data);
- /*
- * for control device, just jump to its open routine
- * after setting up the private data
- */
- if (XGI_IS_CONTROL_DEVICE(inode))
- return xgi_kern_ctl_open(inode, filp);
-
- /* what device are we talking about? */
- dev_num = XGI_DEVICE_NUMBER(inode);
- if (dev_num >= XGI_MAX_DEVICES)
- {
- xgi_free_file_private(filp->private_data);
- filp->private_data = NULL;
- return -ENODEV;
- }
-
- info = &xgi_devices[dev_num];
-
- XGI_INFO("Jong-xgi_kern_open on device %d\n", dev_num);
-
- xgi_down(info->info_sem);
- XGI_CHECK_PCI_CONFIG(info);
-
- XGI_INFO_FROM_FP(filp) = info;
-
- /*
- * map the memory and allocate isr on first open
- */
-
- if (!(info->flags & XGI_FLAG_OPEN))
- {
- XGI_INFO("info->flags & XGI_FLAG_OPEN \n");
-
- if (info->device_id == 0)
- {
- XGI_INFO("open of nonexistent device %d\n", dev_num);
- result = -ENXIO;
- goto failed;
- }
-
- /* initialize struct irqaction */
- status = request_irq(info->irq, xgi_kern_isr,
- SA_INTERRUPT | SA_SHIRQ, "xgi",
- (void *) info);
- if (status != 0)
- {
- if (info->irq && (status == -EBUSY))
- {
- XGI_ERROR("Tried to get irq %d, but another driver",
- (unsigned int) info->irq);
- XGI_ERROR("has it and is not sharing it.\n");
- }
- XGI_ERROR("isr request failed 0x%x\n", status);
- result = -EIO;
- goto failed;
- }
-
- /*
- * #define DECLARE_TASKLET(name, func, data) \
- * struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
- */
- info->tasklet.func = xgi_kern_isr_bh;
- info->tasklet.data = (unsigned long) info;
- tasklet_enable(&info->tasklet);
-
- /* Alloc 1M bytes for cmdbuffer which is flush2D batch array */
- xgi_cmdlist_initialize(info, 0x100000);
-
- info->flags |= XGI_FLAG_OPEN;
- }
-
- XGI_ATOMIC_INC(info->use_count);
-
-failed:
- xgi_up(info->info_sem);
-
- if ((result) && filp->private_data)
- {
- xgi_free_file_private(filp->private_data);
- filp->private_data = NULL;
- }
-
- return result;
-}
-
-int xgi_kern_release(struct inode *inode, struct file *filp)
-{
- xgi_info_t *info = XGI_INFO_FROM_FP(filp);
-
- XGI_CHECK_PCI_CONFIG(info);
-
- /*
- * for control device, just jump to its open routine
- * after setting up the private data
- */
- if (XGI_IS_CONTROL_DEVICE(inode))
- return xgi_kern_ctl_close(inode, filp);
-
- XGI_INFO("Jong-xgi_kern_release on device %d\n", XGI_DEVICE_NUMBER(inode));
-
- xgi_down(info->info_sem);
- if (XGI_ATOMIC_DEC_AND_TEST(info->use_count))
- {
-
- /*
- * The usage count for this device has dropped to zero, it can be shut
- * down safely; disable its interrupts.
- */
-
- /*
- * Disable this device's tasklet to make sure that no bottom half will
- * run with undefined device state.
- */
- tasklet_disable(&info->tasklet);
-
- /*
- * Free the IRQ, which may block until all pending interrupt processing
- * has completed.
- */
- free_irq(info->irq, (void *)info);
-
- xgi_cmdlist_cleanup(info);
-
- /* leave INIT flag alone so we don't reinit every time */
- info->flags &= ~XGI_FLAG_OPEN;
- }
-
- xgi_up(info->info_sem);
-
- if (FILE_PRIVATE(filp))
- {
- xgi_free_file_private(FILE_PRIVATE(filp));
- FILE_PRIVATE(filp) = NULL;
- }
-
- return 0;
-}
-
-int xgi_kern_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- //struct inode *inode = INODE_FROM_FP(filp);
- xgi_info_t *info = XGI_INFO_FROM_FP(filp);
- xgi_pcie_block_t *block;
- int pages = 0;
- unsigned long prot;
-
- XGI_INFO("Jong-VM: mmap([0x%lx-0x%lx] off=0x%lx)\n",
- vma->vm_start,
- vma->vm_end,
- XGI_VMA_OFFSET(vma));
-
- XGI_CHECK_PCI_CONFIG(info);
-
- if (XGI_MASK_OFFSET(vma->vm_start)
- || XGI_MASK_OFFSET(vma->vm_end))
- {
- XGI_ERROR("VM: bad mmap range: %lx - %lx\n",
- vma->vm_start, vma->vm_end);
- return -ENXIO;
- }
-
- pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
-
- vma->vm_ops = &xgi_vm_ops;
-
- /* XGI IO(reg) space */
- if (IS_IO_OFFSET(info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start))
- {
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- if (XGI_REMAP_PAGE_RANGE(vma->vm_start,
- XGI_VMA_OFFSET(vma),
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
-
- /* mark it as IO so that we don't dump it on core dump */
- vma->vm_flags |= VM_IO;
- XGI_INFO("VM: mmap io space \n");
- }
- /* XGI fb space */
- /* Jong 06/14/2006; moved behind PCIE or modify IS_FB_OFFSET */
- else if (IS_FB_OFFSET(info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start))
- {
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- if (XGI_REMAP_PAGE_RANGE(vma->vm_start,
- XGI_VMA_OFFSET(vma),
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
-
- // mark it as IO so that we don't dump it on core dump
- vma->vm_flags |= VM_IO;
- XGI_INFO("VM: mmap fb space \n");
- }
- /* PCIE allocator */
- /* XGI_VMA_OFFSET(vma) is offset based on pcie.base (HW address space) */
- else if (IS_PCIE_OFFSET(info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start))
- {
- xgi_down(info->pcie_sem);
-
- block = (xgi_pcie_block_t *)xgi_find_pcie_block(info, XGI_VMA_OFFSET(vma));
-
- if (block == NULL)
- {
- XGI_ERROR("couldn't find pre-allocated PCIE memory!\n");
- xgi_up(info->pcie_sem);
- return -EAGAIN;
- }
-
- if (block->page_count != pages)
- {
- XGI_ERROR("pre-allocated PCIE memory has wrong number of pages!\n");
- xgi_up(info->pcie_sem);
- return -EAGAIN;
- }
-
- vma->vm_private_data = block;
- XGI_ATOMIC_INC(block->use_count);
- xgi_up(info->pcie_sem);
-
- /*
- * prevent the swapper from swapping it out
- * mark the memory i/o so the buffers aren't
- * dumped on core dumps */
- vma->vm_flags |= (VM_LOCKED | VM_IO);
-
- /* un-cached */
- prot = pgprot_val(vma->vm_page_prot);
- /*
- if (boot_cpu_data.x86 > 3)
- prot |= _PAGE_PCD | _PAGE_PWT;
- */
- vma->vm_page_prot = __pgprot(prot);
-
- XGI_INFO("VM: mmap pcie space \n");
- }
-#if 0
- else if (IS_FB_OFFSET(info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start))
- {
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- if (XGI_REMAP_PAGE_RANGE(vma->vm_start,
- XGI_VMA_OFFSET(vma),
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
-
- // mark it as IO so that we don't dump it on core dump
- vma->vm_flags |= VM_IO;
- XGI_INFO("VM: mmap fb space \n");
- }
-#endif
- else
- {
- vma->vm_flags |= (VM_IO | VM_LOCKED);
- XGI_ERROR("VM: mmap wrong range \n");
- }
-
- vma->vm_file = filp;
-
- return 0;
-}
-
-unsigned int xgi_kern_poll(struct file *filp, struct poll_table_struct *wait)
-{
- xgi_file_private_t *fp;
- xgi_info_t *info;
- unsigned int mask = 0;
- unsigned long eflags;
-
- info = XGI_INFO_FROM_FP(filp);
-
- if (info->device_number == XGI_CONTROL_DEVICE_NUMBER)
- return xgi_kern_ctl_poll(filp, wait);
-
- fp = XGI_GET_FP(filp);
-
- if (!(filp->f_flags & O_NONBLOCK))
- {
- /* add us to the list */
- poll_wait(filp, &fp->wait_queue, wait);
- }
-
- xgi_lock_irqsave(fp->fp_lock, eflags);
-
- /* wake the user on any event */
- if (fp->num_events)
- {
- XGI_INFO("Hey, an event occured!\n");
- /*
- * trigger the client, when they grab the event,
- * we'll decrement the event count
- */
- mask |= (POLLPRI|POLLIN);
- }
- xgi_unlock_irqsave(fp->fp_lock, eflags);
-
- return mask;
-}
-
-int xgi_kern_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- xgi_info_t *info;
- xgi_mem_alloc_t *alloc = NULL;
-
- int status = 0;
- void *arg_copy;
- int arg_size;
- int err = 0;
-
- info = XGI_INFO_FROM_FP(filp);
-
- XGI_INFO("Jong-ioctl(0x%x, 0x%x, 0x%lx, 0x%x)\n", _IOC_TYPE(cmd), _IOC_NR(cmd), arg, _IOC_SIZE(cmd));
- /*
- * extract the type and number bitfields, and don't decode
- * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
- */
- if (_IOC_TYPE(cmd) != XGI_IOCTL_MAGIC) return -ENOTTY;
- if (_IOC_NR(cmd) > XGI_IOCTL_MAXNR) return -ENOTTY;
-
- /*
- * the direction is a bitmask, and VERIFY_WRITE catches R/W
- * transfers. `Type' is user-oriented, while
- * access_ok is kernel-oriented, so the concept of "read" and
- * "write" is reversed
- */
- if (_IOC_DIR(cmd) & _IOC_READ)
- {
- err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
- }
- else if (_IOC_DIR(cmd) & _IOC_WRITE)
- {
- err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
- }
- if (err) return -EFAULT;
-
- XGI_CHECK_PCI_CONFIG(info);
-
- arg_size = _IOC_SIZE(cmd);
- XGI_KMALLOC(arg_copy, arg_size);
- if (arg_copy == NULL)
- {
- XGI_ERROR("failed to allocate ioctl memory\n");
- return -ENOMEM;
- }
-
- /* Jong 05/25/2006 */
- /* copy_from_user(arg_copy, (void *)arg, arg_size); */
- if(copy_from_user(arg_copy, (void *)arg, arg_size))
- {
- XGI_ERROR("failed to copyin ioctl data\n");
- XGI_INFO("Jong-copy_from_user-fail! \n");
- }
- else
- XGI_INFO("Jong-copy_from_user-OK! \n");
-
- alloc = (xgi_mem_alloc_t *)arg_copy;
- XGI_INFO("Jong-succeeded in copy_from_user 0x%lx, 0x%x bytes.\n", arg, arg_size);
-
- switch (_IOC_NR(cmd))
- {
- case XGI_ESC_DEVICE_INFO:
- XGI_INFO("Jong-xgi_ioctl_get_device_info \n");
- xgi_get_device_info(info, (struct xgi_chip_info_s *) arg_copy);
- break;
- case XGI_ESC_POST_VBIOS:
- XGI_INFO("Jong-xgi_ioctl_post_vbios \n");
- break;
- case XGI_ESC_FB_ALLOC:
- XGI_INFO("Jong-xgi_ioctl_fb_alloc \n");
- xgi_fb_alloc(info, (struct xgi_mem_req_s *)arg_copy, alloc);
- break;
- case XGI_ESC_FB_FREE:
- XGI_INFO("Jong-xgi_ioctl_fb_free \n");
- xgi_fb_free(info, *(unsigned long *) arg_copy);
- break;
- case XGI_ESC_MEM_COLLECT:
- XGI_INFO("Jong-xgi_ioctl_mem_collect \n");
- xgi_mem_collect(info, (unsigned int *) arg_copy);
- break;
- case XGI_ESC_PCIE_ALLOC:
- XGI_INFO("Jong-xgi_ioctl_pcie_alloc \n");
- xgi_pcie_alloc(info, ((xgi_mem_req_t *)arg_copy)->size,
- ((xgi_mem_req_t *)arg_copy)->owner, alloc);
- break;
- case XGI_ESC_PCIE_FREE:
- XGI_INFO("Jong-xgi_ioctl_pcie_free: bus_addr = 0x%lx \n", *((unsigned long *) arg_copy));
- xgi_pcie_free(info, *((unsigned long *) arg_copy));
- break;
- case XGI_ESC_PCIE_CHECK:
- XGI_INFO("Jong-xgi_pcie_heap_check \n");
- xgi_pcie_heap_check();
- break;
- case XGI_ESC_GET_SCREEN_INFO:
- XGI_INFO("Jong-xgi_get_screen_info \n");
- xgi_get_screen_info(info, (struct xgi_screen_info_s *) arg_copy);
- break;
- case XGI_ESC_PUT_SCREEN_INFO:
- XGI_INFO("Jong-xgi_put_screen_info \n");
- xgi_put_screen_info(info, (struct xgi_screen_info_s *) arg_copy);
- break;
- case XGI_ESC_MMIO_INFO:
- XGI_INFO("Jong-xgi_ioctl_get_mmio_info \n");
- xgi_get_mmio_info(info, (struct xgi_mmio_info_s *) arg_copy);
- break;
- case XGI_ESC_GE_RESET:
- XGI_INFO("Jong-xgi_ioctl_ge_reset \n");
- xgi_ge_reset(info);
- break;
- case XGI_ESC_SAREA_INFO:
- XGI_INFO("Jong-xgi_ioctl_sarea_info \n");
- xgi_sarea_info(info, (struct xgi_sarea_info_s *) arg_copy);
- break;
- case XGI_ESC_DUMP_REGISTER:
- XGI_INFO("Jong-xgi_ioctl_dump_register \n");
- xgi_dump_register(info);
- break;
- case XGI_ESC_DEBUG_INFO:
- XGI_INFO("Jong-xgi_ioctl_restore_registers \n");
- xgi_restore_registers(info);
- //xgi_write_pcie_mem(info, (struct xgi_mem_req_s *) arg_copy);
- //xgi_read_pcie_mem(info, (struct xgi_mem_req_s *) arg_copy);
- break;
- case XGI_ESC_SUBMIT_CMDLIST:
- XGI_INFO("Jong-xgi_ioctl_submit_cmdlist \n");
- xgi_submit_cmdlist(info, (xgi_cmd_info_t *) arg_copy);
- break;
- case XGI_ESC_TEST_RWINKERNEL:
- XGI_INFO("Jong-xgi_test_rwinkernel \n");
- xgi_test_rwinkernel(info, *(unsigned long*) arg_copy);
- break;
- case XGI_ESC_STATE_CHANGE:
- XGI_INFO("Jong-xgi_state_change \n");
- xgi_state_change(info, (xgi_state_info_t *) arg_copy);
- break;
- case XGI_ESC_CPUID:
- XGI_INFO("Jong-XGI_ESC_CPUID \n");
- xgi_get_cpu_id((struct cpu_info_s*) arg_copy);
- break;
- default:
- XGI_INFO("Jong-xgi_ioctl_default \n");
- status = -EINVAL;
- break;
- }
-
- if (copy_to_user((void *)arg, arg_copy, arg_size))
- {
- XGI_ERROR("failed to copyout ioctl data\n");
- XGI_INFO("Jong-copy_to_user-fail! \n");
- }
- else
- XGI_INFO("Jong-copy_to_user-OK! \n");
-
- XGI_KFREE(arg_copy, arg_size);
- return status;
-}
-
-
-/*
- * xgi control driver operations defined here
- */
-int xgi_kern_ctl_open(struct inode *inode, struct file *filp)
-{
- xgi_info_t *info = &xgi_ctl_device;
-
- int rc = 0;
-
- XGI_INFO("Jong-xgi_kern_ctl_open\n");
-
- xgi_down(info->info_sem);
- info->device_number = XGI_CONTROL_DEVICE_NUMBER;
-
- /* save the xgi info in file->private_data */
- filp->private_data = info;
-
- if (XGI_ATOMIC_READ(info->use_count) == 0)
- {
- init_waitqueue_head(&xgi_ctl_waitqueue);
- }
-
- info->flags |= XGI_FLAG_OPEN + XGI_FLAG_CONTROL;
-
- XGI_ATOMIC_INC(info->use_count);
- xgi_up(info->info_sem);
-
- return rc;
-}
-
-int xgi_kern_ctl_close(struct inode *inode, struct file *filp)
-{
- xgi_info_t *info = XGI_INFO_FROM_FP(filp);
-
- XGI_INFO("Jong-xgi_kern_ctl_close\n");
-
- xgi_down(info->info_sem);
- if (XGI_ATOMIC_DEC_AND_TEST(info->use_count))
- {
- info->flags = 0;
- }
- xgi_up(info->info_sem);
-
- if (FILE_PRIVATE(filp))
- {
- xgi_free_file_private(FILE_PRIVATE(filp));
- FILE_PRIVATE(filp) = NULL;
- }
-
- return 0;
-}
-
-unsigned int xgi_kern_ctl_poll(struct file *filp, poll_table *wait)
-{
- //xgi_info_t *info = XGI_INFO_FROM_FP(filp);;
- unsigned int ret = 0;
-
- if (!(filp->f_flags & O_NONBLOCK))
- {
- poll_wait(filp, &xgi_ctl_waitqueue, wait);
- }
-
- return ret;
-}
-
-/*
- * xgi proc system
- */
-static u8 xgi_find_pcie_capability(struct pci_dev *dev)
-{
- u16 status;
- u8 cap_ptr, cap_id;
-
- pci_read_config_word(dev, PCI_STATUS, &status);
- status &= PCI_STATUS_CAP_LIST;
- if (!status)
- return 0;
-
- switch (dev->hdr_type)
- {
- case PCI_HEADER_TYPE_NORMAL:
- case PCI_HEADER_TYPE_BRIDGE:
- pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr);
- break;
- default:
- return 0;
- }
-
- do
- {
- cap_ptr &= 0xFC;
- pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_ID, &cap_id);
- pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_NEXT, &cap_ptr);
- } while (cap_ptr && cap_id != 0xFF);
-
- return 0;
-}
-
-static struct pci_dev* xgi_get_pci_device(xgi_info_t *info)
-{
- struct pci_dev *dev;
-
- dev = XGI_PCI_GET_DEVICE(info->vendor_id, info->device_id, NULL);
- while (dev)
- {
- if (XGI_PCI_SLOT_NUMBER(dev) == info->slot
- && XGI_PCI_BUS_NUMBER(dev) == info->bus)
- return dev;
- dev = XGI_PCI_GET_DEVICE(info->vendor_id, info->device_id, dev);
- }
-
- return NULL;
-}
-
-int xgi_kern_read_card_info(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- struct pci_dev *dev;
- char *type;
- int len = 0;
-
- xgi_info_t *info;
- info = (xgi_info_t *) data;
-
- dev = xgi_get_pci_device(info);
- if (!dev)
- return 0;
-
- type = xgi_find_pcie_capability(dev) ? "PCIE" : "PCI";
- len += sprintf(page+len, "Card Type: \t %s\n", type);
-
- XGI_PCI_DEV_PUT(dev);
- return len;
-}
-
-int xgi_kern_read_version(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = 0;
-
- len += sprintf(page+len, "XGI version: %s\n", "1.0");
- len += sprintf(page+len, "GCC version: %s\n", "3.0");
-
- return len;
-}
-
-int xgi_kern_read_pcie_info(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- return 0;
-}
-
-int xgi_kern_read_status(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- return 0;
-}
-
-
-static void xgi_proc_create(void)
-{
-#ifdef CONFIG_PROC_FS
-
- struct pci_dev *dev;
- int i = 0;
- char name[6];
-
- struct proc_dir_entry *entry;
- struct proc_dir_entry *proc_xgi_pcie, *proc_xgi_cards;
-
- xgi_info_t *info;
- xgi_info_t *xgi_max_devices;
-
- /* world readable directory */
- int flags = S_IFDIR | S_IRUGO | S_IXUGO;
-
- proc_xgi = create_proc_entry("xgi", flags, proc_root_driver);
- if (!proc_xgi)
- goto failed;
-
- proc_xgi_cards = create_proc_entry("cards", flags, proc_xgi);
- if (!proc_xgi_cards)
- goto failed;
-
- proc_xgi_pcie = create_proc_entry("pcie", flags, proc_xgi);
- if (!proc_xgi_pcie)
- goto failed;
-
- /*
- * Set the module owner to ensure that the reference
- * count reflects accesses to the proc files.
- */
- proc_xgi->owner = THIS_MODULE;
- proc_xgi_cards->owner = THIS_MODULE;
- proc_xgi_pcie->owner = THIS_MODULE;
-
- xgi_max_devices = xgi_devices + XGI_MAX_DEVICES;
- for (info = xgi_devices; info < xgi_max_devices; info++)
- {
- if (info->device_id == 0)
- break;
-
- /* world readable file */
- flags = S_IFREG | S_IRUGO;
-
- dev = xgi_get_pci_device(info);
- if (!dev)
- break;
-
- sprintf(name, "%d", i++);
- entry = create_proc_entry(name, flags, proc_xgi_cards);
- if (!entry)
- {
- XGI_PCI_DEV_PUT(dev);
- goto failed;
- }
-
- entry->data = info;
- entry->read_proc = xgi_kern_read_card_info;
- entry->owner = THIS_MODULE;
-
- if (xgi_find_pcie_capability(dev))
- {
- entry = create_proc_entry("status", flags, proc_xgi_pcie);
- if (!entry)
- {
- XGI_PCI_DEV_PUT(dev);
- goto failed;
- }
-
- entry->data = info;
- entry->read_proc = xgi_kern_read_status;
- entry->owner = THIS_MODULE;
-
- entry = create_proc_entry("card", flags, proc_xgi_pcie);
- if (!entry)
- {
- XGI_PCI_DEV_PUT(dev);
- goto failed;
- }
-
- entry->data = info;
- entry->read_proc = xgi_kern_read_pcie_info;
- entry->owner = THIS_MODULE;
- }
-
- XGI_PCI_DEV_PUT(dev);
- }
-
- entry = create_proc_entry("version", flags, proc_xgi);
- if (!entry)
- goto failed;
-
- entry->read_proc = xgi_kern_read_version;
- entry->owner = THIS_MODULE;
-
- entry = create_proc_entry("host-bridge", flags, proc_xgi_pcie);
- if (!entry)
- goto failed;
-
- entry->data = NULL;
- entry->read_proc = xgi_kern_read_pcie_info;
- entry->owner = THIS_MODULE;
-
- return;
-
-failed:
- XGI_ERROR("failed to create /proc entries!\n");
- xgi_proc_remove_all(proc_xgi);
-#endif
-}
-
-#ifdef CONFIG_PROC_FS
-static void xgi_proc_remove_all(struct proc_dir_entry *entry)
-{
- while (entry)
- {
- struct proc_dir_entry *next = entry->next;
- if (entry->subdir)
- xgi_proc_remove_all(entry->subdir);
- remove_proc_entry(entry->name, entry->parent);
- if (entry == proc_xgi)
- break;
- entry = next;
- }
-}
-#endif
-
-static void xgi_proc_remove(void)
-{
-#ifdef CONFIG_PROC_FS
- xgi_proc_remove_all(proc_xgi);
-#endif
-}
-
-/*
- * driver receives an interrupt if someone waiting, then hand it off.
- */
-irqreturn_t xgi_kern_isr(int irq, void *dev_id, struct pt_regs *regs)
-{
- xgi_info_t *info = (xgi_info_t *) dev_id;
- u32 need_to_run_bottom_half = 0;
-
- //XGI_INFO("xgi_kern_isr \n");
-
- //XGI_CHECK_PCI_CONFIG(info);
-
- //xgi_dvi_irq_handler(info);
-
- if (need_to_run_bottom_half)
- {
- tasklet_schedule(&info->tasklet);
- }
-
- return IRQ_HANDLED;
-}
-
-void xgi_kern_isr_bh(unsigned long data)
-{
- xgi_info_t *info = (xgi_info_t *) data;
-
- XGI_INFO("xgi_kern_isr_bh \n");
-
- //xgi_dvi_irq_handler(info);
-
- XGI_CHECK_PCI_CONFIG(info);
-}
-
-static void xgi_lock_init(xgi_info_t *info)
-{
- if (info == NULL) return;
-
- spin_lock_init(&info->info_lock);
-
- sema_init(&info->info_sem, 1);
- sema_init(&info->fb_sem, 1);
- sema_init(&info->pcie_sem, 1);
-
- XGI_ATOMIC_SET(info->use_count, 0);
-}
-
-static void xgi_dev_init(xgi_info_t *info)
-{
- struct pci_dev *pdev = NULL;
- struct xgi_dev *dev;
- int found = 0;
- u16 pci_cmd;
-
- XGI_INFO("Enter xgi_dev_init \n");
-
- //XGI_PCI_FOR_EACH_DEV(pdev)
- {
- for (dev = xgidev_list; dev->vendor; dev++)
- {
- if ((dev->vendor == pdev->vendor) && (dev->device == pdev->device))
- {
- XGI_INFO("dev->vendor = pdev->vendor= %x \n", dev->vendor);
- XGI_INFO("dev->device = pdev->device= %x \n", dev->device);
-
- xgi_devices[found].device_id = pdev->device;
-
- pci_read_config_byte(pdev, PCI_REVISION_ID, &xgi_devices[found].revision_id);
-
- XGI_INFO("PCI_REVISION_ID= %x \n", xgi_devices[found].revision_id);
-
- pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
-
- XGI_INFO("PCI_COMMAND = %x \n", pci_cmd);
-
- break;
- }
- }
- }
-}
-/*
- * Export to Linux Kernel
- */
-
-static int __init xgi_init_module(void)
-{
- xgi_info_t *info = &xgi_devices[xgi_num_devices];
- int i, result;
-
- XGI_INFO("Jong-xgi kernel driver %s initializing\n", XGI_DRV_VERSION);
- //SET_MODULE_OWNER(&xgi_fops);
-
- memset(xgi_devices, 0, sizeof(xgi_devices));
-
- if (pci_register_driver(&xgi_pci_driver) < 0)
- {
- pci_unregister_driver(&xgi_pci_driver);
- XGI_ERROR("no XGI graphics adapter found\n");
- return -ENODEV;
- }
-
- XGI_INFO("Jong-xgi_devices[%d].fb.base.: 0x%lx \n", xgi_num_devices, xgi_devices[xgi_num_devices].fb.base);
- XGI_INFO("Jong-xgi_devices[%d].fb.size.: 0x%lx \n", xgi_num_devices, xgi_devices[xgi_num_devices].fb.size);
-
-/* Jong 07/27/2006; test for ubuntu */
-/*
-#ifdef CONFIG_DEVFS_FS
-
- XGI_INFO("Jong-Use devfs \n");
- do
- {
- xgi_devfs_handles[0] = XGI_DEVFS_REGISTER("xgi", 0);
- if (xgi_devfs_handles[0] == NULL)
- {
- result = -ENOMEM;
- XGI_ERROR("devfs register failed\n");
- goto failed;
- }
- } while(0);
-#else */ /* no devfs, do it the "classic" way */
-
-
- XGI_INFO("Jong-Use non-devfs \n");
- /*
- * Register your major, and accept a dynamic number. This is the
- * first thing to do, in order to avoid releasing other module's
- * fops in scull_cleanup_module()
- */
- result = XGI_REGISTER_CHRDEV(xgi_major, "xgi", &xgi_fops);
- if (result < 0)
- {
- XGI_ERROR("register chrdev failed\n");
- pci_unregister_driver(&xgi_pci_driver);
- return result;
- }
- if (xgi_major == 0) xgi_major = result; /* dynamic */
-
-/* #endif */ /* CONFIG_DEVFS_FS */
-
- XGI_INFO("Jong-major number %d\n", xgi_major);
-
- /* instantiate tasklets */
- for (i = 0; i < XGI_MAX_DEVICES; i++)
- {
- /*
- * We keep one tasklet per card to avoid latency issues with more
- * than one device; no two instances of a single tasklet are ever
- * executed concurrently.
- */
- XGI_ATOMIC_SET(xgi_devices[i].tasklet.count, 1);
- }
-
- /* init the xgi control device */
- {
- xgi_info_t *info_ctl = &xgi_ctl_device;
- xgi_lock_init(info_ctl);
- }
-
- /* Init the resource manager */
- INIT_LIST_HEAD(&xgi_mempid_list);
- if (!xgi_fb_heap_init(info))
- {
- XGI_ERROR("xgi_fb_heap_init() failed\n");
- result = -EIO;
- goto failed;
- }
-
- /* Init the resource manager */
- if (!xgi_pcie_heap_init(info))
- {
- XGI_ERROR("xgi_pcie_heap_init() failed\n");
- result = -EIO;
- goto failed;
- }
-
- /* create /proc/driver/xgi */
- xgi_proc_create();
-
-#if defined(DEBUG)
- inter_module_register("xgi_devices", THIS_MODULE, xgi_devices);
-#endif
-
- return 0;
-
-failed:
-#ifdef CONFIG_DEVFS_FS
- XGI_DEVFS_REMOVE_CONTROL();
- XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices);
-#endif
-
- if (XGI_UNREGISTER_CHRDEV(xgi_major, "xgi") < 0)
- XGI_ERROR("unregister xgi chrdev failed\n");
-
- for (i = 0; i < xgi_num_devices; i++)
- {
- if (xgi_devices[i].dev)
- {
- release_mem_region(xgi_devices[i].fb.base, xgi_devices[i].fb.size);
- release_mem_region(xgi_devices[i].mmio.base, xgi_devices[i].mmio.size);
- }
- }
-
- pci_unregister_driver(&xgi_pci_driver);
- return result;
-
- return 1;
-}
-
-void __exit xgi_exit_module(void)
-{
- int i;
- xgi_info_t *info, *max_devices;
-
-#ifdef CONFIG_DEVFS_FS
- /*
- XGI_DEVFS_REMOVE_CONTROL();
- for (i = 0; i < XGI_MAX_DEVICES; i++)
- XGI_DEVFS_REMOVE_DEVICE(i);
- */
- XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices);
-#endif
-
- if (XGI_UNREGISTER_CHRDEV(xgi_major, "xgi") < 0)
- XGI_ERROR("unregister xgi chrdev failed\n");
-
- XGI_INFO("Jong-unregister xgi chrdev scceeded\n");
- for (i = 0; i < XGI_MAX_DEVICES; i++)
- {
- if (xgi_devices[i].dev)
- {
- /* clean up the flush2D batch array */
- xgi_cmdlist_cleanup(&xgi_devices[i]);
-
- if(xgi_devices[i].fb.vbase != NULL)
- {
- iounmap((void *)xgi_devices[i].fb.vbase);
- xgi_devices[i].fb.vbase = NULL;
- }
- if(xgi_devices[i].mmio.vbase != NULL)
- {
- iounmap((void *)xgi_devices[i].mmio.vbase);
- xgi_devices[i].mmio.vbase = NULL;
- }
-
- //release_mem_region(xgi_devices[i].fb.base, xgi_devices[i].fb.size);
- //XGI_INFO("release frame buffer mem region scceeded\n");
-
- release_mem_region(xgi_devices[i].mmio.base, xgi_devices[i].mmio.size);
- XGI_INFO("release MMIO mem region scceeded\n");
-
- xgi_fb_heap_cleanup(&xgi_devices[i]);
- XGI_INFO("xgi_fb_heap_cleanup scceeded\n");
-
- xgi_pcie_heap_cleanup(&xgi_devices[i]);
- XGI_INFO("xgi_pcie_heap_cleanup scceeded\n");
-
- XGI_PCI_DISABLE_DEVICE(xgi_devices[i].dev);
- }
- }
-
- pci_unregister_driver(&xgi_pci_driver);
-
- /* remove /proc/driver/xgi */
- xgi_proc_remove();
-
-#if defined(DEBUG)
- inter_module_unregister("xgi_devices");
-#endif
-}
-
-module_init(xgi_init_module);
-module_exit(xgi_exit_module);
-
-#if defined(XGI_PM_SUPPORT_ACPI)
-int xgi_acpi_event(struct pci_dev *dev, u32 state)
-{
- return 1;
-}
-
-int xgi_kern_acpi_standby(struct pci_dev *dev, u32 state)
-{
- return 1;
-}
-
-int xgi_kern_acpi_resume(struct pci_dev *dev)
-{
- return 1;
-}
-#endif
-
-MODULE_AUTHOR("Andrea Zhang <andrea_zhang@macrosynergy.com>");
-MODULE_DESCRIPTION("xgi kernel driver for xgi cards");
-MODULE_LICENSE("GPL");
+
+/****************************************************************************
+ * Copyright (C) 2003-2006 by XGI Technology, Taiwan.
+ * *
+ * 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 on 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL XGI 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 "xgi_types.h"
+#include "xgi_linux.h"
+#include "xgi_drv.h"
+#include "xgi_regs.h"
+#include "xgi_pcie.h"
+#include "xgi_misc.h"
+#include "xgi_cmdlist.h"
+
+/* for debug */
+static int xgi_temp = 1;
+/*
+ * global parameters
+ */
+static struct xgi_dev {
+ u16 vendor;
+ u16 device;
+ const char *name;
+} xgidev_list[] = {
+ {
+ PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XP5, "XP5"}, {
+ PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XG47, "XG47"}, {
+ 0, 0, NULL}
+};
+
+int xgi_major = XGI_DEV_MAJOR; /* xgi reserved major device number. */
+
+static int xgi_num_devices = 0;
+
+xgi_info_t xgi_devices[XGI_MAX_DEVICES];
+
+#if defined(XGI_PM_SUPPORT_APM)
+static struct pm_dev *apm_xgi_dev[XGI_MAX_DEVICES] = { 0 };
+#endif
+
+/* add one for the control device */
+xgi_info_t xgi_ctl_device;
+wait_queue_head_t xgi_ctl_waitqueue;
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *proc_xgi;
+#endif
+
+#ifdef CONFIG_DEVFS_FS
+devfs_handle_t xgi_devfs_handles[XGI_MAX_DEVICES];
+#endif
+
+struct list_head xgi_mempid_list;
+
+/* xgi_ functions.. do not take a state device parameter */
+static int xgi_post_vbios(xgi_ioctl_post_vbios_t * info);
+static void xgi_proc_create(void);
+static void xgi_proc_remove_all(struct proc_dir_entry *);
+static void xgi_proc_remove(void);
+
+/* xgi_kern_ functions, interfaces used by linux kernel */
+int xgi_kern_probe(struct pci_dev *, const struct pci_device_id *);
+
+unsigned int xgi_kern_poll(struct file *, poll_table *);
+int xgi_kern_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+int xgi_kern_mmap(struct file *, struct vm_area_struct *);
+int xgi_kern_open(struct inode *, struct file *);
+int xgi_kern_release(struct inode *inode, struct file *filp);
+
+void xgi_kern_vma_open(struct vm_area_struct *vma);
+void xgi_kern_vma_release(struct vm_area_struct *vma);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1))
+struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type);
+#else
+struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma,
+ unsigned long address, int write_access);
+#endif
+
+int xgi_kern_read_card_info(char *, char **, off_t off, int, int *, void *);
+int xgi_kern_read_status(char *, char **, off_t off, int, int *, void *);
+int xgi_kern_read_pcie_info(char *, char **, off_t off, int, int *, void *);
+int xgi_kern_read_version(char *, char **, off_t off, int, int *, void *);
+
+int xgi_kern_ctl_open(struct inode *, struct file *);
+int xgi_kern_ctl_close(struct inode *, struct file *);
+unsigned int xgi_kern_ctl_poll(struct file *, poll_table *);
+
+void xgi_kern_isr_bh(unsigned long);
+irqreturn_t xgi_kern_isr(int, void *, struct pt_regs *);
+
+static void xgi_lock_init(xgi_info_t * info);
+
+#if defined(XGI_PM_SUPPORT_ACPI)
+int xgi_kern_acpi_standby(struct pci_dev *, u32);
+int xgi_kern_acpi_resume(struct pci_dev *);
+#endif
+
+/*
+ * verify access to pci config space wasn't disabled behind our back
+ * unfortunately, XFree86 enables/disables memory access in pci config space at
+ * various times (such as restoring initial pci config space settings during vt
+ * switches or when doing mulicard). As a result, all of our register accesses
+ * are garbage at this point. add a check to see if access was disabled and
+ * reenable any such access.
+ */
+#define XGI_CHECK_PCI_CONFIG(xgi) \
+ xgi_check_pci_config(xgi, __LINE__)
+
+static inline void xgi_check_pci_config(xgi_info_t * info, int line)
+{
+ unsigned short cmd, flag = 0;
+
+ // don't do this on the control device, only the actual devices
+ if (info->flags & XGI_FLAG_CONTROL)
+ return;
+
+ pci_read_config_word(info->dev, PCI_COMMAND, &cmd);
+ if (!(cmd & PCI_COMMAND_MASTER)) {
+ XGI_INFO("restoring bus mastering! (%d)\n", line);
+ cmd |= PCI_COMMAND_MASTER;
+ flag = 1;
+ }
+
+ if (!(cmd & PCI_COMMAND_MEMORY)) {
+ XGI_INFO("restoring MEM access! (%d)\n", line);
+ cmd |= PCI_COMMAND_MEMORY;
+ flag = 1;
+ }
+
+ if (flag)
+ pci_write_config_word(info->dev, PCI_COMMAND, cmd);
+}
+
+static int xgi_post_vbios(xgi_ioctl_post_vbios_t * info)
+{
+ return 1;
+}
+
+/*
+ * struct pci_device_id {
+ * unsigned int vendor, device; // Vendor and device ID or PCI_ANY_ID
+ * unsigned int subvendor, subdevice; // Subsystem ID's or PCI_ANY_ID
+ * unsigned int class, class_mask; // (class,subclass,prog-if) triplet
+ * unsigned long driver_data; // Data private to the driver
+ * };
+ */
+
+static struct pci_device_id xgi_dev_table[] = {
+ {
+ .vendor = PCI_VENDOR_ID_XGI,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = (PCI_CLASS_DISPLAY_VGA << 8),
+ .class_mask = ~0,
+ },
+ {}
+};
+
+/*
+ * #define MODULE_DEVICE_TABLE(type,name) \
+ * MODULE_GENERIC_TABLE(type##_device,name)
+ */
+MODULE_DEVICE_TABLE(pci, xgi_dev_table);
+
+/*
+ * struct pci_driver {
+ * struct list_head node;
+ * char *name;
+ * const struct pci_device_id *id_table; // NULL if wants all devices
+ * int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); // New device inserted
+ * void (*remove)(struct pci_dev *dev); // Device removed (NULL if not a hot-plug capable driver)
+ * int (*save_state)(struct pci_dev *dev, u32 state); // Save Device Context
+ * int (*suspend)(struct pci_dev *dev, u32 state); // Device suspended
+ * int (*resume)(struct pci_dev *dev); // Device woken up
+ * int (*enable_wake)(struct pci_dev *dev, u32 state, int enable); // Enable wake event
+ * };
+ */
+static struct pci_driver xgi_pci_driver = {
+ .name = "xgi",
+ .id_table = xgi_dev_table,
+ .probe = xgi_kern_probe,
+#if defined(XGI_SUPPORT_ACPI)
+ .suspend = xgi_kern_acpi_standby,
+ .resume = xgi_kern_acpi_resume,
+#endif
+};
+
+/*
+ * find xgi devices and set initial state
+ */
+int xgi_kern_probe(struct pci_dev *dev, const struct pci_device_id *id_table)
+{
+ xgi_info_t *info;
+
+ if ((dev->vendor != PCI_VENDOR_ID_XGI)
+ || (dev->class != (PCI_CLASS_DISPLAY_VGA << 8))) {
+ return -1;
+ }
+
+ if (xgi_num_devices == XGI_MAX_DEVICES) {
+ XGI_INFO("maximum device number (%d) reached!\n",
+ xgi_num_devices);
+ return -1;
+ }
+
+ /* enable io, mem, and bus-mastering in pci config space */
+ if (pci_enable_device(dev) != 0) {
+ XGI_INFO("pci_enable_device failed, aborting\n");
+ return -1;
+ }
+
+ XGI_INFO("maximum device number (%d) reached \n", xgi_num_devices);
+
+ pci_set_master(dev);
+
+ info = &xgi_devices[xgi_num_devices];
+ info->dev = dev;
+ info->vendor_id = dev->vendor;
+ info->device_id = dev->device;
+ info->bus = dev->bus->number;
+ info->slot = PCI_SLOT((dev)->devfn);
+
+ xgi_lock_init(info);
+
+ info->mmio.base = XGI_PCI_RESOURCE_START(dev, 1);
+ info->mmio.size = XGI_PCI_RESOURCE_SIZE(dev, 1);
+
+ /* check IO region */
+ if (!request_mem_region(info->mmio.base, info->mmio.size, "xgi")) {
+ XGI_ERROR("cannot reserve MMIO memory\n");
+ goto error_disable_dev;
+ }
+
+ XGI_INFO("info->mmio.base: 0x%lx \n", info->mmio.base);
+ XGI_INFO("info->mmio.size: 0x%lx \n", info->mmio.size);
+
+ info->mmio.vbase = (unsigned char *)ioremap_nocache(info->mmio.base,
+ info->mmio.size);
+ if (!info->mmio.vbase) {
+ release_mem_region(info->mmio.base, info->mmio.size);
+ XGI_ERROR("info->mmio.vbase failed\n");
+ goto error_disable_dev;
+ }
+ xgi_enable_mmio(info);
+
+ //xgi_enable_ge(info);
+
+ XGI_INFO("info->mmio.vbase: 0x%p \n", info->mmio.vbase);
+
+ info->fb.base = XGI_PCI_RESOURCE_START(dev, 0);
+ info->fb.size = XGI_PCI_RESOURCE_SIZE(dev, 0);
+
+ XGI_INFO("info->fb.base: 0x%lx \n", info->fb.base);
+ XGI_INFO("info->fb.size: 0x%lx \n", info->fb.size);
+
+ info->fb.size = bIn3cf(0x54) * 8 * 1024 * 1024;
+ XGI_INFO("info->fb.size: 0x%lx \n", info->fb.size);
+
+ /* check frame buffer region
+ if (!request_mem_region(info->fb.base, info->fb.size, "xgi"))
+ {
+ release_mem_region(info->mmio.base, info->mmio.size);
+ XGI_ERROR("cannot reserve frame buffer memory\n");
+ goto error_disable_dev;
+ }
+
+ info->fb.vbase = (unsigned char *)ioremap_nocache(info->fb.base,
+ info->fb.size);
+
+ if (!info->fb.vbase)
+ {
+ release_mem_region(info->mmio.base, info->mmio.size);
+ release_mem_region(info->fb.base, info->fb.size);
+ XGI_ERROR("info->fb.vbase failed\n");
+ goto error_disable_dev;
+ }
+ */
+ info->fb.vbase = NULL;
+ XGI_INFO("info->fb.vbase: 0x%p \n", info->fb.vbase);
+
+ info->irq = dev->irq;
+
+ /* check common error condition */
+ if (info->irq == 0) {
+ XGI_ERROR("Can't find an IRQ for your XGI card! \n");
+ goto error_zero_dev;
+ }
+ XGI_INFO("info->irq: %lx \n", info->irq);
+
+ //xgi_enable_dvi_interrupt(info);
+
+ /* sanity check the IO apertures */
+ if ((info->mmio.base == 0) || (info->mmio.size == 0)
+ || (info->fb.base == 0) || (info->fb.size == 0)) {
+ XGI_ERROR("The IO regions for your XGI card are invalid.\n");
+
+ if ((info->mmio.base == 0) || (info->mmio.size == 0)) {
+ XGI_ERROR("mmio appears to be wrong: 0x%lx 0x%lx\n",
+ info->mmio.base, info->mmio.size);
+ }
+
+ if ((info->fb.base == 0) || (info->fb.size == 0)) {
+ XGI_ERROR
+ ("frame buffer appears to be wrong: 0x%lx 0x%lx\n",
+ info->fb.base, info->fb.size);
+ }
+
+ goto error_zero_dev;
+ }
+ //xgi_num_devices++;
+
+ return 0;
+
+ error_zero_dev:
+ release_mem_region(info->fb.base, info->fb.size);
+ release_mem_region(info->mmio.base, info->mmio.size);
+
+ error_disable_dev:
+ pci_disable_device(dev);
+ return -1;
+
+}
+
+/*
+ * vma operations...
+ * this is only called when the vmas are duplicated. this
+ * appears to only happen when the process is cloned to create
+ * a new process, and not when the process is threaded.
+ *
+ * increment the usage count for the physical pages, so when
+ * this clone unmaps the mappings, the pages are not
+ * deallocated under the original process.
+ */
+struct vm_operations_struct xgi_vm_ops = {
+ .open = xgi_kern_vma_open,
+ .close = xgi_kern_vma_release,
+ .nopage = xgi_kern_vma_nopage,
+};
+
+void xgi_kern_vma_open(struct vm_area_struct *vma)
+{
+ XGI_INFO("VM: vma_open for 0x%lx - 0x%lx, offset 0x%lx\n",
+ vma->vm_start, vma->vm_end, XGI_VMA_OFFSET(vma));
+
+ if (XGI_VMA_PRIVATE(vma)) {
+ xgi_pcie_block_t *block =
+ (xgi_pcie_block_t *) XGI_VMA_PRIVATE(vma);
+ XGI_ATOMIC_INC(block->use_count);
+ }
+}
+
+void xgi_kern_vma_release(struct vm_area_struct *vma)
+{
+ XGI_INFO("VM: vma_release for 0x%lx - 0x%lx, offset 0x%lx\n",
+ vma->vm_start, vma->vm_end, XGI_VMA_OFFSET(vma));
+
+ if (XGI_VMA_PRIVATE(vma)) {
+ xgi_pcie_block_t *block =
+ (xgi_pcie_block_t *) XGI_VMA_PRIVATE(vma);
+ XGI_ATOMIC_DEC(block->use_count);
+
+ /*
+ * if use_count is down to 0, the kernel virtual mapping was freed
+ * but the underlying physical pages were not, we need to clear the
+ * bit and free the physical pages.
+ */
+ if (XGI_ATOMIC_READ(block->use_count) == 0) {
+ // Need TO Finish
+ XGI_VMA_PRIVATE(vma) = NULL;
+ }
+ }
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1))
+struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ xgi_pcie_block_t *block = (xgi_pcie_block_t *) XGI_VMA_PRIVATE(vma);
+ struct page *page = NOPAGE_SIGBUS;
+ unsigned long offset = 0;
+ unsigned long page_addr = 0;
+/*
+ XGI_INFO("VM: mmap([0x%lx-0x%lx] off=0x%lx) address: 0x%lx \n",
+ vma->vm_start,
+ vma->vm_end,
+ XGI_VMA_OFFSET(vma),
+ address);
+*/
+ offset = (address - vma->vm_start) + XGI_VMA_OFFSET(vma);
+
+ offset = offset - block->bus_addr;
+
+ offset >>= PAGE_SHIFT;
+
+ page_addr = block->page_table[offset].virt_addr;
+
+ if (xgi_temp) {
+ XGI_INFO("block->bus_addr: 0x%lx block->hw_addr: 0x%lx"
+ "block->page_count: 0x%lx block->page_order: 0x%lx"
+ "block->page_table[0x%lx].virt_addr: 0x%lx\n",
+ block->bus_addr, block->hw_addr,
+ block->page_count, block->page_order,
+ offset, block->page_table[offset].virt_addr);
+ xgi_temp = 0;
+ }
+
+ if (!page_addr)
+ goto out; /* hole or end-of-file */
+ page = virt_to_page(page_addr);
+
+ /* got it, now increment the count */
+ get_page(page);
+ out:
+ return page;
+
+}
+#else
+struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma,
+ unsigned long address, int write_access)
+{
+ xgi_pcie_block_t *block = (xgi_pcie_block_t *) XGI_VMA_PRIVATE(vma);
+ struct page *page = NOPAGE_SIGBUS;
+ unsigned long offset = 0;
+ unsigned long page_addr = 0;
+/*
+ XGI_INFO("VM: mmap([0x%lx-0x%lx] off=0x%lx) address: 0x%lx \n",
+ vma->vm_start,
+ vma->vm_end,
+ XGI_VMA_OFFSET(vma),
+ address);
+*/
+ offset = (address - vma->vm_start) + XGI_VMA_OFFSET(vma);
+
+ offset = offset - block->bus_addr;
+
+ offset >>= PAGE_SHIFT;
+
+ page_addr = block->page_table[offset].virt_addr;
+
+ if (xgi_temp) {
+ XGI_INFO("block->bus_addr: 0x%lx block->hw_addr: 0x%lx"
+ "block->page_count: 0x%lx block->page_order: 0x%lx"
+ "block->page_table[0x%lx].virt_addr: 0x%lx\n",
+ block->bus_addr, block->hw_addr,
+ block->page_count, block->page_order,
+ offset, block->page_table[offset].virt_addr);
+ xgi_temp = 0;
+ }
+
+ if (!page_addr)
+ goto out; /* hole or end-of-file */
+ page = virt_to_page(page_addr);
+
+ /* got it, now increment the count */
+ get_page(page);
+ out:
+ return page;
+}
+#endif
+
+#if 0
+static struct file_operations xgi_fops = {
+ /* owner: THIS_MODULE, */
+ poll:xgi_kern_poll,
+ ioctl:xgi_kern_ioctl,
+ mmap:xgi_kern_mmap,
+ open:xgi_kern_open,
+ release:xgi_kern_release,
+};
+#endif
+
+static struct file_operations xgi_fops = {
+ .owner = THIS_MODULE,
+ .poll = xgi_kern_poll,
+ .ioctl = xgi_kern_ioctl,
+ .mmap = xgi_kern_mmap,
+ .open = xgi_kern_open,
+ .release = xgi_kern_release,
+};
+
+static xgi_file_private_t *xgi_alloc_file_private(void)
+{
+ xgi_file_private_t *fp;
+
+ XGI_KMALLOC(fp, sizeof(xgi_file_private_t));
+ if (!fp)
+ return NULL;
+
+ memset(fp, 0, sizeof(xgi_file_private_t));
+
+ /* initialize this file's event queue */
+ init_waitqueue_head(&fp->wait_queue);
+
+ xgi_init_lock(fp->fp_lock);
+
+ return fp;
+}
+
+static void xgi_free_file_private(xgi_file_private_t * fp)
+{
+ if (fp == NULL)
+ return;
+
+ XGI_KFREE(fp, sizeof(xgi_file_private_t));
+}
+
+int xgi_kern_open(struct inode *inode, struct file *filp)
+{
+ xgi_info_t *info = NULL;
+ int dev_num;
+ int result = 0, status;
+
+ /*
+ * the type and num values are only valid if we are not using devfs.
+ * However, since we use them to retrieve the device pointer, we
+ * don't need them with devfs as filp->private_data is already
+ * initialized
+ */
+ filp->private_data = xgi_alloc_file_private();
+ if (filp->private_data == NULL)
+ return -ENOMEM;
+
+ XGI_INFO("filp->private_data %p\n", filp->private_data);
+ /*
+ * for control device, just jump to its open routine
+ * after setting up the private data
+ */
+ if (XGI_IS_CONTROL_DEVICE(inode))
+ return xgi_kern_ctl_open(inode, filp);
+
+ /* what device are we talking about? */
+ dev_num = XGI_DEVICE_NUMBER(inode);
+ if (dev_num >= XGI_MAX_DEVICES) {
+ xgi_free_file_private(filp->private_data);
+ filp->private_data = NULL;
+ return -ENODEV;
+ }
+
+ info = &xgi_devices[dev_num];
+
+ XGI_INFO("Jong-xgi_kern_open on device %d\n", dev_num);
+
+ xgi_down(info->info_sem);
+ XGI_CHECK_PCI_CONFIG(info);
+
+ XGI_INFO_FROM_FP(filp) = info;
+
+ /*
+ * map the memory and allocate isr on first open
+ */
+
+ if (!(info->flags & XGI_FLAG_OPEN)) {
+ XGI_INFO("info->flags & XGI_FLAG_OPEN \n");
+
+ if (info->device_id == 0) {
+ XGI_INFO("open of nonexistent device %d\n", dev_num);
+ result = -ENXIO;
+ goto failed;
+ }
+
+ /* initialize struct irqaction */
+ status = request_irq(info->irq, xgi_kern_isr,
+ SA_INTERRUPT | SA_SHIRQ, "xgi",
+ (void *)info);
+ if (status != 0) {
+ if (info->irq && (status == -EBUSY)) {
+ XGI_ERROR
+ ("Tried to get irq %d, but another driver",
+ (unsigned int)info->irq);
+ XGI_ERROR("has it and is not sharing it.\n");
+ }
+ XGI_ERROR("isr request failed 0x%x\n", status);
+ result = -EIO;
+ goto failed;
+ }
+
+ /*
+ * #define DECLARE_TASKLET(name, func, data) \
+ * struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
+ */
+ info->tasklet.func = xgi_kern_isr_bh;
+ info->tasklet.data = (unsigned long)info;
+ tasklet_enable(&info->tasklet);
+
+ /* Alloc 1M bytes for cmdbuffer which is flush2D batch array */
+ xgi_cmdlist_initialize(info, 0x100000);
+
+ info->flags |= XGI_FLAG_OPEN;
+ }
+
+ XGI_ATOMIC_INC(info->use_count);
+
+ failed:
+ xgi_up(info->info_sem);
+
+ if ((result) && filp->private_data) {
+ xgi_free_file_private(filp->private_data);
+ filp->private_data = NULL;
+ }
+
+ return result;
+}
+
+int xgi_kern_release(struct inode *inode, struct file *filp)
+{
+ xgi_info_t *info = XGI_INFO_FROM_FP(filp);
+
+ XGI_CHECK_PCI_CONFIG(info);
+
+ /*
+ * for control device, just jump to its open routine
+ * after setting up the private data
+ */
+ if (XGI_IS_CONTROL_DEVICE(inode))
+ return xgi_kern_ctl_close(inode, filp);
+
+ XGI_INFO("Jong-xgi_kern_release on device %d\n",
+ XGI_DEVICE_NUMBER(inode));
+
+ xgi_down(info->info_sem);
+ if (XGI_ATOMIC_DEC_AND_TEST(info->use_count)) {
+
+ /*
+ * The usage count for this device has dropped to zero, it can be shut
+ * down safely; disable its interrupts.
+ */
+
+ /*
+ * Disable this device's tasklet to make sure that no bottom half will
+ * run with undefined device state.
+ */
+ tasklet_disable(&info->tasklet);
+
+ /*
+ * Free the IRQ, which may block until all pending interrupt processing
+ * has completed.
+ */
+ free_irq(info->irq, (void *)info);
+
+ xgi_cmdlist_cleanup(info);
+
+ /* leave INIT flag alone so we don't reinit every time */
+ info->flags &= ~XGI_FLAG_OPEN;
+ }
+
+ xgi_up(info->info_sem);
+
+ if (FILE_PRIVATE(filp)) {
+ xgi_free_file_private(FILE_PRIVATE(filp));
+ FILE_PRIVATE(filp) = NULL;
+ }
+
+ return 0;
+}
+
+int xgi_kern_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ //struct inode *inode = INODE_FROM_FP(filp);
+ xgi_info_t *info = XGI_INFO_FROM_FP(filp);
+ xgi_pcie_block_t *block;
+ int pages = 0;
+ unsigned long prot;
+
+ XGI_INFO("Jong-VM: mmap([0x%lx-0x%lx] off=0x%lx)\n",
+ vma->vm_start, vma->vm_end, XGI_VMA_OFFSET(vma));
+
+ XGI_CHECK_PCI_CONFIG(info);
+
+ if (XGI_MASK_OFFSET(vma->vm_start)
+ || XGI_MASK_OFFSET(vma->vm_end)) {
+ XGI_ERROR("VM: bad mmap range: %lx - %lx\n",
+ vma->vm_start, vma->vm_end);
+ return -ENXIO;
+ }
+
+ pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+
+ vma->vm_ops = &xgi_vm_ops;
+
+ /* XGI IO(reg) space */
+ if (IS_IO_OFFSET
+ (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) {
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ if (XGI_REMAP_PAGE_RANGE(vma->vm_start,
+ XGI_VMA_OFFSET(vma),
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+
+ /* mark it as IO so that we don't dump it on core dump */
+ vma->vm_flags |= VM_IO;
+ XGI_INFO("VM: mmap io space \n");
+ }
+ /* XGI fb space */
+ /* Jong 06/14/2006; moved behind PCIE or modify IS_FB_OFFSET */
+ else if (IS_FB_OFFSET
+ (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) {
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ if (XGI_REMAP_PAGE_RANGE(vma->vm_start,
+ XGI_VMA_OFFSET(vma),
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+
+ // mark it as IO so that we don't dump it on core dump
+ vma->vm_flags |= VM_IO;
+ XGI_INFO("VM: mmap fb space \n");
+ }
+ /* PCIE allocator */
+ /* XGI_VMA_OFFSET(vma) is offset based on pcie.base (HW address space) */
+ else if (IS_PCIE_OFFSET
+ (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) {
+ xgi_down(info->pcie_sem);
+
+ block =
+ (xgi_pcie_block_t *) xgi_find_pcie_block(info,
+ XGI_VMA_OFFSET
+ (vma));
+
+ if (block == NULL) {
+ XGI_ERROR("couldn't find pre-allocated PCIE memory!\n");
+ xgi_up(info->pcie_sem);
+ return -EAGAIN;
+ }
+
+ if (block->page_count != pages) {
+ XGI_ERROR
+ ("pre-allocated PCIE memory has wrong number of pages!\n");
+ xgi_up(info->pcie_sem);
+ return -EAGAIN;
+ }
+
+ vma->vm_private_data = block;
+ XGI_ATOMIC_INC(block->use_count);
+ xgi_up(info->pcie_sem);
+
+ /*
+ * prevent the swapper from swapping it out
+ * mark the memory i/o so the buffers aren't
+ * dumped on core dumps */
+ vma->vm_flags |= (VM_LOCKED | VM_IO);
+
+ /* un-cached */
+ prot = pgprot_val(vma->vm_page_prot);
+ /*
+ if (boot_cpu_data.x86 > 3)
+ prot |= _PAGE_PCD | _PAGE_PWT;
+ */
+ vma->vm_page_prot = __pgprot(prot);
+
+ XGI_INFO("VM: mmap pcie space \n");
+ }
+#if 0
+ else if (IS_FB_OFFSET
+ (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) {
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ if (XGI_REMAP_PAGE_RANGE(vma->vm_start,
+ XGI_VMA_OFFSET(vma),
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+
+ // mark it as IO so that we don't dump it on core dump
+ vma->vm_flags |= VM_IO;
+ XGI_INFO("VM: mmap fb space \n");
+ }
+#endif
+ else {
+ vma->vm_flags |= (VM_IO | VM_LOCKED);
+ XGI_ERROR("VM: mmap wrong range \n");
+ }
+
+ vma->vm_file = filp;
+
+ return 0;
+}
+
+unsigned int xgi_kern_poll(struct file *filp, struct poll_table_struct *wait)
+{
+ xgi_file_private_t *fp;
+ xgi_info_t *info;
+ unsigned int mask = 0;
+ unsigned long eflags;
+
+ info = XGI_INFO_FROM_FP(filp);
+
+ if (info->device_number == XGI_CONTROL_DEVICE_NUMBER)
+ return xgi_kern_ctl_poll(filp, wait);
+
+ fp = XGI_GET_FP(filp);
+
+ if (!(filp->f_flags & O_NONBLOCK)) {
+ /* add us to the list */
+ poll_wait(filp, &fp->wait_queue, wait);
+ }
+
+ xgi_lock_irqsave(fp->fp_lock, eflags);
+
+ /* wake the user on any event */
+ if (fp->num_events) {
+ XGI_INFO("Hey, an event occured!\n");
+ /*
+ * trigger the client, when they grab the event,
+ * we'll decrement the event count
+ */
+ mask |= (POLLPRI | POLLIN);
+ }
+ xgi_unlock_irqsave(fp->fp_lock, eflags);
+
+ return mask;
+}
+
+int xgi_kern_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ xgi_info_t *info;
+ xgi_mem_alloc_t *alloc = NULL;
+
+ int status = 0;
+ void *arg_copy;
+ int arg_size;
+ int err = 0;
+
+ info = XGI_INFO_FROM_FP(filp);
+
+ XGI_INFO("Jong-ioctl(0x%x, 0x%x, 0x%lx, 0x%x)\n", _IOC_TYPE(cmd),
+ _IOC_NR(cmd), arg, _IOC_SIZE(cmd));
+ /*
+ * extract the type and number bitfields, and don't decode
+ * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+ */
+ if (_IOC_TYPE(cmd) != XGI_IOCTL_MAGIC)
+ return -ENOTTY;
+ if (_IOC_NR(cmd) > XGI_IOCTL_MAXNR)
+ return -ENOTTY;
+
+ /*
+ * the direction is a bitmask, and VERIFY_WRITE catches R/W
+ * transfers. `Type' is user-oriented, while
+ * access_ok is kernel-oriented, so the concept of "read" and
+ * "write" is reversed
+ */
+ if (_IOC_DIR(cmd) & _IOC_READ) {
+ err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
+ } else if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
+ }
+ if (err)
+ return -EFAULT;
+
+ XGI_CHECK_PCI_CONFIG(info);
+
+ arg_size = _IOC_SIZE(cmd);
+ XGI_KMALLOC(arg_copy, arg_size);
+ if (arg_copy == NULL) {
+ XGI_ERROR("failed to allocate ioctl memory\n");
+ return -ENOMEM;
+ }
+
+ /* Jong 05/25/2006 */
+ /* copy_from_user(arg_copy, (void *)arg, arg_size); */
+ if (copy_from_user(arg_copy, (void *)arg, arg_size)) {
+ XGI_ERROR("failed to copyin ioctl data\n");
+ XGI_INFO("Jong-copy_from_user-fail! \n");
+ } else
+ XGI_INFO("Jong-copy_from_user-OK! \n");
+
+ alloc = (xgi_mem_alloc_t *) arg_copy;
+ XGI_INFO("Jong-succeeded in copy_from_user 0x%lx, 0x%x bytes.\n", arg,
+ arg_size);
+
+ switch (_IOC_NR(cmd)) {
+ case XGI_ESC_DEVICE_INFO:
+ XGI_INFO("Jong-xgi_ioctl_get_device_info \n");
+ xgi_get_device_info(info, (struct xgi_chip_info_s *)arg_copy);
+ break;
+ case XGI_ESC_POST_VBIOS:
+ XGI_INFO("Jong-xgi_ioctl_post_vbios \n");
+ break;
+ case XGI_ESC_FB_ALLOC:
+ XGI_INFO("Jong-xgi_ioctl_fb_alloc \n");
+ xgi_fb_alloc(info, (struct xgi_mem_req_s *)arg_copy, alloc);
+ break;
+ case XGI_ESC_FB_FREE:
+ XGI_INFO("Jong-xgi_ioctl_fb_free \n");
+ xgi_fb_free(info, *(unsigned long *)arg_copy);
+ break;
+ case XGI_ESC_MEM_COLLECT:
+ XGI_INFO("Jong-xgi_ioctl_mem_collect \n");
+ xgi_mem_collect(info, (unsigned int *)arg_copy);
+ break;
+ case XGI_ESC_PCIE_ALLOC:
+ XGI_INFO("Jong-xgi_ioctl_pcie_alloc \n");
+ xgi_pcie_alloc(info, ((xgi_mem_req_t *) arg_copy)->size,
+ ((xgi_mem_req_t *) arg_copy)->owner, alloc);
+ break;
+ case XGI_ESC_PCIE_FREE:
+ XGI_INFO("Jong-xgi_ioctl_pcie_free: bus_addr = 0x%lx \n",
+ *((unsigned long *)arg_copy));
+ xgi_pcie_free(info, *((unsigned long *)arg_copy));
+ break;
+ case XGI_ESC_PCIE_CHECK:
+ XGI_INFO("Jong-xgi_pcie_heap_check \n");
+ xgi_pcie_heap_check();
+ break;
+ case XGI_ESC_GET_SCREEN_INFO:
+ XGI_INFO("Jong-xgi_get_screen_info \n");
+ xgi_get_screen_info(info, (struct xgi_screen_info_s *)arg_copy);
+ break;
+ case XGI_ESC_PUT_SCREEN_INFO:
+ XGI_INFO("Jong-xgi_put_screen_info \n");
+ xgi_put_screen_info(info, (struct xgi_screen_info_s *)arg_copy);
+ break;
+ case XGI_ESC_MMIO_INFO:
+ XGI_INFO("Jong-xgi_ioctl_get_mmio_info \n");
+ xgi_get_mmio_info(info, (struct xgi_mmio_info_s *)arg_copy);
+ break;
+ case XGI_ESC_GE_RESET:
+ XGI_INFO("Jong-xgi_ioctl_ge_reset \n");
+ xgi_ge_reset(info);
+ break;
+ case XGI_ESC_SAREA_INFO:
+ XGI_INFO("Jong-xgi_ioctl_sarea_info \n");
+ xgi_sarea_info(info, (struct xgi_sarea_info_s *)arg_copy);
+ break;
+ case XGI_ESC_DUMP_REGISTER:
+ XGI_INFO("Jong-xgi_ioctl_dump_register \n");
+ xgi_dump_register(info);
+ break;
+ case XGI_ESC_DEBUG_INFO:
+ XGI_INFO("Jong-xgi_ioctl_restore_registers \n");
+ xgi_restore_registers(info);
+ //xgi_write_pcie_mem(info, (struct xgi_mem_req_s *) arg_copy);
+ //xgi_read_pcie_mem(info, (struct xgi_mem_req_s *) arg_copy);
+ break;
+ case XGI_ESC_SUBMIT_CMDLIST:
+ XGI_INFO("Jong-xgi_ioctl_submit_cmdlist \n");
+ xgi_submit_cmdlist(info, (xgi_cmd_info_t *) arg_copy);
+ break;
+ case XGI_ESC_TEST_RWINKERNEL:
+ XGI_INFO("Jong-xgi_test_rwinkernel \n");
+ xgi_test_rwinkernel(info, *(unsigned long *)arg_copy);
+ break;
+ case XGI_ESC_STATE_CHANGE:
+ XGI_INFO("Jong-xgi_state_change \n");
+ xgi_state_change(info, (xgi_state_info_t *) arg_copy);
+ break;
+ case XGI_ESC_CPUID:
+ XGI_INFO("Jong-XGI_ESC_CPUID \n");
+ xgi_get_cpu_id((struct cpu_info_s *)arg_copy);
+ break;
+ default:
+ XGI_INFO("Jong-xgi_ioctl_default \n");
+ status = -EINVAL;
+ break;
+ }
+
+ if (copy_to_user((void *)arg, arg_copy, arg_size)) {
+ XGI_ERROR("failed to copyout ioctl data\n");
+ XGI_INFO("Jong-copy_to_user-fail! \n");
+ } else
+ XGI_INFO("Jong-copy_to_user-OK! \n");
+
+ XGI_KFREE(arg_copy, arg_size);
+ return status;
+}
+
+/*
+ * xgi control driver operations defined here
+ */
+int xgi_kern_ctl_open(struct inode *inode, struct file *filp)
+{
+ xgi_info_t *info = &xgi_ctl_device;
+
+ int rc = 0;
+
+ XGI_INFO("Jong-xgi_kern_ctl_open\n");
+
+ xgi_down(info->info_sem);
+ info->device_number = XGI_CONTROL_DEVICE_NUMBER;
+
+ /* save the xgi info in file->private_data */
+ filp->private_data = info;
+
+ if (XGI_ATOMIC_READ(info->use_count) == 0) {
+ init_waitqueue_head(&xgi_ctl_waitqueue);
+ }
+
+ info->flags |= XGI_FLAG_OPEN + XGI_FLAG_CONTROL;
+
+ XGI_ATOMIC_INC(info->use_count);
+ xgi_up(info->info_sem);
+
+ return rc;
+}
+
+int xgi_kern_ctl_close(struct inode *inode, struct file *filp)
+{
+ xgi_info_t *info = XGI_INFO_FROM_FP(filp);
+
+ XGI_INFO("Jong-xgi_kern_ctl_close\n");
+
+ xgi_down(info->info_sem);
+ if (XGI_ATOMIC_DEC_AND_TEST(info->use_count)) {
+ info->flags = 0;
+ }
+ xgi_up(info->info_sem);
+
+ if (FILE_PRIVATE(filp)) {
+ xgi_free_file_private(FILE_PRIVATE(filp));
+ FILE_PRIVATE(filp) = NULL;
+ }
+
+ return 0;
+}
+
+unsigned int xgi_kern_ctl_poll(struct file *filp, poll_table * wait)
+{
+ //xgi_info_t *info = XGI_INFO_FROM_FP(filp);;
+ unsigned int ret = 0;
+
+ if (!(filp->f_flags & O_NONBLOCK)) {
+ poll_wait(filp, &xgi_ctl_waitqueue, wait);
+ }
+
+ return ret;
+}
+
+/*
+ * xgi proc system
+ */
+static u8 xgi_find_pcie_capability(struct pci_dev *dev)
+{
+ u16 status;
+ u8 cap_ptr, cap_id;
+
+ pci_read_config_word(dev, PCI_STATUS, &status);
+ status &= PCI_STATUS_CAP_LIST;
+ if (!status)
+ return 0;
+
+ switch (dev->hdr_type) {
+ case PCI_HEADER_TYPE_NORMAL:
+ case PCI_HEADER_TYPE_BRIDGE:
+ pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr);
+ break;
+ default:
+ return 0;
+ }
+
+ do {
+ cap_ptr &= 0xFC;
+ pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_ID, &cap_id);
+ pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_NEXT,
+ &cap_ptr);
+ } while (cap_ptr && cap_id != 0xFF);
+
+ return 0;
+}
+
+static struct pci_dev *xgi_get_pci_device(xgi_info_t * info)
+{
+ struct pci_dev *dev;
+
+ dev = XGI_PCI_GET_DEVICE(info->vendor_id, info->device_id, NULL);
+ while (dev) {
+ if (XGI_PCI_SLOT_NUMBER(dev) == info->slot
+ && XGI_PCI_BUS_NUMBER(dev) == info->bus)
+ return dev;
+ dev = XGI_PCI_GET_DEVICE(info->vendor_id, info->device_id, dev);
+ }
+
+ return NULL;
+}
+
+int xgi_kern_read_card_info(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct pci_dev *dev;
+ char *type;
+ int len = 0;
+
+ xgi_info_t *info;
+ info = (xgi_info_t *) data;
+
+ dev = xgi_get_pci_device(info);
+ if (!dev)
+ return 0;
+
+ type = xgi_find_pcie_capability(dev) ? "PCIE" : "PCI";
+ len += sprintf(page + len, "Card Type: \t %s\n", type);
+
+ XGI_PCI_DEV_PUT(dev);
+ return len;
+}
+
+int xgi_kern_read_version(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len += sprintf(page + len, "XGI version: %s\n", "1.0");
+ len += sprintf(page + len, "GCC version: %s\n", "3.0");
+
+ return len;
+}
+
+int xgi_kern_read_pcie_info(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ return 0;
+}
+
+int xgi_kern_read_status(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ return 0;
+}
+
+static void xgi_proc_create(void)
+{
+#ifdef CONFIG_PROC_FS
+
+ struct pci_dev *dev;
+ int i = 0;
+ char name[6];
+
+ struct proc_dir_entry *entry;
+ struct proc_dir_entry *proc_xgi_pcie, *proc_xgi_cards;
+
+ xgi_info_t *info;
+ xgi_info_t *xgi_max_devices;
+
+ /* world readable directory */
+ int flags = S_IFDIR | S_IRUGO | S_IXUGO;
+
+ proc_xgi = create_proc_entry("xgi", flags, proc_root_driver);
+ if (!proc_xgi)
+ goto failed;
+
+ proc_xgi_cards = create_proc_entry("cards", flags, proc_xgi);
+ if (!proc_xgi_cards)
+ goto failed;
+
+ proc_xgi_pcie = create_proc_entry("pcie", flags, proc_xgi);
+ if (!proc_xgi_pcie)
+ goto failed;
+
+ /*
+ * Set the module owner to ensure that the reference
+ * count reflects accesses to the proc files.
+ */
+ proc_xgi->owner = THIS_MODULE;
+ proc_xgi_cards->owner = THIS_MODULE;
+ proc_xgi_pcie->owner = THIS_MODULE;
+
+ xgi_max_devices = xgi_devices + XGI_MAX_DEVICES;
+ for (info = xgi_devices; info < xgi_max_devices; info++) {
+ if (info->device_id == 0)
+ break;
+
+ /* world readable file */
+ flags = S_IFREG | S_IRUGO;
+
+ dev = xgi_get_pci_device(info);
+ if (!dev)
+ break;
+
+ sprintf(name, "%d", i++);
+ entry = create_proc_entry(name, flags, proc_xgi_cards);
+ if (!entry) {
+ XGI_PCI_DEV_PUT(dev);
+ goto failed;
+ }
+
+ entry->data = info;
+ entry->read_proc = xgi_kern_read_card_info;
+ entry->owner = THIS_MODULE;
+
+ if (xgi_find_pcie_capability(dev)) {
+ entry =
+ create_proc_entry("status", flags, proc_xgi_pcie);
+ if (!entry) {
+ XGI_PCI_DEV_PUT(dev);
+ goto failed;
+ }
+
+ entry->data = info;
+ entry->read_proc = xgi_kern_read_status;
+ entry->owner = THIS_MODULE;
+
+ entry = create_proc_entry("card", flags, proc_xgi_pcie);
+ if (!entry) {
+ XGI_PCI_DEV_PUT(dev);
+ goto failed;
+ }
+
+ entry->data = info;
+ entry->read_proc = xgi_kern_read_pcie_info;
+ entry->owner = THIS_MODULE;
+ }
+
+ XGI_PCI_DEV_PUT(dev);
+ }
+
+ entry = create_proc_entry("version", flags, proc_xgi);
+ if (!entry)
+ goto failed;
+
+ entry->read_proc = xgi_kern_read_version;
+ entry->owner = THIS_MODULE;
+
+ entry = create_proc_entry("host-bridge", flags, proc_xgi_pcie);
+ if (!entry)
+ goto failed;
+
+ entry->data = NULL;
+ entry->read_proc = xgi_kern_read_pcie_info;
+ entry->owner = THIS_MODULE;
+
+ return;
+
+ failed:
+ XGI_ERROR("failed to create /proc entries!\n");
+ xgi_proc_remove_all(proc_xgi);
+#endif
+}
+
+#ifdef CONFIG_PROC_FS
+static void xgi_proc_remove_all(struct proc_dir_entry *entry)
+{
+ while (entry) {
+ struct proc_dir_entry *next = entry->next;
+ if (entry->subdir)
+ xgi_proc_remove_all(entry->subdir);
+ remove_proc_entry(entry->name, entry->parent);
+ if (entry == proc_xgi)
+ break;
+ entry = next;
+ }
+}
+#endif
+
+static void xgi_proc_remove(void)
+{
+#ifdef CONFIG_PROC_FS
+ xgi_proc_remove_all(proc_xgi);
+#endif
+}
+
+/*
+ * driver receives an interrupt if someone waiting, then hand it off.
+ */
+irqreturn_t xgi_kern_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ xgi_info_t *info = (xgi_info_t *) dev_id;
+ u32 need_to_run_bottom_half = 0;
+
+ //XGI_INFO("xgi_kern_isr \n");
+
+ //XGI_CHECK_PCI_CONFIG(info);
+
+ //xgi_dvi_irq_handler(info);
+
+ if (need_to_run_bottom_half) {
+ tasklet_schedule(&info->tasklet);
+ }
+
+ return IRQ_HANDLED;
+}
+
+void xgi_kern_isr_bh(unsigned long data)
+{
+ xgi_info_t *info = (xgi_info_t *) data;
+
+ XGI_INFO("xgi_kern_isr_bh \n");
+
+ //xgi_dvi_irq_handler(info);
+
+ XGI_CHECK_PCI_CONFIG(info);
+}
+
+static void xgi_lock_init(xgi_info_t * info)
+{
+ if (info == NULL)
+ return;
+
+ spin_lock_init(&info->info_lock);
+
+ sema_init(&info->info_sem, 1);
+ sema_init(&info->fb_sem, 1);
+ sema_init(&info->pcie_sem, 1);
+
+ XGI_ATOMIC_SET(info->use_count, 0);
+}
+
+static void xgi_dev_init(xgi_info_t * info)
+{
+ struct pci_dev *pdev = NULL;
+ struct xgi_dev *dev;
+ int found = 0;
+ u16 pci_cmd;
+
+ XGI_INFO("Enter xgi_dev_init \n");
+
+ //XGI_PCI_FOR_EACH_DEV(pdev)
+ {
+ for (dev = xgidev_list; dev->vendor; dev++) {
+ if ((dev->vendor == pdev->vendor)
+ && (dev->device == pdev->device)) {
+ XGI_INFO("dev->vendor = pdev->vendor= %x \n",
+ dev->vendor);
+ XGI_INFO("dev->device = pdev->device= %x \n",
+ dev->device);
+
+ xgi_devices[found].device_id = pdev->device;
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID,
+ &xgi_devices[found].
+ revision_id);
+
+ XGI_INFO("PCI_REVISION_ID= %x \n",
+ xgi_devices[found].revision_id);
+
+ pci_read_config_word(pdev, PCI_COMMAND,
+ &pci_cmd);
+
+ XGI_INFO("PCI_COMMAND = %x \n", pci_cmd);
+
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Export to Linux Kernel
+ */
+
+static int __init xgi_init_module(void)
+{
+ xgi_info_t *info = &xgi_devices[xgi_num_devices];
+ int i, result;
+
+ XGI_INFO("Jong-xgi kernel driver %s initializing\n", XGI_DRV_VERSION);
+ //SET_MODULE_OWNER(&xgi_fops);
+
+ memset(xgi_devices, 0, sizeof(xgi_devices));
+
+ if (pci_register_driver(&xgi_pci_driver) < 0) {
+ pci_unregister_driver(&xgi_pci_driver);
+ XGI_ERROR("no XGI graphics adapter found\n");
+ return -ENODEV;
+ }
+
+ XGI_INFO("Jong-xgi_devices[%d].fb.base.: 0x%lx \n", xgi_num_devices,
+ xgi_devices[xgi_num_devices].fb.base);
+ XGI_INFO("Jong-xgi_devices[%d].fb.size.: 0x%lx \n", xgi_num_devices,
+ xgi_devices[xgi_num_devices].fb.size);
+
+/* Jong 07/27/2006; test for ubuntu */
+/*
+#ifdef CONFIG_DEVFS_FS
+
+ XGI_INFO("Jong-Use devfs \n");
+ do
+ {
+ xgi_devfs_handles[0] = XGI_DEVFS_REGISTER("xgi", 0);
+ if (xgi_devfs_handles[0] == NULL)
+ {
+ result = -ENOMEM;
+ XGI_ERROR("devfs register failed\n");
+ goto failed;
+ }
+ } while(0);
+ #else *//* no devfs, do it the "classic" way */
+
+ XGI_INFO("Jong-Use non-devfs \n");
+ /*
+ * Register your major, and accept a dynamic number. This is the
+ * first thing to do, in order to avoid releasing other module's
+ * fops in scull_cleanup_module()
+ */
+ result = XGI_REGISTER_CHRDEV(xgi_major, "xgi", &xgi_fops);
+ if (result < 0) {
+ XGI_ERROR("register chrdev failed\n");
+ pci_unregister_driver(&xgi_pci_driver);
+ return result;
+ }
+ if (xgi_major == 0)
+ xgi_major = result; /* dynamic */
+
+ /* #endif *//* CONFIG_DEVFS_FS */
+
+ XGI_INFO("Jong-major number %d\n", xgi_major);
+
+ /* instantiate tasklets */
+ for (i = 0; i < XGI_MAX_DEVICES; i++) {
+ /*
+ * We keep one tasklet per card to avoid latency issues with more
+ * than one device; no two instances of a single tasklet are ever
+ * executed concurrently.
+ */
+ XGI_ATOMIC_SET(xgi_devices[i].tasklet.count, 1);
+ }
+
+ /* init the xgi control device */
+ {
+ xgi_info_t *info_ctl = &xgi_ctl_device;
+ xgi_lock_init(info_ctl);
+ }
+
+ /* Init the resource manager */
+ INIT_LIST_HEAD(&xgi_mempid_list);
+ if (!xgi_fb_heap_init(info)) {
+ XGI_ERROR("xgi_fb_heap_init() failed\n");
+ result = -EIO;
+ goto failed;
+ }
+
+ /* Init the resource manager */
+ if (!xgi_pcie_heap_init(info)) {
+ XGI_ERROR("xgi_pcie_heap_init() failed\n");
+ result = -EIO;
+ goto failed;
+ }
+
+ /* create /proc/driver/xgi */
+ xgi_proc_create();
+
+#if defined(DEBUG)
+ inter_module_register("xgi_devices", THIS_MODULE, xgi_devices);
+#endif
+
+ return 0;
+
+ failed:
+#ifdef CONFIG_DEVFS_FS
+ XGI_DEVFS_REMOVE_CONTROL();
+ XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices);
+#endif
+
+ if (XGI_UNREGISTER_CHRDEV(xgi_major, "xgi") < 0)
+ XGI_ERROR("unregister xgi chrdev failed\n");
+
+ for (i = 0; i < xgi_num_devices; i++) {
+ if (xgi_devices[i].dev) {
+ release_mem_region(xgi_devices[i].fb.base,
+ xgi_devices[i].fb.size);
+ release_mem_region(xgi_devices[i].mmio.base,
+ xgi_devices[i].mmio.size);
+ }
+ }
+
+ pci_unregister_driver(&xgi_pci_driver);
+ return result;
+
+ return 1;
+}
+
+void __exit xgi_exit_module(void)
+{
+ int i;
+ xgi_info_t *info, *max_devices;
+
+#ifdef CONFIG_DEVFS_FS
+ /*
+ XGI_DEVFS_REMOVE_CONTROL();
+ for (i = 0; i < XGI_MAX_DEVICES; i++)
+ XGI_DEVFS_REMOVE_DEVICE(i);
+ */
+ XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices);
+#endif
+
+ if (XGI_UNREGISTER_CHRDEV(xgi_major, "xgi") < 0)
+ XGI_ERROR("unregister xgi chrdev failed\n");
+
+ XGI_INFO("Jong-unregister xgi chrdev scceeded\n");
+ for (i = 0; i < XGI_MAX_DEVICES; i++) {
+ if (xgi_devices[i].dev) {
+ /* clean up the flush2D batch array */
+ xgi_cmdlist_cleanup(&xgi_devices[i]);
+
+ if (xgi_devices[i].fb.vbase != NULL) {
+ iounmap((void *)xgi_devices[i].fb.vbase);
+ xgi_devices[i].fb.vbase = NULL;
+ }
+ if (xgi_devices[i].mmio.vbase != NULL) {
+ iounmap((void *)xgi_devices[i].mmio.vbase);
+ xgi_devices[i].mmio.vbase = NULL;
+ }
+ //release_mem_region(xgi_devices[i].fb.base, xgi_devices[i].fb.size);
+ //XGI_INFO("release frame buffer mem region scceeded\n");
+
+ release_mem_region(xgi_devices[i].mmio.base,
+ xgi_devices[i].mmio.size);
+ XGI_INFO("release MMIO mem region scceeded\n");
+
+ xgi_fb_heap_cleanup(&xgi_devices[i]);
+ XGI_INFO("xgi_fb_heap_cleanup scceeded\n");
+
+ xgi_pcie_heap_cleanup(&xgi_devices[i]);
+ XGI_INFO("xgi_pcie_heap_cleanup scceeded\n");
+
+ XGI_PCI_DISABLE_DEVICE(xgi_devices[i].dev);
+ }
+ }
+
+ pci_unregister_driver(&xgi_pci_driver);
+
+ /* remove /proc/driver/xgi */
+ xgi_proc_remove();
+
+#if defined(DEBUG)
+ inter_module_unregister("xgi_devices");
+#endif
+}
+
+module_init(xgi_init_module);
+module_exit(xgi_exit_module);
+
+#if defined(XGI_PM_SUPPORT_ACPI)
+int xgi_acpi_event(struct pci_dev *dev, u32 state)
+{
+ return 1;
+}
+
+int xgi_kern_acpi_standby(struct pci_dev *dev, u32 state)
+{
+ return 1;
+}
+
+int xgi_kern_acpi_resume(struct pci_dev *dev)
+{
+ return 1;
+}
+#endif
+
+MODULE_AUTHOR("Andrea Zhang <andrea_zhang@macrosynergy.com>");
+MODULE_DESCRIPTION("xgi kernel driver for xgi cards");
+MODULE_LICENSE("GPL");