View | Details | Raw Unified
Collapse All | Expand All

(-) linux-2.6.6.orig/Makefile (-1 / +1 lines)
 Lines 1-7    Link Here 
VERSION = 2
VERSION = 2
PATCHLEVEL = 6
PATCHLEVEL = 6
SUBLEVEL = 6
SUBLEVEL = 6
EXTRAVERSION =
EXTRAVERSION = -xbox
NAME=Zonked Quokka
NAME=Zonked Quokka
# *DOCUMENTATION*
# *DOCUMENTATION*
(-) linux-2.6.6.orig/arch/i386/Kconfig (-2 / +22 lines)
 Lines 52-57    Link Here 
	  If unsure, choose "PC-compatible" instead.
	  If unsure, choose "PC-compatible" instead.
config X86_XBOX
	bool "Microsoft Xbox"
	help
	  This option is needed to make Linux boot on XBox Gaming Systems.
	
	  The XBox can be considered as a standard PC with a Coppermine-based Celeron 733 MHz,
	  IDE harddrive, DVD, Ethernet, USB and graphics.
	
	  To boot the kernel you need "_romwell", either used as a replacement BIOS (cromwell)
	  or as a bootloader.
	
	  For more information see http://xbox-linux.sourceforge.net/
	
	  If you do not specifically need a kernel for XBOX machine,
	  say N here otherwise the kernel you build will not be bootable.
config X86_VOYAGER
config X86_VOYAGER
	bool "Voyager (NCR)"
	bool "Voyager (NCR)"
	help
	help
 Lines 521-526    Link Here 
	  If you have a system with several CPUs, you do not need to say Y
	  If you have a system with several CPUs, you do not need to say Y
	  here: the IO-APIC will be used automatically.
	  here: the IO-APIC will be used automatically.
config XBOX_EJECT
	bool "XBOX eject fix"
	depends on X86_XBOX
config X86_LOCAL_APIC
config X86_LOCAL_APIC
	bool
	bool
	depends on !SMP && X86_UP_APIC
	depends on !SMP && X86_UP_APIC
 Lines 1127-1133    Link Here 
config MCA
config MCA
	bool "MCA support"
	bool "MCA support"
	depends on !(X86_VISWS || X86_VOYAGER)
	depends on !(X86_VISWS || X86_VOYAGER || X86_XBOX)
	help
	help
	  MicroChannel Architecture is found in some IBM PS/2 machines and
	  MicroChannel Architecture is found in some IBM PS/2 machines and
	  laptops.  It is a bus system similar to PCI or ISA. See
	  laptops.  It is a bus system similar to PCI or ISA. See
 Lines 1314-1320    Link Here 
config X86_BIOS_REBOOT
config X86_BIOS_REBOOT
	bool
	bool
	depends on !(X86_VISWS || X86_VOYAGER)
	depends on !(X86_VISWS || X86_VOYAGER || X86_XBOX)
	default y
	default y
config X86_TRAMPOLINE
config X86_TRAMPOLINE
(-) linux-2.6.6.orig/arch/i386/Makefile (+4 lines)
 Lines 65-70    Link Here 
# Default subarch .c files
# Default subarch .c files
mcore-y  := mach-default
mcore-y  := mach-default
# Xbox subarch support
mflags-$(CONFIG_X86_XBOX)	:= -Iinclude/asm-i386/mach-xbox
mcore-$(CONFIG_X86_XBOX)	:= mach-xbox
# Voyager subarch support
# Voyager subarch support
mflags-$(CONFIG_X86_VOYAGER)	:= -Iinclude/asm-i386/mach-voyager
mflags-$(CONFIG_X86_VOYAGER)	:= -Iinclude/asm-i386/mach-voyager
mcore-$(CONFIG_X86_VOYAGER)	:= mach-voyager
mcore-$(CONFIG_X86_VOYAGER)	:= mach-voyager
(-) linux-2.6.6.orig/arch/i386/boot/compressed/Makefile (+11 lines)
 Lines 5-10    Link Here 
#
#
targets		:= vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
targets		:= vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
#
# There is some strange interaction when paging is off, that makes
# newer v1.1+ Xboxen (manufactured August 2002 or later) crash while
# decrompressing the kernel. Compiling the decrompressor without any
# optimization reliably works around this problem.
#
ifeq ($(CONFIG_X86_XBOX),y)
CFLAGS_misc.o	:= -O0
endif
EXTRA_AFLAGS	:= -traditional
EXTRA_AFLAGS	:= -traditional
LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32
LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32
(-) linux-2.6.6.orig/arch/i386/kernel/Makefile (+1 lines)
 Lines 25-30    Link Here 
obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
obj-$(CONFIG_X86_SUMMIT_NUMA)	+= summit.o
obj-$(CONFIG_X86_SUMMIT_NUMA)	+= summit.o
obj-$(CONFIG_XBOX_EJECT)        += xboxejectfix.o
obj-$(CONFIG_MODULES)		+= module.o
obj-$(CONFIG_MODULES)		+= module.o
obj-y				+= sysenter.o vsyscall.o
obj-y				+= sysenter.o vsyscall.o
obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
(-) linux-2.6.6.orig/arch/i386/kernel/xboxejectfix.c (+147 lines)
Line 0    Link Here 
/**
 * Driver that handles the EXTSMI# interrupt on the xbox.
 * Makes it possible to use the eject-button without the xbox rebooting...
 *
 * smbus-command sequence to prevent reboot from cromwell.
 *
 * Changelog:
 *  2003-01-14 Anders Gustafsson <andersg@0x63.nu>
 *             initial version
 *  2003-02-08 Milosch Meriac <xboxlinux@meriac.de>
 *             rewrote debug macros because of compiler errors
 *  2003-08-06 Michael Steil <mist@c64.org>
 *             removed Linux I2C dependency, now compiles
 *             without I2C in the kernel
 *
 * Todo: add errorhandling!
 *
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/xbox.h>
#include <linux/interrupt.h>
#define IRQ 12
#define DRIVER_NAME "xboxejectfix"
/* just some crap */
static char dev[]=DRIVER_NAME;
/* External variable from ide-cd.c that specifies whether we simulate drive
   locking in software */
extern volatile int Xbox_simulate_drive_locked;
#define BASE 0x8000
/* Power Management 1 Enable Register */
#define PM02 (BASE+0x02)
/* Power Management 1 Control Register */
#define PM04 (BASE+0x04)
/* ACPI GP Status Register */
#define PM20 (BASE+0x20)
/* ACPI GP Enable Register */
#define PM22 (BASE+0x22)
# define EXTSMI_EN_MASK 0x0002
/* Global SMI Enable Register */
#define PM2A (BASE+0x2A)
static DECLARE_MUTEX(extsmi_sem);
static DECLARE_COMPLETION(extsmi_exited);
static int extsmi_pid=0;
static irqreturn_t extsmi_interupt(int unused, void *dev_id, struct pt_regs *regs) {
	int reason;
	reason=inw(0x8020);
	outw(reason,0x8020); /* ack  IS THIS NEEDED? */
	if(reason&0x2){
		/* wake up thread */
		up(&extsmi_sem);
	}
	return 0;
}
/**
 * Process an event. This is run in process-context.
 */
static void extsmi_process(void){
	int reason;
	reason=Xbox_SMC_read(SMC_CMD_INTERRUPT_REASON);
	if(reason&TRAYBUTTON_MASK){ /* Tray button! Respond to prevent reboot! */
		Xbox_SMC_write(SMC_CMD_INTERRUPT_RESPOND, SMC_SUBCMD_RESPOND_CONTINUE);
		Xbox_SMC_write(0x00, 0x0c);
		/* eject unless lock simulation is being used */
		if (!Xbox_simulate_drive_locked)
			Xbox_tray_eject();
	}
}
static int extsmi_thread(void *data){
	daemonize("extsmi");
	reparent_to_init();
	strcpy(current->comm, "xbox_extsmi");
	do {
		extsmi_process();
		down_interruptible(&extsmi_sem);
	} while (!signal_pending(current));
	
         complete_and_exit(&extsmi_exited, 0);
}
static int extsmi_init(void){
	int pid;
	
	if (!machine_is_xbox) {
		printk("This machine is no Xbox.\n");
		return -1;
	}
	printk("Enabling Xbox eject problem workaround.\n");
        pid = kernel_thread(extsmi_thread, NULL,
			    CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
	if (pid < 0) {
		return pid;
	}
	extsmi_pid = pid;
	/* this shuts a lot of interrupts off! */
	outw(inw(0x80e2)&0xf8c7,0x80e2);
	outw(0,0x80ac);
	outb(0,0x8025);
	outw(EXTSMI_EN_MASK,PM22); /* enable the EXTSMI# interupt! */
	outw(0,PM02);
	outb(1,PM04); /* enable sci interrupts! */
	Xbox_SMC_write(SMC_CMD_RESET_ON_EJECT, SMC_SUBCMD_RESET_ON_EJECT_DISABLE);
	/* FIXME! retval! */
	request_irq(IRQ,extsmi_interupt,SA_INTERRUPT|SA_SHIRQ,"xboxejectfix",dev);
	return 0;
}
static void extsmi_exit(void){
	int res;
	if (!machine_is_xbox) return; /* can this happen??? */
	free_irq(IRQ,dev);
	/* Kill the thread */
	res = kill_proc(extsmi_pid, SIGTERM, 1);
	wait_for_completion(&extsmi_exited);
	return;
}
module_init(extsmi_init);
module_exit(extsmi_exit);
MODULE_AUTHOR("Anders Gustafsson <andersg@0x63.nu>");
MODULE_LICENSE("GPL");
(-) linux-2.6.6.orig/arch/i386/mach-xbox/Makefile (+5 lines)
Line 0    Link Here 
#
# Makefile for the linux kernel.
#
obj-y				:= setup.o reboot.o
(-) linux-2.6.6.orig/arch/i386/mach-xbox/reboot.c (+51 lines)
Line 0    Link Here 
/*
 * arch/i386/mach-xbox/reboot.c 
 * Olivier Fauchon <olivier.fauchon@free.fr>
 * Anders Gustafsson <andersg@0x63.nu>
 *
 */
#include <asm/io.h>
/* we don't use any of those, but dmi_scan.c needs 'em */
void (*pm_power_off)(void);
int reboot_thru_bios;
#define XBOX_SMB_IO_BASE		0xC000
#define XBOX_SMB_HOST_ADDRESS		(0x4 + XBOX_SMB_IO_BASE)
#define XBOX_SMB_HOST_COMMAND		(0x8 + XBOX_SMB_IO_BASE)
#define XBOX_SMB_HOST_DATA		(0x6 + XBOX_SMB_IO_BASE)
#define XBOX_SMB_GLOBAL_ENABLE		(0x2 + XBOX_SMB_IO_BASE)
#define XBOX_PIC_ADDRESS		0x10
#define SMC_CMD_POWER			0x02
#define SMC_SUBCMD_POWER_RESET		0x01
#define SMC_SUBCMD_POWER_CYCLE		0x40
#define SMC_SUBCMD_POWER_OFF		0x80
static void xbox_pic_cmd(u8 command)
{
	outw_p(((XBOX_PIC_ADDRESS) << 1), XBOX_SMB_HOST_ADDRESS);
	outb_p(SMC_CMD_POWER, XBOX_SMB_HOST_COMMAND);
	outw_p(command, XBOX_SMB_HOST_DATA);
	outw_p(inw(XBOX_SMB_IO_BASE), XBOX_SMB_IO_BASE);
	outb_p(0x0a, XBOX_SMB_GLOBAL_ENABLE);
}
void machine_restart(char * __unused)
{
	printk(KERN_INFO "Sending POWER_CYCLE to XBOX-PIC.\n");
	xbox_pic_cmd(SMC_SUBCMD_POWER_CYCLE);  
}
void machine_power_off(void)
{
	printk(KERN_INFO "Sending POWER_OFF to XBOX-PIC.\n");
	xbox_pic_cmd(SMC_SUBCMD_POWER_OFF);  
}
void machine_halt(void)
{
}
(-) linux-2.6.6.orig/arch/i386/mach-xbox/setup.c (+84 lines)
Line 0    Link Here 
/*
 *	Machine specific setup for xbox
 */
#include <linux/config.h>
#include <linux/smp.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/arch_hooks.h>
/**
 * pre_intr_init_hook - initialisation prior to setting up interrupt vectors
 *
 * Description:
 *	Perform any necessary interrupt initialisation prior to setting up
 *	the "ordinary" interrupt call gates.  For legacy reasons, the ISA
 *	interrupts should be initialised here if the machine emulates a PC
 *	in any way.
 **/
void __init pre_intr_init_hook(void)
{
	init_ISA_irqs();
}
/*
 * IRQ2 is cascade interrupt to second interrupt controller
 */
static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL };
/**
 * intr_init_hook - post gate setup interrupt initialisation
 *
 * Description:
 *	Fill in any interrupts that may have been left out by the general
 *	init_IRQ() routine.  interrupts having to do with the machine rather
 *	than the devices on the I/O bus (like APIC interrupts in intel MP
 *	systems) are started here.
 **/
void __init intr_init_hook(void)
{
#ifdef CONFIG_X86_LOCAL_APIC
	apic_intr_init();
#endif
	setup_irq(2, &irq2);
}
/**
 * pre_setup_arch_hook - hook called prior to any setup_arch() execution
 *
 * Description:
 *	generally used to activate any machine specific identification
 *	routines that may be needed before setup_arch() runs.  On VISWS
 *	this is used to get the board revision and type.
 **/
void __init pre_setup_arch_hook(void)
{
}
/**
 * trap_init_hook - initialise system specific traps
 *
 * Description:
 *	Called as the final act of trap_init().  Used in VISWS to initialise
 *	the various board specific APIC traps.
 **/
void __init trap_init_hook(void)
{
}
static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL };
/**
 * time_init_hook - do any specific initialisations for the system timer.
 *
 * Description:
 *	Must plug the system timer interrupt source at HZ into the IRQ listed
 *	in irq_vectors.h:TIMER_IRQ
 **/
void __init time_init_hook(void)
{
	setup_irq(0, &irq0);
}
(-) linux-2.6.6.orig/arch/i386/pci/direct.c (+4 lines)
 Lines 4-9    Link Here 
#include <linux/pci.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/init.h>
#include "mach_pci_blacklist.h"
#include "pci.h"
#include "pci.h"
/*
/*
 Lines 20-25    Link Here 
	if (!value || (bus > 255) || (devfn > 255) || (reg > 255))
	if (!value || (bus > 255) || (devfn > 255) || (reg > 255))
		return -EINVAL;
		return -EINVAL;
	if (mach_pci_is_blacklisted(bus, PCI_SLOT(devfn), PCI_FUNC(devfn)))
		return -EINVAL;
	spin_lock_irqsave(&pci_config_lock, flags);
	spin_lock_irqsave(&pci_config_lock, flags);
	outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
	outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
(-) linux-2.6.6.orig/drivers/i2c/busses/Kconfig (+4 lines)
 Lines 49-54    Link Here 
	  This driver can also be built as a module.  If so, the module
	  This driver can also be built as a module.  If so, the module
	  will be called i2c-amd756.
	  will be called i2c-amd756.
config I2C_XBOX
	tristate "XBOX I2C"
	depends on I2C && EXPERIMENTAL
config I2C_AMD8111
config I2C_AMD8111
	tristate "AMD 8111"
	tristate "AMD 8111"
	depends on I2C && EXPERIMENTAL
	depends on I2C && EXPERIMENTAL
(-) linux-2.6.6.orig/drivers/i2c/busses/Makefile (+1 lines)
 Lines 6-11    Link Here 
obj-$(CONFIG_I2C_ALI1563)	+= i2c-ali1563.o
obj-$(CONFIG_I2C_ALI1563)	+= i2c-ali1563.o
obj-$(CONFIG_I2C_ALI15X3)	+= i2c-ali15x3.o
obj-$(CONFIG_I2C_ALI15X3)	+= i2c-ali15x3.o
obj-$(CONFIG_I2C_AMD756)	+= i2c-amd756.o
obj-$(CONFIG_I2C_AMD756)	+= i2c-amd756.o
obj-$(CONFIG_I2C_XBOX)		+= i2c-xbox.o
obj-$(CONFIG_I2C_AMD8111)	+= i2c-amd8111.o
obj-$(CONFIG_I2C_AMD8111)	+= i2c-amd8111.o
obj-$(CONFIG_I2C_ELEKTOR)	+= i2c-elektor.o
obj-$(CONFIG_I2C_ELEKTOR)	+= i2c-elektor.o
obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
(-) linux-2.6.6.orig/drivers/i2c/busses/i2c-xbox.c (+417 lines)
Line 0    Link Here 
/*
    i2c-xbox.c - Part of lm_sensors, Linux kernel modules for hardware
              monitoring
    Copyright (c) 1999-2002 Edgar Hucek <hostmaster@ed-soft.at>
    Shamelessly ripped from i2c-xbox.c:
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
   Supports XBOX, Note: we assume there can only be one device, with one SMBus interface.
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/errno.h>  /* error codes */
#include <linux/interrupt.h> /* intr_count */
#include <linux/xbox.h>
#include <linux/delay.h>
#define GS_ABRT_STS (1 << 0)
#define GS_COL_STS (1 << 1)
#define GS_PRERR_STS (1 << 2)
#define GS_HST_STS (1 << 3)
#define GS_IRQ_ON (1 << 4)
#define GS_HCYC_STS (1 << 4)
#define GS_TO_STS (1 << 5)
#define GS_SMB_STS (1 << 11)
#define SMB_GCTL_HOST_START      (1 << 3)
#define SMB_GCTL_HOST_INTERRUPT  (1 << 4)
#define SMB_GCTL_ABORT           (1 << 5)
#define SMB_GCTL_SNOOP           (1 << 8)
#define SMB_GCTL_SLAVE_INTERRUPT (1 << 9)
#define SMB_GCTL_ALERT_INTERRUPT (1 << 10)
#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
  GS_HCYC_STS | GS_TO_STS)
#define GE_CYC_TYPE_MASK (7)
#define GE_HOST_STC (1 << 3)
#define GE_ABORT (1 << 5)
#define I2C_HW_SMBUS_XBOX   0x05
#define SMBGCFG   0x041          /* mh */
#define SMBBA     0x058           /* mh */
struct sd {
    const unsigned short vendor;
    const unsigned short device;
    const unsigned short function;
    const char* name;
    int amdsetup:1;
};
static struct sd supported[] = {
    {PCI_VENDOR_ID_NVIDIA, 0x01b4, 1, "nVidia XBOX nForce", 0},
    {0, 0, 0}
};
/* XBOX SMBus address offsets */
#define SMB_ADDR_OFFSET        0x04
#define SMB_IOSIZE             8
#define SMB_GLOBAL_STATUS      (0x0 + xbox_smba)
#define SMB_GLOBAL_ENABLE      (0x2 + xbox_smba)
#define SMB_HOST_ADDRESS       (0x4 + xbox_smba)
#define SMB_HOST_DATA          (0x6 + xbox_smba)
#define SMB_HOST_COMMAND       (0x8 + xbox_smba)
/* Other settings */
#define MAX_TIMEOUT 500
/* XBOX constants */
#define XBOX_QUICK        0x00
#define XBOX_BYTE         0x01
#define XBOX_BYTE_DATA    0x02
#define XBOX_WORD_DATA    0x03
#define XBOX_PROCESS_CALL 0x04
#define XBOX_BLOCK_DATA   0x05
/* insmod parameters */
#ifdef MODULE
static
#else
extern
#endif
int __init i2c_xbox_init(void);
static int __init xbox_cleanup(void);
static int xbox_setup(void);
static s32 xbox_access(struct i2c_adapter *adap, u16 addr,
			 unsigned short flags, char read_write,
			 u8 command, int size, union i2c_smbus_data *data);
static void xbox_do_pause(unsigned int amount);
static void xbox_abort(void);
static int xbox_transaction(void);
static u32 xbox_func(struct i2c_adapter *adapter);
static struct i2c_algorithm smbus_algorithm = {
	/* name */ "Non-I2C SMBus adapter",
	/* id */ I2C_ALGO_SMBUS,
	/* master_xfer */ NULL,
	/* smbus_access */ xbox_access,
	/* slave;_send */ NULL,
	/* slave_rcv */ NULL,
	/* algo_control */ NULL,
	/* functionality */ xbox_func,
};
static struct i2c_adapter xbox_adapter = {
	.owner          = THIS_MODULE,
	.class          = I2C_ADAP_CLASS_SMBUS,
	.algo           = &smbus_algorithm,
	.name           = "unset",
};
static int __initdata xbox_initialized;
static unsigned short xbox_smba = 0;
spinlock_t xbox_driver_lock = SPIN_LOCK_UNLOCKED;
struct driver_data;
static struct pci_dev *XBOX_dev;
/* Detect whether a XBOX can be found, and initialize it, where necessary.
   Note the differences between kernels with the old PCI BIOS interface and
   newer kernels with the real PCI interface. In compat.h some things are
   defined to make the transition easier. */
int xbox_setup(void)
{
	unsigned char temp;
	struct sd *currdev;
	u16 cmd;
	XBOX_dev = NULL;
	/* Look for a supported chip */
	for(currdev = supported; currdev->vendor; ) {
		XBOX_dev = pci_find_device(currdev->vendor,
						currdev->device, XBOX_dev);
		if (XBOX_dev != NULL)	{
	                pci_read_config_byte(XBOX_dev, SMBGCFG, &temp);
			pci_read_config_word(XBOX_dev, 0x14, &xbox_smba);
			
			xbox_smba &= 0xfffc;
			if (PCI_FUNC(XBOX_dev->devfn) == currdev->function)
			{
				pci_read_config_word(XBOX_dev,PCI_STATUS,&cmd);
				break;
			}
		} else {
		    currdev++;
		}
	}
	if (XBOX_dev == NULL) {
		printk
		    ("i2c-xbox.o: Error: No XBOX or compatible device detected!\n");
		return(-ENODEV);
	}
	printk(KERN_INFO "i2c-xbox.o: Found %s SMBus controller.\n", currdev->name);
	/* Everything is happy, let's grab the memory and set things up. */
	if(!request_region(xbox_smba, SMB_IOSIZE, "xbox-smbus")) {
		printk
		    ("i2c-xbox.o: SMB region 0x%x already in use!\n",
		     xbox_smba);
		return(-ENODEV);
	}
	return 0;
}
/* 
  SMBUS event = I/O 28-29 bit 11
     see E0 for the status bits and enabled in E2
     
*/
/* Internally used pause function */
void xbox_do_pause(unsigned int amount)
{
	current->state = TASK_INTERRUPTIBLE;
	schedule_timeout(amount);
}
void xbox_abort(void)
{
	printk("i2c-xbox.o: Sending abort.\n");
	outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
	xbox_do_pause(100);
	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
}
int xbox_transaction(void)
{
	int temp;
	int result = 0;
	int timeout = 0;
	/* Make sure the SMBus host is ready to start transmitting */
	if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
		do {
			udelay(100);
			temp = inw_p(SMB_GLOBAL_STATUS);
		} while ((temp & (GS_HST_STS | GS_SMB_STS)) &&
		         (timeout++ < MAX_TIMEOUT));
		/* If the SMBus is still busy, we give up */
		if (timeout >= MAX_TIMEOUT) {
			printk("i2c-xbox.o: Busy wait timeout! (%04x)\n", temp);
			xbox_abort();
			return(-1);
		}
		timeout = 0;
	}
	/* start the transaction by setting the start bit */
	outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC , SMB_GLOBAL_ENABLE);
	/* We will always wait for a fraction of a second! */
	temp = inw_p(SMB_GLOBAL_STATUS);
	while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT)) {
		udelay(100);
		temp = inw_p(SMB_GLOBAL_STATUS);		
	} 
	/* If the SMBus is still busy, we give up */
	if (timeout >= MAX_TIMEOUT) {
		printk("i2c-xbox.o: Completion timeout!\n");
		xbox_abort ();
		return(-1);
	}
	if (temp & GS_PRERR_STS) {
		result = -1;
	}
	if (temp & GS_COL_STS) {
		result = -1;
		printk("i2c-xbox.o: SMBus collision!\n");
	}
	if (temp & GS_TO_STS) {
		result = -1;
	}
	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
	return result;
}
/* Return -1 on error. */
s32 xbox_access(struct i2c_adapter * adap, u16 addr,
		  unsigned short flags, char read_write,
		  u8 command, int size, union i2c_smbus_data * data)
{
  /** TODO: Should I supporte the 10-bit transfers? */
	switch (size) {
	case I2C_SMBUS_PROC_CALL:
		printk
		    ("i2c-xbox.o: I2C_SMBUS_PROC_CALL not supported!\n");
		/* TODO: Well... It is supported, I'm just not sure what to do here... */
		return -1;
	case I2C_SMBUS_QUICK:
		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
		       SMB_HOST_ADDRESS);
		size = XBOX_QUICK;
		break;
	case I2C_SMBUS_BYTE:
		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
		       SMB_HOST_ADDRESS);
		/* TODO: Why only during write? */
		if (read_write == I2C_SMBUS_WRITE)
			outb_p(command, SMB_HOST_COMMAND);
		size = XBOX_BYTE;
		break;
	case I2C_SMBUS_BYTE_DATA:
		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
		       SMB_HOST_ADDRESS);
		outb_p(command, SMB_HOST_COMMAND);
		if (read_write == I2C_SMBUS_WRITE)
			outw_p(data->byte, SMB_HOST_DATA);
		size = XBOX_BYTE_DATA;
		break;
	case I2C_SMBUS_WORD_DATA:
		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
		       SMB_HOST_ADDRESS);
		outb_p(command, SMB_HOST_COMMAND);
		if (read_write == I2C_SMBUS_WRITE)
			outw_p(data->word, SMB_HOST_DATA);	/* TODO: endian???? */
		size = XBOX_WORD_DATA;
		break;
	}
	/* How about enabling interrupts... */
	outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
	if (xbox_transaction())	/* Error in transaction */
		return -1;
	if ((read_write == I2C_SMBUS_WRITE) || (size == XBOX_QUICK))
		return 0;
	switch (size) {
	case XBOX_BYTE:
		data->byte = inw_p(SMB_HOST_DATA);
		break;
	case XBOX_BYTE_DATA:
		data->byte = inw_p(SMB_HOST_DATA);
		break;
	case XBOX_WORD_DATA:
		data->word = inw_p(SMB_HOST_DATA);	/* TODO: endian???? */
		break;
	}
	return 0;
}
u32 xbox_func(struct i2c_adapter *adapter)
{
	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
	    I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL;
}
int __init i2c_xbox_init(void)
{
	int res;
	printk("i2c-xbox.o version 0.0.1\n");
	xbox_initialized = 0;
	if ((res = xbox_setup())) {
		printk
		    ("i2c-xbox.o: XBOX or compatible device not detected, module not inserted.\n");
		xbox_cleanup();
		return res;
	}
	xbox_initialized++;
	sprintf(xbox_adapter.name, "SMBus adapter at %04x",xbox_smba);
	if ((res = i2c_add_adapter(&xbox_adapter))) {
		printk
		    ("i2c-xbox.o: Adapter registration failed, module not inserted.\n");
		xbox_cleanup();
		return res;
	}
	xbox_initialized++;
	printk("i2c-xbox.o: SMBus bus detected and initialized\n");
	return 0;
}
int __init xbox_cleanup(void)
{
	int res;
	if (xbox_initialized >= 2) {
		if ((res = i2c_del_adapter(&xbox_adapter))) {
			printk
			    ("i2c-xbox.o: i2c_del_adapter failed, module not removed\n");
			return res;
		} else
			xbox_initialized--;
	}
	if (xbox_initialized >= 1) {
		release_region(xbox_smba, SMB_IOSIZE);
		xbox_initialized--;
	}
	free_irq(XBOX_dev->irq, XBOX_dev);
	return 0;
}
EXPORT_SYMBOL(i2c_xbox_init);
#ifdef MODULE
MODULE_AUTHOR("Edgar Hucek <hostmaster@ed-soft.at>");
MODULE_DESCRIPTION("XBOX nForce SMBus driver");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
int init_module(void)
{
	return i2c_xbox_init();
}
void cleanup_module(void)
{
	xbox_cleanup();
}
#endif				/* MODULE */
(-) linux-2.6.6.orig/drivers/ide/ide-cd.c (+96 lines)
 Lines 324-329    Link Here 
#include "ide-cd.h"
#include "ide-cd.h"
#ifdef CONFIG_X86_XBOX
#include <linux/xbox.h>
/* Global flag indicating whether to simulate Xbox drive locking in
 * software.  There should only be one Xbox drive in a system!  This
 * variable is externally referenced by arch/i386/kernel/xboxejectfix.c. */
volatile int Xbox_simulate_drive_locked = 0;
#endif /* CONFIG_X86_XBOX */
 
/****************************************************************************
/****************************************************************************
 * Generic packet command support and error handling routines.
 * Generic packet command support and error handling routines.
 */
 */
 Lines 2121-2126    Link Here 
	if (sense == NULL)
	if (sense == NULL)
		sense = &my_sense;
		sense = &my_sense;
#ifdef CONFIG_X86_XBOX
	/* If we're on an Xbox and this is an Xbox drive, simulate the lock
	   request in software.  (See arch/i386/kernel/xboxejectfix.c) */
	if (CDROM_CONFIG_FLAGS(drive)->xbox_drive && machine_is_xbox) {
		CDROM_STATE_FLAGS(drive)->door_locked = lockflag;
		Xbox_simulate_drive_locked = lockflag;
		return 0;
	}
#endif /* CONFIG_X86_XBOX */
		
	/* If the drive cannot lock the door, just pretend. */
	/* If the drive cannot lock the door, just pretend. */
	if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
	if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
		stat = 0;
		stat = 0;
 Lines 2169-2174    Link Here 
	if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
	if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
		return 0;
		return 0;
#ifdef CONFIG_X86_XBOX
        /* Older Xbox DVD drives don't understand the ATAPI command, but the SMC
	   can do the eject.  Note that some Xbox drives support the eject
	   command, namely the Samsung, so for that drive we do a regular eject
	   sequence. */
	if (machine_is_xbox && CDROM_CONFIG_FLAGS(drive)->xbox_drive &&
		CDROM_CONFIG_FLAGS(drive)->xbox_eject) {
		if (ejectflag) {
			Xbox_tray_load();
		} else {
			Xbox_simulate_drive_locked = 0;
			Xbox_tray_eject();
		}
		return 0;
	}
#endif
		
	cdrom_prepare_request(&req);
	cdrom_prepare_request(&req);
	/* only tell drive to close tray if open, if it can do that */
	/* only tell drive to close tray if open, if it can do that */
 Lines 3258-3263    Link Here 
                 /* uses CD in slot 0 when value is set to 3 */
                 /* uses CD in slot 0 when value is set to 3 */
                 cdi->sanyo_slot = 3;
                 cdi->sanyo_slot = 3;
        }
        }
#ifdef CONFIG_X86_XBOX
	/* THOMSON DVD drives in the Xbox report incorrect capabilities
	   and do not understand the ATAPI eject command, but the SMC
	   can do the eject. */
	else if ((strcmp(drive->id->model, "THOMSON-DVD") == 0)) {
		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
		CDROM_CONFIG_FLAGS(drive)->dvd = 1;
		CDROM_CONFIG_FLAGS(drive)->xbox_drive = 1;
		CDROM_CONFIG_FLAGS(drive)->xbox_eject = 1;
	}
	/* PHILIPS drives in Xboxen manufactured pre September 2003,
	   report correct capabilities, but do not understand the ATAPI
	   eject command, hence require the SMC to do so. */
	else if ((strcmp(drive->id->model, "PHILIPS XBOX DVD DRIVE") == 0)) {
		CDROM_CONFIG_FLAGS(drive)->xbox_drive = 1;
		CDROM_CONFIG_FLAGS(drive)->xbox_eject = 1;
	}
	/* PHILIPS drives in Xboxen manufactured post September 2003,
	   report incorrect capabilities, but understand the ATAPI
	   eject command. */
	else if ((strcmp(drive->id->model, "PHILIPS J5 3235C") == 0)) {
		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
		CDROM_CONFIG_FLAGS(drive)->dvd = 1;
		CDROM_CONFIG_FLAGS(drive)->xbox_drive = 1;
		CDROM_CONFIG_FLAGS(drive)->xbox_eject = 0;
	}
	/* SAMSUNG drives in the Xbox report correct capabilities
	   and understand the ATAPI eject command. */
	else if (strcmp(drive->id->model, "SAMSUNG DVD-ROM SDG-605B") == 0) {
		CDROM_CONFIG_FLAGS(drive)->xbox_drive = 1;
		CDROM_CONFIG_FLAGS(drive)->xbox_eject = 0;
	}
#endif
	/* Is an Xbox drive detected? */
#ifdef CONFIG_X86_XBOX
	if (CDROM_CONFIG_FLAGS(drive)->xbox_drive) {
#endif
		/* If an Xbox drive is present in a regular PC, we can't eject.
		   Act like the drive cannot eject, unless the ATAPI eject command
		   is supported by the drive.  If the drive doesn't support ATAPI
		   ejecting, act like door locking is impossible as well. */
#ifdef CONFIG_X86_XBOX
		if (!machine_is_xbox) {
#endif /* CONFIG_X86_XBOX */
			CDROM_CONFIG_FLAGS(drive)->no_doorlock = CDROM_CONFIG_FLAGS
				(drive)->xbox_eject;
			CDROM_CONFIG_FLAGS(drive)->no_eject = CDROM_CONFIG_FLAGS(drive)
				->xbox_eject;
#ifdef CONFIG_X86_XBOX
		} else {
			/* An Xbox drive in an Xbox.  We can support ejecting through
			   the SMC and support drive locking in software by ignoring
			   the eject interrupt (see arch/i386/kernel/xboxejectfix.c). */
			CDROM_CONFIG_FLAGS(drive)->no_doorlock = 0;
			CDROM_CONFIG_FLAGS(drive)->no_eject = 0;
			Xbox_simulate_drive_locked = 0;
		}
#endif
	}
#endif /* not STANDARD_ATAPI */
#endif /* not STANDARD_ATAPI */
	info->toc		= NULL;
	info->toc		= NULL;
(-) linux-2.6.6.orig/drivers/ide/ide-cd.h (+4 lines)
 Lines 93-98    Link Here 
	__u8 close_tray		: 1; /* can close the tray */
	__u8 close_tray		: 1; /* can close the tray */
	__u8 writing		: 1; /* pseudo write in progress */
	__u8 writing		: 1; /* pseudo write in progress */
	__u8 mo_drive		: 1; /* drive is an MO device */
	__u8 mo_drive		: 1; /* drive is an MO device */
#ifdef CONFIG_X86_XBOX
	__u8 xbox_drive         : 1; /* drive is an Xbox drive */
	__u8 xbox_eject         : 1; /* use Xbox SMC eject mechanism */	
#endif
	__u8 reserved		: 2;
	__u8 reserved		: 2;
	byte max_speed;		     /* Max speed of the drive */
	byte max_speed;		     /* Max speed of the drive */
};
};
(-) linux-2.6.6.orig/drivers/pci/pci.ids (+1 lines)
 Lines 2856-2861    Link Here 
	0286  NV28 [GeForce4 Ti 4200 Go AGP 8x]
	0286  NV28 [GeForce4 Ti 4200 Go AGP 8x]
	0288  NV28GL [Quadro4 980 XGL]
	0288  NV28GL [Quadro4 980 XGL]
	0289  NV28GL [Quadro4 780 XGL]
	0289  NV28GL [Quadro4 780 XGL]
	02a0  NV16 [GeForce3 MX - nForce GPU]
	0300  NV30 [GeForce FX]
	0300  NV30 [GeForce FX]
	0301  NV30 [GeForce FX 5800 Ultra]
	0301  NV30 [GeForce FX 5800 Ultra]
	0302  NV30 [GeForce FX 5800]
	0302  NV30 [GeForce FX 5800]
(-) linux-2.6.6.orig/drivers/usb/input/Kconfig (-3 / +13 lines)
 Lines 192-210    Link Here 
	  module will be called mtouchusb.
	  module will be called mtouchusb.
config USB_XPAD
config USB_XPAD
	tristate "X-Box gamepad support"
	tristate "X-Box controller (gamepad) support"
	depends on USB && INPUT
	depends on USB && INPUT
	---help---
	---help---
	  Say Y here if you want to use the X-Box pad with your computer.
	  Say Y here if you want to use Xbox controllers with your computer.
	  Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV)
	  Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV)
	  and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well.
	  and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well.
	  For information about how to connect the X-Box pad to USB, see
	  For information about how to connect an Xbox controller to USB, see
	  <file:Documentation/input/xpad.txt>.
	  <file:Documentation/input/xpad.txt>.
	  To compile this driver as a module, choose M here: the
	  To compile this driver as a module, choose M here: the
	  module will be called xpad.
	  module will be called xpad.
	  
	  
config USB_XPAD_MOUSE
       bool "Mouse emulation for Xbox controller"
       depends on USB_XPAD
       ---help---
         Say Y here if you want to enable mouse emulation for your Xbox
         controller.
         Make sure to say Y to "Mouse support" (CONFIG_INPUT_MOUSEDEV)
         and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well.
config USB_ATI_REMOTE
config USB_ATI_REMOTE
	tristate "ATI USB RF remote control"
	tristate "ATI USB RF remote control"
	depends on USB && INPUT
	depends on USB && INPUT
(-) linux-2.6.6.orig/drivers/usb/input/Makefile (+5 lines)
 Lines 4-9    Link Here 
# Multipart objects.
# Multipart objects.
usbhid-objs	:= hid-core.o
usbhid-objs	:= hid-core.o
xpad-objs     := xpad-core.o
# Optional parts of multipart objects.
# Optional parts of multipart objects.
 Lines 26-31    Link Here 
	usbhid-objs	+= hid-ff.o
	usbhid-objs	+= hid-ff.o
endif
endif
ifeq ($(CONFIG_USB_XPAD_MOUSE),y)
	xpad-objs	+= xpad-mouse.o
endif
obj-$(CONFIG_USB_AIPTEK)	+= aiptek.o
obj-$(CONFIG_USB_AIPTEK)	+= aiptek.o
obj-$(CONFIG_USB_ATI_REMOTE)	+= ati_remote.o
obj-$(CONFIG_USB_ATI_REMOTE)	+= ati_remote.o
obj-$(CONFIG_USB_HID)		+= usbhid.o
obj-$(CONFIG_USB_HID)		+= usbhid.o
(-) linux-2.6.6.orig/drivers/usb/input/xpad-core.c (+579 lines)
Line 0    Link Here 
/*
 * Xbox input device driver for Linux - v0.1.4
 *
 * Copyright (c)  2002 - 2004  Marko Friedemann <mfr@bmx-chemnitz.de>
 *
 *	Contributors:
 *		Vojtech Pavlik <vojtech@suse.sz>,
 *		Oliver Schwartz <Oliver.Schwartz@gmx.de>,
 *		Steven Toth <steve@toth.demon.co.uk>,
 *		Franz Lehner <franz@caos.at>,
 *		Ivan Hawkes <blackhawk@ivanhawkes.com>
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 *
 * This driver is based on:
 *  - information from     http://euc.jp/periphs/xbox-controller.en.html
 *  - the iForce driver    drivers/char/joystick/iforce.c
 *  - the skeleton-driver  drivers/usb/usb-skeleton.c
 *
 * Thanks to:
 *  - ITO Takayuki for providing essential xpad information on his website
 *  - Vojtech Pavlik     - iforce driver / input subsystem
 *  - Greg Kroah-Hartman - usb-skeleton driver
 *
 * TODO:
 *  - fine tune axes
 *  - fine tune mouse behaviour (should not do linear acceleration)
 *  - NEW: get rumble working correctly, fix all the bugs and support multiple
 *         simultaneous effects
 *  - NEW: split funtionality mouse/joustick into two source files
 *  - NEW: implement /proc interface (toggle mouse/rumble enable/disable, etc.)
 *  - NEW: implement user space daemon application that handles that interface
 *
 * History: moved to end of file
 */
 
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/version.h>
#include <linux/timer.h>
#include <asm/uaccess.h>
#include "xpad.h"
static struct xpad_device xpad_device[] = {
	/* please keep those ordered wrt. vendor/product ids
	  vendor, product, isMat, name                              */
	{ 0x044f, 0x0f07, 0, "Thrustmaster, Inc. Controller" },
	{ 0x045e, 0x0202, 0, "Microsoft Xbox Controller" },
	{ 0x045e, 0x0285, 0, "Microsoft Xbox Controller S" },
	{ 0x045e, 0x0289, 0, "Microsoft Xbox Controller S" }, /* microsoft is stupid */
	{ 0x046d, 0xca88, 0, "Logitech Compact Controller for Xbox" },
	{ 0x05fd, 0x1007, 0, "???Mad Catz Controller???" }, /* CHECKME: this seems strange */
	{ 0x05fd, 0x107a, 0, "InterAct PowerPad Pro" },
	{ 0x0738, 0x4516, 0, "Mad Catz Control Pad" },
	{ 0x0738, 0x4522, 0, "Mad Catz LumiCON" },
	{ 0x0738, 0x4526, 0, "Mad Catz Control Pad Pro" },
	{ 0x0738, 0x4536, 0, "Mad Catz MicroCON" },
	{ 0x0738, 0x4540, 1, "Mad Catz Beat Pad" },
	{ 0x0738, 0x4556, 0, "Mad Catz Lynx Wireless Controller" },
	{ 0x0738, 0x6040, 1, "Mad Catz Beat Pad Pro" },
	{ 0x0c12, 0x9902, 0, "HAMA VibraX - *FAULTY HARDWARE*" }, /* these are broken */
	{ 0x0e4c, 0x2390, 0, "Radica Games Jtech Controller"},	
	{ 0x0e6f, 0x0003, 0, "Logic3 Freebird wireless Controller" },
	{ 0x0f30, 0x0202, 0, "Joytech Advanced Controller" },
	{ 0x12ab, 0x8809, 1, "Xbox DDR dancepad" },
	{ 0xffff, 0xffff, 0, "Chinese-made Xbox Controller" }, /* WTF are device IDs for? */
	{ 0x0000, 0x0000, 0, "nothing detected - FAIL" }
};
static signed short xpad_btn[] = {
	BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,	/* analogue buttons */
	BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */
	BTN_0, BTN_1, BTN_2, BTN_3,			/* d-pad as buttons */
	-1						/* terminating entry */
};
static signed short xpad_mat_btn[] = {
	BTN_A, BTN_B, BTN_X, BTN_Y, 	/* A, B, X, Y */
	BTN_START, BTN_BACK, 		/* start/back */
	BTN_0, BTN_1, BTN_2, BTN_3,	/* directions, LEFT/RIGHT is mouse
					 * so we cannot use those! */
	-1				/* terminating entry */
};
static signed short xpad_abs[] = {
	ABS_X, ABS_Y,		/* left stick */
	ABS_RX, ABS_RY,		/* right stick */
	ABS_Z, ABS_RZ,		/* triggers left/right */
	ABS_HAT0X, ABS_HAT0Y,	/* digital pad */
	ABS_HAT1X, ABS_HAT1Y,	/* analogue buttons A + B */
	ABS_HAT2X, ABS_HAT2Y,	/* analogue buttons C + X */
	ABS_HAT3X, ABS_HAT3Y,	/* analogue buttons Y + Z */
	-1			/* terminating entry */
};
static struct usb_device_id xpad_table [] = {
	{ USB_INTERFACE_INFO('X', 'B', 0) },	/* Xbox USB-IF not approved class */
	{ USB_INTERFACE_INFO( 3 ,  0 , 0) },	/* for Joytech Advanced Controller */
	{ }
};
MODULE_DEVICE_TABLE(usb, xpad_table);
/**
 *	xpad_process_packet
 *
 *	Completes a request by converting the data into events
 *	for the input subsystem.
 *
 *	The report descriptor was taken from ITO Takayukis website:
 *	 http://euc.jp/periphs/xbox-controller.en.html
 */
static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data, struct pt_regs *regs)
{
	struct input_dev *dev = &xpad->dev;
	
	input_regs(dev, regs);
	/* digital pad (button mode) bits (3 2 1 0) (right left down up) */
	input_report_key(dev, BTN_0, (data[2] & 0x01));
	input_report_key(dev, BTN_1, (data[2] & 0x08) >> 3);
	input_report_key(dev, BTN_2, (data[2] & 0x02) >> 1);
	input_report_key(dev, BTN_3, (data[2] & 0x04) >> 2);	
	
	/* start and back buttons */
	input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4);
	input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5);
	
	/* buttons A, B, X, Y digital mode */
	input_report_key(dev, BTN_A, data[4]);
	input_report_key(dev, BTN_B, data[5]);
	input_report_key(dev, BTN_X, data[6]);
	input_report_key(dev, BTN_Y, data[7]);
	
	if (xpad->isMat)
		return;
	
	/* left stick */
	input_report_abs(dev, ABS_X, ((__s16) (((__s16)data[13] << 8) | data[12])));
	input_report_abs(dev, ABS_Y, ((__s16) (((__s16)data[15] << 8) | data[14])));
	
	/* right stick */
	input_report_abs(dev, ABS_RX, ((__s16) (((__s16)data[17] << 8) | data[16])));
	input_report_abs(dev, ABS_RY, ((__s16) (((__s16)data[19] << 8) | data[18])));
   	
   	/* triggers left/right */
	input_report_abs(dev, ABS_Z, data[10]);
	input_report_abs(dev, ABS_RZ, data[11]);
	
	/* digital pad (analogue mode): bits (3 2 1 0) (right left down up) */
	input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
	input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x01) - !!(data[2] & 0x02));
	/* stick press left/right */
	input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6);
	input_report_key(dev, BTN_THUMBR, data[2] >> 7);
	
	/* button A, B, X, Y analogue mode */
	input_report_abs(dev, ABS_HAT1X, data[4]);
	input_report_abs(dev, ABS_HAT1Y, data[5]);
	input_report_abs(dev, ABS_HAT2Y, data[6]);
	input_report_abs(dev, ABS_HAT3X, data[7]);
	
	/* button C (black) digital/analogue mode */
	input_report_key(dev, BTN_C, data[8]);
	input_report_abs(dev, ABS_HAT2X, data[8]);
	
	/* button Z (white) digital/analogue mode */
	input_report_key(dev, BTN_Z, data[9]);
	input_report_abs(dev, ABS_HAT3Y, data[9]);
	
	input_sync(dev);
	
	/* process input data for mouse event generation */
	xpad_mouse_process_packet(xpad, cmd, data);
}
/**
 *	xpad_irq_in
 *
 *	Completion handler for interrupt in transfers (user input).
 *	Just calls xpad_process_packet which does then emit input events.
 */
static void xpad_irq_in(struct urb *urb, struct pt_regs *regs)
{
	struct usb_xpad *xpad = urb->context;
	int retval;
	
	switch (urb->status) {
	case 0:
		/* success */
		break;
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* this urb is terminated, clean up */
		dbg("%s - urb shutting down with status: %d",
		    __FUNCTION__, urb->status);
		return;
	default:
		dbg("%s - nonzero urb status received: %d",
		    __FUNCTION__, urb->status);
		goto exit;
	}
	
	xpad_process_packet(xpad, 0, xpad->idata, regs);
	
exit:
	retval = usb_submit_urb(urb, GFP_ATOMIC);
	if (retval)
		err("%s - usb_submit_urb failed with result %d",
		    __FUNCTION__, retval);
}
/*	xpad_init_urb
 *
 *	initialize the input urb
 *	this is to be called when joystick or mouse device are opened
 */
int xpad_start_urb(struct usb_xpad *xpad)
{
	int status;
	
	// check if joystick or mouse device are opened
	if (xpad->open_count + xpad->mouse_open_count > 0)
		return 0;
	xpad->irq_in->dev = xpad->udev;
	if ((status = usb_submit_urb(xpad->irq_in, GFP_KERNEL))) {
		err("open input urb failed: %d", status);
		return -EIO;
	}
	
	return 0;
}
/**
 *	xpad_open
 *
 *	Called when a an application opens the device.
 */
static int xpad_open(struct input_dev *dev)
{
	struct usb_xpad *xpad = dev->private;
	int status;
	
	if (xpad->open_count)
		return 0;
		
	info("opening device");
	
	if ((status = xpad_start_urb(xpad)))
		return status;
		
	++xpad->open_count;
	xpad_rumble_open(xpad);
	
	return 0;
}
void xpad_stop_urb(struct usb_xpad *xpad)
{
	if (xpad->open_count + xpad->mouse_open_count > 0)
		return;
	
	usb_unlink_urb(xpad->irq_in);
}
/**
 *	xpad_close
 *
 *	Called when an application closes the device.
 */
static void xpad_close(struct input_dev *dev)
{
	struct usb_xpad *xpad = dev->private;
	
	if (--xpad->open_count)
		return;
	
	info("closing device");
	
	xpad_stop_urb(xpad);
	xpad_rumble_close(xpad);
}
/**	xpad_init_input_device
 *
 *	setup the input device for the kernel
 */
static void xpad_init_input_device(struct usb_interface *intf, struct xpad_device device)
{
	struct usb_xpad *xpad = usb_get_intfdata(intf);
	struct usb_device *udev = interface_to_usbdev(intf);
	char path[64];
	int i;
	
	xpad->dev.id.bustype = BUS_USB;
	xpad->dev.id.vendor = udev->descriptor.idVendor;
	xpad->dev.id.product = udev->descriptor.idProduct;
	xpad->dev.id.version = udev->descriptor.bcdDevice;
	xpad->dev.dev = &intf->dev;
	xpad->dev.private = xpad;
	xpad->dev.name = device.name;
	xpad->dev.phys = xpad->phys;
	xpad->dev.open = xpad_open;
	xpad->dev.close = xpad_close;
	
	usb_make_path(udev, path, 64);
	snprintf(xpad->phys, 64, "%s/input0", path);
	
	/* this was meant to allow a user space tool on-the-fly configuration
	   of driver options (mouse on, rumble on, etc)
	   yet, Vojtech said this is better done using sysfs (linux 2.6)
	   plus, it needs a patch to the input subsystem */
//	xpad->dev.ioctl = xpad_ioctl;
	if (xpad->isMat) {
		xpad->dev.evbit[0] = BIT(EV_KEY);
		for (i = 0; xpad_mat_btn[i] >= 0; ++i)
			set_bit(xpad_mat_btn[i], xpad->dev.keybit);
	} else {
		xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
		
		for (i = 0; xpad_btn[i] >= 0; ++i)
		set_bit(xpad_btn[i], xpad->dev.keybit);
		
		for (i = 0; xpad_abs[i] >= 0; ++i) {
			
			signed short t = xpad_abs[i];
			
			set_bit(t, xpad->dev.absbit);
			
			switch (t) {
			case ABS_X:
			case ABS_Y:
			case ABS_RX:
			case ABS_RY:	/* the two sticks */
				xpad->dev.absmax[t] =  32767;
				xpad->dev.absmin[t] = -32768;
				xpad->dev.absflat[t] = 128;
				xpad->dev.absfuzz[t] = 16;
				break;
			case ABS_Z:	/* left trigger */
			case ABS_RZ:	/* right trigger */
			case ABS_HAT1X:	/* analogue button A */
			case ABS_HAT1Y:	/* analogue button B */
			case ABS_HAT2X:	/* analogue button C */
			case ABS_HAT2Y:	/* analogue button X */
			case ABS_HAT3X:	/* analogue button Y */
			case ABS_HAT3Y:	/* analogue button Z */
				xpad->dev.absmax[t] = 255;
				xpad->dev.absmin[t] = 0;
				break;
			case ABS_HAT0X:
			case ABS_HAT0Y:	/* the d-pad */
				xpad->dev.absmax[t] =  1;
				xpad->dev.absmin[t] = -1;
				break;
			}
		}
		
		if (xpad_rumble_probe(udev, xpad, ifnum) != 0)
			err("could not init rumble");
	}
	input_register_device(&xpad->dev);
	printk(KERN_INFO "input: %s on %s\n", xpad->dev.name, path);
}
/**
 *	xpad_probe
 *
 *	Called upon device detection to find a suitable driver.
 *	Must return NULL when no xpad is found, else setup everything.
 */
static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct usb_device *udev = interface_to_usbdev(intf);
	struct usb_xpad *xpad = NULL;
	struct usb_endpoint_descriptor *ep_irq_in;
	int i;
	int probedDevNum = -1;	/* this takes the index into the known devices
				   array for the recognized device */
	
	// try to detect the device we are called for
	for (i = 0; xpad_device[i].idVendor; ++i) {
		if ((udev->descriptor.idVendor == xpad_device[i].idVendor) &&
		    (udev->descriptor.idProduct == xpad_device[i].idProduct)) {
			probedDevNum = i;
			break;
		}
	}
	
	// sanity check, did we recognize this device? if not, fail
	if ((probedDevNum == -1) || (!xpad_device[probedDevNum].idVendor &&
				     !xpad_device[probedDevNum].idProduct))
		return -ENODEV;
		
	if ((xpad = kmalloc (sizeof(struct usb_xpad), GFP_KERNEL)) == NULL) {
		err("cannot allocate memory for new pad");
		return -ENOMEM;
	}
	memset(xpad, 0, sizeof(struct usb_xpad));
	
	xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN,
				       SLAB_ATOMIC, &xpad->idata_dma);
	if (!xpad->idata) {
		kfree(xpad);
		return -ENOMEM;
	}
	
	/* setup input interrupt pipe (button and axis state) */
	xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
        if (!xpad->irq_in) {
		err("cannot allocate memory for new pad irq urb");
		usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
                kfree(xpad);
                return -ENOMEM;
	}
	
	ep_irq_in = &intf->altsetting[0].endpoint[0].desc;
	
	xpad->udev = udev;
	xpad->isMat = xpad_device[probedDevNum].isMat;
	
	/* init input URB for USB INT transfer from device */
	usb_fill_int_urb(xpad->irq_in, udev,
			 usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
			 xpad->idata, XPAD_PKT_LEN,
			 xpad_irq_in, xpad, ep_irq_in->bInterval);
	xpad->irq_in->transfer_dma = xpad->idata_dma;
	xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
	
	// we set this here so we can extract it in the two functions below
	usb_set_intfdata(intf, xpad);
	
	xpad_init_input_device(intf, xpad_device[probedDevNum]);
	xpad_mouse_init_input_device(intf, xpad_device[probedDevNum]);
	
	return 0;
}
/**
 *	xpad_disconnect
 *
 *	Called upon device disconnect to dispose of the structures and
 *	close the USB connections.
 */
static void xpad_disconnect(struct usb_interface *intf)
{
	struct usb_xpad *xpad = usb_get_intfdata(intf);
	
	usb_set_intfdata(intf, NULL);
	if (xpad) {
		info( "disconnecting device" );
		usb_unlink_urb(xpad->irq_in);
		xpad_rumble_close(xpad);
		input_unregister_device(&xpad->dev);
		
		usb_free_urb(xpad->irq_in);
		xpad_mouse_cleanup(xpad);
		
		usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN,
				xpad->idata, xpad->idata_dma);
	
		xpad_rumble_disconnect(xpad);
		
		kfree(xpad);
	}
}
/******************* Linux driver framework specific stuff ************/
static struct usb_driver xpad_driver = {
	.owner		= THIS_MODULE,
	.name		= "xpad",
	.probe		= xpad_probe,
	.disconnect	= xpad_disconnect,
	.id_table	= xpad_table,
};
/**
 * driver init entry point
 */
static int __init usb_xpad_init(void)
{
	int result = usb_register(&xpad_driver);
	if (result == 0)
		info(DRIVER_DESC " " DRIVER_VERSION);
	return result;
}
/**
 * driver exit entry point
 */
static void __exit usb_xpad_exit(void)
{
	usb_deregister(&xpad_driver);
}
module_init(usb_xpad_init);
module_exit(usb_xpad_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/*
 *  driver history
 * ----------------
 *
 * 2003-05-15 - 0.1.2 : ioctls, dynamic mouse/rumble activation, /proc fs
 *  - added some /proc files for informational purposes (readonly right now)
 *  - added init parameters for mouse/rumble activation upon detection
 *  - added dynamic changes to mouse events / rumble effect generation via
 *    ioctls - NOTE: this requires a currently unofficial joydev patch!
 *
 * 2003-04-29 - 0.1.1 : minor cleanups, some comments
 *  - fixed incorrect handling of unknown devices (please try ir dongle now)
 *  - fixed input URB length (the 256 bytes from 0.1.0 broke everything for the
 *    MS controller as well as my Interact device, set back to 32 (please
 *    REPORT problems BEFORE any further changes here, since those can be fatal)
 *  - fixed rumbling for MS controllers (need 6 bytes output report)
 *  - dropped kernel-2.5 ifdefs, much more readable now
 *  - preparation for major rework under way, stay tuned
 *
 * 2003-03-25 - 0.1.0 : (Franz) Some Debuggin
 *  - Better Handling
 *  - X/Y support, Speed differenting
 *  - Landing Zone, Dead Zone, Offset kompensation, Zero-adjustment, .... aso.
 *  - Removed Wheel handling in Mouse Emulation .. sensless..
 *
 * 2003-01-23 - 0.1.0-pre : added mouse emulation and rumble support
 *  - can provide mouse emulation (compile time switch)
 *    this code has been taken from Oliver Schwartz' xpad-mouse driver
 *  - basic rumble support (compile time switch)        EXPERIMENTAL!  
 *
 * 2002-08-05 - 0.0.6 : added analog button support
 *
 * 2002-07-17 - 0.0.5 : (Vojtech Pavlik) rework
 *  - simplified d-pad handling
 *
 * 2002-07-16 - 0.0.4 : minor changes, merge with Vojtech's v0.0.3
 *  - verified the lack of HID and report descriptors
 *  - verified that ALL buttons WORK
 *  - fixed d-pad to axes mapping
 *
 * 2002-07-14 - 0.0.3 : (Vojtech Pavlik) rework
 *  - indentation fixes
 *  - usb + input init sequence fixes
 *
 * 2002-07-02 - 0.0.2 : basic working version
 *  - all axes and 9 of the 10 buttons work (german InterAct device)
 *  - the black button does not work
 *
 * 2002-06-27 - 0.0.1 : first version, just said "XBOX HID controller"
 */
(-) linux-2.6.6.orig/drivers/usb/input/xpad-mouse.c (+270 lines)
Line 0    Link Here 
/*
 * Xbox input device driver for Linux - v0.1.4
 *
 *	mouse emulation stuff, merged from Olivers xpad-mouse
 *
 * Copyright (c)  2003, 2004  Marko Friedemann <mfr@bmx-chemnitz.de>
 *	portions Copyright (c)	2002  Oliver Schwartz <Oliver.Schwartz@gmx.de>,
 *				2003  Franz Lehner <franz@chaos.at>
 *
 * Released under GPL. See xpad-core.c for details
 */
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/proc_fs.h>
#include <linux/usb.h>
#include <linux/version.h>
#include <linux/timer.h>
#include <asm/uaccess.h>
#define __USB_XPAD_MOUSE
#include "xpad.h"
#undef __USB_XPAD_MOUSE
#define XPAD_WHEELBRAKE		20
#define JOY_DeadZone_fast	6000
#define JOY_DeadZone_slow	200
#define XPAD_OFFSET_COUNTER	5
static int mouse_on_load = 1;
MODULE_PARM( mouse_on_load, "i" );
MODULE_PARM_DESC( mouse_on_load, "set to 0 to deactivate mouse support on insmod (default 1)" );
/**
 *	xpad_removedeadzone
 *
 *	Franz? Please clarify and correct.
 *
 *	Removes the deadzone for mouse operation.
 *	Allows for better handling near the stick's center.
 */   
static int xpad_mouse_removedeadzone(signed int position, int speed, int deadzone)
{
	if (position>31000) position=31000;
	if (position<-31000) position=-31000; 
	
	if ((position>0)&(position<deadzone)) return 0;
	if ((position<0)&(position>(-deadzone))) return 0;
	if (position>deadzone) position -= deadzone;	
	if (position<(-(deadzone))) position+= deadzone;	
	position = (int)(position / speed);
	return position;
}
void xpad_mouse_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
{
        struct input_dev *dev_mouse = &xpad->dev_mouse;
	
        int signledirection, xyspeed;
        //int joy_y2;
	unsigned char MouseLeft,MouseRight, MouseMiddle;
        signed int left_joy_x, left_joy_y, right_joy_x, right_joy_y;
	
	if (!xpad->mouse_open_count || !xpad->mouse_enabled)
		return;
	
	left_joy_x = ((__s16) (((__s16)data[13] << 8) | data[12]));
	left_joy_y = ((__s16) (((__s16)data[15] << 8) | data[14]));
	
	right_joy_x = ((__s16) (((__s16)data[17] << 8) | data[16]));
	right_joy_y = ((__s16) (((__s16)data[19] << 8) | data[18]));
	
	// Creates Offset when first starting
	/* CHECKME: who coded this? Franz? Please clarify:
		1) is this necessary for joystick operation?
		2) offset_counter was only defined when MOUSE
		   support was configured (has been FIXED, see above) */
	if (xpad->offsetset_compensation>0) {
		
		if (xpad->offsetset_compensation == XPAD_OFFSET_COUNTER) {
			xpad->left_offset_x  = left_joy_x;
			xpad->left_offset_y  = left_joy_y;
			xpad->right_offset_x = right_joy_x;
			xpad->right_offset_y = right_joy_y;  
		} else {
			xpad->left_offset_x  += left_joy_x;
			xpad->left_offset_y  += left_joy_y;
			xpad->right_offset_x += right_joy_x;
			xpad->right_offset_y += right_joy_y;  
		}
		
		if (xpad->offsetset_compensation == 1) {
			xpad->left_offset_x  = xpad->left_offset_x  / XPAD_OFFSET_COUNTER;
			xpad->left_offset_y  = xpad->left_offset_y  / XPAD_OFFSET_COUNTER;
			xpad->right_offset_x = xpad->right_offset_x / XPAD_OFFSET_COUNTER;
			xpad->right_offset_y = xpad->right_offset_y / XPAD_OFFSET_COUNTER;  
		}
		
		xpad->offsetset_compensation--;
	}
	
	left_joy_x -= xpad->left_offset_x;
	left_joy_y -= xpad->left_offset_y;
	
	right_joy_x -= xpad->right_offset_x;
	right_joy_y -= xpad->right_offset_y;
	
	if (data[11]<0x10) {
		// Normal Speed Mode
		xpad->rel_x =  (xpad_mouse_removedeadzone(left_joy_x,0x1500,JOY_DeadZone_fast));
		xpad->rel_y = -(xpad_mouse_removedeadzone(left_joy_y,0x1500,JOY_DeadZone_fast));
		xyspeed = 2;
		//printk("%d:",xpad->rel_y);
	} else {
		// Ultra Slow Mode                                                 
		xpad->rel_x =  (xpad_mouse_removedeadzone(left_joy_x,0x3500,JOY_DeadZone_slow));
		xpad->rel_y = -(xpad_mouse_removedeadzone(left_joy_y,0x3500,JOY_DeadZone_slow));    
		xyspeed = 1;
	}
	
	// X-Y Steering
	signledirection=1;
	if (signledirection&((data[2] & 0x04)!=0)) { signledirection=0; xpad->rel_x -=xyspeed; }
	if (signledirection&((data[2] & 0x08)!=0)) { signledirection=0; xpad->rel_x +=xyspeed; }
	if (signledirection&((data[2] & 0x02)!=0)) { signledirection=0; xpad->rel_y +=xyspeed; }
	if (signledirection&((data[2] & 0x01)!=0)) { signledirection=0; xpad->rel_y -=xyspeed; }
  	
	/* wheel handling */
	//joy_y2 = xpad_mouse_removedeadzone(joy_y2);
	//xpad->rel_wheel = (joy_y2>0)?1:(joy_y2<0)?-1:0;
	xpad->rel_wheel=0;
	
	if (data[10]==0xFF) MouseLeft=1; else MouseLeft =0;
	if ((MouseLeft==0)&(data[7]!=0)) MouseLeft =1;
	if ((MouseLeft==0)&(data[4]!=0)) MouseLeft = 1;
	if ((MouseLeft==0)&((data[2] >> 7)!=0)) MouseLeft = 1;
	if ((MouseLeft==0)&(((data[2] & 0x40) >> 6)!=0)) MouseLeft = 1;
	
	if (data[5]!=0) MouseRight=1; else MouseRight=0;
	if (data[6]!=0) MouseMiddle =1; else MouseMiddle=0;
	
	// Generating Mouse Emulation Events  (Button Events)
	input_report_key(dev_mouse, BTN_LEFT, MouseLeft);
	input_report_key(dev_mouse, BTN_RIGHT, MouseRight);
	input_report_key(dev_mouse, BTN_MIDDLE, MouseMiddle);
	
	input_sync(dev_mouse);
}
/**
 *	xpad_timer
 *
 *	Reports the mouse events in the interval given in xpad_open.
 *
 *	Taken from Oliver Schwartz' xpad-mouse driver to avoid strange mouse
 *	 behaviour encountered when the input events where send directly
 *	 in xpad_process_packet.
 */
static void xpad_timer(unsigned long data)
{
	struct usb_xpad *xpad = (struct usb_xpad *)data;
	if (xpad->mouse_enabled) {
		input_report_rel(&xpad->dev_mouse, REL_X, xpad->rel_x);
		input_report_rel(&xpad->dev_mouse, REL_Y, xpad->rel_y); 
		
		input_sync(&xpad->dev_mouse);
	
		/*if (xpad->rel_wheeltimer == 0) {
			input_report_rel(&xpad->dev_mouse, REL_WHEEL, xpad->rel_wheel);
			xpad->rel_wheeltimer = XPAD_WHEELBRAKE;
		} else
			xpad->rel_wheeltimer--;*/
	}
	
	// reschedule the timer so that it fires continually
	add_timer(&xpad->timer);
}
static int xpad_mouse_open(struct input_dev *dev)
{
	struct usb_xpad *xpad = dev->private;
	int status;
	
	if (xpad->mouse_open_count)
		return 0;
	
	if ((status = xpad_start_urb(xpad)))
		return status;
		
	++xpad->mouse_open_count;
	
	info("opening mouse device");
	// set up timer for mouse event generation
	init_timer(&xpad->timer);
	xpad->timer.expires = 1*HZ/5; /* every 200 ms */
	xpad->timer.data = (unsigned long)xpad;
	xpad->timer.function = xpad_timer;
	// now start the timer
	add_timer(&xpad->timer);
	
	return 0;
}
static void xpad_mouse_close(struct input_dev *dev)
{
	struct usb_xpad *xpad = dev->private;
	
	if (--xpad->mouse_open_count)
		return;
		
	xpad_stop_urb(xpad);
	
	info("closing mouse device"); 
	del_timer(&xpad->timer);
}
int xpad_mouse_init_input_device(struct usb_interface *intf, struct xpad_device device)
{
	struct usb_xpad *xpad = usb_get_intfdata(intf);
	struct usb_device *udev = interface_to_usbdev(intf);
	/* the mouse device struct for the kernel (mouse emulation) */
	xpad->dev_mouse.id.bustype = BUS_USB;
	xpad->dev_mouse.id.vendor = udev->descriptor.idVendor;
	xpad->dev_mouse.id.product = udev->descriptor.idProduct;
	xpad->dev_mouse.id.version = udev->descriptor.bcdDevice;
	xpad->dev_mouse.dev = &intf->dev;
	xpad->dev_mouse.private = xpad;
	xpad->dev_mouse.name = device.name;
	xpad->dev_mouse.phys = xpad->phys;
	xpad->dev_mouse.open = xpad_mouse_open;
	xpad->dev_mouse.close = xpad_mouse_close;
	xpad->offsetset_compensation = XPAD_OFFSET_COUNTER; // Find new offset point
	xpad->mouse_enabled = mouse_on_load;
	
	/* mouse setup */
	xpad->dev_mouse.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
	set_bit(REL_X,     xpad->dev_mouse.relbit);
	set_bit(REL_Y,     xpad->dev_mouse.relbit);
	set_bit(REL_WHEEL, xpad->dev_mouse.relbit);
	set_bit(BTN_LEFT,   xpad->dev_mouse.keybit);
	set_bit(BTN_RIGHT,  xpad->dev_mouse.keybit);
	set_bit(BTN_MIDDLE, xpad->dev_mouse.keybit);
	set_bit(BTN_SIDE,   xpad->dev_mouse.keybit);
	set_bit(BTN_EXTRA,  xpad->dev_mouse.keybit);
	
	input_register_device(&xpad->dev_mouse);
	printk(KERN_INFO "input: mouse emulation %s@ %s\n",
	       (mouse_on_load ? "" : "(disabled) "), xpad->dev_mouse.name);
}
void xpad_mouse_cleanup(struct usb_xpad *xpad)
{
	// the timer exists only when the mouse device is used
	if (xpad->mouse_open_count)
		del_timer(&xpad->timer);
	input_unregister_device(&xpad->dev_mouse);
}
(-) linux-2.6.6.orig/drivers/usb/input/xpad.h (+167 lines)
Line 0    Link Here 
/*
 * Xbox Controller driver for Linux - v0.1.4
 *
 *	header file containing ioctl definitions
 *
 * Copyright (c)  2003  Marko Friedemann <mfr@bmx-chemnitz.de>
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
 
#ifndef __XPAD_h
#define __XPAD_h
/*********** ioctl stuff, can be used outside of the driver ***********/
#define USB_XPAD_IOC_MAGIC 	'x'
#define USB_XPAD_IOCRESET 	_IO(  USB_XPAD_IOC_MAGIC, 0 )
#define USB_XPAD_IOCSMOUSE 	_IOW( USB_XPAD_IOC_MAGIC, 1, int )
#define USB_XPAD_IOCGMOUSE 	_IOR( USB_XPAD_IOC_MAGIC, 2, int )
#define USB_XPAD_IOCSRUMBLE 	_IOW( USB_XPAD_IOC_MAGIC, 3, int )
#define USB_XPAD_IOCGRUMBLE 	_IOR( USB_XPAD_IOC_MAGIC, 4, int )
#define USB_XPAD_IOCSIR 	_IOW( USB_XPAD_IOC_MAGIC, 5, int )
#define USB_XPAD_IOCGIR 	_IOR( USB_XPAD_IOC_MAGIC, 6, int )
#define USB_XPAD_IOC_MAXNR 	6
/************************* driver internals ***************************/
#ifdef __KERNEL__
#include <linux/input.h>
#include <linux/circ_buf.h>
/****************** driver description and version ********************/
#define DRIVER_VERSION		"v0.1.4"
#define DRIVER_AUTHOR		"Marko Friedemann <mfr@bmx-chemnitz.de>,\
 Oliver Schwartz <Oliver.Schwartz@gmx.de>, Georg Lukas <georg@op-co.de>"
#ifdef CONFIG_USB_XPAD_MOUSE
#define DRIVER_DESC		"driver for Xbox controllers with mouse emulation"
#else
#define DRIVER_DESC		"driver for Xbox controllers"
#endif
/****************************** constants *****************************/
#define XPAD_MAX_DEVICES	4
#define XPAD_PKT_LEN		32	/* input packet size */
#define XPAD_PKT_LEN_FF		6	/* output packet size - rumble */
#define XPAD_TX_BUFSIZE		XPAD_PKT_LEN_FF * 8	/* max. 8 requests */
/************************* the device struct **************************/
struct usb_xpad {
	struct input_dev dev;			/* input device interface */
	struct usb_device *udev;		/* usb device */
	
	struct urb *irq_in;			/* urb for int. in report */
	unsigned char *idata;			/* input data */
	dma_addr_t idata_dma;
	
	char phys[65];				/* physical input dev path */
	
	int open_count;				/* reference count */
	unsigned char offsetset_compensation;
	int left_offset_x;
	int left_offset_y;
	int right_offset_x;
	int right_offset_y;
	
	int isMat;				/* is this a dancepad/mat? */
	
#ifdef CONFIG_USB_XPAD_RUMBLE
	int rumble_enabled;			/* ioctl can toggle rumble */
	
	int ep_out_adr;				/* number of out endpoint */
	unsigned char tx_data[XPAD_PKT_LEN_FF];	/* output data (rumble) */
	int strong_rumble, play_strong;		/* strong rumbling */
	int weak_rumble, play_weak;		/* weak rumbling */
	struct timer_list rumble_timer;		/* timed urb out retry */
	wait_queue_head_t wait;			/* wait for URBs on queue */
	
	spinlock_t tx_lock;
	struct circ_buf tx;
	unsigned char tx_buf[XPAD_TX_BUFSIZE];
	long tx_flags[1];			/* transmit flags */
#endif
	
#ifdef CONFIG_USB_XPAD_MOUSE
	struct input_dev dev_mouse;		/* mouse device interface */
	int mouse_open_count;			/* reference count */
	int mouse_enabled;			/* ioctl can toggle rumble */
	
	int rel_x;
	int rel_y;
	int rel_wheel;
	int rel_wheeltimer;
	struct timer_list timer;		/* timed mouse input events */
#endif
};
/* for the list of know devices */
struct xpad_device {
	u16 idVendor;
	u16 idProduct;
	u8  isMat;
	char *name;
};
#ifdef __USB_XPAD_MOUSE
 extern int xpad_start_urb(struct usb_xpad *xpad);
 extern void xpad_stop_urb(struct usb_xpad *xpad);
#endif
/************************ mouse function stubs ************************/
#ifndef CONFIG_USB_XPAD_MOUSE
 #define mouse_open_count open_count
 #define xpad_mouse_process_packet(xpad, cmd, data) {}
 #define xpad_mouse_init_input_device(intf, device) {}
 #define xpad_mouse_cleanup(xpad) {}
#else /* CONFIG_USB_XPAD_MOUSE */
 #ifndef __USB_XPAD_MOUSE
  extern void xpad_mouse_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data);
  extern void xpad_mouse_init_input_device(struct usb_interface *intf, struct xpad_device device);
  extern void xpad_mouse_cleanup(struct usb_xpad *xpad);
 #endif /* __USB_XPAD_MOUSE */
#endif /* CONFIG_USB_XPAD_MOUSE */
/************************ rumble function stubs ***********************/
#ifndef CONFIG_USB_XPAD_RUMBLE
 #define xpad_rumble_ioctl(dev, cmd, arg) -ENOTTY
 #define xpad_rumble_open(xpad) {}
 #define xpad_rumble_probe(udev, xpad, ifnum) 0
 #define xpad_rumble_close(xpad) {}
 #define xpad_rumble_disconnect(xpad) {}
#else /* CONFIG_USB_XPAD_RUMBLE */
 #define XPAD_TX_RUNNING	0
 #define XPAD_TX_INC(var, n)	(var) += n; (var) %= XPAD_TX_BUFSIZE
 #ifndef __USB_XPAD_RUMBLE
  extern int  xpad_rumble_ioctl(struct input_dev *dev, unsigned int cmd, unsigned long arg);
  extern void xpad_rumble_open(struct usb_xpad *xpad);
  extern int  xpad_rumble_probe(struct usb_device *udev, struct usb_xpad *xpad, unsigned int ifnum);
  extern void xpad_rumble_close(struct usb_xpad *xpad);
  extern void xpad_rumble_disconnect(struct usb_xpad *xpad);
 #endif /* __USB_XPAD_RUMBLE */
#endif /* CONFIG_USB_XPAD_RUMBLE */
#endif /* __KERNEL__ */
#endif /* __XPAD_h */
(-) linux-2.6.6.orig/drivers/video/Kconfig (+10 lines)
 Lines 405-410    Link Here 
	  To compile this driver as a module, choose M here: the
	  To compile this driver as a module, choose M here: the
	  module will be called rivafb.
	  module will be called rivafb.
config FB_XBOX
	tristate "nVidia Xbox support"
	depends on FB && PCI && I2C_XBOX && EXPERIMENTAL
	help
	  This driver supports the graphics chip of the Microsoft Xbox. 
	  Say Y if you have an Xbox, N otherwise
	  To compile this driver as a module, choose M here: the
	  module will be called xboxfb.
config FB_I810
config FB_I810
	tristate "Intel 810/815 support (EXPERIMENTAL)"
	tristate "Intel 810/815 support (EXPERIMENTAL)"
	depends on FB && AGP && AGP_INTEL && EXPERIMENTAL && PCI	
	depends on FB && AGP && AGP_INTEL && EXPERIMENTAL && PCI	
(-) linux-2.6.6.orig/drivers/video/Makefile (+1 lines)
 Lines 56-61    Link Here 
obj-$(CONFIG_FB_MATROX)		  += matrox/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_MATROX)		  += matrox/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_RIVA)		  += riva/ cfbimgblt.o vgastate.o 
obj-$(CONFIG_FB_RIVA)		  += riva/ cfbimgblt.o vgastate.o 
obj-$(CONFIG_FB_XBOX)		  += xbox/ cfbimgblt.o vgastate.o 
obj-$(CONFIG_FB_SIS)		  += sis/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_SIS)		  += sis/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_ATY)		  += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_ATY)		  += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_ATY128)		  += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_ATY128)		  += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
(-) linux-2.6.6.orig/drivers/video/fbmem.c (+5 lines)
 Lines 123-128    Link Here 
extern int sgivwfb_setup(char*);
extern int sgivwfb_setup(char*);
extern int rivafb_init(void);
extern int rivafb_init(void);
extern int rivafb_setup(char*);
extern int rivafb_setup(char*);
extern int xboxfb_init(void);
extern int xboxfb_setup(char*);
extern int tdfxfb_init(void);
extern int tdfxfb_init(void);
extern int tdfxfb_setup(char*);
extern int tdfxfb_setup(char*);
extern int tridentfb_init(void);
extern int tridentfb_init(void);
 Lines 218-223    Link Here 
#ifdef CONFIG_FB_RIVA
#ifdef CONFIG_FB_RIVA
	{ "rivafb", rivafb_init, rivafb_setup },
	{ "rivafb", rivafb_init, rivafb_setup },
#endif
#endif
#ifdef CONFIG_FB_XBOX
	{ "xboxfb", xboxfb_init, xboxfb_setup },
#endif
#ifdef CONFIG_FB_3DFX
#ifdef CONFIG_FB_3DFX
	{ "tdfxfb", tdfxfb_init, tdfxfb_setup },
	{ "tdfxfb", tdfxfb_init, tdfxfb_setup },
#endif
#endif
(-) linux-2.6.6.orig/drivers/video/xbox/Makefile (+7 lines)
Line 0    Link Here 
#
# Makefile for the Xbox framebuffer driver
#
obj-$(CONFIG_FB_XBOX) += xboxfb.o
xboxfb-objs := fbdev.o riva_hw.o nv_driver.o encoder-i2c.o encoder.o focus.o conexant.o xlb.o
(-) linux-2.6.6.orig/drivers/video/xbox/conexant.c (+639 lines)
Line 0    Link Here 
/*
 * linux/drivers/video/riva/conexant.c - Xbox driver for conexant chip
 *
 * Maintainer: Oliver Schwartz <Oliver.Schwartz@gmx.de>
 *
 * Contributors:
 * 
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 *
 * Known bugs and issues:
 *
 *      none
 */
#include "conexant.h"
#include "focus.h"
#define ADR(x) (x / 2 - 0x17)
typedef struct {
	long v_activeo;
	long v_linesi;
	long h_clki;
	long h_clko;
	long h_blanki;
	long h_blanko;
	long v_blanki;
	long v_blanko;
	long vscale;
	double clk_ratio;
} xbox_tv_mode_parameter;
	// and here is all the video timing for every standard
static const conexant_video_parameter vidstda[] = {
	{ 3579545.00, 0.0000053, 0.00000782, 0.0000047, 0.000063555, 0.0000094, 0.000035667, 0.0000015, 243, 262.5, 0.0000092 },
	{ 3579545.00, 0.0000053, 0.00000782, 0.0000047, 0.000064000, 0.0000094, 0.000035667, 0.0000015, 243, 262.5, 0.0000092 },
	{ 4433618.75, 0.0000056, 0.00000785, 0.0000047, 0.000064000, 0.0000105, 0.000036407, 0.0000015, 288, 312.5, 0.0000105 },
	{ 4433618.75, 0.0000056, 0.00000785, 0.0000047, 0.000064000, 0.0000094, 0.000035667, 0.0000015, 288, 312.5, 0.0000092 },
	{ 3582056.25, 0.0000056, 0.00000811, 0.0000047, 0.000064000, 0.0000105, 0.000036407, 0.0000015, 288, 312.5, 0.0000105 },
	{ 3575611.88, 0.0000058, 0.00000832, 0.0000047, 0.000063555, 0.0000094, 0.000035667, 0.0000015, 243, 262.5, 0.0000092 },
	{ 4433619.49, 0.0000053, 0.00000755, 0.0000047, 0.000063555, 0.0000105, 0.000036407, 0.0000015, 243, 262.5, 0.0000092 }
};
static const unsigned char default_mode[] = {
	0x00,
	0x00, 0x28, 0x80, 0xE4, 0x00, 0x00, 0x80, 0x80,
	0x80, 0x13, 0xDA, 0x4B, 0x28, 0xA3, 0x9F, 0x25,
	0xA3, 0x9F, 0x25, 0x00, 0x00, 0x00, 0x00, 0x44,
	0xC7, 0x00, 0x00, 0x41, 0x35, 0x03, 0x46, 0x00,
	0x02, 0x00, 0x01, 0x60, 0x88, 0x8a, 0xa6, 0x68,
	0xc1, 0x2e, 0xf2, 0x27, 0x00, 0xb0, 0x0a, 0x0b,
	0x71, 0x5a, 0xe0, 0x36, 0x00, 0x50, 0x72, 0x1c,
	0x0d, 0x24, 0xf0, 0x58, 0x81, 0x49, 0x8c, 0x0c,
	0x8c, 0x79, 0x26, 0x52, 0x00, 0x24, 0x00, 0x00,
	0x00, 0x00, 0x01, 0x9C, 0x9B, 0xC0, 0xC0, 0x19,
	0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x57, 0x20,
	0x40, 0x6E, 0x7E, 0xF4, 0x51, 0x0F, 0xF1, 0x05,
	0xD3, 0x78, 0xA2, 0x25, 0x54, 0xA5, 0x00, 0x00
};
static const double pll_base = 13.5e6;
static void conexant_calc_blankings(
	xbox_video_mode * mode,
	xbox_tv_mode_parameter * param
);
static int conexant_calc_mode_params(
	xbox_video_mode * mode,
	xbox_tv_mode_parameter * param
);
static double fabs(double d) {
	if (d > 0) return d;
	else return -d;
}
int conexant_calc_vga_mode(
	xbox_av_type av_type,
	unsigned char pll_int,
	unsigned char * regs
){
	memset(regs, 0, NUM_CONEXANT_REGS);
	// Protect against overclocking
	if (pll_int > 36) {
		pll_int = 36; // 36 / 6 * 13.5 MHz = 81 MHz, just above the limit.
	}
	if (pll_int == 0) {
		pll_int = 1;  // 0 will cause a burnout ...
	}
	if (av_type == AV_VGA) {
		// use internal sync signals
		regs[ADR(0x2e)] = 0xbd; // HDTV_EN = 1, RPR_SYNC_DIS = 1, BPB_SYNC_DIS = 1, GY_SYNC_DIS=1, HD_SYNC_EDGE = 1, RASTER_SEL = 01
	}
	else {
 		// use sync on green
		regs[ADR(0x2e)] = 0xad; // HDTV_EN = 1, RPR_SYNC_DIS = 1, BPB_SYNC_DIS = 1, HD_SYNC_EDGE = 1, RASTER_SEL = 01
	}
	regs[ADR(0x32)] = 0x48; // DRVS = 2, IN_MODE[3] = 1;
	regs[ADR(0x3c)] = 0x80; // MCOMPY
	regs[ADR(0x3e)] = 0x80; // MCOMPU
	regs[ADR(0x40)] = 0x80; // MCOMPV
	regs[ADR(0xc6)] = 0x98; // IN_MODE = 24 bit RGB multiplexed
	regs[ADR(0x6c)] = 0x46; // FLD_MODE = 10, EACTIVE = 1, EN_SCART = 0, EN_REG_RD = 1
	regs[ADR(0x9c)] = 0x00; // PLL_FRACT
	regs[ADR(0x9e)] = 0x00; // PLL_FRACT
	regs[ADR(0xa0)] = pll_int; // PLL_INT
	regs[ADR(0xba)] = 0x28; // SLAVER = 1, DACDISD = 1
	regs[ADR(0xce)] = 0xe1; // OUT_MUXA = 01, OUT_MUXB = 00, OUT_MUXC = 10, OUT_MUXD = 11
	regs[ADR(0xd6)] = 0x0c; // OUT_MODE = 11 (RGB / SCART / HDTV)
	return 1;
}
int conexant_calc_hdtv_mode(
	xbox_hdtv_mode hdtv_mode,
	unsigned char pll_int,
	unsigned char * regs
){
	memset(regs, 0, NUM_CONEXANT_REGS);
	// Protect against overclocking
	if (pll_int > 36) {
		pll_int = 36; // 36 / 6 * 13.5 MHz = 81 MHz, just above the limit.
	}
	if (pll_int == 0) {
		pll_int = 1;  // 0 will cause a burnout ...
	}
	switch (hdtv_mode) {
		case HDTV_480p:
			// use sync on green
			regs[ADR(0x2e)] = 0xed; // HDTV_EN = 1, RGB2PRPB = 1, RPR_SYNC_DIS = 1, BPB_SYNC_DIS = 1, HD_SYNC_EDGE = 1, RASTER_SEL = 01
			regs[ADR(0x32)] = 0x48; // DRVS = 2, IN_MODE[3] = 1;
			regs[ADR(0x3e)] = 0x45; // MCOMPU
			regs[ADR(0x40)] = 0x51; // MCOMPV
			break;
		case HDTV_720p:
			// use sync on green
			regs[ADR(0x2e)] = 0xea; // HDTV_EN = 1, RGB2PRPB = 1, RPR_SYNC_DIS = 1, BPB_SYNC_DIS = 1, HD_SYNC_EDGE = 1, RASTER_SEL = 01
			regs[ADR(0x32)] = 0x49; // DRVS = 2, IN_MODE[3] = 1, CSC_SEL=1;
			regs[ADR(0x3e)] = 0x45; // MCOMPU
			regs[ADR(0x40)] = 0x51; // MCOMPV
			break;
		case HDTV_1080i:
			// use sync on green
			regs[ADR(0x2e)] = 0xeb; // HDTV_EN = 1, RGB2PRPB = 1, RPR_SYNC_DIS = 1, BPB_SYNC_DIS = 1, HD_SYNC_EDGE = 1, RASTER_SEL = 01
			regs[ADR(0x32)] = 0x49; // DRVS = 2, IN_MODE[3] = 1, CSC_SEL=1;
			regs[ADR(0x3e)] = 0x48; // MCOMPU
			regs[ADR(0x40)] = 0x5b; // MCOMPV
			break;
	}
	regs[ADR(0x3c)] = 0x80; // MCOMPY
	regs[ADR(0xa0)] = pll_int; // PLL_INT
	regs[ADR(0xc6)] = 0x98; // IN_MODE = 24 bit RGB multiplexed
	regs[ADR(0x6c)] = 0x46; // FLD_MODE = 10, EACTIVE = 1, EN_SCART = 0, EN_REG_RD = 1
	regs[ADR(0x9c)] = 0x00; // PLL_FRACT
	regs[ADR(0x9e)] = 0x00; // PLL_FRACT
	regs[ADR(0xba)] = 0x28; // SLAVER = 1, DACDISD = 1
	regs[ADR(0xce)] = 0xe1; // OUT_MUXA = 01, OUT_MUXB = 00, OUT_MUXC = 10, OUT_MUXD = 11
	regs[ADR(0xd6)] = 0x0c; // OUT_MODE = 11 (RGB / SCART / HDTV)
	return 1;
}
int conexant_calc_mode(xbox_video_mode * mode, struct riva_regs * riva_out)
{
	unsigned char b;
	unsigned int m = 0;
	double dPllOutputFrequency;
	xbox_tv_mode_parameter param;
	char* regs = riva_out->encoder_mode;
	if (conexant_calc_mode_params(mode, &param))
	{
		// copy default mode settings
		memcpy(regs,default_mode,sizeof(default_mode));
		regs[ADR(0x32)] = 0x28; // DRVS = 1, IN_MODE[3] = 1;
		// H_CLKI
		b=regs[ADR(0x8e)]&(~0x07);
		regs[ADR(0x8e)] = ((param.h_clki>>8)&0x07)|b;
		regs[ADR(0x8a)] = ((param.h_clki)&0xff);
		// H_CLKO
		b=regs[ADR(0x86)]&(~0x0f);
		regs[ADR(0x86)] = ((param.h_clko>>8)&0x0f)|b;
		regs[ADR(0x76)] = ((param.h_clko)&0xff);
		// V_LINESI
		b=regs[ADR(0x38)]&(~0x02);
		regs[ADR(0x38)] = ((param.v_linesi>>9)&0x02)|b;
		b=regs[ADR(0x96)]&(~0x03);
		regs[ADR(0x96)] = ((param.v_linesi>>8)&0x03)|b;
		regs[ADR(0x90)] = ((param.v_linesi)&0xff);
		// V_ACTIVEO
		/* TODO: Absolutely not sure about other modes than plain NTSC / PAL */
		switch(mode->tv_encoding) {
			case TV_ENC_NTSC:
			case TV_ENC_NTSC60:
			case TV_ENC_PALM:
			case TV_ENC_PAL60:
				m=param.v_activeo + 1;
				break;
			case TV_ENC_PALBDGHI:
				m=param.v_activeo + 2;
				break;
			default:
				m=param.v_activeo + 2;
				break;
		}
		b=regs[ADR(0x86)]&(~0x80);
		regs[ADR(0x86)] = ((m>>1)&0x80)|b;
		regs[ADR(0x84)] = ((m)&0xff);
		// H_ACTIVE
		b=regs[ADR(0x86)]&(~0x70);
		regs[ADR(0x86)] = (((mode->xres + 5)>>4)&0x70)|b;
		regs[ADR(0x78)] = ((mode->xres + 5)&0xff);
		// V_ACTIVEI
		b=regs[ADR(0x96)]&(~0x0c);
		regs[ADR(0x96)] = ((mode->yres>>6)&0x0c)|b;
		regs[ADR(0x94)] = ((mode->yres)&0xff);
		// H_BLANKI
		b=regs[ADR(0x38)]&(~0x01);
		regs[ADR(0x38)] = ((param.h_blanki>>9)&0x01)|b;
		b=regs[ADR(0x8e)]&(~0x08);
		regs[ADR(0x8e)] = ((param.h_blanki>>5)&0x08)|b;
		regs[ADR(0x8c)] = ((param.h_blanki)&0xff);
		// H_BLANKO
		b=regs[ADR(0x9a)]&(~0xc0);
		regs[ADR(0x9a)] = ((param.h_blanko>>2)&0xc0)|b;
		regs[ADR(0x80)] = ((param.h_blanko)&0xff);
		// V_SCALE
		b=regs[ADR(0x9a)]&(~0x3f);
		regs[ADR(0x9a)] = ((param.vscale>>8)&0x3f)|b;
		regs[ADR(0x98)] = ((param.vscale)&0xff);
		// V_BLANKO
		regs[ADR(0x82)] = ((param.v_blanko)&0xff);
		// V_BLANKI
		regs[ADR(0x92)] = ((param.v_blanki)&0xff);
		{
			unsigned int dwPllRatio, dwFract, dwInt;
			// adjust PLL
			dwPllRatio = (int)(6.0 * ((double)param.h_clko / vidstda[mode->tv_encoding].m_dSecHsyncPeriod) *
				param.clk_ratio * 0x10000 / pll_base + 0.5);
			dwInt = dwPllRatio / 0x10000;
			dwFract = dwPllRatio - (dwInt * 0x10000);
			b=regs[ADR(0xa0)]&(~0x3f);
			regs[ADR(0xa0)] = ((dwInt)&0x3f)|b;
			regs[ADR(0x9e)] = ((dwFract>>8)&0xff);
			regs[ADR(0x9c)] = ((dwFract)&0xff);
			// recalc value
			dPllOutputFrequency = ((double)dwInt + ((double)dwFract)/65536.0)/(6 * param.clk_ratio / pll_base);
			// enable 3:2 clocking mode
			b=regs[ADR(0x38)]&(~0x20);
			if (param.clk_ratio > 1.1) {
				b |= 0x20;
			}
			regs[ADR(0x38)] = b;
			// update burst start position
			m=(vidstda[mode->tv_encoding].m_dSecBurstStart) * dPllOutputFrequency + 0.5;
			b=regs[ADR(0x38)]&(~0x04);
			regs[ADR(0x38)] = ((m>>6)&0x04)|b;
			regs[ADR(0x7c)] = (m&0xff);
			// update burst end position (note +128 is in hardware)
			m=(vidstda[mode->tv_encoding].m_dSecBurstEnd) * dPllOutputFrequency + 0.5;
			if(m<128) m=128;
			b=regs[ADR(0x38)]&(~0x08);
			regs[ADR(0x38)] = (((m-128)>>5)&0x08)|b;
			regs[ADR(0x7e)] = ((m-128)&0xff);
			// update HSYNC width
			m=(vidstda[mode->tv_encoding].m_dSecHsyncWidth) * dPllOutputFrequency + 0.5;
			regs[ADR(0x7a)] = ((m)&0xff);
		}
		// adjust Subcarrier generation increment
		{
			unsigned int dwSubcarrierIncrement = (unsigned int) (
				(65536.0 * 65536.0) * (
					vidstda[mode->tv_encoding].m_dHzBurstFrequency
					* vidstda[mode->tv_encoding].m_dSecHsyncPeriod
					/ (double)param.h_clko
				) + 0.5
			);
			regs[ADR(0xae)] = (dwSubcarrierIncrement&0xff);
			regs[ADR(0xb0)] = ((dwSubcarrierIncrement>>8)&0xff);
			regs[ADR(0xb2)] = ((dwSubcarrierIncrement>>16)&0xff);
			regs[ADR(0xb4)] = ((dwSubcarrierIncrement>>24)&0xff);
		}
		// adjust WSS increment
		{
			unsigned int dwWssIncrement = 0;
			switch(mode->tv_encoding) {
				case TV_ENC_NTSC:
				case TV_ENC_NTSC60:
					dwWssIncrement=(unsigned int) ((1048576.0 / ( 0.000002234 * dPllOutputFrequency))+0.5);
					break;
				case TV_ENC_PALBDGHI:
				case TV_ENC_PALN:
				case TV_ENC_PALNC:
				case TV_ENC_PALM:
				case TV_ENC_PAL60:
					dwWssIncrement=(unsigned int) ((1048576.0 / ( 0.0000002 * dPllOutputFrequency))+0.5);
					break;
				default:
					break;
				}
			regs[ADR(0x66)] = (dwWssIncrement&0xff);
			regs[ADR(0x68)] = ((dwWssIncrement>>8)&0xff);
			regs[ADR(0x6a)] = ((dwWssIncrement>>16)&0xf);
		}
		// set mode register
		b=regs[ADR(0xa2)]&(0x41);
		switch(mode->tv_encoding) {
				case TV_ENC_NTSC:
					b |= 0x0a; // SETUP + VSYNC_DUR
					break;
				case TV_ENC_NTSC60:
					b |= 0x08; // VSYNC_DUR
					break;
				case TV_ENC_PALBDGHI:
				case TV_ENC_PALNC:
						b |= 0x24; // PAL_MD + 625LINE
					break;
				case TV_ENC_PALN:
					b |= 0x2e; // PAL_MD + SETUP + 625LINE + VSYNC_DUR
					break;
				case TV_ENC_PALM:
					b |= 0x2a; // PAL_MD + SETUP + VSYNC_DUR
					break;
				case TV_ENC_PAL60:
					b |= 0x28; // PAL_MD + VSYNC_DUR
					break;
				default:
					break;
		}
		regs[ADR(0xa2)] = b;
		regs[ADR(0xc6)] = 0x98; // IN_MODE = 24 bit RGB multiplexed
		switch(mode->av_type) {
			case AV_COMPOSITE:
			case AV_SVIDEO:
				regs[ADR(0x2e)] |= 0x40; // RGB2YPRPB = 1
				regs[ADR(0x6c)] = 0x46; // FLD_MODE = 10, EACTIVE = 1, EN_SCART = 0, EN_REG_RD = 1
				regs[ADR(0x5a)] = 0x00; // Y_OFF (Brightness)
				regs[ADR(0xa4)] = 0xe5; // SYNC_AMP
				regs[ADR(0xa6)] = 0x74; // BST_AMP
				regs[ADR(0xba)] = 0x24; // SLAVER = 1, DACDISC = 1
				regs[ADR(0xce)] = 0x19; // OUT_MUXA = 01, OUT_MUXB = 10, OUT_MUXC = 10, OUT_MUXD = 00
				regs[ADR(0xd6)] = 0x00; // OUT_MODE = 00 (CVBS)
				break;
			case AV_SCART_RGB:
				regs[ADR(0x6c)] = 0x4e; // FLD_MODE = 10, EACTIVE = 1, EN_SCART = 1, EN_REG_RD = 1
				regs[ADR(0x5a)] = 0xff; // Y_OFF (Brightness)
				regs[ADR(0xa4)] = 0xe7; // SYNC_AMP
				regs[ADR(0xa6)] = 0x77; // BST_AMP
				regs[ADR(0xba)] = 0x20; // SLAVER = 1, enable all DACs
				regs[ADR(0xce)] = 0xe1; // OUT_MUXA = 01, OUT_MUXB = 00, OUT_MUXC = 10, OUT_MUXD = 11
				regs[ADR(0xd6)] = 0x0c; // OUT_MODE = 11 (RGB / SCART / HDTV)
				break;
			default:
				break;
		}
		riva_out->ext.vend = mode->yres;
		riva_out->ext.vtotal = param.v_linesi - 1;
		riva_out->ext.vcrtc = mode->yres;
		riva_out->ext.vsyncstart = param.v_linesi - param.v_blanki;
		riva_out->ext.vsyncend = riva_out->ext.vsyncstart + 3;
		riva_out->ext.vvalidstart = 0;
		riva_out->ext.vvalidend = mode->yres;
		riva_out->ext.hend = mode->xres + 7;
		riva_out->ext.htotal = param.h_clki - 1;
		riva_out->ext.hcrtc = mode->xres - 1;
		riva_out->ext.hsyncstart = param.h_clki - param.h_blanki - 7;
		riva_out->ext.hsyncend = riva_out->ext.hsyncstart + 32;
		riva_out->ext.hvalidstart = 0;
		riva_out->ext.hvalidend = mode->xres - 1;
		riva_out->ext.crtchdispend = mode->xres + 8;
		riva_out->ext.crtcvstart = mode->yres + 34;
		riva_out->ext.crtcvtotal = param.v_linesi + 32;
		return 1;
	}
	else
	{
		return 0;
	}
}
static int conexant_calc_mode_params(
	xbox_video_mode * mode,
	xbox_tv_mode_parameter * param
){
	const double dMinHBT = 2.5e-6; // 2.5uSec time for horizontal syncing
	const double invalidMetric = 1000;
	/* algorithm shamelessly ripped from nvtv/calc_bt.c */
	double dTempVOC = 0;
	double dTempHOC = 0;
	double dBestMetric = invalidMetric;
	double dTempVSR = 0;
	double dBestVSR = 0;
	double dTempCLKRATIO = 1;
	double dBestCLKRATIO = 1;
	unsigned int  minTLI = 0;
	unsigned int  maxTLI = 0;
	unsigned int  tempTLI = 0;
	unsigned int  bestTLI = 0;
	unsigned int  minHCLKO = 0;
	unsigned int  maxHCLKO = 0;
	unsigned int  minHCLKI = 0;
	unsigned int  tempHCLKI = 0;
	unsigned int  bestHCLKI = 0;
	int    actCLKRATIO;
	unsigned int  dTempHCLKO = 0;
	double dTempVACTIVEO = 0;
	double dDelta = 0;
	double dMetric = 0;
	double alo =  vidstda[mode->tv_encoding].m_dwALO;
	double tlo =  vidstda[mode->tv_encoding].m_TotalLinesOut;
	double tto = vidstda[mode->tv_encoding].m_dSecHsyncPeriod;
	double ato = tto - (vidstda[mode->tv_encoding].m_dSecBlankBeginToHsync + vidstda[mode->tv_encoding].m_dSecActiveBegin);
	/* Range to search */
	double dMinHOC = mode->hoc - 0.02;
	double dMaxHOC = mode->hoc + 0.02;
	double dMinVOC = mode->voc - 0.02;
	double dMaxVOC = mode->voc + 0.02;
	if (dMinHOC < 0) dMinHOC = 0;
	if (dMinVOC < 0) dMinVOC = 0;
	minTLI= (unsigned int)(mode->yres / ((1 - dMinVOC) * alo) * tlo);
	maxTLI = min((unsigned int)(mode->yres / ((1 - dMaxVOC) * alo) * tlo), (unsigned int)1023);
	minHCLKO = (unsigned int) ((mode->xres * 2) /
				((1 - dMinHOC) * (ato / tto)));
	maxHCLKO = (unsigned int) ((mode->xres * 2) /
				((1 - dMaxHOC) * (ato / tto)));
	for (actCLKRATIO = 0; actCLKRATIO <= 1; actCLKRATIO++)
	{
		dTempCLKRATIO = 1.0;
		if (actCLKRATIO) dTempCLKRATIO = 3.0/2.0;
		for(tempTLI = minTLI; tempTLI <= maxTLI; tempTLI++)
		{
			dTempVSR = (double)tempTLI / tlo;
			dTempVACTIVEO = (int)((((double)mode->yres * tlo) +
						(tempTLI - 1)) / tempTLI);
			dTempVOC = 1 - dTempVACTIVEO / alo;
			for(dTempHCLKO = minHCLKO; dTempHCLKO <= maxHCLKO; dTempHCLKO++)
			{
				tempHCLKI = (unsigned int)((dTempHCLKO * dTempCLKRATIO) * (tlo / tempTLI) + 0.5);
				minHCLKI = ((dMinHBT / tto) * tempHCLKI) + mode->xres;
				// check if solution is valid
				if ((fabs((double)(tempTLI * tempHCLKI) - (tlo * dTempHCLKO * dTempCLKRATIO)) < 1e-3) &&
					(tempHCLKI >= minHCLKI) && (tempHCLKI < 2048))
				{
					dTempHOC = 1 - (((double)mode->xres / ((double)dTempHCLKO / 2)) /
						(ato / tto));
					dDelta = fabs(dTempHOC - mode->hoc) + fabs(dTempVOC - mode->voc);
					dMetric = ((dTempHOC - mode->hoc) * (dTempHOC - mode->hoc)) +
						((dTempVOC - mode->voc) * (dTempVOC - mode->voc)) +
						(2 * dDelta * dDelta);
					if(dMetric < dBestMetric)
					{
						dBestVSR = dTempVSR;
						dBestMetric = dMetric;
						bestTLI = tempTLI;
						bestHCLKI = tempHCLKI;
						dBestCLKRATIO = dTempCLKRATIO;
					}
				} /* valid solution */
			} /* dTempHCLKO loop */
		} /* tempTLI loop */
	} /* CLKRATIO loop */
	if(dBestMetric != invalidMetric)
	{
		param->v_linesi = bestTLI;
		param->h_clki = bestHCLKI;
		param->clk_ratio = dBestCLKRATIO;
		param->v_activeo = (unsigned int)(
			(
				(mode->yres * vidstda[mode->tv_encoding].m_TotalLinesOut)
				+ param->v_linesi - 1
			) / param->v_linesi
		);
		param->h_clko = (unsigned int)(
			(
				(param->v_linesi * param->h_clki) /
				(vidstda[mode->tv_encoding].m_TotalLinesOut * param->clk_ratio)
			)
			+ 0.5
		);
		conexant_calc_blankings(mode, param);
		return 1;
	}
	else
	{
		return 0;
	}
}
static void conexant_calc_blankings(
	xbox_video_mode * mode,
	xbox_tv_mode_parameter * param
){
	double dTotalHBlankI;
	double dFrontPorchIn;
	double dFrontPorchOut;
	double dMinFrontPorchIn;
	double dBackPorchIn;
	double dBackPorchOut;
	double dTotalHBlankO;
	double dHeadRoom;
	double dMaxHsyncDrift;
	double dFifoMargin;
	double vsrq;
	double dMaxHR;
	double tlo =  vidstda[mode->tv_encoding].m_TotalLinesOut;
	const int MFP = 14; // Minimum front porch
	const int MBP = 4;  // Minimum back porch
	const int FIFO_SIZE = 1024;
	double vsr = (double)param->v_linesi / vidstda[mode->tv_encoding].m_TotalLinesOut;
	// H_BLANKO
	param->h_blanko = 2 * (int)(
		vidstda[mode->tv_encoding].m_dSecImageCentre / (2 * vidstda[mode->tv_encoding].m_dSecHsyncPeriod) *
		param->h_clko
		+ 0.5
	) - mode->xres + 15;
	// V_BLANKO
	switch (mode->tv_encoding) {
		case TV_ENC_NTSC:
		case TV_ENC_NTSC60:
		case TV_ENC_PAL60:
		case TV_ENC_PALM:
			param->v_blanko = (int)( 140 - ( param->v_activeo / 2.0 ) + 0.5 );
			break;
		default:
			param->v_blanko = (int)( 167 - ( param->v_activeo / 2.0 ) + 0.5 );
			break;
	}
	// V_BLANKI
	vsrq = ( (int)( vsr * 4096.0 + .5 ) ) / 4096.0;
	param->vscale = (int)( ( vsr - 1 ) * 4096 + 0.5 );
	if( vsrq < vsr )
	{
	// These calculations are in units of dHCLKO
		dMaxHsyncDrift = ( vsrq - vsr ) * tlo / vsr * param->h_clko;
		dMinFrontPorchIn = MFP / ( (double)param->h_clki * vsr ) * param->h_clko;
		dFrontPorchOut = param->h_clko - param->h_blanko - mode->xres * 2;
		dFifoMargin = ( FIFO_SIZE - mode->xres ) * 2;
		// Check for fifo overflow
		if( dFrontPorchOut + dFifoMargin < -dMaxHsyncDrift + dMinFrontPorchIn )
		{
			dTotalHBlankO = param->h_clko - mode->xres * 2;
			dTotalHBlankI = ( (double)param->h_clki - (double)mode->xres ) / param->h_clki / vsr * param->h_clko;
			// Try forcing the Hsync drift the opposite direction
			dMaxHsyncDrift = ( vsrq + 1.0 / 4096 - vsr ) * tlo / vsr * param->h_clko;
			// Check that fifo overflow and underflow can be avoided
			if( dTotalHBlankO + dFifoMargin >= dTotalHBlankI + dMaxHsyncDrift )
			{
				vsrq = vsrq + 1.0 / 4096;
				param->vscale = (int)( ( vsrq - 1 ) * 4096 );
			}
			// NOTE: If fifo overflow and underflow can't be avoided,
			//       alternative overscan compensation ratios should
			//       be selected and all calculations repeated.  If
			//       that is not feasible, the calculations for
			//       H_BLANKI below will delay the overflow or under-
			//       flow as much as possible, to minimize the visible
			//       artifacts.
		}
	}
	param->v_blanki = (int)( ( param->v_blanko - 1 ) * vsrq );
	// H_BLANKI
	// These calculations are in units of dHCLKI
	dTotalHBlankI = param->h_clki - mode->xres;
	dFrontPorchIn = max( (double)MFP, min( dTotalHBlankI / 8.0, dTotalHBlankI - (double)MBP ) );
	dBackPorchIn = dTotalHBlankI - dFrontPorchIn;
	dMaxHsyncDrift = ( vsrq - vsr ) * tlo * param->h_clki;
	dTotalHBlankO = ( param->h_clko - mode->xres * 2.0 ) / param->h_clko * vsr * param->h_clki;
	dBackPorchOut = ((double)param->h_blanko) / (double)param->h_clko * vsr * param->h_clki;
	dFrontPorchOut = dTotalHBlankO - dBackPorchOut;
	dFifoMargin = ( FIFO_SIZE - mode->xres ) * 2.0 / param->h_clko * vsr * param->h_clki;
	// This may be excessive, but is adjusted by the code.
	dHeadRoom = 32.0;
	// Check that fifo overflow and underflow can be avoided
	if( ( dTotalHBlankO + dFifoMargin ) >= ( dTotalHBlankI + fabs( dMaxHsyncDrift ) ) )
	{
		dMaxHR = ( dTotalHBlankO + dFifoMargin ) - ( dTotalHBlankI - fabs( dMaxHsyncDrift ) );
		if( dMaxHR < ( dHeadRoom * 2.0 ) )
		{
			dHeadRoom = (int)( dMaxHR / 2.0);
		}
		// Check for overflow
		if( ( ( dFrontPorchOut + dFifoMargin ) - dHeadRoom ) < ( dFrontPorchIn - min( dMaxHsyncDrift, 0.0 ) ) )
		{
			dFrontPorchIn = max( (double)MFP, ( dFrontPorchOut + dFifoMargin + min( dMaxHsyncDrift, 0.0 ) - dHeadRoom ) );
			dBackPorchIn = dTotalHBlankI - dFrontPorchIn;
		}
		// Check for underflow
		if( dBackPorchOut - dHeadRoom < dBackPorchIn + max( dMaxHsyncDrift, 0.0 ) )
		{
			dBackPorchIn = max( (double)MBP, ( dBackPorchOut - max( dMaxHsyncDrift, 0.0 ) - dHeadRoom ) );
			dFrontPorchIn = dTotalHBlankI - dBackPorchIn;
		}
	}
	else if( dMaxHsyncDrift < 0 )
	{
		// Delay the overflow as long as possible
		dBackPorchIn = min( ( dBackPorchOut - 1 ), ( dTotalHBlankI - MFP ) );
		dFrontPorchIn = dTotalHBlankI - dBackPorchIn;
	}
	else
	{
		// Delay the underflow as long as possible
		dFrontPorchIn = min( ( dFrontPorchOut + dFifoMargin - 1 ), ( dTotalHBlankI - MBP ) );
		dBackPorchIn = dTotalHBlankI - dFrontPorchIn;
	}
	param->h_blanki = (int)( dBackPorchIn );
}
(-) linux-2.6.6.orig/drivers/video/xbox/conexant.h (+28 lines)
Line 0    Link Here 
/*
 * linux/drivers/video/riva/conexant.h - Xbox driver for conexant chip
 *
 * Maintainer: Oliver Schwartz <Oliver.Schwartz@gmx.de>
 *
 * Contributors:
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 *
 * Known bugs and issues:
 *
 *      none
 */
#ifndef conexant_h
#define conexant_h
#include <linux/xboxfbctl.h>
#include "xboxfb.h"
#include "encoder.h"
int conexant_calc_mode(xbox_video_mode * mode, struct riva_regs * riva_out);
int conexant_calc_vga_mode(xbox_av_type av_type, unsigned char pll_int, unsigned char * mode_out);
int conexant_calc_hdtv_mode(xbox_hdtv_mode hdtv_mode, unsigned char pll_int, unsigned char * mode_out);
#endif
(-) linux-2.6.6.orig/drivers/video/xbox/encoder-i2c.c (+203 lines)
Line 0    Link Here 
/*
 * linux/drivers/video/riva/encoder-i2c.c - Xbox I2C driver for encoder chip
 *
 * Maintainer: Oliver Schwartz <Oliver.Schwartz@gmx.de>
 *
 * Contributors:
 *
 * Most of the code was stolen from extsmi.c
 * 
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 *
 * Known bugs and issues:
 *
 *      none
 */
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/delay.h>
#define CONEXANT_ADDRESS 0x45
#define FOCUS_ADDRESS 0x6a
#define XLB_ADDRESS 0x70
#define EEPROM_ADDRESS 0x54
#define PIC_ADDRESS 0x10
#define DRIVER_NAME "xbox-tv-i2c"
extern int __init i2c_xbox_init(void);
static int tv_attach_adapter(struct i2c_adapter *adap);
static struct i2c_driver tv_driver = {
	.name		= "i2c xbox conexant driver",
	.id		= I2C_DRIVERID_I2CDEV,
	.flags		= I2C_DF_NOTIFY,
	.attach_adapter	= tv_attach_adapter,
};
static struct i2c_client pic_client = {
	.name		= "I2C xbox pic client",
	.id		= 2,
	.flags		= 0,
	.addr		= PIC_ADDRESS,
	.adapter	= NULL,
	.driver		= &tv_driver,
};
static struct i2c_client conexant_client = {
	.name		= "I2C xbox conexant client",
	.id		= 1,
	.flags		= 0,
	.addr		= CONEXANT_ADDRESS,
	.adapter	= NULL,
	.driver		= &tv_driver,
};
static struct i2c_client focus_client = {
	.name		= "I2C xbox focus client",
	.id		= 1,
	.flags		= 0,
	.addr		= FOCUS_ADDRESS,
	.adapter	= NULL,
	.driver		= &tv_driver,
};
static struct i2c_client xlb_client = {
	.name		= "I2C xbox XLB client",
	.id		= 1,
	.flags		= 0,
	.addr		= XLB_ADDRESS,
	.adapter	= NULL,
	.driver		= &tv_driver,
};
static struct i2c_client eeprom_client = {
	.name		= "I2C xbox eeprom client",
	.id		= 3,
	.flags		= 0,
	.addr		= EEPROM_ADDRESS,
	.adapter	= NULL,
	.driver		= &tv_driver,
};
static int tv_attach_adapter(struct i2c_adapter *adap)
{
	int i;
	if ((i = i2c_adapter_id(adap)) < 0) {
		printk("i2c-dev.o: Unknown adapter ?!?\n");
		return -ENODEV;
	}
	printk(KERN_INFO DRIVER_NAME ": Using '%s'!\n",adap->name);
	conexant_client.adapter = adap;
	focus_client.adapter = adap;
	xlb_client.adapter = adap;
	pic_client.adapter = adap;
	eeprom_client.adapter = adap;
	i2c_attach_client(&conexant_client);
	i2c_attach_client(&focus_client);
	i2c_attach_client(&xlb_client);
	i2c_attach_client(&pic_client);
	i2c_attach_client(&eeprom_client);
	return 0;
}
int tv_i2c_init(void) {
	int res;
	i2c_xbox_init();
	if ((res = i2c_add_driver(&tv_driver))) {
		printk(KERN_ERR DRIVER_NAME ": XBox tv driver registration failed.\n");
		return res;
	}
	return 0;
}
int conexant_i2c_read_reg(unsigned char adr) {
	if (!conexant_client.adapter) {
		printk(KERN_ERR DRIVER_NAME " : No conexant client attached.\n");
		return -1;
	}
	udelay(500);
	return i2c_smbus_read_byte_data(&conexant_client, adr);
}
int conexant_i2c_write_reg(unsigned char adr, unsigned char value) {
	if (!conexant_client.adapter) {
		printk(KERN_ERR DRIVER_NAME " : No conexant client attached.\n");
		return -1;
	}
	udelay(500);
	return i2c_smbus_write_byte_data(&conexant_client, adr, value);
}
int focus_i2c_read_reg(unsigned char adr) {
	if (!focus_client.adapter) {
		printk(KERN_ERR DRIVER_NAME " : No focus client attached.\n");
		return -1;
	}
	udelay(500);
	return i2c_smbus_read_byte_data(&focus_client, adr);
}
int focus_i2c_write_reg(unsigned char adr, unsigned char value) {
	if (!focus_client.adapter) {
		printk(KERN_ERR DRIVER_NAME " : No focus client attached.\n");
		return -1;
	}
	udelay(500);
	return i2c_smbus_write_byte_data(&focus_client, adr, value);
}
int xlb_i2c_read_reg(unsigned char adr) {
	if (!xlb_client.adapter) {
		printk(KERN_ERR DRIVER_NAME " : No XLB client attached.\n");
		return -1;
	}
	udelay(500);
	return i2c_smbus_read_byte_data(&xlb_client, adr);
}
int xlb_i2c_write_reg(unsigned char adr, unsigned char value) {
	if (!xlb_client.adapter) {
		printk(KERN_ERR DRIVER_NAME " : No XLB client attached.\n");
		return -1;
	}
	udelay(500);
	return i2c_smbus_write_byte_data(&xlb_client, adr, value);
}
unsigned char pic_i2c_read_reg(unsigned char adr) {
	if (!pic_client.adapter) {
		printk(KERN_ERR DRIVER_NAME " : No pic client attached.\n");
		return 0;
	}
	udelay(500);
	return (unsigned char)i2c_smbus_read_byte_data(&pic_client, adr);
}
unsigned char eeprom_i2c_read(unsigned char adr) {
	if (!eeprom_client.adapter) {
		printk(KERN_ERR DRIVER_NAME " : No eeprom client attached.\n");
		return 0;
	}
	udelay(500);
	return (unsigned char)i2c_smbus_read_byte_data(&eeprom_client, adr);
}
void tv_i2c_exit(void){
	int res;
	
	if ((res = i2c_del_driver(&tv_driver))) {
		printk(KERN_ERR DRIVER_NAME ": XBox tv Driver deregistration failed, "
		       "module not removed.\n");
	}
	return;
}
(-) linux-2.6.6.orig/drivers/video/xbox/encoder-i2c.h (+31 lines)
Line 0    Link Here 
/*
 * linux/drivers/video/riva/encoder-i2c.h - Xbox I2C driver for encoder chip
 *
 * Maintainer: Oliver Schwartz <Oliver.Schwartz@gmx.de>
 *
 * Contributors:
 * 
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 *
 * Known bugs and issues:
 *
 *      none
 */
 
#ifndef encoder_i2c_h
#define encoder_i2c_h
int tv_i2c_init(void);
void tv_i2c_exit(void);
int conexant_i2c_read_reg(unsigned char adr);
int conexant_i2c_write_reg(unsigned char adr, unsigned char value);
int focus_i2c_read_reg(unsigned char adr);
int focus_i2c_write_reg(unsigned char adr, unsigned char value);
int xlb_i2c_read_reg(unsigned char adr);
int xlb_i2c_write_reg(unsigned char adr, unsigned char value);
unsigned char pic_i2c_read_reg(unsigned char adr);
unsigned char eeprom_i2c_read(unsigned char adr);
#endif
(-) linux-2.6.6.orig/drivers/video/xbox/encoder.c (+174 lines)
Line 0    Link Here 
/*
 * linux/drivers/video/riva/encoder.c - Xbox driver for encoder chip
 *
 * Maintainer: Oliver Schwartz <Oliver.Schwartz@gmx.de>
 *
 * Contributors:
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 *
 * Known bugs and issues:
 *
 *      none
 */
#include "encoder-i2c.h"
#include "encoder.h"
#include "focus.h"
#include <asm/io.h>
#define ADR(x) (x / 2 - 0x17)
static const conexant_video_parameter vidstda[] = {
	{ 3579545.00, 0.0000053, 0.00000782, 0.0000047, 0.000063555, 0.0000094, 0.000035667, 0.0000015, 243, 262.5, 0.0000092 },
	{ 3579545.00, 0.0000053, 0.00000782, 0.0000047, 0.000064000, 0.0000094, 0.000035667, 0.0000015, 243, 262.5, 0.0000092 },
	{ 4433618.75, 0.0000056, 0.00000785, 0.0000047, 0.000064000, 0.0000105, 0.000036407, 0.0000015, 288, 312.5, 0.0000105 },
	{ 4433618.75, 0.0000056, 0.00000785, 0.0000047, 0.000064000, 0.0000094, 0.000035667, 0.0000015, 288, 312.5, 0.0000092 },
	{ 3582056.25, 0.0000056, 0.00000811, 0.0000047, 0.000064000, 0.0000105, 0.000036407, 0.0000015, 288, 312.5, 0.0000105 },
	{ 3575611.88, 0.0000058, 0.00000832, 0.0000047, 0.000063555, 0.0000094, 0.000035667, 0.0000015, 243, 262.5, 0.0000092 },
	{ 4433619.49, 0.0000053, 0.00000755, 0.0000047, 0.000063555, 0.0000105, 0.000036407, 0.0000015, 243, 262.5, 0.0000092 }
};
static const double pll_base = 13.5e6;
xbox_encoder_type tv_get_video_encoder(void) {
	unsigned char b = 0;
	b = conexant_i2c_read_reg(0x00);
	if(b != 255) {
		return ENCODER_CONEXANT;
	}
	b = focus_i2c_read_reg(0x00);
	if(b != 255) {
		return ENCODER_FOCUS;
	}
	b = xlb_i2c_read_reg(0x00);
	if(b != 255) {
		return ENCODER_XLB;
	}
	return 0;
}
int tv_init(void) {
	return tv_i2c_init();
}
void tv_exit(void) {
	tv_i2c_exit();
}
void tv_load_mode(unsigned char * mode) {
	int n, n1;
	unsigned char b;
	
	switch (tv_get_video_encoder()) {
		case ENCODER_CONEXANT:
			conexant_i2c_write_reg(0xc4, 0x00); // EN_OUT = 1
			// Conexant init (starts at register 0x2e)
			n1=0;
			for(n=0x2e;n<0x100;n+=2) {
				switch(n) {
					case 0x6c: // reset
						conexant_i2c_write_reg(n, mode[n1] & 0x7f);
						break;
					case 0xc4: // EN_OUT
						conexant_i2c_write_reg(n, mode[n1] & 0xfe);
						break;
					case 0xb8: // autoconfig
						break;
	
					default:
						conexant_i2c_write_reg(n, mode[n1]);
						break;
				}
				n1++;
			}
			// Timing Reset
			b=conexant_i2c_read_reg(0x6c) & (0x7f);
			conexant_i2c_write_reg(0x6c, 0x80|b);
			b=conexant_i2c_read_reg(0xc4) & (0xfe);
			conexant_i2c_write_reg(0xc4, 0x01|b); // EN_OUT = 1
			
			/*
			conexant_i2c_write_reg(0xA8, (0xD9/1.3));
			conexant_i2c_write_reg(0xAA, (0x9A/1.3));
			conexant_i2c_write_reg(0xAC, (0xA4/1.3));
			*/
		
			conexant_i2c_write_reg(0xA8, 0x81);
			conexant_i2c_write_reg(0xAA, 0x49);
			conexant_i2c_write_reg(0xAC, 0x8C);
			break;
		case ENCODER_FOCUS:
			//Set the command register soft reset
			focus_i2c_write_reg(0x0c,0x03);
			focus_i2c_write_reg(0x0d,0x21);
			
			for (n = 0; n<0xc4; n++) {
				focus_i2c_write_reg(n,mode[n]);
			}
			//Clear soft reset flag
			b = focus_i2c_read_reg(0x0c);
			b &= ~0x01;
			focus_i2c_write_reg(0x0c,b);
			b = focus_i2c_read_reg(0x0d);
			focus_i2c_write_reg(0x0d,b);
			break;
		case ENCODER_XLB:
			//Nothing yet
			break;		
		}	
}
void tv_save_mode(unsigned char * mode) {
	int n, n1;
	switch (tv_get_video_encoder()) {
		case ENCODER_CONEXANT:
			// Conexant init (starts at register 0x2e)
			n1=0;		
			for(n=0x2e;n<0x100;n+=2) {
				mode[n1] = conexant_i2c_read_reg(n);
				n1++;
			}
			break;
		case ENCODER_FOCUS:
			for (n=0;n<0xc4;n++) {
				mode[n] = focus_i2c_read_reg(n);
			}
			break;
		case ENCODER_XLB:
			break;
	}			
}
xbox_tv_encoding get_tv_encoding(void) {
	unsigned char eeprom_value;
	xbox_tv_encoding enc = TV_ENC_PALBDGHI;
	eeprom_value = eeprom_i2c_read(0x5a);
	if (eeprom_value == 0x40) {
		enc = TV_ENC_NTSC;
	}
	else {
		enc = TV_ENC_PALBDGHI;
	}
	return enc;
}
xbox_av_type detect_av_type(void) {
	xbox_av_type avType;
	switch (pic_i2c_read_reg(0x04)) {
		case 0: avType = AV_SCART_RGB; break;
		case 1: avType = AV_HDTV; break;
		case 2: avType = AV_VGA_SOG; break;
		case 4: avType = AV_SVIDEO; break;
		case 6: avType = AV_COMPOSITE; break;
		case 7: avType = AV_VGA; break;
		default: avType = AV_COMPOSITE; break;
	}
	return avType;
}
(-) linux-2.6.6.orig/drivers/video/xbox/encoder.h (+64 lines)
Line 0    Link Here 
/*
 * linux/drivers/video/riva/encoder.h - Xbox driver for encoder chip
 *
 * Maintainer: Oliver Schwartz <Oliver.Schwartz@gmx.de>
 *
 * Contributors:
 * 
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 *
 * Known bugs and issues:
 *
 *      none
 */
#ifndef encoder_h
#define encoder_h
#include <linux/xboxfbctl.h>
typedef struct {
	double m_dHzBurstFrequency;
	double m_dSecBurstStart;
	double m_dSecBurstEnd;
	double m_dSecHsyncWidth;
	double m_dSecHsyncPeriod;
	double m_dSecActiveBegin;
	double m_dSecImageCentre;
	double m_dSecBlankBeginToHsync;
	unsigned int m_dwALO;
	double m_TotalLinesOut;
	double m_dSecHsyncToBlankEnd;
} conexant_video_parameter;
typedef struct _xbox_video_mode {
	int xres;
	int yres;
	int bpp;
	double hoc;
	double voc;
	xbox_av_type av_type;
	xbox_tv_encoding tv_encoding;
} xbox_video_mode;
typedef enum enumHdtvModes {
        HDTV_480p,
	HDTV_720p,
	HDTV_1080i
} xbox_hdtv_mode;
static const conexant_video_parameter vidstda[];
int tv_init(void);
void tv_exit(void);
xbox_encoder_type tv_get_video_encoder(void);
void tv_save_mode(unsigned char * mode_out);
void tv_load_mode(unsigned char * mode);
xbox_tv_encoding get_tv_encoding(void);
xbox_av_type detect_av_type(void);
#endif
(-) linux-2.6.6.orig/drivers/video/xbox/fbdev.c (+2254 lines)
Line 0    Link Here 
/*
 * linux/drivers/video/riva/fbdev.c - nVidia Xbox fb driver
 *
 * Maintained by Oliver Schwartz <Oliver.Schwartz@gmx.de>
 *
 * Based on the nVidia RIVA 128/TNT/TNT2 fb driver, maintained by 
 * Ani Joshi <ajoshi@shell.unixbox.com>
 *
 * Copyright 1999-2000 Jeff Garzik
 *
 * Contributors:
 *
 *	Ani Joshi:  Lots of debugging and cleanup work, really helped
 *	get the driver going
 *
 *	Ferenc Bakonyi:  Bug fixes, cleanup, modularization
 *
 *	Jindrich Makovicka:  Accel code help, hw cursor, mtrr
 *
 *	Paul Richards:  Bug fixes, updates
 *
 * Initial template from skeletonfb.c, created 28 Dec 1997 by Geert Uytterhoeven
 * Includes riva_hw.c from nVidia, see copyright below.
 * KGI code provided the basis for state storage, init, and mode switching.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 *
 * Known bugs and issues:
 *	restoring text mode fails
 *	doublescan modes are broken
 */
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
#ifdef CONFIG_PPC_OF
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#endif
#include "xboxfb.h"
#include "nvreg.h"
#include <linux/sys.h>
#include <asm/uaccess.h>
#include <linux/xboxfbctl.h>
#include "encoder-i2c.h"
#include "conexant.h"
#include "focus.h"
#include "xlb.h"
#ifndef CONFIG_PCI		/* sanity check */
#error This driver requires PCI support.
#endif
/* version number of this driver */
#define RIVAFB_VERSION "0.9.5b"
/* ------------------------------------------------------------------------- *
 *
 * various helpful macros and constants
 *
 * ------------------------------------------------------------------------- */
#undef RIVAFBDEBUG
#ifdef RIVAFBDEBUG
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
#define DPRINTK(fmt, args...)
#endif
#ifndef RIVA_NDEBUG
#define assert(expr) \
	if(!(expr)) { \
	printk( "Assertion failed! %s,%s,%s,line=%d\n",\
	#expr,__FILE__,__FUNCTION__,__LINE__); \
	BUG(); \
	}
#else
#define assert(expr)
#endif
#define PFX "xboxfb: "
/* macro that allows you to set overflow bits */
#define SetBitField(value,from,to) SetBF(to,GetBF(value,from))
#define SetBit(n)		(1<<(n))
#define Set8Bits(value)		((value)&0xff)
/* HW cursor parameters */
#define MAX_CURS		32
/* ------------------------------------------------------------------------- *
 *
 * prototypes
 *
 * ------------------------------------------------------------------------- */
static int xboxfb_blank(int blank, struct fb_info *info);
/* ------------------------------------------------------------------------- *
 *
 * card identification
 *
 * ------------------------------------------------------------------------- */
enum riva_chips {
	CH_GEFORCE3_XBOX
};
/* directly indexed by riva_chips enum, above */
static struct riva_chip_info {
	const char *name;
	unsigned arch_rev;
} riva_chip_info[] __initdata = {
        { "GeForce3", NV_ARCH_20}
};
static struct pci_device_id xboxfb_pci_tbl[] = {
	{ PCI_VENDOR_ID_NVIDIA, 0x2a0,
	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_XBOX },
	{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, xboxfb_pci_tbl);
/* ------------------------------------------------------------------------- *
 *
 * global variables
 *
 * ------------------------------------------------------------------------- */
/* command line data, set in xboxfb_setup() */
static u32 pseudo_palette[17];
static int flatpanel __initdata = -1; /* Autodetect later */
static int forceCRTC __initdata = -1;
#ifdef CONFIG_MTRR
static int nomtrr __initdata = 0;
#endif
#ifndef MODULE
static char *mode_option __initdata = NULL;
#endif
static xbox_tv_encoding tv_encoding  __initdata = TV_ENC_INVALID;
static xbox_av_type av_type __initdata = AV_INVALID;
static int hoc __initdata = -1;
static int voc __initdata = -1;
static struct fb_fix_screeninfo xboxfb_fix = {
	.id		= "Xbox",
	.type		= FB_TYPE_PACKED_PIXELS,
	.xpanstep	= 1,
	.ypanstep	= 1,
};
static struct fb_var_screeninfo xboxfb_default_var = {
	.xres		= 640,
	.yres		= 480,
	.xres_virtual	= 640,
	.yres_virtual	= 480,
	.bits_per_pixel	= 8,
	.red		= {0, 8, 0},
	.green		= {0, 8, 0},
	.blue		= {0, 8, 0},
	.transp		= {0, 0, 0},
	.activate	= FB_ACTIVATE_NOW,
	.height		= -1,
	.width		= -1,
	.accel_flags	= FB_ACCELF_TEXT,
	.pixclock	= 39721,
	.left_margin	= 40,
	.right_margin	= 24,
	.upper_margin	= 32,
	.lower_margin	= 11,
	.hsync_len	= 96,
	.vsync_len	= 2,
	.vmode		= FB_VMODE_NONINTERLACED
};
static struct fb_var_screeninfo xboxfb_mode_480p = {
	.xres           = 720,
	.yres           = 480,
	.xres_virtual   = 720,
	.yres_virtual   = 480,
	.bits_per_pixel = 32,
	.red            = {0, 8, 16},
	.green          = {0, 8, 8},
	.blue           = {0, 8, 0},
	.transp         = {0, 0, 0},
	.activate       = FB_ACTIVATE_NOW,
	.height         = -1,
	.width          = -1,
	.accel_flags    = FB_ACCELF_TEXT,
	.pixclock       = 37000,
	.left_margin    = 56,
	.right_margin   = 18,
	.upper_margin   = 29,
	.lower_margin   = 9,
	.hsync_len      = 64,
	.vsync_len      = 7,
	.vmode          = FB_VMODE_NONINTERLACED
};
static struct fb_var_screeninfo xboxfb_mode_720p = {
	.xres           = 1280,
	.yres           = 720,
	.xres_virtual   = 1280,
	.yres_virtual   = 720,
	.bits_per_pixel = 8,
	.red            = {0, 8, 0},
	.green          = {0, 8, 0},
	.blue           = {0, 8, 0},
	.transp         = {0, 0, 0},
	.activate       = FB_ACTIVATE_NOW,
	.height         = -1,
	.width          = -1,
	.accel_flags    = FB_ACCELF_TEXT,
	.pixclock       = 13468,
	.left_margin    = 220,
	.right_margin   = 70,
	.upper_margin   = 22,
	.lower_margin   = 3,
	.hsync_len      = 80,
	.vsync_len      = 5,
	.vmode          = FB_VMODE_NONINTERLACED
};
static const char* tvEncodingNames[] = {
        "NTSC",
        "NTSC-60",
        "PAL-BDGHI",
        "PAL-N",
        "PAL-NC",
        "PAL-M",
        "PAL-60"
};
static const char* avTypeNames[] = {
        "SCART (RGB)",
        "S-Video",
        "VGA (Sync on green)",
        "HDTV (Component video)",
        "Composite",
        "VGA (internal syncs)"
};
/* from GGI */
static const struct riva_regs reg_template = {
	{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	/* ATTR */
	 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
	 0x41, 0x01, 0x0F, 0x00, 0x00},
	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* CRT  */
	 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3,	/* 0x10 */
	 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 0x20 */
	 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 0x30 */
	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	 0x00,							/* 0x40 */
	 },
	{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,	/* GRA  */
	 0xFF},
	{0x03, 0x01, 0x0F, 0x00, 0x0E},				/* SEQ  */
	0xEB							/* MISC */
};
/* ------------------------------------------------------------------------- *
 *
 * MMIO access macros
 *
 * ------------------------------------------------------------------------- */
static inline void CRTCout(struct riva_par *par, unsigned char index,
			   unsigned char val)
{
	VGA_WR08(par->riva.PCIO, 0x3d4, index);
	VGA_WR08(par->riva.PCIO, 0x3d5, val);
}
static inline unsigned char CRTCin(struct riva_par *par,
				   unsigned char index)
{
	VGA_WR08(par->riva.PCIO, 0x3d4, index);
	return (VGA_RD08(par->riva.PCIO, 0x3d5));
}
static inline void GRAout(struct riva_par *par, unsigned char index,
			  unsigned char val)
{
	VGA_WR08(par->riva.PVIO, 0x3ce, index);
	VGA_WR08(par->riva.PVIO, 0x3cf, val);
}
static inline unsigned char GRAin(struct riva_par *par,
				  unsigned char index)
{
	VGA_WR08(par->riva.PVIO, 0x3ce, index);
	return (VGA_RD08(par->riva.PVIO, 0x3cf));
}
static inline void SEQout(struct riva_par *par, unsigned char index,
			  unsigned char val)
{
	VGA_WR08(par->riva.PVIO, 0x3c4, index);
	VGA_WR08(par->riva.PVIO, 0x3c5, val);
}
static inline unsigned char SEQin(struct riva_par *par,
				  unsigned char index)
{
	VGA_WR08(par->riva.PVIO, 0x3c4, index);
	return (VGA_RD08(par->riva.PVIO, 0x3c5));
}
static inline void ATTRout(struct riva_par *par, unsigned char index,
			   unsigned char val)
{
	VGA_WR08(par->riva.PCIO, 0x3c0, index);
	VGA_WR08(par->riva.PCIO, 0x3c0, val);
}
static inline unsigned char ATTRin(struct riva_par *par,
				   unsigned char index)
{
	VGA_WR08(par->riva.PCIO, 0x3c0, index);
	return (VGA_RD08(par->riva.PCIO, 0x3c1));
}
static inline void MISCout(struct riva_par *par, unsigned char val)
{
	VGA_WR08(par->riva.PVIO, 0x3c2, val);
}
static inline unsigned char MISCin(struct riva_par *par)
{
	return (VGA_RD08(par->riva.PVIO, 0x3cc));
}
static u8 byte_rev[256] = {
	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
};
static inline void reverse_order(u32 *l)
{
	u8 *a = (u8 *)l;
	*a = byte_rev[*a], a++;
	*a = byte_rev[*a], a++;
	*a = byte_rev[*a], a++;
	*a = byte_rev[*a];
}
/* ------------------------------------------------------------------------- *
 *
 * cursor stuff
 *
 * ------------------------------------------------------------------------- */
/**
 * xboxfb_load_cursor_image - load cursor image to hardware
 * @data: address to monochrome bitmap (1 = foreground color, 0 = background)
 * @par:  pointer to private data
 * @w:    width of cursor image in pixels
 * @h:    height of cursor image in scanlines
 * @bg:   background color (ARGB1555) - alpha bit determines opacity
 * @fg:   foreground color (ARGB1555)
 *
 * DESCRIPTiON:
 * Loads cursor image based on a monochrome source and mask bitmap.  The
 * image bits determines the color of the pixel, 0 for background, 1 for
 * foreground.  Only the affected region (as determined by @w and @h 
 * parameters) will be updated.
 *
 * CALLED FROM:
 * xboxfb_cursor()
 */
static void xboxfb_load_cursor_image(struct riva_par *par, u8 *data, 
				     u8* mask, u16 bg, u16 fg, u32 w, u32 h)
{
	int i, j, k = 0;
	u32 b, m, tmp;
	for (i = 0; i < h; i++) {
		b = *((u32 *)data);
		data = (u8 *)((u32 *)data + 1);
		m = *((u32 *)mask);
		mask = (u8 *)((u32 *)mask + 1);
		reverse_order(&b);
		
		for (j = 0; j < w/2; j++) {
			tmp = 0;
#if defined (__BIG_ENDIAN)
			tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
			if (m & (1 << 31)) {
				tmp |= 1 << 31;
			}
			b <<= 1;
			m <<= 1;
			tmp |= (b & (1 << 31)) ? fg : bg;
			if (m & (1 << 31)) {
				tmp |= 1 << 15;
			}
			b <<= 1;
			m <<= 1;
#else
			tmp = (b & 1) ? fg : bg;
			if (m & 1) {
				tmp |= 1 << 15;
			}
			b >>= 1;
			m >>= 1;
			
			tmp |= (b & 1) ? fg << 16 : bg << 16;
			if (m & 1) {
				tmp |= 1 << 31;
			}
			b >>= 1;
			m >>= 1;
#endif
			writel(tmp, par->riva.CURSOR + k++);
		}
		k += (MAX_CURS - w)/2;
	}
}
/* ------------------------------------------------------------------------- *
 *
 * general utility functions
 *
 * ------------------------------------------------------------------------- */
/**
 * riva_wclut - set CLUT entry
 * @chip: pointer to RIVA_HW_INST object
 * @regnum: register number
 * @red: red component
 * @green: green component
 * @blue: blue component
 *
 * DESCRIPTION:
 * Sets color register @regnum.
 *
 * CALLED FROM:
 * xboxfb_setcolreg()
 */
static void riva_wclut(RIVA_HW_INST *chip,
		       unsigned char regnum, unsigned char red,
		       unsigned char green, unsigned char blue)
{
	VGA_WR08(chip->PDIO, 0x3c8, regnum);
	VGA_WR08(chip->PDIO, 0x3c9, red);
	VGA_WR08(chip->PDIO, 0x3c9, green);
	VGA_WR08(chip->PDIO, 0x3c9, blue);
}
/**
 * riva_rclut - read fromCLUT register
 * @chip: pointer to RIVA_HW_INST object
 * @regnum: register number
 * @red: red component
 * @green: green component
 * @blue: blue component
 *
 * DESCRIPTION:
 * Reads red, green, and blue from color register @regnum.
 *
 * CALLED FROM:
 * xboxfb_setcolreg()
 */
static void riva_rclut(RIVA_HW_INST *chip,
		       unsigned char regnum, unsigned char *red,
		       unsigned char *green, unsigned char *blue)
{
	
	VGA_WR08(chip->PDIO, 0x3c8, regnum);
	*red = VGA_RD08(chip->PDIO, 0x3c9);
	*green = VGA_RD08(chip->PDIO, 0x3c9);
	*blue = VGA_RD08(chip->PDIO, 0x3c9);
}
/**
 * riva_save_state - saves current chip state
 * @par: pointer to riva_par object containing info for current riva board
 * @regs: pointer to riva_regs object
 *
 * DESCRIPTION:
 * Saves current chip state to @regs.
 *
 * CALLED FROM:
 * xboxfb_probe()
 */
/* from GGI */
static void riva_save_state(struct riva_par *par, struct riva_regs *regs)
{
	int i;
	par->riva.LockUnlock(&par->riva, 0);
	par->riva.UnloadStateExt(&par->riva, &regs->ext);
	regs->misc_output = MISCin(par);
	for (i = 0; i < NUM_CRT_REGS; i++)
		regs->crtc[i] = CRTCin(par, i);
	for (i = 0; i < NUM_ATC_REGS; i++)
		regs->attr[i] = ATTRin(par, i);
	for (i = 0; i < NUM_GRC_REGS; i++)
		regs->gra[i] = GRAin(par, i);
	for (i = 0; i < NUM_SEQ_REGS; i++)
		regs->seq[i] = SEQin(par, i);
}
/**
 * riva_load_state - loads current chip state
 * @par: pointer to riva_par object containing info for current riva board
 * @regs: pointer to riva_regs object
 *
 * DESCRIPTION:
 * Loads chip state from @regs.
 *
 * CALLED FROM:
 * riva_load_video_mode()
 * xboxfb_probe()
 * xboxfb_remove()
 */
/* from GGI */
static void riva_load_state(struct riva_par *par, struct riva_regs *regs)
{
	RIVA_HW_STATE *state = &regs->ext;
	int i;
	CRTCout(par, 0x11, 0x00);
	par->riva.LockUnlock(&par->riva, 0);
	par->riva.LoadStateExt(&par->riva, state);
	par->riva.PGRAPH[0x00000820/4] = par->riva_fb_start;
	par->riva.PGRAPH[0x00000824/4] = par->riva_fb_start;
	par->riva.PGRAPH[0x00000828/4] = par->riva_fb_start;
	par->riva.PGRAPH[0x0000082c/4] = par->riva_fb_start;
	par->riva.PGRAPH[0x00000684/4] = par->riva.RamAmountKBytes * 1024 - 1;
	par->riva.PGRAPH[0x00000688/4] = par->riva.RamAmountKBytes * 1024 - 1;
	par->riva.PGRAPH[0x0000068c/4] = par->riva.RamAmountKBytes * 1024 - 1;
	par->riva.PGRAPH[0x00000690/4] = par->riva.RamAmountKBytes * 1024 - 1;
	par->riva.PRAMDAC[0x00000848/4] = 0x10100111;
	par->riva.PRAMDAC[0x00000880/4] = 0;
	par->riva.PRAMDAC[0x000008a0/4] = 0;
	par->riva.PMC[0x00008908/4] = par->riva.RamAmountKBytes * 1024 - 1;
	par->riva.PMC[0x0000890c/4] = par->riva.RamAmountKBytes * 1024 - 1;
	/* Switch GPU to RGB output */
	par->riva.PRAMDAC[0x00000630/4] = 0; 
	/* These fix the maroon borders seen when booting from Xromwell or 
	* xbeboot
	*/
	par->riva.PRAMDAC[0x0000084c/4] = 0;
	par->riva.PRAMDAC[0x000008c4/4] = 0;
	
	/* for YCrCb:
	par->riva.PRAMDAC[0x00000630/4] = 2; 
	par->riva.PRAMDAC[0x0000084c/4] =0x00801080;
	par->riva.PRAMDAC[0x000008c4/4] =0x40801080;
	*/
	MISCout(par, regs->misc_output);
	for (i = 0; i < NUM_CRT_REGS; i++) {
		switch (i) {
		case 0x0c:
		case 0x0d:
		case 0x19:
		case 0x20 ... 0x40:
			break;
		default:
			CRTCout(par, i, regs->crtc[i]);
		}
	}
	for (i = 0; i < NUM_ATC_REGS; i++)
		ATTRout(par, i, regs->attr[i]);
	for (i = 0; i < NUM_GRC_REGS; i++)
		GRAout(par, i, regs->gra[i]);
	for (i = 0; i < NUM_SEQ_REGS; i++)
		SEQout(par, i, regs->seq[i]);
	tv_save_mode(regs->encoder_mode);
}
static inline unsigned long xbox_memory_size(void) {
	/* make a guess on the xbox memory size. There are just
	two possibilities */
	if ((num_physpages << PAGE_SHIFT) > 64*1024*1024) {
		return 128*1024*1024;
	} else {
		return 64*1024*1024;
	}
}
static inline unsigned long available_framebuffer_memory(void) {
	return xbox_memory_size() - (num_physpages << PAGE_SHIFT);
}
/**
 * riva_load_video_mode - calculate timings
 * @info: pointer to fb_info object containing info for current riva board
 *
 * DESCRIPTION:
 * Calculate some timings and then send em off to riva_load_state().
 *
 * CALLED FROM:
 * xboxfb_set_par()
 */
static void riva_load_video_mode(struct fb_info *info)
{
	int bpp, width, height, hDisplaySize, hStart, hTotal, vStart, vTotal;
	int crtc_hDisplay, crtc_hStart, crtc_hEnd, crtc_hTotal;
	int crtc_vDisplay, crtc_vStart, crtc_vEnd, crtc_vTotal, dotClock;
	int crtc_hBlankStart, crtc_hBlankEnd, crtc_vBlankStart, crtc_vBlankEnd;
	struct riva_par *par = (struct riva_par *) info->par;
	struct riva_regs newmode;
	int encoder_ok = 0;	
	
	/* time to calculate */
	xboxfb_blank(1, info);
	bpp = info->var.bits_per_pixel;
	if (bpp == 16 && info->var.green.length == 5)
		bpp = 15;
	width = info->var.xres_virtual;
	height = info->var.yres_virtual;
	hDisplaySize = info->var.xres;
	hStart = hDisplaySize + info->var.right_margin;
	hTotal = hDisplaySize + info->var.right_margin +
		  info->var.hsync_len + info->var.left_margin;
	vStart = info->var.yres + info->var.lower_margin;
	vTotal = info->var.yres + info->var.lower_margin +
		 info->var.vsync_len + info->var.upper_margin;
	
	crtc_hDisplay = (hDisplaySize / 8) - 1;
	crtc_hStart = (hTotal - 32) / 8;
	/* crtc_hStart = hStart / 8 - 1; */
	crtc_hEnd = crtc_hStart + 1;
	/* crtc_hEnd = (hStart + info->var.hsync_len) / 8 - 1; */
	crtc_hTotal = hTotal / 8 - 5;
	crtc_hBlankStart = crtc_hDisplay;
	crtc_hBlankEnd = crtc_hTotal + 4;
	
	crtc_vDisplay = info->var.yres - 1;
	/* crtc_vStart = vStart - 1; */
	crtc_vStart = vStart - 1;
	/* crtc_vEnd = vStart + info->var.vsync_len - 1; */
	crtc_vEnd = crtc_vStart + 2;
	crtc_vTotal = vTotal + 2;
	crtc_vDisplay = info->var.yres - 1;
	crtc_vBlankStart = crtc_vDisplay;
	crtc_vBlankEnd = crtc_vTotal + 1;
	
	dotClock = 1000000000 / info->var.pixclock;
	memcpy(&newmode, &reg_template, sizeof(struct riva_regs));
	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
		vTotal |= 1;
	if (par->FlatPanel) {
		crtc_vStart = crtc_vTotal - 3;
		crtc_vEnd = crtc_vTotal - 2;
		crtc_vBlankStart = crtc_vStart;
		crtc_hStart = crtc_hTotal - 3;
		crtc_hEnd = crtc_hTotal - 2;
		crtc_hBlankEnd = crtc_hTotal + 4;
	}
	newmode.ext.bpp = bpp;
	newmode.ext.fb_start = par->riva_fb_start;
	if((par->av_type == AV_VGA) || (par->av_type == AV_VGA_SOG) || (par->av_type == AV_HDTV)) {
		unsigned char pll_int = (unsigned char)((double)dotClock * 6.0 / 13.5e3 + 0.5);
		if (par->av_type == AV_HDTV) {
			xbox_hdtv_mode hdtv_mode = HDTV_480p;
			if (info->var.yres > 800) {
				hdtv_mode = HDTV_1080i;
				crtc_vStart = vStart + 31;
				crtc_vEnd = crtc_vStart + 2;
			}
			else if (info->var.yres > 600) {
				hdtv_mode = HDTV_720p;
			}
			switch (par->video_encoder) {
				case ENCODER_CONEXANT:
					encoder_ok = conexant_calc_hdtv_mode(hdtv_mode, pll_int, newmode.encoder_mode);
					break;
				case ENCODER_FOCUS:
					encoder_ok = focus_calc_hdtv_mode(hdtv_mode, pll_int, newmode.encoder_mode);
					break;
				case ENCODER_XLB:
					encoder_ok = xlb_calc_hdtv_mode(hdtv_mode, pll_int, newmode.encoder_mode);
					break;
				default:
					printk("Error - unknown encoder type detected\n");
			}
		}
		else {
			switch (par->video_encoder) {
				case ENCODER_CONEXANT:
					encoder_ok = conexant_calc_vga_mode(par->av_type, pll_int, newmode.encoder_mode);
					break;
				case ENCODER_FOCUS:
					//No vga functions as yet - so set up for 480p otherwise we dont boot at all. 
					encoder_ok = focus_calc_hdtv_mode(HDTV_480p, pll_int, newmode.encoder_mode);
					break;
				case ENCODER_XLB:
					//No vga functions as yet - so set up for 480p otherwise we dont boot at all. 
					encoder_ok = xlb_calc_hdtv_mode(HDTV_480p, pll_int, newmode.encoder_mode);
					break;
				default:
					printk("Error - unknown encoder type detected\n");
			}
		}
		newmode.ext.vend = info->var.yres - 1;
		newmode.ext.vtotal = vTotal;
		newmode.ext.vcrtc = info->var.yres - 1;
		newmode.ext.vsyncstart = vStart;
		newmode.ext.vsyncend = vStart + 3;
		newmode.ext.vvalidstart = 0;
		newmode.ext.vvalidend = info->var.yres - 1;
		newmode.ext.hend = info->var.xres - 1;
		newmode.ext.htotal = hTotal;
		newmode.ext.hcrtc = info->var.xres - 1;
		newmode.ext.hsyncstart = hStart;
		newmode.ext.hsyncend = hStart + 32;
		newmode.ext.hvalidstart = 0;
		newmode.ext.hvalidend = info->var.xres - 1;
	}
	/* Normal composite */
	else {
		xbox_video_mode encoder_mode;
		encoder_mode.xres = info->var.xres;
		encoder_mode.yres = info->var.yres;
		encoder_mode.tv_encoding = par->tv_encoding;
		encoder_mode.bpp = bpp;
		encoder_mode.hoc = par->hoc;
		encoder_mode.voc = par->voc;
		encoder_mode.av_type = par->av_type;
		switch (par->video_encoder) {
			case ENCODER_CONEXANT:
				encoder_ok = conexant_calc_mode(&encoder_mode, &newmode);
				break;
			case ENCODER_FOCUS:
				encoder_ok = focus_calc_mode(&encoder_mode, &newmode);
				break;
			case ENCODER_XLB:
				encoder_ok = xlb_calc_mode(&encoder_mode, &newmode);
				break;
			default:
				printk("Error - unknown encoder type detected\n");
		}
		crtc_hDisplay = (newmode.ext.crtchdispend / 8) - 1;
		crtc_hStart = (newmode.ext.htotal - 32) / 8;
		crtc_hEnd = crtc_hStart + 1;
		crtc_hTotal = (newmode.ext.htotal) / 8 - 5;
		crtc_hBlankStart = crtc_hDisplay;
		crtc_hBlankEnd = (newmode.ext.htotal) / 8 - 1;
		
		crtc_vDisplay = info->var.yres - 1;
		crtc_vStart = newmode.ext.crtcvstart;
		crtc_vEnd = newmode.ext.crtcvstart + 3;
		crtc_vTotal = newmode.ext.crtcvtotal;
		crtc_vBlankStart = crtc_vDisplay;
		crtc_vBlankEnd = crtc_vTotal + 1;
	}
	if (encoder_ok) {
		newmode.crtc[0x0] = Set8Bits (crtc_hTotal); 
		newmode.crtc[0x1] = Set8Bits (crtc_hDisplay);
		newmode.crtc[0x2] = Set8Bits (crtc_hBlankStart);
		newmode.crtc[0x3] = SetBitField (crtc_hBlankEnd, 4: 0, 4:0) | SetBit (7);
		newmode.crtc[0x4] = Set8Bits (crtc_hStart);
		newmode.crtc[0x5] = SetBitField (crtc_hBlankEnd, 5: 5, 7:7)
			| SetBitField (crtc_hEnd, 4: 0, 4:0);
		newmode.crtc[0x6] = SetBitField (crtc_vTotal, 7: 0, 7:0);
		newmode.crtc[0x7] = SetBitField (crtc_vTotal, 8: 8, 0:0)
			| SetBitField (crtc_vDisplay, 8: 8, 1:1)
			| SetBitField (crtc_vStart, 8: 8, 2:2)
			| SetBitField (crtc_vBlankStart, 8: 8, 3:3)
			| SetBit (4)
			| SetBitField (crtc_vTotal, 9: 9, 5:5)
			| SetBitField (crtc_vDisplay, 9: 9, 6:6)
			| SetBitField (crtc_vStart, 9: 9, 7:7);
		newmode.crtc[0x9] = SetBitField (crtc_vBlankStart, 9: 9, 5:5)
			| SetBit (6);
		newmode.crtc[0x10] = Set8Bits (crtc_vStart);
		newmode.crtc[0x11] = SetBitField (crtc_vEnd, 3: 0, 3:0)
			| SetBit (5);
		newmode.crtc[0x12] = Set8Bits (crtc_vDisplay);
		newmode.crtc[0x13] = (width / 8) * ((bpp + 1) / 8);
		newmode.crtc[0x15] = Set8Bits (crtc_vBlankStart);
		newmode.crtc[0x16] = Set8Bits (crtc_vBlankEnd);
	
		newmode.ext.screen = SetBitField(crtc_hBlankEnd,6:6,4:4)
			| SetBitField(crtc_vBlankStart,10:10,3:3)
			| SetBitField(crtc_vStart,10:10,2:2)
			| SetBitField(crtc_vDisplay,10:10,1:1)
			| SetBitField(crtc_vTotal,10:10,0:0);
		newmode.ext.horiz  = SetBitField(crtc_hTotal,8:8,0:0) 
			| SetBitField(crtc_hDisplay,8:8,1:1)
			| SetBitField(crtc_hBlankStart,8:8,2:2)
			| SetBitField(crtc_hStart,8:8,3:3);
		newmode.ext.extra  = SetBitField(crtc_vTotal,11:11,0:0)
			| SetBitField(crtc_vDisplay,11:11,2:2)
			| SetBitField(crtc_vStart,11:11,4:4)
			| SetBitField(crtc_vBlankStart,11:11,6:6); 
	
		if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
			int tmp = (crtc_hTotal >> 1) & ~1;
			newmode.ext.interlace = Set8Bits(tmp);
			newmode.ext.horiz |= SetBitField(tmp, 8:8,4:4);
		} else 
			newmode.ext.interlace = 0xff; /* interlace off */
	
		if (par->riva.Architecture >= NV_ARCH_10)
			/* use 2 KByte at top of framebuffer */
			par->riva.CURSOR = (U032 *)(info->screen_base + info->fix.smem_len - 2 * 1024);
	
		if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
			newmode.misc_output &= ~0x40;
		else
			newmode.misc_output |= 0x40;
		if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
			newmode.misc_output &= ~0x80;
		else
			newmode.misc_output |= 0x80;	
	
		par->riva.CalcStateExt(&par->riva, &newmode.ext, bpp, width,
					hDisplaySize, height, dotClock);
	
		newmode.ext.scale = par->riva.PRAMDAC[0x00000848/4] & 0xfff000ff;
		if (par->FlatPanel == 1) {
			newmode.ext.pixel |= (1 << 7);
			newmode.ext.scale |= (1 << 8);
		}
		if (par->SecondCRTC) {
			newmode.ext.head  = par->riva.PCRTC0[0x00000860/4] & ~0x00001000;
			newmode.ext.head2 = par->riva.PCRTC0[0x00002860/4] | 0x00001000;
			newmode.ext.crtcOwner = 3;
			newmode.ext.pllsel |= 0x20000800;
			newmode.ext.vpll2 = newmode.ext.vpll;
		} else if (par->riva.twoHeads) {
			newmode.ext.head  =  par->riva.PCRTC0[0x00000860/4] | 0x00001000;
			newmode.ext.head2 =  par->riva.PCRTC0[0x00002860/4] & ~0x00001000;
			newmode.ext.crtcOwner = 0;
			newmode.ext.vpll2 = par->riva.PRAMDAC0[0x00000520/4];
		}
		if (par->FlatPanel == 1) {
			newmode.ext.pixel |= (1 << 7);
			newmode.ext.scale |= (1 << 8);
		}
		newmode.ext.cursorConfig = 0x02000100;
		par->current_state = newmode;
		riva_load_state(par, &par->current_state);
		tv_load_mode(newmode.encoder_mode);
		par->riva.LockUnlock(&par->riva, 0); /* important for HW cursor */
	}
	else {
		printk("Error: Unable to set encoder resolution %dx%d\n",info->var.xres, info->var.yres);
	}
	
	xboxfb_blank(0, info);
}
/**
 * xboxfb_do_maximize - 
 * @info: pointer to fb_info object containing info for current riva board
 * @var:
 * @nom:
 * @den:
 *
 * DESCRIPTION:
 * .
 *
 * RETURNS:
 * -EINVAL on failure, 0 on success
 * 
 *
 * CALLED FROM:
 * xboxfb_check_var()
 */
static int xboxfb_do_maximize(struct fb_info *info,
			      struct fb_var_screeninfo *var,
			      int nom, int den)
{
	static struct {
		int xres, yres;
	} modes[] = {
		{1600, 1280},
		{1280, 1024},
		{1024, 768},
		{800, 600},
		{640, 480},
		{-1, -1}
	};
	int i;
	/* use highest possible virtual resolution */
	if (var->xres_virtual == -1 && var->yres_virtual == -1) {
		printk(KERN_WARNING PFX
		       "using maximum available virtual resolution\n");
		for (i = 0; modes[i].xres != -1; i++) {
			if (modes[i].xres * nom / den * modes[i].yres <
			    info->fix.smem_len / 2)
				break;
		}
		if (modes[i].xres == -1) {
			printk(KERN_ERR PFX
			       "could not find a virtual resolution that fits into video memory!!\n");
			DPRINTK("EXIT - EINVAL error\n");
			return -EINVAL;
		}
		var->xres_virtual = modes[i].xres;
		var->yres_virtual = modes[i].yres;
		printk(KERN_INFO PFX
		       "virtual resolution set to maximum of %dx%d\n",
		       var->xres_virtual, var->yres_virtual);
	} else if (var->xres_virtual == -1) {
		var->xres_virtual = (info->fix.smem_len * den /
			(nom * var->yres_virtual * 2)) & ~15;
		printk(KERN_WARNING PFX
		       "setting virtual X resolution to %d\n", var->xres_virtual);
	} else if (var->yres_virtual == -1) {
		var->xres_virtual = (var->xres_virtual + 15) & ~15;
		var->yres_virtual = info->fix.smem_len * den /
			(nom * var->xres_virtual * 2);
		printk(KERN_WARNING PFX
		       "setting virtual Y resolution to %d\n", var->yres_virtual);
	} else {
		var->xres_virtual = (var->xres_virtual + 15) & ~15;
		if (var->xres_virtual * nom / den * var->yres_virtual > info->fix.smem_len) {
			printk(KERN_ERR PFX
			       "mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
			       var->xres, var->yres, var->bits_per_pixel);
			DPRINTK("EXIT - EINVAL error\n");
			return -EINVAL;
		}
	}
	
	if (var->xres_virtual * nom / den >= 8192) {
		printk(KERN_WARNING PFX
		       "virtual X resolution (%d) is too high, lowering to %d\n",
		       var->xres_virtual, 8192 * den / nom - 16);
		var->xres_virtual = 8192 * den / nom - 16;
	}
	
	if (var->xres_virtual < var->xres) {
		printk(KERN_ERR PFX
		       "virtual X resolution (%d) is smaller than real\n", var->xres_virtual);
		return -EINVAL;
	}
	if (var->yres_virtual < var->yres) {
		printk(KERN_ERR PFX
		       "virtual Y resolution (%d) is smaller than real\n", var->yres_virtual);
		return -EINVAL;
	}
	return 0;
}
/* acceleration routines */
inline void wait_for_idle(struct riva_par *par)
{
	while (par->riva.Busy(&par->riva));
}
/* set copy ROP, no mask */
static void riva_setup_ROP(struct riva_par *par)
{
	RIVA_FIFO_FREE(par->riva, Patt, 5);
	par->riva.Patt->Shape = 0;
	par->riva.Patt->Color0 = 0xffffffff;
	par->riva.Patt->Color1 = 0xffffffff;
	par->riva.Patt->Monochrome[0] = 0xffffffff;
	par->riva.Patt->Monochrome[1] = 0xffffffff;
	RIVA_FIFO_FREE(par->riva, Rop, 1);
	par->riva.Rop->Rop3 = 0xCC;
}
void riva_setup_accel(struct riva_par *par)
{
	RIVA_FIFO_FREE(par->riva, Clip, 2);
	par->riva.Clip->TopLeft     = 0x0;
	par->riva.Clip->WidthHeight = 0x80008000;
	riva_setup_ROP(par);
	wait_for_idle(par);
}
/**
 * riva_get_cmap_len - query current color map length
 * @var: standard kernel fb changeable data
 *
 * DESCRIPTION:
 * Get current color map length.
 *
 * RETURNS:
 * Length of color map
 *
 * CALLED FROM:
 * xboxfb_setcolreg()
 */
static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
{
	int rc = 256;		/* reasonable default */
	switch (var->green.length) {
	case 8:
		rc = 256;	/* 256 entries (2^8), 8 bpp and RGB8888 */
		break;
	case 5:
		rc = 32;	/* 32 entries (2^5), 16 bpp, RGB555 */
		break;
	case 6:
		rc = 64;	/* 64 entries (2^6), 16 bpp, RGB565 */
		break;		
	default:
		/* should not occur */
		break;
	}
	return rc;
}
/* ------------------------------------------------------------------------- *
 *
 * framebuffer operations
 *
 * ------------------------------------------------------------------------- */
static int xboxfb_open(struct fb_info *info, int user)
{
	struct riva_par *par = (struct riva_par *) info->par;
	int cnt = atomic_read(&par->ref_count);
	if (!cnt) {
		memset(&par->state, 0, sizeof(struct vgastate));
		par->state.flags = VGA_SAVE_MODE  | VGA_SAVE_FONTS;
		/* save the DAC for Riva128 */
		if (par->riva.Architecture == NV_ARCH_03)
			par->state.flags |= VGA_SAVE_CMAP;
		save_vga(&par->state);
		RivaGetConfig(&par->riva, par->Chipset);
		par->riva.CURSOR = (U032*)(info->screen_base + info->fix.smem_len);
		par->riva.PCRTC[0x00000800/4] = par->riva_fb_start;
		par->riva.PGRAPH[0x00000820/4] = par->riva_fb_start;
		par->riva.PGRAPH[0x00000824/4] = par->riva_fb_start;
		par->riva.PGRAPH[0x00000828/4] = par->riva_fb_start;
		par->riva.PGRAPH[0x0000082c/4] = par->riva_fb_start;
		
		par->riva.PGRAPH[0x00000684/4] = par->riva.RamAmountKBytes * 1024 - 1;
		par->riva.PGRAPH[0x00000688/4] = par->riva.RamAmountKBytes * 1024 - 1;
		par->riva.PGRAPH[0x0000068c/4] = par->riva.RamAmountKBytes * 1024 - 1;
		par->riva.PGRAPH[0x00000690/4] = par->riva.RamAmountKBytes * 1024 - 1;
		par->riva.PMC[0x00008908/4] = par->riva.RamAmountKBytes * 1024 - 1;
		par->riva.PMC[0x0000890c/4] = par->riva.RamAmountKBytes * 1024 - 1;
		
		/* vgaHWunlock() + riva unlock (0x7F) */		
		CRTCout(par, 0x11, 0xFF);
		par->riva.LockUnlock(&par->riva, 0);
	
		riva_save_state(par, &par->initial_state);
	}
	atomic_inc(&par->ref_count);
	return 0;
}
static int xboxfb_release(struct fb_info *info, int user)
{
	struct riva_par *par = (struct riva_par *) info->par;
	int cnt = atomic_read(&par->ref_count);
	if (!cnt)
		return -EINVAL;
	if (cnt == 1) {
		par->riva.LockUnlock(&par->riva, 0);
		par->riva.LoadStateExt(&par->riva, &par->initial_state.ext);
		riva_load_state(par, &par->initial_state);
		restore_vga(&par->state);
		par->riva.LockUnlock(&par->riva, 1);
	}
	atomic_dec(&par->ref_count);
	return 0;
}
static int xboxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
	int nom, den;		/* translating from pixels->bytes */
	
	switch (var->bits_per_pixel) {
	case 1 ... 8:
		var->red.offset = var->green.offset = var->blue.offset = 0;
		var->red.length = var->green.length = var->blue.length = 8;
		var->bits_per_pixel = 8;
		nom = den = 1;
		break;
	case 9 ... 15:
		var->green.length = 5;
		/* fall through */
	case 16:
		var->bits_per_pixel = 16;
		if (var->green.length == 5) {
			/* 0rrrrrgg gggbbbbb */
			var->red.offset = 10;
			var->green.offset = 5;
			var->blue.offset = 0;
			var->red.length = 5;
			var->green.length = 5;
			var->blue.length = 5;
		} else {
			/* rrrrrggg gggbbbbb */
			var->red.offset = 11;
			var->green.offset = 5;
			var->blue.offset = 0;
			var->red.length = 5;
			var->green.length = 6;
			var->blue.length = 5;
		}
		nom = 2;
		den = 1;
		break;
	case 17 ... 32:
		var->red.length = var->green.length = var->blue.length = 8;
		var->bits_per_pixel = 32;
		var->red.offset = 16;
		var->green.offset = 8;
		var->blue.offset = 0;
		nom = 4;
		den = 1;
		break;
	default:
		printk(KERN_ERR PFX
		       "mode %dx%dx%d rejected...color depth not supported.\n",
		       var->xres, var->yres, var->bits_per_pixel);
		DPRINTK("EXIT, returning -EINVAL\n");
		return -EINVAL;
	}
	if (xboxfb_do_maximize(info, var, nom, den) < 0)
		return -EINVAL;
	if (var->xoffset < 0)
		var->xoffset = 0;
	if (var->yoffset < 0)
		var->yoffset = 0;
	/* truncate xoffset and yoffset to maximum if too high */
	if (var->xoffset > var->xres_virtual - var->xres)
		var->xoffset = var->xres_virtual - var->xres - 1;
	if (var->yoffset > var->yres_virtual - var->yres)
		var->yoffset = var->yres_virtual - var->yres - 1;
	var->red.msb_right = 
	    var->green.msb_right =
	    var->blue.msb_right =
	    var->transp.offset = var->transp.length = var->transp.msb_right = 0;
	return 0;
}
static int xboxfb_set_par(struct fb_info *info)
{
	struct riva_par *par = (struct riva_par *) info->par;
	riva_load_video_mode(info);
	riva_setup_accel(par);
	
	info->fix.line_length = (info->var.xres_virtual * (info->var.bits_per_pixel >> 3));
	info->fix.visual = (info->var.bits_per_pixel == 8) ?
				FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
	return 0;
}
/**
 * xboxfb_pan_display
 * @var: standard kernel fb changeable data
 * @con: TODO
 * @info: pointer to fb_info object containing info for current riva board
 *
 * DESCRIPTION:
 * Pan (or wrap, depending on the `vmode' field) the display using the
 * `xoffset' and `yoffset' fields of the `var' structure.
 * If the values don't fit, return -EINVAL.
 *
 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
 */
static int xboxfb_pan_display(struct fb_var_screeninfo *var,
			      struct fb_info *info)
{
	struct riva_par *par = (struct riva_par *)info->par;
	unsigned int base;
	if (var->xoffset > (var->xres_virtual - var->xres))
		return -EINVAL;
	if (var->yoffset > (var->yres_virtual - var->yres))
		return -EINVAL;
	if (var->vmode & FB_VMODE_YWRAP) {
		if (var->yoffset < 0
		    || var->yoffset >= info->var.yres_virtual
		    || var->xoffset) return -EINVAL;
	} else {
		if (var->xoffset + info->var.xres > info->var.xres_virtual ||
		    var->yoffset + info->var.yres > info->var.yres_virtual)
			return -EINVAL;
	}
	base = var->yoffset * info->fix.line_length + var->xoffset;
	base += par->riva_fb_start;
	
	par->riva.SetStartAddress(&par->riva, base);
	info->var.xoffset = var->xoffset;
	info->var.yoffset = var->yoffset;
	if (var->vmode & FB_VMODE_YWRAP)
		info->var.vmode |= FB_VMODE_YWRAP;
	else
		info->var.vmode &= ~FB_VMODE_YWRAP;
	return 0;
}
static int xboxfb_blank(int blank, struct fb_info *info)
{
	struct riva_par *par= (struct riva_par *)info->par;
	unsigned char tmp, vesa;
	tmp = SEQin(par, 0x01) & ~0x20;	/* screen on/off */
	vesa = CRTCin(par, 0x1a) & ~0xc0;	/* sync on/off */
	if (blank) {
		tmp |= 0x20;
		switch (blank - 1) {
		case VESA_NO_BLANKING:
			break;
		case VESA_VSYNC_SUSPEND:
			vesa |= 0x80;
			break;
		case VESA_HSYNC_SUSPEND:
			vesa |= 0x40;
			break;
		case VESA_POWERDOWN:
			vesa |= 0xc0;
			break;
		}
	}
	SEQout(par, 0x01, tmp);
	CRTCout(par, 0x1a, vesa);
	return 0;
}
/**
 * xboxfb_setcolreg
 * @regno: register index
 * @red: red component
 * @green: green component
 * @blue: blue component
 * @transp: transparency
 * @info: pointer to fb_info object containing info for current riva board
 *
 * DESCRIPTION:
 * Set a single color register. The values supplied have a 16 bit
 * magnitude.
 *
 * RETURNS:
 * Return != 0 for invalid regno.
 *
 * CALLED FROM:
 * fbcmap.c:fb_set_cmap()
 */
static int xboxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
			  unsigned blue, unsigned transp,
			  struct fb_info *info)
{
	struct riva_par *par = (struct riva_par *)info->par;
	RIVA_HW_INST *chip = &par->riva;
	int i;
	if (regno >= riva_get_cmap_len(&info->var))
		return -EINVAL;
	if (info->var.grayscale) {
		/* gray = 0.30*R + 0.59*G + 0.11*B */
		red = green = blue =
		    (red * 77 + green * 151 + blue * 28) >> 8;
	}
	switch (info->var.bits_per_pixel) {
	case 8:
		/* "transparent" stuff is completely ignored. */
		riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8);
		break;
	case 16:
		if (info->var.green.length == 5) {
			if (regno < 16) {
				/* 0rrrrrgg gggbbbbb */
				((u32 *)info->pseudo_palette)[regno] =
					((red & 0xf800) >> 1) |
					((green & 0xf800) >> 6) |
					((blue & 0xf800) >> 11);
			}
			for (i = 0; i < 8; i++) 
				riva_wclut(chip, regno*8+i, red >> 8,
					   green >> 8, blue >> 8);
		} else {
			u8 r, g, b;
			if (regno < 16) {
				/* rrrrrggg gggbbbbb */
				((u32 *)info->pseudo_palette)[regno] =
					((red & 0xf800) >> 0) |
					((green & 0xf800) >> 5) |
					((blue & 0xf800) >> 11);
			}
			if (regno < 32) {
				for (i = 0; i < 8; i++) {
					riva_wclut(chip, regno*8+i, red >> 8, 
						   green >> 8, blue >> 8);
				}
			}
			for (i = 0; i < 4; i++) {
				riva_rclut(chip, regno*2+i, &r, &g, &b);
				riva_wclut(chip, regno*4+i, r, green >> 8, b);
			}
		}
		break;
	case 32:
		if (regno < 16) {
			((u32 *)info->pseudo_palette)[regno] =
				((red & 0xff00) << 8) |
				((green & 0xff00)) | ((blue & 0xff00) >> 8);
			
		}
		riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8);
		break;
	default:
		/* do nothing */
		break;
	}
	return 0;
}
/**
 * xboxfb_fillrect - hardware accelerated color fill function
 * @info: pointer to fb_info structure
 * @rect: pointer to fb_fillrect structure
 *
 * DESCRIPTION:
 * This function fills up a region of framebuffer memory with a solid
 * color with a choice of two different ROP's, copy or invert.
 *
 * CALLED FROM:
 * framebuffer hook
 */
static void xboxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
	struct riva_par *par = (struct riva_par *) info->par;
	u_int color, rop = 0;
	if (info->var.bits_per_pixel == 8)
		color = rect->color;
	else
		color = ((u32 *)info->pseudo_palette)[rect->color];
	switch (rect->rop) {
	case ROP_XOR:
		rop = 0x66;
		break;
	case ROP_COPY:
	default:
		rop = 0xCC;
		break;
	}
	RIVA_FIFO_FREE(par->riva, Rop, 1);
	par->riva.Rop->Rop3 = rop;
	RIVA_FIFO_FREE(par->riva, Bitmap, 1);
	par->riva.Bitmap->Color1A = color;
	RIVA_FIFO_FREE(par->riva, Bitmap, 2);
	par->riva.Bitmap->UnclippedRectangle[0].TopLeft =
			(rect->dx << 16) | rect->dy;
	par->riva.Bitmap->UnclippedRectangle[0].WidthHeight =
			(rect->width << 16) | rect->height;
	RIVA_FIFO_FREE(par->riva, Rop, 1);
	par->riva.Rop->Rop3 = 0xCC;	/* back to COPY */
}
/**
 * xboxfb_copyarea - hardware accelerated blit function
 * @info: pointer to fb_info structure
 * @region: pointer to fb_copyarea structure
 *
 * DESCRIPTION:
 * This copies an area of pixels from one location to another
 *
 * CALLED FROM:
 * framebuffer hook
 */
static void xboxfb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
	struct riva_par *par = (struct riva_par *) info->par;
	RIVA_FIFO_FREE(par->riva, Blt, 3);
	par->riva.Blt->TopLeftSrc  = (region->sy << 16) | region->sx;
	par->riva.Blt->TopLeftDst  = (region->dy << 16) | region->dx;
	par->riva.Blt->WidthHeight = (region->height << 16) | region->width;
	wait_for_idle(par);
}
static inline void convert_bgcolor_16(u32 *col)
{
	*col = ((*col & 0x00007C00) << 9)
		| ((*col & 0x000003E0) << 6)
		| ((*col & 0x0000001F) << 3)
		|	   0xFF000000;
}
/**
 * xboxfb_imageblit: hardware accelerated color expand function
 * @info: pointer to fb_info structure
 * @image: pointer to fb_image structure
 *
 * DESCRIPTION:
 * If the source is a monochrome bitmap, the function fills up a a region
 * of framebuffer memory with pixels whose color is determined by the bit
 * setting of the bitmap, 1 - foreground, 0 - background.
 *
 * If the source is not a monochrome bitmap, color expansion is not done.
 * In this case, it is channeled to a software function.
 *
 * CALLED FROM:
 * framebuffer hook
 */
static void xboxfb_imageblit(struct fb_info *info, 
			     const struct fb_image *image)
{
	struct riva_par *par = (struct riva_par *) info->par;
	u32 fgx = 0, bgx = 0, width, tmp;
	u8 *cdat = (u8 *) image->data;
	volatile u32 *d;
	int i, size;
	if (image->depth != 1) {
		cfb_imageblit(info, image);
		return;
	}
	switch (info->var.bits_per_pixel) {
	case 8:
		fgx = image->fg_color;
		bgx = image->bg_color;
		break;
	case 16:
		fgx = ((u32 *)info->pseudo_palette)[image->fg_color];
		bgx = ((u32 *)info->pseudo_palette)[image->bg_color];
		if (info->var.green.length == 6)
			convert_bgcolor_16(&bgx);	
		break;
	case 32:
		fgx = ((u32 *)info->pseudo_palette)[image->fg_color];
		bgx = ((u32 *)info->pseudo_palette)[image->bg_color];
		break;
	}
	RIVA_FIFO_FREE(par->riva, Bitmap, 7);
	par->riva.Bitmap->ClipE.TopLeft     = 
		(image->dy << 16) | (image->dx & 0xFFFF);
	par->riva.Bitmap->ClipE.BottomRight = 
		(((image->dy + image->height) << 16) |
		 ((image->dx + image->width) & 0xffff));
	par->riva.Bitmap->Color0E           = bgx;
	par->riva.Bitmap->Color1E           = fgx;
	par->riva.Bitmap->WidthHeightInE    = 
		(image->height << 16) | ((image->width + 31) & ~31);
	par->riva.Bitmap->WidthHeightOutE   = 
		(image->height << 16) | ((image->width + 31) & ~31);
	par->riva.Bitmap->PointE            = 
		(image->dy << 16) | (image->dx & 0xFFFF);
	d = &par->riva.Bitmap->MonochromeData01E;
	width = (image->width + 31)/32;
	size = width * image->height;
	while (size >= 16) {
		RIVA_FIFO_FREE(par->riva, Bitmap, 16);
		for (i = 0; i < 16; i++) {
			tmp = *((u32 *)cdat);
			cdat = (u8 *)((u32 *)cdat + 1);
			reverse_order(&tmp);
			d[i] = tmp;
		}
		size -= 16;
	}
	if (size) {
		RIVA_FIFO_FREE(par->riva, Bitmap, size);
		for (i = 0; i < size; i++) {
			tmp = *((u32 *) cdat);
			cdat = (u8 *)((u32 *)cdat + 1);
			reverse_order(&tmp);
			d[i] = tmp;
		}
	}
}
/**
 * xboxfb_cursor - hardware cursor function
 * @info: pointer to info structure
 * @cursor: pointer to fbcursor structure
 *
 * DESCRIPTION:
 * A cursor function that supports displaying a cursor image via hardware.
 * Within the kernel, copy and invert rops are supported.  If exported
 * to user space, only the copy rop will be supported.
 *
 * CALLED FROM
 * framebuffer hook
 */
static int xboxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
	struct riva_par *par = (struct riva_par *) info->par;
	u8 mask[MAX_CURS * MAX_CURS/8];
	u16 fg, bg;
	par->riva.ShowHideCursor(&par->riva, 0);
	if (cursor->set & FB_CUR_SETPOS) {
		u32 xx, yy, temp;
		info->cursor.image.dx = cursor->image.dx;
		info->cursor.image.dy = cursor->image.dy;
		yy = cursor->image.dy - info->var.yoffset;
		xx = cursor->image.dx - info->var.xoffset;
		temp = xx & 0xFFFF;
		temp |= yy << 16;
		par->riva.PRAMDAC[0x0000300/4] = temp;
	}
	if (cursor->set & FB_CUR_SETSIZE) {
		info->cursor.image.height = cursor->image.height;
		info->cursor.image.width = cursor->image.width;
		memset_io(par->riva.CURSOR, 0, MAX_CURS * MAX_CURS * 2);
	}
	if (cursor->set & FB_CUR_SETCMAP) {
		info->cursor.image.bg_color = cursor->image.bg_color;
		info->cursor.image.fg_color = cursor->image.fg_color;
	}
	if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP)) {
		u32 bg_idx = info->cursor.image.bg_color;
		u32 fg_idx = info->cursor.image.fg_color;
		u32 s_pitch = (info->cursor.image.width+7) >> 3;
		u32 d_pitch = MAX_CURS/8;
		u8 *msk = (u8 *) info->cursor.mask;
		
		fb_move_buf_aligned(info, &info->sprite, mask, d_pitch, msk, s_pitch, info->cursor.image.height);
		bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
		     ((info->cmap.green[bg_idx] & 0xf8) << 2) |
		     ((info->cmap.blue[bg_idx] & 0xf8) >> 3);
		fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
		     ((info->cmap.green[fg_idx] & 0xf8) << 2) |
		     ((info->cmap.blue[fg_idx] & 0xf8) >> 3);
		par->riva.LockUnlock(&par->riva, 0);
		xboxfb_load_cursor_image(par, mask, mask, bg, fg,
					 info->cursor.image.width, 
					 info->cursor.image.height);
	}
	if (info->cursor.enable)
		par->riva.ShowHideCursor(&par->riva, 1);
	return 0;
}
static int xboxfb_sync(struct fb_info *info)
{
	struct riva_par *par = (struct riva_par *)info->par;
	wait_for_idle(par);
	return 0;
}
static int xboxfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        unsigned long arg, struct fb_info *info)
{
	struct riva_par *par = (struct riva_par *) info->par;
	
	xbox_overscan overscan;
	xboxfb_config config;
	xbox_tv_encoding encoding;
	int ret = 0;
	switch (cmd) {
	case FBIO_XBOX_SET_OVERSCAN:
		if(!copy_from_user(&overscan, (xbox_overscan*)arg, sizeof(overscan))) {
			par->hoc = overscan.hoc;
			par->voc = overscan.voc;
			riva_load_video_mode (info);
			if (info->var.accel_flags & FB_ACCELF_TEXT) {
				riva_setup_accel(par);
			}
		}
		else {
			ret = -EFAULT;
		}
	break;
	case FBIO_XBOX_GET_OVERSCAN:
		overscan.hoc = par->hoc;
		overscan.voc = par->voc;
		if (copy_to_user((xbox_overscan*)arg, &overscan, sizeof(overscan))) {
			ret = -EFAULT;
		}
	break;
	case FBIO_XBOX_GET_CONFIG:
		config.av_type = par->av_type;
		config.encoder_type = par->video_encoder;
		if (copy_to_user((xboxfb_config*)arg, &config, sizeof(config))) {
			ret = -EFAULT;
		}
	break;
	case FBIO_XBOX_GET_TV_ENCODING:
		encoding = par->tv_encoding;
		if (copy_to_user((xbox_tv_encoding*)arg, &encoding, sizeof(encoding))) {
			ret = -EFAULT;
		}
	break;
	case FBIO_XBOX_SET_TV_ENCODING:
		if(!copy_from_user(&encoding, (xbox_tv_encoding*)arg, sizeof(encoding))) {
			par->tv_encoding = encoding;
			riva_load_video_mode (info);
			if (info->var.accel_flags & FB_ACCELF_TEXT) {
				riva_setup_accel(par);
			}
		}
		else {
			ret = -EFAULT;
		}
	break;
	default:
		ret = -EINVAL;
	}
	return ret;
}
/* ------------------------------------------------------------------------- *
 *
 * initialization helper functions
 *
 * ------------------------------------------------------------------------- */
/* kernel interface */
static struct fb_ops riva_fb_ops = {
	.owner 		= THIS_MODULE,
	.fb_open	= xboxfb_open,
	.fb_release	= xboxfb_release,
	.fb_check_var 	= xboxfb_check_var,
	.fb_set_par 	= xboxfb_set_par,
	.fb_setcolreg 	= xboxfb_setcolreg,
	.fb_pan_display	= xboxfb_pan_display,
	.fb_blank 	= xboxfb_blank,
	.fb_fillrect 	= xboxfb_fillrect,
	.fb_copyarea 	= xboxfb_copyarea,
	.fb_imageblit 	= xboxfb_imageblit,
	.fb_cursor	= xboxfb_cursor,
	.fb_sync 	= xboxfb_sync,
	.fb_ioctl	= xboxfb_ioctl,
};
static int __devinit riva_set_fbinfo(struct fb_info *info)
{
	struct riva_par *par = (struct riva_par *) info->par;
	unsigned int cmap_len;
	info->flags = FBINFO_FLAG_DEFAULT;
	info->var = xboxfb_default_var;
	info->fix = xboxfb_fix;
	info->fbops = &riva_fb_ops;
	info->pseudo_palette = pseudo_palette;
#ifndef MODULE
	if (mode_option)
	{
		if (!strncmp(mode_option, "480p", 4)) {
			info->var = xboxfb_mode_480p;
		}
		else if (!strncmp(mode_option, "720p", 4)) {
			info->var = xboxfb_mode_720p;
		}
		else {
			fb_find_mode(&info->var, info, mode_option,
				NULL, 0, NULL, 8);
		}
	}
#endif
	if (par->use_default_var)
		/* We will use the modified default var */
		info->var = xboxfb_default_var;
	cmap_len = riva_get_cmap_len(&info->var);
	fb_alloc_cmap(&info->cmap, cmap_len, 0);	
	info->pixmap.size = 64 * 1024;
	info->pixmap.buf_align = 4;
	info->pixmap.scan_align = 4;
	info->pixmap.flags = FB_PIXMAP_SYSTEM;
	return 0;
}
#ifdef CONFIG_PPC_OF
static int riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
{
	struct riva_par *par = (struct riva_par *) info->par;
	struct device_node *dp;
	unsigned char *pedid = NULL;
	dp = pci_device_to_OF_node(pd);
	pedid = (unsigned char *)get_property(dp, "EDID,B", 0);
	if (pedid) {
		par->EDID = pedid;
		return 1;
	} else
		return 0;
}
#endif /* CONFIG_PPC_OF */
static int riva_dfp_parse_EDID(struct riva_par *par)
{
	unsigned char *block = par->EDID;
	if (!block)
		return 0;
	/* jump to detailed timing block section */
	block += 54;
	par->clock = (block[0] + (block[1] << 8));
	par->panel_xres = (block[2] + ((block[4] & 0xf0) << 4));
	par->hblank = (block[3] + ((block[4] & 0x0f) << 8));
	par->panel_yres = (block[5] + ((block[7] & 0xf0) << 4));
	par->vblank = (block[6] + ((block[7] & 0x0f) << 8));
	par->hOver_plus = (block[8] + ((block[11] & 0xc0) << 2));
	par->hSync_width = (block[9] + ((block[11] & 0x30) << 4));
	par->vOver_plus = ((block[10] >> 4) + ((block[11] & 0x0c) << 2));
	par->vSync_width = ((block[10] & 0x0f) + ((block[11] & 0x03) << 4));
	par->interlaced = ((block[17] & 0x80) >> 7);
	par->synct = ((block[17] & 0x18) >> 3);
	par->misc = ((block[17] & 0x06) >> 1);
	par->hAct_high = par->vAct_high = 0;
	if (par->synct == 3) {
		if (par->misc & 2)
			par->hAct_high = 1;
		if (par->misc & 1)
			par->vAct_high = 1;
	}
	printk(KERN_INFO PFX
			"detected DFP panel size from EDID: %dx%d\n", 
			par->panel_xres, par->panel_yres);
	par->got_dfpinfo = 1;
	return 1;
}
static void riva_update_default_var(struct fb_info *info)
{
	struct fb_var_screeninfo *var = &xboxfb_default_var;
	struct riva_par *par = (struct riva_par *) info->par;
        var->xres = par->panel_xres;
        var->yres = par->panel_yres;
        var->xres_virtual = par->panel_xres;
        var->yres_virtual = par->panel_yres;
        var->xoffset = var->yoffset = 0;
        var->bits_per_pixel = 8;
        var->pixclock = 100000000 / par->clock;
        var->left_margin = (par->hblank - par->hOver_plus - par->hSync_width);
        var->right_margin = par->hOver_plus;
        var->upper_margin = (par->vblank - par->vOver_plus - par->vSync_width);
        var->lower_margin = par->vOver_plus;
        var->hsync_len = par->hSync_width;
        var->vsync_len = par->vSync_width;
        var->sync = 0;
        if (par->synct == 3) {
                if (par->hAct_high)
                        var->sync |= FB_SYNC_HOR_HIGH_ACT;
                if (par->vAct_high)
                        var->sync |= FB_SYNC_VERT_HIGH_ACT;
        }
 
        var->vmode = 0;
        if (par->interlaced)
                var->vmode |= FB_VMODE_INTERLACED;
	var->accel_flags |= FB_ACCELF_TEXT;
        
        par->use_default_var = 1;
}
static void riva_get_EDID(struct fb_info *info, struct pci_dev *pdev)
{
#ifdef CONFIG_PPC_OF
	if (!riva_get_EDID_OF(info, pdev))
		printk("xboxfb: could not retrieve EDID from OF\n");
#else
	/* XXX use other methods later */
#endif
}
static void riva_get_dfpinfo(struct fb_info *info)
{
	struct riva_par *par = (struct riva_par *) info->par;
	if (riva_dfp_parse_EDID(par))
		riva_update_default_var(info);
	/* if user specified flatpanel, we respect that */
	if (par->got_dfpinfo == 1)
		par->FlatPanel = 1;
}
/* ------------------------------------------------------------------------- *
 *
 * PCI bus
 *
 * ------------------------------------------------------------------------- */
static int __devinit xboxfb_probe(struct pci_dev *pd,
			     	const struct pci_device_id *ent)
{
	struct riva_chip_info *rci = &riva_chip_info[ent->driver_data];
	struct riva_par *default_par;
	struct fb_info *info;
	unsigned long fb_start;
	unsigned long fb_size;
	assert(pd != NULL);
	assert(rci != NULL);
	info = kmalloc(sizeof(struct fb_info), GFP_KERNEL);
	if (!info)
		goto err_out;
	default_par = kmalloc(sizeof(struct riva_par), GFP_KERNEL);
	if (!default_par)
		goto err_out_kfree;
	memset(info, 0, sizeof(struct fb_info));
	memset(default_par, 0, sizeof(struct riva_par));
	info->pixmap.addr = kmalloc(64 * 1024, GFP_KERNEL);
	if (info->pixmap.addr == NULL)
		goto err_out_kfree1;
	memset(info->pixmap.addr, 0, 64 * 1024);
	strcat(xboxfb_fix.id, rci->name);
	default_par->riva.Architecture = rci->arch_rev;
	default_par->Chipset = (pd->vendor << 16) | pd->device;
	printk(KERN_INFO PFX "nVidia device/chipset %X\n",default_par->Chipset);
	
	default_par->FlatPanel = flatpanel;
	if (flatpanel == 1)
		printk(KERN_INFO PFX "flatpanel support enabled\n");
	default_par->forceCRTC = forceCRTC;
	
	xboxfb_fix.mmio_len = pci_resource_len(pd, 0);
	{
		/* enable IO and mem if not already done */
		unsigned short cmd;
		pci_read_config_word(pd, PCI_COMMAND, &cmd);
		cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
		pci_write_config_word(pd, PCI_COMMAND, cmd);
	}
	
	xboxfb_fix.mmio_start = pci_resource_start(pd, 0);
	xboxfb_fix.smem_start = pci_resource_start(pd, 1);
	
        if (xbox_memory_size() == 64*1024*1024) printk(KERN_INFO PFX "Detected 64MB of system RAM\n");
	else printk(KERN_INFO PFX "Detected 128MB of system RAM\n");
	
	fb_size = available_framebuffer_memory();
	fb_start = xbox_memory_size() - fb_size;
	printk(KERN_INFO PFX "Using %dM framebuffer memory\n", (int)(fb_size/(1024*1024)));
	default_par->riva_fb_start = fb_start;
	xboxfb_fix.smem_start += fb_start;
	xboxfb_fix.smem_len = fb_size; 
	tv_init();
	if (tv_encoding == TV_ENC_INVALID) {
		tv_encoding = get_tv_encoding();
		printk(KERN_INFO PFX "Setting TV mode from EEPROM (%s)\n", tvEncodingNames[tv_encoding]);
	}
	default_par->tv_encoding = tv_encoding;
	default_par->video_encoder = tv_get_video_encoder();
	switch(default_par->video_encoder) {
		case ENCODER_CONEXANT:
			printk(KERN_INFO PFX "detected conexant encoder\n");
			break;
		case ENCODER_FOCUS:
			printk(KERN_INFO PFX "detected focus encoder\n");
			break;
		case ENCODER_XLB:
			printk(KERN_INFO PFX "detected Xcalibur encoder\n");
			break;
		default: 
			printk(KERN_INFO PFX "detected unknown encoder\n");
	}
	
	
	if (av_type == AV_INVALID) {
		av_type = detect_av_type();
		printk(KERN_INFO PFX "Setting cable type from AVIP ID: %s\n", avTypeNames[av_type]);
	}
	default_par->av_type = av_type;
	if ((hoc < 0) || (hoc > 20)) {
		hoc = 10;
	}
	default_par->hoc = hoc / 100.0;
	if ((voc < 0) || (voc > 20)) {
		voc = 10;
	}
	default_par->voc = voc / 100.0;
	
	if (!request_mem_region(xboxfb_fix.mmio_start,
				xboxfb_fix.mmio_len, "xboxfb")) {
		printk(KERN_ERR PFX "cannot reserve MMIO region\n");
		goto err_out_kfree2;
	}
	default_par->ctrl_base = ioremap(xboxfb_fix.mmio_start,
					 xboxfb_fix.mmio_len);
	if (!default_par->ctrl_base) {
		printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
		goto err_out_free_base0;
	}
	info->par = default_par;
	riva_get_EDID(info, pd);
	riva_get_dfpinfo(info);
	switch (default_par->riva.Architecture) {
	case NV_ARCH_03:
		/* Riva128's PRAMIN is in the "framebuffer" space
		 * Since these cards were never made with more than 8 megabytes
		 * we can safely allocate this separately.
		 */
		if (!request_mem_region(xboxfb_fix.smem_start + 0x00C00000,
					 0x00008000, "xboxfb")) {
			printk(KERN_ERR PFX "cannot reserve PRAMIN region\n");
			goto err_out_iounmap_ctrl;
		}
		default_par->riva.PRAMIN = ioremap(xboxfb_fix.smem_start + 0x00C00000, 0x00008000);
		if (!default_par->riva.PRAMIN) {
			printk(KERN_ERR PFX "cannot ioremap PRAMIN region\n");
			goto err_out_free_nv3_pramin;
		}
		xboxfb_fix.accel = FB_ACCEL_NV3;
		break;
	case NV_ARCH_04:
	case NV_ARCH_10:
	case NV_ARCH_20:
		default_par->riva.PCRTC0 = (unsigned *)(default_par->ctrl_base + 0x00600000);
		default_par->riva.PRAMIN = (unsigned *)(default_par->ctrl_base + 0x00710000);
		xboxfb_fix.accel = FB_ACCEL_NV4;
		break;
	}
	riva_common_setup(default_par);
	if (default_par->riva.Architecture == NV_ARCH_03) {
		default_par->riva.PCRTC = default_par->riva.PCRTC0 = default_par->riva.PGRAPH;
	}
	/* xboxfb_fix.smem_len = riva_get_memlen(default_par) * 1024; */
	default_par->dclk_max = riva_get_maxdclk(default_par) * 1000;
	if (!request_mem_region(xboxfb_fix.smem_start, xboxfb_fix.smem_len, "xboxfb")) {
		printk(KERN_ERR PFX "cannot reserve FB region\n");
		goto err_out_iounmap_nv3_pramin;
	}
	
	info->screen_base = ioremap(xboxfb_fix.smem_start, fb_size);
	if (!info->screen_base) {
		printk(KERN_ERR PFX "cannot ioremap FB base\n");
		goto err_out_free_base1;
	}
#ifdef CONFIG_MTRR
	if (!nomtrr) {
		default_par->mtrr.vram = mtrr_add(xboxfb_fix.smem_start, fb_size,
			MTRR_TYPE_WRCOMB, 1);
		if (default_par->mtrr.vram < 0) {
			printk(KERN_ERR PFX "unable to setup MTRR\n");
		} else {
			default_par->mtrr.vram_valid = 1;
			/* let there be speed */
			printk(KERN_INFO PFX "RIVA MTRR set to ON\n");
		}
	}
#endif /* CONFIG_MTRR */
	if (riva_set_fbinfo(info) < 0) {
		printk(KERN_ERR PFX "error setting initial video mode\n");
		goto err_out_iounmap_fb;
	}
	if (register_framebuffer(info) < 0) {
		printk(KERN_ERR PFX
			"error registering riva framebuffer\n");
		goto err_out_iounmap_fb;
	}
	pci_set_drvdata(pd, info);
	printk(KERN_INFO PFX
		"PCI nVidia NV%x framebuffer ver %s (%s, %ldMB @ 0x%lX)\n",
		default_par->riva.Architecture,
		RIVAFB_VERSION,
		info->fix.id,
		fb_size / (1024 * 1024),
		info->fix.smem_start);
	return 0;
err_out_iounmap_fb:
	iounmap(info->screen_base);
err_out_free_base1:
	release_mem_region(xboxfb_fix.smem_start, fb_size);
err_out_iounmap_nv3_pramin:
	if (default_par->riva.Architecture == NV_ARCH_03) 
		iounmap((caddr_t)default_par->riva.PRAMIN);
err_out_free_nv3_pramin:
	if (default_par->riva.Architecture == NV_ARCH_03)
		release_mem_region(xboxfb_fix.smem_start + 0x00C00000, 0x00008000);
err_out_iounmap_ctrl:
	iounmap(default_par->ctrl_base);
err_out_free_base0:
	release_mem_region(xboxfb_fix.mmio_start, xboxfb_fix.mmio_len);
err_out_kfree2:
	kfree(info->pixmap.addr);
err_out_kfree1:
	kfree(default_par);
err_out_kfree:
	kfree(info);
err_out:
	return -ENODEV;
}
static void __exit xboxfb_remove(struct pci_dev *pd)
{
	struct fb_info *info = pci_get_drvdata(pd);
	struct riva_par *par = (struct riva_par *) info->par;
	
	if (!info)
		return;
	unregister_framebuffer(info);
#ifdef CONFIG_MTRR
	if (par->mtrr.vram_valid)
		mtrr_del(par->mtrr.vram, info->fix.smem_start, info->fix.smem_len);
#endif /* CONFIG_MTRR */
	iounmap(par->ctrl_base);
	iounmap(info->screen_base);
	release_mem_region(info->fix.mmio_start,
			   info->fix.mmio_len);
	release_mem_region(info->fix.smem_start, info->fix.smem_len);
	if (par->riva.Architecture == NV_ARCH_03) {
		iounmap((caddr_t)par->riva.PRAMIN);
		release_mem_region(info->fix.smem_start + 0x00C00000, 0x00008000);
	}
	kfree(info->pixmap.addr);
	kfree(par);
	kfree(info);
	pci_set_drvdata(pd, NULL);
}
/* ------------------------------------------------------------------------- *
 *
 * initialization
 *
 * ------------------------------------------------------------------------- */
#ifndef MODULE
int __init xboxfb_setup(char *options)
{
	char *this_opt;
	if (!options || !*options)
		return 0;
	while ((this_opt = strsep(&options, ",")) != NULL) {
		if (!strncmp(this_opt, "forceCRTC", 9)) {
			char *p;
			
			p = this_opt + 9;
			if (!*p || !*(++p)) continue; 
			forceCRTC = *p - '0';
			if (forceCRTC < 0 || forceCRTC > 1) 
				forceCRTC = -1;
		} else if (!strncmp(this_opt, "flatpanel", 9)) {
			flatpanel = 1;
#ifdef CONFIG_MTRR
		} else if (!strncmp(this_opt, "nomtrr", 6)) {
			nomtrr = 1;
#endif
		} else if (!strncmp(this_opt, "tv=", 3)) {
				if(!strncmp(this_opt + 3, "PAL", 3)) {
						tv_encoding = TV_ENC_PALBDGHI;
				}
				else if(!strncmp(this_opt + 3, "NTSC", 4)) {
						tv_encoding = TV_ENC_NTSC;
				}
				else if(!strncmp(this_opt + 3, "VGA", 3)) {
						av_type = AV_VGA_SOG;
				}
		} else if (!strncmp(this_opt, "hoc=", 4)) {
				sscanf(this_opt+4, "%d", &hoc);
		} else if (!strncmp(this_opt, "voc=", 4)) {
				sscanf(this_opt+4, "%d", &voc);
		} else
			mode_option = this_opt;
	}
	return 0;
}
#endif /* !MODULE */
static struct pci_driver xboxfb_driver = {
	.name		= "xboxfb",
	.id_table	= xboxfb_pci_tbl,
	.probe		= xboxfb_probe,
	.remove		= __exit_p(xboxfb_remove),
};
/* ------------------------------------------------------------------------- *
 *
 * modularization
 *
 * ------------------------------------------------------------------------- */
int __init xboxfb_init(void)
{
	if (pci_register_driver(&xboxfb_driver) > 0)
		return 0;
	pci_unregister_driver(&xboxfb_driver);
	return -ENODEV;
}
#ifdef MODULE
static void __exit xboxfb_exit(void)
{
	pci_unregister_driver(&xboxfb_driver);
}
module_init(xboxfb_init);
module_exit(xboxfb_exit);
MODULE_PARM(flatpanel, "i");
MODULE_PARM_DESC(flatpanel, "Enables experimental flat panel support for some chipsets. (0 or 1=enabled) (default=0)");
MODULE_PARM(forceCRTC, "i");
MODULE_PARM_DESC(forceCRTC, "Forces usage of a particular CRTC in case autodetection fails. (0 or 1) (default=autodetect)");
#ifdef CONFIG_MTRR
MODULE_PARM(nomtrr, "i");
MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) (default=0)");
#endif
MODULE_PARM(tv, "s");
MODULE_PARM_DESC(tv, "Specifies the TV encoding (\"PAL\", \"NTSC\" or \"VGA\").");
MODULE_PARM(hoc, "i");
MODULE_PARM_DESC(hoc, "Horizontal overscan compensation ratio, in % (0-20)");
MODULE_PARM(voc, "i");
MODULE_PARM_DESC(voc, "Vertical overscan compensation ratio, in % (0-20)");
#endif /* MODULE */
MODULE_AUTHOR("Oliver Schwartz");
MODULE_DESCRIPTION("Framebuffer driver for Xbox");
MODULE_LICENSE("GPL");
(-) linux-2.6.6.orig/drivers/video/xbox/focus.c (+328 lines)
Line 0    Link Here 
/*
 * linux/drivers/video/riva/focus.c - Xbox driver for Focus encoder
 *
 * Maintainer: David Pye (dmp) <dmp@davidmpye.dyndns.org>
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 *
 * Known bugs and issues:
 *
 * VGA SoG/internal sync not yet implemented
*/
#include "focus.h"
#include "encoder.h"
static const unsigned char focus_defaults[0xc4] = {
	/*0x00*/ 0x00,0x00,0x00,0x00,0x80,0x02,0xaa,0x0a,
	/*0x08*/ 0x00,0x10,0x00,0x00,0x03,0x21,0x15,0x04,
	/*0x10*/ 0x00,0xe9,0x07,0x00,0x80,0xf5,0x20,0x00,
	/*0x18*/ 0xef,0x21,0x1f,0x00,0x03,0x03,0x00,0x00,
	/*0x20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
	/*0x28*/ 0x0c,0x01,0x00,0x00,0x00,0x00,0x08,0x11,
	/*0x30*/ 0x00,0x0f,0x05,0xfe,0x0b,0x80,0x00,0x00,
	/*0x38*/ 0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	/*0x40*/ 0x2a,0x09,0x8a,0xcb,0x00,0x00,0x8d,0x00,
	/*0x48*/ 0x7c,0x3c,0x9a,0x2f,0x21,0x01,0x3f,0x00,
	/*0x50*/ 0x3e,0x03,0x17,0x21,0x1b,0x1b,0x24,0x9c,
	/*0x58*/ 0x01,0x3e,0x0f,0x0f,0x60,0x05,0xc8,0x00,
	/*0x60*/ 0x9d,0x04,0x9d,0x01,0x02,0x00,0x0a,0x05,
	/*0x68*/ 0x00,0x1a,0xff,0x03,0x1e,0x0f,0x78,0x00,
	/*0x70*/ 0x00,0xb1,0x04,0x15,0x49,0x10,0x00,0xa3,
	/*0x78*/ 0xc8,0x15,0x05,0x15,0x3e,0x03,0x00,0x20,
	/*0x80*/ 0x57,0x2f,0x07,0x00,0x00,0x08,0x00,0x00,
	/*0x88*/ 0x08,0x16,0x16,0x9c,0x03,0x00,0x00,0x00,
	/*0x90*/ 0x00,0x00,0xc4,0x48,0x00,0x00,0x00,0x00,
	/*0x98*/ 0x00,0x00,0x00,0x80,0x00,0x00,0xe4,0x00,
	/*0xa0*/ 0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
	/*0xa8*/ 0xFF,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,
	/*0xb0*/ 0x00,0x00,0xd7,0x05,0x00,0x00,0xf0,0x00,
	/*0xb8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	/*0xc0*/ 0x00,0x00,0xee,0x00
};
int focus_calc_hdtv_mode(
	xbox_hdtv_mode hdtv_mode,
	unsigned char pll_int,
	unsigned char * regs
	){
	unsigned char b;
	int m=0;
	int tv_vtotal, tv_htotal, tv_vactive, tv_hactive, vga_htotal, vga_vtotal;
	int pll_n, pll_m, pll_p, ncon, ncod;
	memcpy(regs,focus_defaults,sizeof(focus_defaults));	
	/* Uncomment for HDTV 480p colour bars */
	//regs[0x0d]|=0x02;
	
	/* Turn on bridge bypass */
	regs[0x0a] |= 0x10;
	/* Turn on the HDTV clock, and turn off the SDTV one */	
	regs[0xa1] = 0x04;
	
	/* HDTV Hor start */
	regs[0xb8] = 0xbe;
	
	/*Set up video mode to HDTV, progressive, 
	 * and disable YUV matrix bypass */
	regs[0x92] = 0x1a;	
	regs[0x93] &= ~0x40;
	
	switch (hdtv_mode) {
		case HDTV_480p:
			/* PLL settings */
			regs[0x10] = 0x00;
			regs[0x11] = 0x00;
			regs[0x12] = 0x00;
			regs[0x13] = 0x00;
			regs[0x14] = 0x00;
			regs[0x15] = 0x00;
			regs[0x16] = 0x00;
			regs[0x17] = 0x00;
			regs[0x18] = 0xD7;
			regs[0x19] = 0x03;
			regs[0x1A] = 0x7C;
			regs[0x1B] = 0x00;
			regs[0x1C] = 0x07;
			regs[0x1D] = 0x07;
			/* Porches/HSync width/Luma offset */
			regs[0x94] = 0x3F;
			regs[0x95] = 0x2D;
			regs[0x96] = 0x3B;
			regs[0x97] = 0x00;
			regs[0x98] = 0x1B;
			regs[0x99] = 0x03;
			/* Colour scaling */
			regs[0xA2] = 0x4D;
			regs[0xA4] = 0x96;
			regs[0xA6] = 0x1D;
			regs[0xA8] = 0x58;
			regs[0xAA] = 0x8A;
			regs[0xAC] = 0x4A;
			break;
		case HDTV_720p:
			/* PLL settings */
			regs[0x10] = 0x00;
			regs[0x11] = 0x00;
			regs[0x12] = 0x00;
			regs[0x13] = 0x00;
			regs[0x14] = 0x00;
			regs[0x15] = 0x00;
			regs[0x16] = 0x00;
			regs[0x17] = 0x00;
			regs[0x18] = 0x3B;
			regs[0x19] = 0x04;
			regs[0x1A] = 0xC7;
			regs[0x1B] = 0x00;
			regs[0x1C] = 0x01;
			regs[0x1D] = 0x01;
			/* Porches/HSync width/Luma offset */
			regs[0x94] = 0x28;
			regs[0x95] = 0x46;
			regs[0x96] = 0xDC;
			regs[0x97] = 0x00;
			regs[0x98] = 0x2C;
			regs[0x99] = 0x06;
			/* Colour scaling */
			regs[0xA2] = 0x36;
			regs[0xA4] = 0xB7;
			regs[0xA6] = 0x13;
			regs[0xA8] = 0x58;
			regs[0xAA] = 0x8A;
			regs[0xAC] = 0x4A;
			/* HSync timing invert - needed to centre picture */
			regs[0x93] |= 0x01;
			
			break;
		case HDTV_1080i:
			/* PLL settings */
			regs[0x10] = 0x00;
			regs[0x11] = 0x00;
			regs[0x12] = 0x00;
			regs[0x13] = 0x00;
			regs[0x14] = 0x00;
			regs[0x15] = 0x00;
			regs[0x16] = 0x00;
			regs[0x17] = 0x00;
			regs[0x18] = 0x3B;
			regs[0x19] = 0x04;
			regs[0x1A] = 0xC7;
			regs[0x1B] = 0x00;
			regs[0x1C] = 0x01;
			regs[0x1D] = 0x01;
			/* Porches/HSync width/Luma offset */
			regs[0x94] = 0x2C;
			regs[0x95] = 0x2C;
			regs[0x96] = 0x58;
			regs[0x97] = 0x00;
			regs[0x98] = 0x6C;
			regs[0x99] = 0x08;
			/* Colour scaling */
			regs[0xA2] = 0x36;
			regs[0xA4] = 0xB7;
			regs[0xA6] = 0x13;
			regs[0xA8] = 0x58;
			regs[0xAA] = 0x8A;
			regs[0xAC] = 0x4A;
			/* Set mode to interlaced */
			regs[0x92] |= 0x80;
			break;
	}
	return 1;
}
int focus_calc_mode(xbox_video_mode * mode, struct riva_regs * riva_out)
{
	unsigned char b;
	char* regs = riva_out->encoder_mode;
	int m = 0;
	int tv_htotal, tv_vtotal, tv_vactive, tv_hactive;
	int vga_htotal, vga_vtotal;
	long ncon, ncod;
	int pll_m, pll_n, pll_p, vsc, hsc;
	memcpy(regs,focus_defaults,sizeof(focus_defaults));
	
	/* Uncomment for SDTV colour bars */
	//regs[0x45]=0x02;
	
	switch(mode->tv_encoding) {
		case TV_ENC_NTSC:
			tv_vtotal=525;
			tv_vactive=480;			
			tv_hactive = 710;
			tv_htotal  = 858;
			regs[0x0d] &= ~0x01;
			regs[0x40] = 0x21;
			regs[0x41] = 0xF0;
			regs[0x42] = 0x7C;
			regs[0x43] = 0x1F;
			regs[0x49] = 0x44;
			regs[0x4a] = 0x76;
			regs[0x4b] = 0x3B;
			regs[0x4c] = 0x00;
			regs[0x60] = 0x89;
			regs[0x62] = 0x89;
			regs[0x69] = 0x16;
			regs[0x6C] = 0x20;
			regs[0x74] = 0x04;		
			regs[0x75] = 0x10;
			regs[0x80] = 0x67; 
			regs[0x81] = 0x21; 
			regs[0x82] = 0x0C;
			regs[0x83] = 0x18;
			regs[0x86] = 0x18;
			regs[0x89] = 0x13;
			regs[0x8A] = 0x13;
			break;
		case TV_ENC_PALBDGHI:
			tv_vtotal = 625;
			tv_vactive = 576;
			tv_hactive = 702;
			tv_htotal = 864;
			break;
		default:
			/* Default to PAL */
			tv_vtotal = 625;
			tv_vactive = 576;
			tv_hactive = 702;
			tv_htotal = 864;
			break;
	}
	/* Video control  - set to RGB input*/
	b = (regs[0x92] &= ~0x04);
	regs[0x92] = (b|= 0x01);
	regs[0x93] &= ~0x40;
	/* Colour scaling */
	regs[0xA2] = 0x4D;
	regs[0xA4] = 0x96;
	regs[0xA6] = 0x1D;
	regs[0xA8] = 0xA0;
	regs[0xAA] = 0xDB;
	regs[0xAC] = 0x7E;
	
	tv_vactive = tv_vactive * (1.0f-mode->voc);
	vga_vtotal = mode->yres * ((float)tv_vtotal/tv_vactive);
	vga_htotal = mode->xres * 1.25f;
	tv_hactive = tv_hactive * (1.0f-mode->hoc);
	/*These should be calculated or at least deduced.
	 *However they are good enough for 640x480 -> 800x600 now*/
	pll_n  = 32;
	pll_m = 512;
	pll_p = 4; 
	
	ncon = vga_htotal * vga_vtotal;
	ncod = tv_htotal * tv_vtotal  * pll_p;
	
	regs[0x04] = (mode->xres+64)&0xFF;
	regs[0x05] = ((mode->xres+64)>>8)&0xFF;
	if (tv_vtotal>vga_vtotal) {
		/* Upscaling */
		vsc = ((((float)tv_vtotal/(float)vga_vtotal)-1)*65536);
		/* For upscaling, adjust FIFO_LAT (FIFO latency) */
		regs[0x38] = 0x82;
	}
	else {
		/* Downscaling */
		vsc = ((((float)tv_vtotal/(float)vga_vtotal))*65536);
	}
	regs[0x06] = (vsc)&0xFF;
	regs[0x07] = (vsc>>8)&0xFF;
	hsc = 128*((float)tv_hactive/(float)mode->xres-1);
	if (tv_hactive > mode->xres) {
		/* Upscaling */
		regs[0x08] = 0;
		regs[0x09] = hsc&0xFF;
	}
	else {  /* Downscaling */
		hsc = 256 + hsc;
		regs[0x08] = hsc&0xFF;
		regs[0x09] = 0;
	}
	regs[0x10] = (ncon)&0xFF;
	regs[0x11] = (ncon>>8)&0xFF ;
	regs[0x12] = (ncon>>16)&0xFF ;
	regs[0x13] = (ncon>>24)&0xFF ;
	regs[0x14] = (ncod)&0xFF ;
	regs[0x15] = (ncod>>8)&0xFF ;
	regs[0x16] = (ncod>>16)&0xFF ;
	regs[0x17] = (ncod>>24)&0xFF ;
	regs[0x18] = (pll_m-17)&0xFF;
	regs[0x19] = ((pll_m-17)>>8)&0xFF;
	regs[0x1A] = (pll_n-1)&0xFF ;
	regs[0x1B] = ((pll_n-1)>>8)&0xFF ;
	regs[0x1C] = (pll_p-1)&0xFF;
	regs[0x1D] = (pll_p-1)&0xFF;
	        
	/* Guesswork */
	riva_out->ext.vsyncstart = vga_vtotal * 0.95;
	riva_out->ext.hsyncstart = vga_htotal * 0.95;
	
	riva_out->ext.width = mode->xres;
	riva_out->ext.height = mode->yres;
	riva_out->ext.htotal = vga_htotal - 1;
	riva_out->ext.vend = mode->yres - 1;
	riva_out->ext.vtotal = vga_vtotal- 1;
	riva_out->ext.vcrtc = mode->yres - 1;
	riva_out->ext.vsyncend = riva_out->ext.vsyncstart + 3;
        riva_out->ext.vvalidstart = 0;
	riva_out->ext.vvalidend = mode->yres - 1;
	riva_out->ext.hend = mode->xres + 7 ;
	riva_out->ext.hcrtc = mode->xres - 1;
        riva_out->ext.hsyncend = riva_out->ext.hsyncstart + 32;
        riva_out->ext.hvalidstart = 0;
        riva_out->ext.hvalidend = mode->xres - 1;
	riva_out->ext.crtchdispend = mode->xres;
        riva_out->ext.crtcvstart = mode->yres + 32;
	//increased from 32
	riva_out->ext.crtcvtotal = mode->yres + 64;
	return 1;
}
(-) linux-2.6.6.orig/drivers/video/xbox/focus.h (+24 lines)
Line 0    Link Here 
/*
 * linux/drivers/video/riva/focus.c - Xbox driver for Focus encoder
 *
 * Maintainer: David Pye (dmp) <dmp@davidmpye.dyndns.org>
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 *
 * Known bugs and issues:
 *
 * none
 */
#ifndef focus_h_
#define focus_h_
#include "encoder.h"
#include "xboxfb.h"
int focus_calc_mode(xbox_video_mode * mode, struct riva_regs * riva_out );
int focus_calc_hdtv_mode(xbox_hdtv_mode hdtv_mode, unsigned char pll_int, unsigned char * mode_out);
#endif
(-) linux-2.6.6.orig/drivers/video/xbox/nv_driver.c (+364 lines)
Line 0    Link Here 
/* $XConsortium: nv_driver.c /main/3 1996/10/28 05:13:37 kaleb $ */
/*
 * Copyright 1996-1997  David J. McKay
 *
 * 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
 * DAVID J. MCKAY 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.
 */
/*
 * GPL licensing note -- nVidia is allowing a liberal interpretation of
 * the documentation restriction above, to merely say that this nVidia's
 * copyright and disclaimer should be included with all code derived
 * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
 */
/* Hacked together from mga driver and 3.3.4 NVIDIA driver by Jarno Paananen
   <jpaana@s2.org> */
/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_setup.c,v 1.18 2002/08/0
5 20:47:06 mvojkovi Exp $ */
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include "nv_type.h"
#include "xboxfb.h"
#include "nvreg.h"
#ifndef CONFIG_PCI		/* sanity check */
#error This driver requires PCI support.
#endif
#define PFX "rivafb: "
static inline unsigned char MISCin(struct riva_par *par)
{
	return (VGA_RD08(par->riva.PVIO, 0x3cc));
}
static Bool 
riva_is_connected(struct riva_par *par, Bool second)
{
	volatile U032 *PRAMDAC = par->riva.PRAMDAC0;
	U032 reg52C, reg608;
	Bool present;
	if(second) PRAMDAC += 0x800;
	reg52C = PRAMDAC[0x052C/4];
	reg608 = PRAMDAC[0x0608/4];
	PRAMDAC[0x0608/4] = reg608 & ~0x00010000;
	PRAMDAC[0x052C/4] = reg52C & 0x0000FEEE;
	mdelay(1); 
	PRAMDAC[0x052C/4] |= 1;
	par->riva.PRAMDAC0[0x0610/4] = 0x94050140;
	par->riva.PRAMDAC0[0x0608/4] |= 0x00001000;
	mdelay(1);
	present = (PRAMDAC[0x0608/4] & (1 << 28)) ? TRUE : FALSE;
	par->riva.PRAMDAC0[0x0608/4] &= 0x0000EFFF;
	PRAMDAC[0x052C/4] = reg52C;
	PRAMDAC[0x0608/4] = reg608;
	return present;
}
static void
riva_override_CRTC(struct riva_par *par)
{
	printk(KERN_INFO PFX
		"Detected CRTC controller %i being used\n",
		par->SecondCRTC ? 1 : 0);
	if(par->forceCRTC != -1) {
		printk(KERN_INFO PFX
			"Forcing usage of CRTC %i\n", par->forceCRTC);
		par->SecondCRTC = par->forceCRTC;
	}
}
static void
riva_is_second(struct riva_par *par)
{
	if (par->FlatPanel == 1) {
		switch(par->Chipset) {
		case NV_CHIP_GEFORCE4_440_GO:
		case NV_CHIP_GEFORCE4_440_GO_M64:
		case NV_CHIP_GEFORCE4_420_GO:
		case NV_CHIP_GEFORCE4_420_GO_M32:
		case NV_CHIP_QUADRO4_500_GOGL:
			par->SecondCRTC = TRUE;
			break;
		default:
			par->SecondCRTC = FALSE;
			break;
		}
	} else {
		if(riva_is_connected(par, 0)) {
			if(par->riva.PRAMDAC0[0x0000052C/4] & 0x100)
				par->SecondCRTC = TRUE;
			else
				par->SecondCRTC = FALSE;
		} else 
		if (riva_is_connected(par, 1)) {
			if(par->riva.PRAMDAC0[0x0000252C/4] & 0x100)
				par->SecondCRTC = TRUE;
			else
				par->SecondCRTC = FALSE;
		} else /* default */
			par->SecondCRTC = FALSE;
	}
	riva_override_CRTC(par);
}
unsigned long riva_get_memlen(struct riva_par *par)
{
	RIVA_HW_INST *chip = &par->riva;
	unsigned long memlen = 0;
	unsigned int chipset = par->Chipset;
	struct pci_dev* dev;
	int amt;
	switch (chip->Architecture) {
	case NV_ARCH_03:
		if (chip->PFB[0x00000000/4] & 0x00000020) {
			if (((chip->PMC[0x00000000/4] & 0xF0) == 0x20)
			    && ((chip->PMC[0x00000000/4] & 0x0F) >= 0x02)) {
				/*
				 * SDRAM 128 ZX.
				 */
				switch (chip->PFB[0x00000000/4] & 0x03) {
				case 2:
					memlen = 1024 * 4;
					break;
				case 1:
					memlen = 1024 * 2;
					break;
				default:
					memlen = 1024 * 8;
					break;
				}
			} else {
				memlen = 1024 * 8;
			}            
		} else 	{
			/*
			 * SGRAM 128.
			 */
			switch (chip->PFB[0x00000000/4] & 0x00000003) {
			case 0:
				memlen = 1024 * 8;
				break;
			case 2:
				memlen = 1024 * 4;
				break;
			default:
				memlen = 1024 * 2;
				break;
			}
		}        
		break;
	case NV_ARCH_04:
		if (chip->PFB[0x00000000/4] & 0x00000100) {
			memlen = ((chip->PFB[0x00000000/4] >> 12) & 0x0F) * 
				1024 * 2 + 1024 * 2;
		} else {
			switch (chip->PFB[0x00000000/4] & 0x00000003) {
			case 0:
				memlen = 1024 * 32;
				break;
			case 1:
				memlen = 1024 * 4;
				break;
			case 2:
				memlen = 1024 * 8;
				break;
			case 3:
			default:
				memlen = 1024 * 16;
				break;
			}
		}
		break;
	case NV_ARCH_10:
	case NV_ARCH_20:
		if(chipset == NV_CHIP_IGEFORCE2) {
			dev = pci_find_slot(0, 1);
			pci_read_config_dword(dev, 0x7C, &amt);
			memlen = (((amt >> 6) & 31) + 1) * 1024;
		} else if (chipset == NV_CHIP_0x01F0) {
			dev = pci_find_slot(0, 1);
			pci_read_config_dword(dev, 0x84, &amt);
			memlen = (((amt >> 4) & 127) + 1) * 1024;
		} else {
			switch ((chip->PFB[0x0000020C/4] >> 20) & 0x000000FF){
			case 0x02:
				memlen = 1024 * 2;
				break;
			case 0x04:
				memlen = 1024 * 4;
				break;
			case 0x08:
				memlen = 1024 * 8;
				break;
			case 0x10:
				memlen = 1024 * 16;
				break;
			case 0x20:
				memlen = 1024 * 32;
				break;
			case 0x40:
				memlen = 1024 * 64;
				break;
			case 0x80:
				memlen = 1024 * 128;
				break;
			default:
				memlen = 1024 * 16;
				break;
			}
		}
		break;
	}
	return memlen;
}
unsigned long riva_get_maxdclk(struct riva_par *par)
{
	RIVA_HW_INST *chip = &par->riva;
	unsigned long dclk = 0;
	switch (chip->Architecture) {
	case NV_ARCH_03:
		if (chip->PFB[0x00000000/4] & 0x00000020) {
			if (((chip->PMC[0x00000000/4] & 0xF0) == 0x20)
			    && ((chip->PMC[0x00000000/4] & 0x0F) >= 0x02)) {   
				/*
				 * SDRAM 128 ZX.
				 */
				dclk = 800000;
			} else {
				dclk = 1000000;
			}            
		} else {
			/*
			 * SGRAM 128.
			 */
			dclk = 1000000;
		} 
		break;
	case NV_ARCH_04:
	case NV_ARCH_10:
	case NV_ARCH_20:
		switch ((chip->PFB[0x00000000/4] >> 3) & 0x00000003) {
		case 3:
			dclk = 800000;
			break;
		default:
			dclk = 1000000;
			break;
		}
		break;
	}
	return dclk;
}
void
riva_common_setup(struct riva_par *par)
{
	par->riva.EnableIRQ = 0;
	par->riva.PRAMDAC0 = (unsigned *)(par->ctrl_base + 0x00680000);
	par->riva.PFB = (unsigned *)(par->ctrl_base + 0x00100000);
	par->riva.PFIFO = (unsigned *)(par->ctrl_base + 0x00002000);
	par->riva.PGRAPH = (unsigned *)(par->ctrl_base + 0x00400000);
	par->riva.PEXTDEV = (unsigned *)(par->ctrl_base + 0x00101000);
	par->riva.PTIMER = (unsigned *)(par->ctrl_base + 0x00009000);
	par->riva.PMC = (unsigned *)(par->ctrl_base + 0x00000000);
	par->riva.FIFO = (unsigned *)(par->ctrl_base + 0x00800000);
	par->riva.PCIO0 = (U008 *)(par->ctrl_base + 0x00601000);
	par->riva.PDIO0 = (U008 *)(par->ctrl_base + 0x00681000);
	par->riva.PVIO = (U008 *)(par->ctrl_base + 0x000C0000);
	par->riva.IO = (MISCin(par) & 0x01) ? 0x3D0 : 0x3B0;
	
	if (par->FlatPanel == -1) {
		switch (par->Chipset) {
		case NV_CHIP_GEFORCE4_440_GO:
		case NV_CHIP_GEFORCE4_440_GO_M64:
		case NV_CHIP_GEFORCE4_420_GO:
		case NV_CHIP_GEFORCE4_420_GO_M32:
		case NV_CHIP_QUADRO4_500_GOGL:
		case NV_CHIP_GEFORCE2_GO:
			printk(KERN_INFO PFX 
				"On a laptop.  Assuming Digital Flat Panel\n");
			par->FlatPanel = 1;
			break;
		default:
			break;
		}
	}
	
	switch (par->Chipset & 0x0ff0) {
	case 0x0110:
		if (par->Chipset == NV_CHIP_GEFORCE2_GO)
			par->SecondCRTC = TRUE; 
#if defined(__powerpc__)
		if (par->FlatPanel == 1)
			par->SecondCRTC = TRUE;
#endif
		riva_override_CRTC(par);
		break;
	case 0x0170:
	case 0x0180:
	case 0x01F0:
	case 0x0250:
	case 0x0280:
		riva_is_second(par);
		break;
	default:
		break;
	}
	if (par->SecondCRTC) {
		par->riva.PCIO = par->riva.PCIO0 + 0x2000;
		par->riva.PCRTC = par->riva.PCRTC0 + 0x800;
		par->riva.PRAMDAC = par->riva.PRAMDAC0 + 0x800;
		par->riva.PDIO = par->riva.PDIO0 + 0x2000;
	} else {
		par->riva.PCIO = par->riva.PCIO0;
		par->riva.PCRTC = par->riva.PCRTC0;
		par->riva.PRAMDAC = par->riva.PRAMDAC0;
		par->riva.PDIO = par->riva.PDIO0;
	}
	if (par->FlatPanel == -1) {
		/* Fix me, need x86 DDC code */
		par->FlatPanel = 0;
	}
	par->riva.flatPanel = (par->FlatPanel > 0) ? TRUE : FALSE;
}
(-) linux-2.6.6.orig/drivers/video/xbox/nv_type.h (+58 lines)
Line 0    Link Here 
/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_type.h,v 1.35 2002/08/05 20:47:06 mvojkovi Exp $ */
#ifndef __NV_STRUCT_H__
#define __NV_STRUCT_H__
#define NV_CHIP_RIVA_128            ((PCI_VENDOR_ID_NVIDIA_SGS << 16)| PCI_DEVICE_ID_NVIDIA_RIVA128)
#define NV_CHIP_TNT                 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_TNT)
#define NV_CHIP_TNT2                ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_TNT2)
#define NV_CHIP_UTNT2               ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_UTNT2)
#define NV_CHIP_VTNT2               ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_VTNT2)
#define NV_CHIP_UVTNT2              ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_UVTNT2)
#define NV_CHIP_ITNT2               ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_ITNT2)
#define NV_CHIP_GEFORCE_256         ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_GEFORCE_256)
#define NV_CHIP_GEFORCE_DDR         ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR)
#define NV_CHIP_QUADRO              ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_QUADRO)
#define NV_CHIP_GEFORCE2_MX         ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX)
#define NV_CHIP_GEFORCE2_MX_100     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX_100)
#define NV_CHIP_QUADRO2_MXR         ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR)
#define NV_CHIP_GEFORCE2_GO         ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO)
#define NV_CHIP_GEFORCE2_GTS        ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS)
#define NV_CHIP_GEFORCE2_TI         ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_TI)
#define NV_CHIP_GEFORCE2_ULTRA      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA)
#define NV_CHIP_QUADRO2_PRO         ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO)
#define NV_CHIP_GEFORCE4_MX_460     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460)
#define NV_CHIP_GEFORCE4_MX_440     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440)
#define NV_CHIP_GEFORCE4_MX_420     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420)
#define NV_CHIP_GEFORCE4_440_GO     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO)
#define NV_CHIP_GEFORCE4_420_GO     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO)
#define NV_CHIP_GEFORCE4_420_GO_M32 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32)
#define NV_CHIP_QUADRO4_500XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL)
#define NV_CHIP_GEFORCE4_440_GO_M64 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64)
#define NV_CHIP_QUADRO4_200         ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_200)
#define NV_CHIP_QUADRO4_550XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL)
#define NV_CHIP_QUADRO4_500_GOGL    ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL)
#define NV_CHIP_0x0180              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0180)
#define NV_CHIP_0x0181              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0181)
#define NV_CHIP_0x0182              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0182)
#define NV_CHIP_0x0188              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0188)
#define NV_CHIP_0x018A              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x018A)
#define NV_CHIP_0x018B              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x018B)
#define NV_CHIP_IGEFORCE2           ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_IGEFORCE2)
#define NV_CHIP_0x01F0              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x01F0)
#define NV_CHIP_GEFORCE3            ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE3)
#define NV_CHIP_GEFORCE3_TI_200     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE3_TI_200)
#define NV_CHIP_GEFORCE3_TI_500     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE3_TI_500)
#define NV_CHIP_QUADRO_DCC          ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO_DCC)
#define NV_CHIP_GEFORCE4_TI_4600    ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600)
#define NV_CHIP_GEFORCE4_TI_4400    ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400)
#define NV_CHIP_GEFORCE4_TI_4200    ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200)
#define NV_CHIP_QUADRO4_900XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL)
#define NV_CHIP_QUADRO4_750XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL)
#define NV_CHIP_QUADRO4_700XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL)
#define NV_CHIP_0x0280              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0280)
#define NV_CHIP_0x0281              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0281)
#define NV_CHIP_0x0288              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0288)
#define NV_CHIP_0x0289              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0289)
#endif /* __NV_STRUCT_H__ */
(-) linux-2.6.6.orig/drivers/video/xbox/nvreg.h (+188 lines)
Line 0    Link Here 
/* $XConsortium: nvreg.h /main/2 1996/10/28 05:13:41 kaleb $ */
/*
 * Copyright 1996-1997  David J. McKay
 *
 * 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
 * DAVID J. MCKAY 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.
 */
/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/nv/nvreg.h,v 3.2.2.1 1998/01/18 10:35:36 hohndel Exp $ */
#ifndef __NVREG_H_
#define __NVREG_H_
/* Little macro to construct bitmask for contiguous ranges of bits */
#define BITMASK(t,b) (((unsigned)(1U << (((t)-(b)+1)))-1)  << (b))
#define MASKEXPAND(mask) BITMASK(1?mask,0?mask)
/* Macro to set specific bitfields (mask has to be a macro x:y) ! */
#define SetBF(mask,value) ((value) << (0?mask))
#define GetBF(var,mask) (((unsigned)((var) & MASKEXPAND(mask))) >> (0?mask) )
#define MaskAndSetBF(var,mask,value) (var)=(((var)&(~MASKEXPAND(mask)) \
                                             | SetBF(mask,value)))
#define DEVICE_BASE(device) (0?NV##_##device)
#define DEVICE_SIZE(device) ((1?NV##_##device) - DEVICE_BASE(device)+1)
/* This is where we will have to have conditional compilation */
#define DEVICE_ACCESS(device,reg) \
  nvCONTROL[(NV_##device##_##reg)/4]
#define DEVICE_WRITE(device,reg,value) DEVICE_ACCESS(device,reg)=(value)
#define DEVICE_READ(device,reg)        DEVICE_ACCESS(device,reg)
#define DEVICE_PRINT(device,reg) \
  ErrorF("NV_"#device"_"#reg"=#%08lx\n",DEVICE_ACCESS(device,reg))
#define DEVICE_DEF(device,mask,value) \
  SetBF(NV_##device##_##mask,NV_##device##_##mask##_##value)
#define DEVICE_VALUE(device,mask,value) SetBF(NV_##device##_##mask,value)
#define DEVICE_MASK(device,mask) MASKEXPAND(NV_##device##_##mask)
#define PDAC_Write(reg,value)           DEVICE_WRITE(PDAC,reg,value)
#define PDAC_Read(reg)                  DEVICE_READ(PDAC,reg)
#define PDAC_Print(reg)                 DEVICE_PRINT(PDAC,reg)
#define PDAC_Def(mask,value)            DEVICE_DEF(PDAC,mask,value)
#define PDAC_Val(mask,value)            DEVICE_VALUE(PDAC,mask,value)
#define PDAC_Mask(mask)                 DEVICE_MASK(PDAC,mask)
#define PFB_Write(reg,value)            DEVICE_WRITE(PFB,reg,value)
#define PFB_Read(reg)                   DEVICE_READ(PFB,reg)
#define PFB_Print(reg)                  DEVICE_PRINT(PFB,reg)
#define PFB_Def(mask,value)             DEVICE_DEF(PFB,mask,value)
#define PFB_Val(mask,value)             DEVICE_VALUE(PFB,mask,value)
#define PFB_Mask(mask)                  DEVICE_MASK(PFB,mask)
#define PRM_Write(reg,value)            DEVICE_WRITE(PRM,reg,value)
#define PRM_Read(reg)                   DEVICE_READ(PRM,reg)
#define PRM_Print(reg)                  DEVICE_PRINT(PRM,reg)
#define PRM_Def(mask,value)             DEVICE_DEF(PRM,mask,value)
#define PRM_Val(mask,value)             DEVICE_VALUE(PRM,mask,value)
#define PRM_Mask(mask)                  DEVICE_MASK(PRM,mask)
#define PGRAPH_Write(reg,value)         DEVICE_WRITE(PGRAPH,reg,value)
#define PGRAPH_Read(reg)                DEVICE_READ(PGRAPH,reg)
#define PGRAPH_Print(reg)               DEVICE_PRINT(PGRAPH,reg)
#define PGRAPH_Def(mask,value)          DEVICE_DEF(PGRAPH,mask,value)
#define PGRAPH_Val(mask,value)          DEVICE_VALUE(PGRAPH,mask,value)
#define PGRAPH_Mask(mask)               DEVICE_MASK(PGRAPH,mask)
#define PDMA_Write(reg,value)           DEVICE_WRITE(PDMA,reg,value)
#define PDMA_Read(reg)                  DEVICE_READ(PDMA,reg)
#define PDMA_Print(reg)                 DEVICE_PRINT(PDMA,reg)
#define PDMA_Def(mask,value)            DEVICE_DEF(PDMA,mask,value)
#define PDMA_Val(mask,value)            DEVICE_VALUE(PDMA,mask,value)
#define PDMA_Mask(mask)                 DEVICE_MASK(PDMA,mask)
#define PTIMER_Write(reg,value)         DEVICE_WRITE(PTIMER,reg,value)
#define PTIMER_Read(reg)                DEVICE_READ(PTIMER,reg)
#define PTIMER_Print(reg)               DEVICE_PRINT(PTIMER,reg)
#define PTIMER_Def(mask,value)          DEVICE_DEF(PTIMER,mask,value)
#define PTIMER_Val(mask,value)          DEVICE_VALUE(PTIEMR,mask,value)
#define PTIMER_Mask(mask)               DEVICE_MASK(PTIMER,mask)
#define PEXTDEV_Write(reg,value)         DEVICE_WRITE(PEXTDEV,reg,value)
#define PEXTDEV_Read(reg)                DEVICE_READ(PEXTDEV,reg)
#define PEXTDEV_Print(reg)               DEVICE_PRINT(PEXTDEV,reg)
#define PEXTDEV_Def(mask,value)          DEVICE_DEF(PEXTDEV,mask,value)
#define PEXTDEV_Val(mask,value)          DEVICE_VALUE(PEXTDEV,mask,value)
#define PEXTDEV_Mask(mask)               DEVICE_MASK(PEXTDEV,mask)
#define PFIFO_Write(reg,value)          DEVICE_WRITE(PFIFO,reg,value)
#define PFIFO_Read(reg)                 DEVICE_READ(PFIFO,reg)
#define PFIFO_Print(reg)                DEVICE_PRINT(PFIFO,reg)
#define PFIFO_Def(mask,value)           DEVICE_DEF(PFIFO,mask,value)
#define PFIFO_Val(mask,value)           DEVICE_VALUE(PFIFO,mask,value)
#define PFIFO_Mask(mask)                DEVICE_MASK(PFIFO,mask)
#define PRAM_Write(reg,value)           DEVICE_WRITE(PRAM,reg,value)
#define PRAM_Read(reg)                  DEVICE_READ(PRAM,reg)
#define PRAM_Print(reg)                 DEVICE_PRINT(PRAM,reg)
#define PRAM_Def(mask,value)            DEVICE_DEF(PRAM,mask,value)
#define PRAM_Val(mask,value)            DEVICE_VALUE(PRAM,mask,value)
#define PRAM_Mask(mask)                 DEVICE_MASK(PRAM,mask)
#define PRAMFC_Write(reg,value)         DEVICE_WRITE(PRAMFC,reg,value)
#define PRAMFC_Read(reg)                DEVICE_READ(PRAMFC,reg)
#define PRAMFC_Print(reg)               DEVICE_PRINT(PRAMFC,reg)
#define PRAMFC_Def(mask,value)          DEVICE_DEF(PRAMFC,mask,value)
#define PRAMFC_Val(mask,value)          DEVICE_VALUE(PRAMFC,mask,value)
#define PRAMFC_Mask(mask)               DEVICE_MASK(PRAMFC,mask)
#define PMC_Write(reg,value)            DEVICE_WRITE(PMC,reg,value)
#define PMC_Read(reg)                   DEVICE_READ(PMC,reg)
#define PMC_Print(reg)                  DEVICE_PRINT(PMC,reg)
#define PMC_Def(mask,value)             DEVICE_DEF(PMC,mask,value)
#define PMC_Val(mask,value)             DEVICE_VALUE(PMC,mask,value)
#define PMC_Mask(mask)                  DEVICE_MASK(PMC,mask)
#define PMC_Write(reg,value)            DEVICE_WRITE(PMC,reg,value)
#define PMC_Read(reg)                   DEVICE_READ(PMC,reg)
#define PMC_Print(reg)                  DEVICE_PRINT(PMC,reg)
#define PMC_Def(mask,value)             DEVICE_DEF(PMC,mask,value)
#define PMC_Val(mask,value)             DEVICE_VALUE(PMC,mask,value)
#define PMC_Mask(mask)                  DEVICE_MASK(PMC,mask)
#define PBUS_Write(reg,value)         DEVICE_WRITE(PBUS,reg,value)
#define PBUS_Read(reg)                DEVICE_READ(PBUS,reg)
#define PBUS_Print(reg)               DEVICE_PRINT(PBUS,reg)
#define PBUS_Def(mask,value)          DEVICE_DEF(PBUS,mask,value)
#define PBUS_Val(mask,value)          DEVICE_VALUE(PBUS,mask,value)
#define PBUS_Mask(mask)               DEVICE_MASK(PBUS,mask)
#define PRAMDAC_Write(reg,value)         DEVICE_WRITE(PRAMDAC,reg,value)
#define PRAMDAC_Read(reg)                DEVICE_READ(PRAMDAC,reg)
#define PRAMDAC_Print(reg)               DEVICE_PRINT(PRAMDAC,reg)
#define PRAMDAC_Def(mask,value)          DEVICE_DEF(PRAMDAC,mask,value)
#define PRAMDAC_Val(mask,value)          DEVICE_VALUE(PRAMDAC,mask,value)
#define PRAMDAC_Mask(mask)               DEVICE_MASK(PRAMDAC,mask)
#define PDAC_ReadExt(reg) \
  ((PDAC_Write(INDEX_LO,(NV_PDAC_EXT_##reg) & 0xff)),\
  (PDAC_Write(INDEX_HI,((NV_PDAC_EXT_##reg) >> 8) & 0xff)),\
  (PDAC_Read(INDEX_DATA)))
#define PDAC_WriteExt(reg,value)\
  ((PDAC_Write(INDEX_LO,(NV_PDAC_EXT_##reg) & 0xff)),\
  (PDAC_Write(INDEX_HI,((NV_PDAC_EXT_##reg) >> 8) & 0xff)),\
  (PDAC_Write(INDEX_DATA,(value))))
#define CRTC_Write(index,value) outb((index), 0x3d4); outb(value, 0x3d5)
#define CRTC_Read(index) (outb(index, 0x3d4),inb(0x3d5))
#define PCRTC_Write(index,value) CRTC_Write(NV_PCRTC_##index,value)
#define PCRTC_Read(index) CRTC_Read(NV_PCRTC_##index)
#define PCRTC_Def(mask,value)          DEVICE_DEF(PCRTC,mask,value)
#define PCRTC_Val(mask,value)          DEVICE_VALUE(PCRTC,mask,value)
#define PCRTC_Mask(mask)               DEVICE_MASK(PCRTC,mask)
#define SR_Write(index,value) outb(0x3c4,(index));outb(0x3c5,value)
#define SR_Read(index) (outb(0x3c4,index),inb(0x3c5))
extern volatile unsigned  *nvCONTROL;
typedef enum {NV1,NV3,NV4,NumNVChips} NVChipType;
NVChipType GetChipType(void);
#endif
(-) linux-2.6.6.orig/drivers/video/xbox/riva_hw.c (+2253 lines)
Line 0    Link Here 
 /***************************************************************************\
|*                                                                           *|
|*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
|*                                                                           *|
|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
|*     international laws.  Users and possessors of this source code are     *|
|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
|*     use this code in individual and commercial software.                  *|
|*                                                                           *|
|*     Any use of this source code must include,  in the user documenta-     *|
|*     tion and  internal comments to the code,  notices to the end user     *|
|*     as follows:                                                           *|
|*                                                                           *|
|*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
|*                                                                           *|
|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
|*     SULTING 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 SOURCE CODE.     *|
|*                                                                           *|
|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
|*     consisting  of "commercial  computer  software"  and  "commercial     *|
|*     computer  software  documentation,"  as such  terms  are  used in     *|
|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
|*     all U.S. Government End Users  acquire the source code  with only     *|
|*     those rights set forth herein.                                        *|
|*                                                                           *|
 \***************************************************************************/
/*
 * GPL licensing note -- nVidia is allowing a liberal interpretation of
 * the documentation restriction above, to merely say that this nVidia's
 * copyright and disclaimer should be included with all code derived
 * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
 */
/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.c,v 1.33 2002/08/05 20:47:06 mvojkovi Exp $ */
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include "riva_hw.h"
#include "riva_tbl.h"
#include "nv_type.h"
/*
 * This file is an OS-agnostic file used to make RIVA 128 and RIVA TNT
 * operate identically (except TNT has more memory and better 3D quality.
 */
static int nv3Busy
(
    RIVA_HW_INST *chip
)
{
    return ((chip->Rop->FifoFree < chip->FifoEmptyCount) || (chip->PGRAPH[0x000006B0/4] & 0x01));
}
static int nv4Busy
(
    RIVA_HW_INST *chip
)
{
    return ((chip->Rop->FifoFree < chip->FifoEmptyCount) || (chip->PGRAPH[0x00000700/4] & 0x01));
}
static int nv10Busy
(
    RIVA_HW_INST *chip
)
{
    return ((chip->Rop->FifoFree < chip->FifoEmptyCount) || (chip->PGRAPH[0x00000700/4] & 0x01));
}
static void vgaLockUnlock
(
    RIVA_HW_INST *chip,
    int           Lock
)
{
    U008 cr11;
    VGA_WR08(chip->PCIO, 0x3D4, 0x11);
    cr11 = VGA_RD08(chip->PCIO, 0x3D5);
    if(Lock) cr11 |= 0x80;
    else cr11 &= ~0x80;
    VGA_WR08(chip->PCIO, 0x3D5, cr11);
}
static void nv3LockUnlock
(
    RIVA_HW_INST *chip,
    int           Lock
)
{
    VGA_WR08(chip->PVIO, 0x3C4, 0x06);
    VGA_WR08(chip->PVIO, 0x3C5, Lock ? 0x99 : 0x57);
    vgaLockUnlock(chip, Lock);
}
static void nv4LockUnlock
(
    RIVA_HW_INST *chip,
    int           Lock
)
{
    VGA_WR08(chip->PCIO, 0x3D4, 0x1F);
    VGA_WR08(chip->PCIO, 0x3D5, Lock ? 0x99 : 0x57);
    vgaLockUnlock(chip, Lock);
}
static int ShowHideCursor
(
    RIVA_HW_INST *chip,
    int           ShowHide
)
{
    int cursor;
    cursor                      =  chip->CurrentState->cursor1;
    chip->CurrentState->cursor1 = (chip->CurrentState->cursor1 & 0xFE) |
                                  (ShowHide & 0x01);
    VGA_WR08(chip->PCIO, 0x3D4, 0x31);
    VGA_WR08(chip->PCIO, 0x3D5, chip->CurrentState->cursor1);
    return (cursor & 0x01);
}
static int nv10ShowHideCursor
(
    RIVA_HW_INST *chip,
    int           ShowHide
)
{
    unsigned int cursor;
    cursor                           =  chip->CurrentState->cursorConfig;
    chip->CurrentState->cursorConfig = (chip->PCRTC[0x00000810/4] & 0xFFFFFFFE) |
                                  (ShowHide & 0x01);
    chip->PCRTC[0x00000810/4] = chip->CurrentState->cursorConfig;
    return (cursor & 0x01);
}
/****************************************************************************\
*                                                                            *
* The video arbitration routines calculate some "magic" numbers.  Fixes      *
* the snow seen when accessing the framebuffer without it.                   *
* It just works (I hope).                                                    *
*                                                                            *
\****************************************************************************/
#define DEFAULT_GR_LWM 100
#define DEFAULT_VID_LWM 100
#define DEFAULT_GR_BURST_SIZE 256
#define DEFAULT_VID_BURST_SIZE 128
#define VIDEO		0
#define GRAPHICS	1
#define MPORT		2
#define ENGINE		3
#define GFIFO_SIZE	320
#define GFIFO_SIZE_128	256
#define MFIFO_SIZE	120
#define VFIFO_SIZE	256
#define	ABS(a)	(a>0?a:-a)
typedef struct {
  int gdrain_rate;
  int vdrain_rate;
  int mdrain_rate;
  int gburst_size;
  int vburst_size;
  char vid_en;
  char gr_en;
  int wcmocc, wcgocc, wcvocc, wcvlwm, wcglwm;
  int by_gfacc;
  char vid_only_once;
  char gr_only_once;
  char first_vacc;
  char first_gacc;
  char first_macc;
  int vocc;
  int gocc;
  int mocc;
  char cur;
  char engine_en;
  char converged;
  int priority;
} nv3_arb_info;
typedef struct {
  int graphics_lwm;
  int video_lwm;
  int graphics_burst_size;
  int video_burst_size;
  int graphics_hi_priority;
  int media_hi_priority;
  int rtl_values;
  int valid;
} nv3_fifo_info;
typedef struct {
  char pix_bpp;
  char enable_video;
  char gr_during_vid;
  char enable_mp;
  int memory_width;
  int video_scale;
  int pclk_khz;
  int mclk_khz;
  int mem_page_miss;
  int mem_latency;
  char mem_aligned;
} nv3_sim_state;
typedef struct {
  int graphics_lwm;
  int video_lwm;
  int graphics_burst_size;
  int video_burst_size;
  int valid;
} nv4_fifo_info;
typedef struct {
  int pclk_khz;
  int mclk_khz;
  int nvclk_khz;
  char mem_page_miss;
  char mem_latency;
  int memory_width;
  char enable_video;
  char gr_during_vid;
  char pix_bpp;
  char mem_aligned;
  char enable_mp;
} nv4_sim_state;
typedef struct {
  int graphics_lwm;
  int video_lwm;
  int graphics_burst_size;
  int video_burst_size;
  int valid;
} nv10_fifo_info;
typedef struct {
  int pclk_khz;
  int mclk_khz;
  int nvclk_khz;
  char mem_page_miss;
  char mem_latency;
  int memory_type;
  int memory_width;
  char enable_video;
  char gr_during_vid;
  char pix_bpp;
  char mem_aligned;
  char enable_mp;
} nv10_sim_state;
static int nv3_iterate(nv3_fifo_info *res_info, nv3_sim_state * state, nv3_arb_info *ainfo)
{
    int iter = 0;
    int tmp;
    int vfsize, mfsize, gfsize;
    int mburst_size = 32;
    int mmisses, gmisses, vmisses;
    int misses;
    int vlwm, glwm, mlwm;
    int last, next, cur;
    int max_gfsize ;
    long ns;
    vlwm = 0;
    glwm = 0;
    mlwm = 0;
    vfsize = 0;
    gfsize = 0;
    cur = ainfo->cur;
    mmisses = 2;
    gmisses = 2;
    vmisses = 2;
    if (ainfo->gburst_size == 128) max_gfsize = GFIFO_SIZE_128;
    else  max_gfsize = GFIFO_SIZE;
    max_gfsize = GFIFO_SIZE;
    while (1)
    {
        if (ainfo->vid_en)
        {
            if (ainfo->wcvocc > ainfo->vocc) ainfo->wcvocc = ainfo->vocc;
            if (ainfo->wcvlwm > vlwm) ainfo->wcvlwm = vlwm ;
            ns = 1000000 * ainfo->vburst_size/(state->memory_width/8)/state->mclk_khz;
            vfsize = ns * ainfo->vdrain_rate / 1000000;
            vfsize =  ainfo->wcvlwm - ainfo->vburst_size + vfsize;
        }
        if (state->enable_mp)
        {
            if (ainfo->wcmocc > ainfo->mocc) ainfo->wcmocc = ainfo->mocc;
        }
        if (ainfo->gr_en)
        {
            if (ainfo->wcglwm > glwm) ainfo->wcglwm = glwm ;
            if (ainfo->wcgocc > ainfo->gocc) ainfo->wcgocc = ainfo->gocc;
            ns = 1000000 * (ainfo->gburst_size/(state->memory_width/8))/state->mclk_khz;
            gfsize = (ns * (long) ainfo->gdrain_rate)/1000000;
            gfsize = ainfo->wcglwm - ainfo->gburst_size + gfsize;
        }
        mfsize = 0;
        if (!state->gr_during_vid && ainfo->vid_en)
            if (ainfo->vid_en && (ainfo->vocc < 0) && !ainfo->vid_only_once)
                next = VIDEO;
            else if (ainfo->mocc < 0)
                next = MPORT;
            else if (ainfo->gocc< ainfo->by_gfacc)
                next = GRAPHICS;
            else return (0);
        else switch (ainfo->priority)
            {
                case VIDEO:
                    if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
                        next = VIDEO;
                    else if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
                        next = GRAPHICS;
                    else if (ainfo->mocc<0)
                        next = MPORT;
                    else    return (0);
                    break;
                case GRAPHICS:
                    if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
                        next = GRAPHICS;
                    else if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
                        next = VIDEO;
                    else if (ainfo->mocc<0)
                        next = MPORT;
                    else    return (0);
                    break;
                default:
                    if (ainfo->mocc<0)
                        next = MPORT;
                    else if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
                        next = GRAPHICS;
                    else if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
                        next = VIDEO;
                    else    return (0);
                    break;
            }
        last = cur;
        cur = next;
        iter++;
        switch (cur)
        {
            case VIDEO:
                if (last==cur)    misses = 0;
                else if (ainfo->first_vacc)   misses = vmisses;
                else    misses = 1;
                ainfo->first_vacc = 0;
                if (last!=cur)
                {
                    ns =  1000000 * (vmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz; 
                    vlwm = ns * ainfo->vdrain_rate/ 1000000;
                    vlwm = ainfo->vocc - vlwm;
                }
                ns = 1000000*(misses*state->mem_page_miss + ainfo->vburst_size)/(state->memory_width/8)/state->mclk_khz;
                ainfo->vocc = ainfo->vocc + ainfo->vburst_size - ns*ainfo->vdrain_rate/1000000;
                ainfo->gocc = ainfo->gocc - ns*ainfo->gdrain_rate/1000000;
                ainfo->mocc = ainfo->mocc - ns*ainfo->mdrain_rate/1000000;
                break;
            case GRAPHICS:
                if (last==cur)    misses = 0;
                else if (ainfo->first_gacc)   misses = gmisses;
                else    misses = 1;
                ainfo->first_gacc = 0;
                if (last!=cur)
                {
                    ns = 1000000*(gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz ;
                    glwm = ns * ainfo->gdrain_rate/1000000;
                    glwm = ainfo->gocc - glwm;
                }
                ns = 1000000*(misses*state->mem_page_miss + ainfo->gburst_size/(state->memory_width/8))/state->mclk_khz;
                ainfo->vocc = ainfo->vocc + 0 - ns*ainfo->vdrain_rate/1000000;
                ainfo->gocc = ainfo->gocc + ainfo->gburst_size - ns*ainfo->gdrain_rate/1000000;
                ainfo->mocc = ainfo->mocc + 0 - ns*ainfo->mdrain_rate/1000000;
                break;
            default:
                if (last==cur)    misses = 0;
                else if (ainfo->first_macc)   misses = mmisses;
                else    misses = 1;
                ainfo->first_macc = 0;
                ns = 1000000*(misses*state->mem_page_miss + mburst_size/(state->memory_width/8))/state->mclk_khz;
                ainfo->vocc = ainfo->vocc + 0 - ns*ainfo->vdrain_rate/1000000;
                ainfo->gocc = ainfo->gocc + 0 - ns*ainfo->gdrain_rate/1000000;
                ainfo->mocc = ainfo->mocc + mburst_size - ns*ainfo->mdrain_rate/1000000;
                break;
        }
        if (iter>100)
        {
            ainfo->converged = 0;
            return (1);
        }
        ns = 1000000*ainfo->gburst_size/(state->memory_width/8)/state->mclk_khz;
        tmp = ns * ainfo->gdrain_rate/1000000;
        if (ABS(ainfo->gburst_size) + ((ABS(ainfo->wcglwm) + 16 ) & ~0x7) - tmp > max_gfsize)
        {
            ainfo->converged = 0;
            return (1);
        }
        ns = 1000000*ainfo->vburst_size/(state->memory_width/8)/state->mclk_khz;
        tmp = ns * ainfo->vdrain_rate/1000000;
        if (ABS(ainfo->vburst_size) + (ABS(ainfo->wcvlwm + 32) & ~0xf)  - tmp> VFIFO_SIZE)
        {
            ainfo->converged = 0;
            return (1);
        }
        if (ABS(ainfo->gocc) > max_gfsize)
        {
            ainfo->converged = 0;
            return (1);
        }
        if (ABS(ainfo->vocc) > VFIFO_SIZE)
        {
            ainfo->converged = 0;
            return (1);
        }
        if (ABS(ainfo->mocc) > MFIFO_SIZE)
        {
            ainfo->converged = 0;
            return (1);
        }
        if (ABS(vfsize) > VFIFO_SIZE)
        {
            ainfo->converged = 0;
            return (1);
        }
        if (ABS(gfsize) > max_gfsize)
        {
            ainfo->converged = 0;
            return (1);
        }
        if (ABS(mfsize) > MFIFO_SIZE)
        {
            ainfo->converged = 0;
            return (1);
        }
    }
}
static char nv3_arb(nv3_fifo_info * res_info, nv3_sim_state * state,  nv3_arb_info *ainfo) 
{
    long ens, vns, mns, gns;
    int mmisses, gmisses, vmisses, eburst_size, mburst_size;
    int refresh_cycle;
    refresh_cycle = 0;
    refresh_cycle = 2*(state->mclk_khz/state->pclk_khz) + 5;
    mmisses = 2;
    if (state->mem_aligned) gmisses = 2;
    else    gmisses = 3;
    vmisses = 2;
    eburst_size = state->memory_width * 1;
    mburst_size = 32;
    gns = 1000000 * (gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz;
    ainfo->by_gfacc = gns*ainfo->gdrain_rate/1000000;
    ainfo->wcmocc = 0;
    ainfo->wcgocc = 0;
    ainfo->wcvocc = 0;
    ainfo->wcvlwm = 0;
    ainfo->wcglwm = 0;
    ainfo->engine_en = 1;
    ainfo->converged = 1;
    if (ainfo->engine_en)
    {
        ens =  1000000*(state->mem_page_miss + eburst_size/(state->memory_width/8) +refresh_cycle)/state->mclk_khz;
        ainfo->mocc = state->enable_mp ? 0-ens*ainfo->mdrain_rate/1000000 : 0;
        ainfo->vocc = ainfo->vid_en ? 0-ens*ainfo->vdrain_rate/1000000 : 0;
        ainfo->gocc = ainfo->gr_en ? 0-ens*ainfo->gdrain_rate/1000000 : 0;
        ainfo->cur = ENGINE;
        ainfo->first_vacc = 1;
        ainfo->first_gacc = 1;
        ainfo->first_macc = 1;
        nv3_iterate(res_info, state,ainfo);
    }
    if (state->enable_mp)
    {
        mns = 1000000 * (mmisses*state->mem_page_miss + mburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
        ainfo->mocc = state->enable_mp ? 0 : mburst_size - mns*ainfo->mdrain_rate/1000000;
        ainfo->vocc = ainfo->vid_en ? 0 : 0- mns*ainfo->vdrain_rate/1000000;
        ainfo->gocc = ainfo->gr_en ? 0: 0- mns*ainfo->gdrain_rate/1000000;
        ainfo->cur = MPORT;
        ainfo->first_vacc = 1;
        ainfo->first_gacc = 1;
        ainfo->first_macc = 0;
        nv3_iterate(res_info, state,ainfo);
    }
    if (ainfo->gr_en)
    {
        ainfo->first_vacc = 1;
        ainfo->first_gacc = 0;
        ainfo->first_macc = 1;
        gns = 1000000*(gmisses*state->mem_page_miss + ainfo->gburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
        ainfo->gocc = ainfo->gburst_size - gns*ainfo->gdrain_rate/1000000;
        ainfo->vocc = ainfo->vid_en? 0-gns*ainfo->vdrain_rate/1000000 : 0;
        ainfo->mocc = state->enable_mp ?  0-gns*ainfo->mdrain_rate/1000000: 0;
        ainfo->cur = GRAPHICS;
        nv3_iterate(res_info, state,ainfo);
    }
    if (ainfo->vid_en)
    {
        ainfo->first_vacc = 0;
        ainfo->first_gacc = 1;
        ainfo->first_macc = 1;
        vns = 1000000*(vmisses*state->mem_page_miss + ainfo->vburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
        ainfo->vocc = ainfo->vburst_size - vns*ainfo->vdrain_rate/1000000;
        ainfo->gocc = ainfo->gr_en? (0-vns*ainfo->gdrain_rate/1000000) : 0;
        ainfo->mocc = state->enable_mp? 0-vns*ainfo->mdrain_rate/1000000 :0 ;
        ainfo->cur = VIDEO;
        nv3_iterate(res_info, state, ainfo);
    }
    if (ainfo->converged)
    {
        res_info->graphics_lwm = (int)ABS(ainfo->wcglwm) + 16;
        res_info->video_lwm = (int)ABS(ainfo->wcvlwm) + 32;
        res_info->graphics_burst_size = ainfo->gburst_size;
        res_info->video_burst_size = ainfo->vburst_size;
        res_info->graphics_hi_priority = (ainfo->priority == GRAPHICS);
        res_info->media_hi_priority = (ainfo->priority == MPORT);
        if (res_info->video_lwm > 160)
        {
            res_info->graphics_lwm = 256;
            res_info->video_lwm = 128;
            res_info->graphics_burst_size = 64;
            res_info->video_burst_size = 64;
            res_info->graphics_hi_priority = 0;
            res_info->media_hi_priority = 0;
            ainfo->converged = 0;
            return (0);
        }
        if (res_info->video_lwm > 128)
        {
            res_info->video_lwm = 128;
        }
        return (1);
    }
    else
    {
        res_info->graphics_lwm = 256;
        res_info->video_lwm = 128;
        res_info->graphics_burst_size = 64;
        res_info->video_burst_size = 64;
        res_info->graphics_hi_priority = 0;
        res_info->media_hi_priority = 0;
        return (0);
    }
}
static char nv3_get_param(nv3_fifo_info *res_info, nv3_sim_state * state, nv3_arb_info *ainfo)
{
    int done, g,v, p;
    
    done = 0;
    for (p=0; p < 2; p++)
    {
        for (g=128 ; g > 32; g= g>> 1)
        {
            for (v=128; v >=32; v = v>> 1)
            {
                ainfo->priority = p;
                ainfo->gburst_size = g;     
                ainfo->vburst_size = v;
                done = nv3_arb(res_info, state,ainfo);
                if (done && (g==128))
                    if ((res_info->graphics_lwm + g) > 256)
                        done = 0;
                if (done)
                    goto Done;
            }
        }
    }
 Done:
    return done;
}
static void nv3CalcArbitration 
(
    nv3_fifo_info * res_info,
    nv3_sim_state * state
)
{
    nv3_fifo_info save_info;
    nv3_arb_info ainfo;
    char   res_gr, res_vid;
    ainfo.gr_en = 1;
    ainfo.vid_en = state->enable_video;
    ainfo.vid_only_once = 0;
    ainfo.gr_only_once = 0;
    ainfo.gdrain_rate = (int) state->pclk_khz * (state->pix_bpp/8);
    ainfo.vdrain_rate = (int) state->pclk_khz * 2;
    if (state->video_scale != 0)
        ainfo.vdrain_rate = ainfo.vdrain_rate/state->video_scale;
    ainfo.mdrain_rate = 33000;
    res_info->rtl_values = 0;
    if (!state->gr_during_vid && state->enable_video)
    {
        ainfo.gr_only_once = 1;
        ainfo.gr_en = 1;
        ainfo.gdrain_rate = 0;
        res_vid = nv3_get_param(res_info, state,  &ainfo);
        res_vid = ainfo.converged;
        save_info.video_lwm = res_info->video_lwm;
        save_info.video_burst_size = res_info->video_burst_size;
        ainfo.vid_en = 1;
        ainfo.vid_only_once = 1;
        ainfo.gr_en = 1;
        ainfo.gdrain_rate = (int) state->pclk_khz * (state->pix_bpp/8);
        ainfo.vdrain_rate = 0;
        res_gr = nv3_get_param(res_info, state,  &ainfo);
        res_gr = ainfo.converged;
        res_info->video_lwm = save_info.video_lwm;
        res_info->video_burst_size = save_info.video_burst_size;
        res_info->valid = res_gr & res_vid;
    }
    else
    {
        if (!ainfo.gr_en) ainfo.gdrain_rate = 0;
        if (!ainfo.vid_en) ainfo.vdrain_rate = 0;
        res_gr = nv3_get_param(res_info, state,  &ainfo);
        res_info->valid = ainfo.converged;
    }
}
static void nv3UpdateArbitrationSettings
(
    unsigned      VClk, 
    unsigned      pixelDepth, 
    unsigned     *burst,
    unsigned     *lwm,
    RIVA_HW_INST *chip
)
{
    nv3_fifo_info fifo_data;
    nv3_sim_state sim_data;
    unsigned int M, N, P, pll, MClk;
    
    pll = chip->PRAMDAC0[0x00000504/4]; 
    M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F;
    MClk = (N * chip->CrystalFreqKHz / M) >> P;
    sim_data.pix_bpp        = (char)pixelDepth;
    sim_data.enable_video   = 0;
    sim_data.enable_mp      = 0;
    sim_data.video_scale    = 1;
    sim_data.memory_width   = (chip->PEXTDEV[0x00000000/4] & 0x10) ? 128 : 64;
    sim_data.memory_width   = 128;
    sim_data.mem_latency    = 9;
    sim_data.mem_aligned    = 1;
    sim_data.mem_page_miss  = 11;
    sim_data.gr_during_vid  = 0;
    sim_data.pclk_khz       = VClk;
    sim_data.mclk_khz       = MClk;
    nv3CalcArbitration(&fifo_data, &sim_data);
    if (fifo_data.valid)
    {
        int  b = fifo_data.graphics_burst_size >> 4;
        *burst = 0;
        while (b >>= 1) (*burst)++;
        *lwm   = fifo_data.graphics_lwm >> 3;
    }
    else
    {
        *lwm   = 0x24;
        *burst = 0x2;
    }
}
static void nv4CalcArbitration 
(
    nv4_fifo_info *fifo,
    nv4_sim_state *arb
)
{
    int data, pagemiss, cas,width, video_enable, color_key_enable, bpp, align;
    int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs;
    int found, mclk_extra, mclk_loop, cbs, m1, p1;
    int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
    int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate;
    int vpm_us, us_video, vlwm, video_fill_us, cpm_us, us_crt,clwm;
    int craw, vraw;
    fifo->valid = 1;
    pclk_freq = arb->pclk_khz;
    mclk_freq = arb->mclk_khz;
    nvclk_freq = arb->nvclk_khz;
    pagemiss = arb->mem_page_miss;
    cas = arb->mem_latency;
    width = arb->memory_width >> 6;
    video_enable = arb->enable_video;
    color_key_enable = arb->gr_during_vid;
    bpp = arb->pix_bpp;
    align = arb->mem_aligned;
    mp_enable = arb->enable_mp;
    clwm = 0;
    vlwm = 0;
    cbs = 128;
    pclks = 2;
    nvclks = 2;
    nvclks += 2;
    nvclks += 1;
    mclks = 5;
    mclks += 3;
    mclks += 1;
    mclks += cas;
    mclks += 1;
    mclks += 1;
    mclks += 1;
    mclks += 1;
    mclk_extra = 3;
    nvclks += 2;
    nvclks += 1;
    nvclks += 1;
    nvclks += 1;
    if (mp_enable)
        mclks+=4;
    nvclks += 0;
    pclks += 0;
    found = 0;
    vbs = 0;
    while (found != 1)
    {
        fifo->valid = 1;
        found = 1;
        mclk_loop = mclks+mclk_extra;
        us_m = mclk_loop *1000*1000 / mclk_freq;
        us_n = nvclks*1000*1000 / nvclk_freq;
        us_p = nvclks*1000*1000 / pclk_freq;
        if (video_enable)
        {
            video_drain_rate = pclk_freq * 2;
            crtc_drain_rate = pclk_freq * bpp/8;
            vpagemiss = 2;
            vpagemiss += 1;
            crtpagemiss = 2;
            vpm_us = (vpagemiss * pagemiss)*1000*1000/mclk_freq;
            if (nvclk_freq * 2 > mclk_freq * width)
                video_fill_us = cbs*1000*1000 / 16 / nvclk_freq ;
            else
                video_fill_us = cbs*1000*1000 / (8 * width) / mclk_freq;
            us_video = vpm_us + us_m + us_n + us_p + video_fill_us;
            vlwm = us_video * video_drain_rate/(1000*1000);
            vlwm++;
            vbs = 128;
            if (vlwm > 128) vbs = 64;
            if (vlwm > (256-64)) vbs = 32;
            if (nvclk_freq * 2 > mclk_freq * width)
                video_fill_us = vbs *1000*1000/ 16 / nvclk_freq ;
            else
                video_fill_us = vbs*1000*1000 / (8 * width) / mclk_freq;
            cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
            us_crt =
            us_video
            +video_fill_us
            +cpm_us
            +us_m + us_n +us_p
            ;
            clwm = us_crt * crtc_drain_rate/(1000*1000);
            clwm++;
        }
        else
        {
            crtc_drain_rate = pclk_freq * bpp/8;
            crtpagemiss = 2;
            crtpagemiss += 1;
            cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
            us_crt =  cpm_us + us_m + us_n + us_p ;
            clwm = us_crt * crtc_drain_rate/(1000*1000);
            clwm++;
        }
        m1 = clwm + cbs - 512;
        p1 = m1 * pclk_freq / mclk_freq;
        p1 = p1 * bpp / 8;
        if ((p1 < m1) && (m1 > 0))
        {
            fifo->valid = 0;
            found = 0;
            if (mclk_extra ==0)   found = 1;
            mclk_extra--;
        }
        else if (video_enable)
        {
            if ((clwm > 511) || (vlwm > 255))
            {
                fifo->valid = 0;
                found = 0;
                if (mclk_extra ==0)   found = 1;
                mclk_extra--;
            }
        }
        else
        {
            if (clwm > 519)
            {
                fifo->valid = 0;
                found = 0;
                if (mclk_extra ==0)   found = 1;
                mclk_extra--;
            }
        }
        craw = clwm;
        vraw = vlwm;
        if (clwm < 384) clwm = 384;
        if (vlwm < 128) vlwm = 128;
        data = (int)(clwm);
        fifo->graphics_lwm = data;
        fifo->graphics_burst_size = 128;
        data = (int)((vlwm+15));
        fifo->video_lwm = data;
        fifo->video_burst_size = vbs;
    }
}
static void nv4UpdateArbitrationSettings
(
    unsigned      VClk, 
    unsigned      pixelDepth, 
    unsigned     *burst,
    unsigned     *lwm,
    RIVA_HW_INST *chip
)
{
    nv4_fifo_info fifo_data;
    nv4_sim_state sim_data;
    unsigned int M, N, P, pll, MClk, NVClk, cfg1;
    pll = chip->PRAMDAC0[0x00000504/4];
    M = (pll >> 0)  & 0xFF; N = (pll >> 8)  & 0xFF; P = (pll >> 16) & 0x0F;
    MClk  = (N * chip->CrystalFreqKHz / M) >> P;
    pll = chip->PRAMDAC0[0x00000500/4];
    M = (pll >> 0)  & 0xFF; N = (pll >> 8)  & 0xFF; P = (pll >> 16) & 0x0F;
    NVClk  = (N * chip->CrystalFreqKHz / M) >> P;
    cfg1 = chip->PFB[0x00000204/4];
    sim_data.pix_bpp        = (char)pixelDepth;
    sim_data.enable_video   = 0;
    sim_data.enable_mp      = 0;
    sim_data.memory_width   = (chip->PEXTDEV[0x00000000/4] & 0x10) ? 128 : 64;
    sim_data.mem_latency    = (char)cfg1 & 0x0F;
    sim_data.mem_aligned    = 1;
    sim_data.mem_page_miss  = (char)(((cfg1 >> 4) &0x0F) + ((cfg1 >> 31) & 0x01));
    sim_data.gr_during_vid  = 0;
    sim_data.pclk_khz       = VClk;
    sim_data.mclk_khz       = MClk;
    sim_data.nvclk_khz      = NVClk;
    nv4CalcArbitration(&fifo_data, &sim_data);
    if (fifo_data.valid)
    {
        int  b = fifo_data.graphics_burst_size >> 4;
        *burst = 0;
        while (b >>= 1) (*burst)++;
        *lwm   = fifo_data.graphics_lwm >> 3;
    }
}
static void nv10CalcArbitration 
(
    nv10_fifo_info *fifo,
    nv10_sim_state *arb
)
{
    int data, pagemiss, cas,width, video_enable, color_key_enable, bpp, align;
    int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs;
    int nvclk_fill, us_extra;
    int found, mclk_extra, mclk_loop, cbs, m1;
    int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
    int us_m, us_m_min, us_n, us_p, video_drain_rate, crtc_drain_rate;
    int vus_m, vus_n, vus_p;
    int vpm_us, us_video, vlwm, cpm_us, us_crt,clwm;
    int clwm_rnd_down;
    int craw, m2us, us_pipe, us_pipe_min, vus_pipe, p1clk, p2;
    int pclks_2_top_fifo, min_mclk_extra;
    int us_min_mclk_extra;
    fifo->valid = 1;
    pclk_freq = arb->pclk_khz; /* freq in KHz */
    mclk_freq = arb->mclk_khz;
    nvclk_freq = arb->nvclk_khz;
    pagemiss = arb->mem_page_miss;
    cas = arb->mem_latency;
    width = arb->memory_width/64;
    video_enable = arb->enable_video;
    color_key_enable = arb->gr_during_vid;
    bpp = arb->pix_bpp;
    align = arb->mem_aligned;
    mp_enable = arb->enable_mp;
    clwm = 0;
    vlwm = 1024;
    cbs = 512;