View | Details | Raw Unified
Collapse All | Expand All

(-) linux-2.4.26/Documentation/Configure.help (+117 lines)
 Lines 412-417    Link Here 
  Otherwise low memory pages are used as bounce buffers causing a
  Otherwise low memory pages are used as bounce buffers causing a
  degrade in performance.
  degrade in performance.
Xbox support
CONFIG_XBOX
  If you want your kernel to be compatible with the Microsoft Xbox,
  say Y. This option includes adjustments so that the kernel runs
  both on a standard PC or on an Xbox.
  This code autodetects an Xbox at boot, and if it is found, it
  avoids the PCI enumeration chipset bug, adjusts the system
  frequency and adds the Xbox shutdown/reset sequence.
Xbox DVD eject fix
CONFIG_XBOX_EJECT
  If you want to be able to eject the DVD drive tray, say Y, or else
  your eject button will be a reset button. For security reasons, the
  Xbox is reset by default when the optical media is supposed to be
  ejected.
  If you want to compile this as a module ( = code which can be
  inserted in and removed from the running kernel whenever you want),
  say M and read <file:Documentation/modules.txt>. The module will be
  called xboxejectfix.o.
  You should really say Y here. If you compile it as a module, make
  sure that it gets loaded as soon as possible, so that you are
  protected against accidental resets from the very beginning.
OOM killer support
OOM killer support
CONFIG_OOM_KILLER
CONFIG_OOM_KILLER
   This option selects the kernel behaviour during total out of memory
   This option selects the kernel behaviour during total out of memory
 Lines 5010-5015    Link Here 
  module will be called rivafb.o. If you want to compile it as a
  module will be called rivafb.o. If you want to compile it as a
  module, say M here and read <file:Documentation/modules.txt>.
  module, say M here and read <file:Documentation/modules.txt>.
Xbox (nVidia) support
CONFIG_FB_XBOX
  This driver supports graphics boards with the nVidia GeForce 3MX GPU
  as found in the Microsoft Xbox. Note that this driver and CONFIG_FB_RIVA
  (nVidia Riva support) are mutually exclusive, ie. you can enable only
  one and not both.
  Note 2: This driver depends on both CONFIG_XBOX (Xbox support) and
  CONFIG_I2C_AMD756 (I2C support for nForce chipsets).
  Say Y if you are running Linux on the Xbox, otherwise, say N.
  The driver is also available as a module ( = code which can be
  inserted and removed from the running kernel whenever you want). The
  module will be called xboxfb.o. If you want to compile it as a
  module, say M here and read <file:Documentation/modules.txt>.
Trident Blade/Image support
Trident Blade/Image support
CONFIG_FB_TRIDENT
CONFIG_FB_TRIDENT
  This driver is supposed to support graphics boards with the
  This driver is supposed to support graphics boards with the
 Lines 12446-12451    Link Here 
  <file:Documentation/networking/net-modules.txt>.  The module will be
  <file:Documentation/networking/net-modules.txt>.  The module will be
  called forcedeth.o.
  called forcedeth.o.
nForce Ethernet support (EXPERIMENTAL)
CONFIG_FORCEDETH
  If you have a network (Ethernet) controller of this type, say Y and
  read the Ethernet-HOWTO, available from
  <http://www.tldp.org/docs.html#howto>.
  To compile this driver as a module, choose M here and read
  <file:Documentation/networking/net-modules.txt>.  The module will be
  called forcedeth.o.
CS89x0 support (Daynaport CS and LC cards)
CS89x0 support (Daynaport CS and LC cards)
CONFIG_CS89x0
CONFIG_CS89x0
  Support for CS89x0 chipset based Ethernet cards. If you have a
  Support for CS89x0 chipset based Ethernet cards. If you have a
 Lines 14968-14973    Link Here 
  The module will be called powermate.o. If you want to compile it as a
  The module will be called powermate.o. If you want to compile it as a
  module, say M here and read <file:Documentation/modules.txt>.
  module, say M here and read <file:Documentation/modules.txt>.
Xbox Infrared DVD dongle support (EXPERIMENTAL)
CONFIG_USB_XBOXIR
  Say Y here if you want to use the Xbox DVD dongle and remote control
  to help control running applications using keyboard codes. Make sure
  to say Y to "USB Keyboard support" (CONFIG_INPUT_KBD) and/or
  "Event interface support" (CONFIG_INPUT_EVDEV) as well.
Xbox Controller (XPad)
CONFIG_USB_XPAD
  Say Y here if you want to use the X-Box pad with your computer.
  Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV)
  and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well.
  For information about how to connect the X-Box pad to USB, see
  Documentation/input/xpad.txt.
  This driver is also available as a module ( = code which can be
  inserted in and removed from the running kernel whenever you want).
  The module will be called xpad.o.  If you want to compile it as a
  module, say M here and read <file:Documentation/modules.txt>.
Xbox Controller Mouse Emulation
CONFIG_USB_XPAD_MOUSE
  Say Y here if you want to use the Xbox pad as a mouse
  with your computer. Make sure to say Y to "Mouse support"
  (CONFIG_INPUT_MOUSEDEV) as well. This emulation is part of the
  regular XPad driver, so you have to enable CONFIG_USB_XPAD for
  this to work.
  For information about how to connect the Xbox pad to USB, see
  Documentation/input/xpad.txt.
Aiptek HyperPen tablet support
Aiptek HyperPen tablet support
CONFIG_USB_AIPTEK
CONFIG_USB_AIPTEK
  Say Y here if you want to use the USB version of the Aiptek HyperPen
  Say Y here if you want to use the USB version of the Aiptek HyperPen
 Lines 16865-16870    Link Here 
  root partition (the one containing the directory /) cannot be a
  root partition (the one containing the directory /) cannot be a
  module, so saying M could be dangerous.  If unsure, say N.
  module, so saying M could be dangerous.  If unsure, say N.
FATX (Xbox) fs support
CONFIG_FATX_FS
  This adds support for the FATX filesystem as found in Microsoft's Xbox.
  The FATX filesystem is a derivative of the FAT filesystem minus some
  legacy fields and redundant information. For lengthier discussions on
  the filesystem, see:
  http://xbox-linux.sourceforge.net/docs/fatxfat.html
  http://xbox-linux.sourceforge.net/docs/hdpartfs.html
  http://xbox-linux.sourceforge.net/docs/hackingfatx.html
  If you are running Linux on the Xbox, say Y unless you know what
  you're doing. Otherwise, say N.
  If you want to compile this as a module ( = code which can be
  inserted in and removed from the running kernel whenever you want),
  say M here and read <file:Documentation/modules.txt>.  The module
  will be called fatx.o.
/proc file system support
/proc file system support
CONFIG_PROC_FS
CONFIG_PROC_FS
  This is a virtual file system providing information about the status
  This is a virtual file system providing information about the status
 Lines 17496-17501    Link Here 
  Say Y here if you would like to use hard disks under Linux which
  Say Y here if you would like to use hard disks under Linux which
  were partitioned on a Macintosh.
  were partitioned on a Macintosh.
Xbox partition support
CONFIG_XBOX_PARTITION
  The Xbox makes use of a static and implicit partitioning scheme.
  The locations and sizes of the four partitions on the Xbox hard
  disk are hard-coded into the native Xbox kernel.
  Say Y here if you are running Linux on the Xbox, or would like
  to access a hard disk partitioned for the Xbox under a PC
  running Linux.
  If unsure, say N.
Windows Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL)
Windows Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL)
CONFIG_LDM_PARTITION
CONFIG_LDM_PARTITION
  Say Y here if you would like to use hard disks under Linux which
  Say Y here if you would like to use hard disks under Linux which
(-) linux-2.4.26/Documentation/README.xbox (+232 lines)
Line 0    Link Here 
$Id: README.xbox,v 1.6 2004/02/19 15:13:44 aothieno Exp $
We are baselined on 2.4.25
Introductory Note
-----------------
First, if you are shaking with excitement and fear and this is your first 
attempt to compile the kernel, don't worry if things don't work out first time.
Expect trouble the first couple of attempts, make sure you have a way to boot 
an old kernel after trying a fresh one.  Note too that the kernel compile 
process does nothing to your system config until you copy the new kernel image 
to /boot and make it the default choice for boot.
A very easy mistake to make is to forget to do the make modules and 
make modules_install after doing the bzImage, since it takes a little while 
and your mind has probably wandered.
Don't be afraid to come on IRC irc.oftc.net, #xbox-linux or the devel mailing 
list and ask some of the old hands there.
Compiling the kernel patched for Xbox
-------------------------------------
In order to use this CVS archive you need to setup things properly.
This document decribes three different ways to build the xbox kernel.
The first method attempts to build the kernel from the "HEAD" or current
version inside CVS. The current version is traditionally unstable and
(like in most projects) is very user unfriendly and may not even compile.
This is traditionally used by the experienced developers only. The code
changes frequently.
The second method is more 'user friendly'. It shows you how to extract a known
(tagged) working release of the kernel which will always compile. In essence,
the developers have put together a working set of files, tested them, tried them
and 'tagged' them as 'user friendly', IE. a fully working kernel.
The third, and easiest method, it to download and apply one of the tagged
release patches and apply it to the vanilla base kernel. This option is the
easiest option for users. You don't even need to know anything about cvs!
If you are unsure, choose this option.
Independent of how you've chosen to build your kernel, you will most certainly
perform these preliminary steps:
1. Download a kernel source tarball from:
   http://www.XY.kernel.org/pub/linux/kernel/v2.4/linux-2.4.25.tar.gz
   where XY is a two-letter country code, eg. `us', `de', `fr', etc.
2. Extract the contents of the archive into /usr/src:
   $ cd /usr/src
   $ tar xzvf linux-2.4.25.tar.gz
   $ mv linux-2.4.25{,-xbox}
Option 1: Installing From A Recent CVS Snapshot.
------------------------------------------------
3.1 Assuming you have a SF.net account, checkout the latest CVS snapshot:
    $ cvs -d:ext:username@cvs.sf.net:/cvsroot/xbox-linux co kernel
    If you do not have a SF.net user account, you may perform an anonymous
    checkout instead:
    $ cvs -d:pserver:anonymous@cvs.sf.net:/cvsroot/xbox-linux login
    $ cvs -d:pserver:anonymous@cvs.sf.net:/cvsroot/xbox-linux co kernel
    Now, you may copy the contents of the CVS repository into the kernel
    source directory:
    $ cp -rf kernel/* linux-2.4.25-xbox/
Option 2: Installing From A Tagged CVS Release.
-----------------------------------------------
3.2 Tagged releases are known to work, although this can not be fully
    guaranteed. Information regarding available tags can always be
    obtained from either the user or developer mailing lists. The
    current tagged release is `kernel-2_4_25-0_1_0'.
    So, assuming you have a SF.net account, you may proceed to
    checkout a tagged release like this:
    $ cvs -d:ext:username@cvs.sf.net:/cvsroot/xbox-linux \
      co -r kernel-2_4_25-0_1_0 kernel
    Or anonymously, if you don't have a SF.net account:
    $ cvs -d:pserver:anonymous@cvs.sf.net:/cvsroot/xbox-linux login
    $ cvs -d:pserver:anonymous@cvs.sf.net:/cvsroot/xbox-linux \
      co -r kernel-2_4_25-0_1_0 kernel
    Then copy the contents of the tagged release into the kernel source
    directory:
    $ cp -rf kernel/* linux-2.4.25-xbox/
Option 3: Installing From A Tagged CVS Release by Patching.
-----------------------------------------------------------
3.3 Tagged releases are also available in form of a patch against a stock
    version of the Linux kernel. Grab it from the SF.net project download
    page, save it in /usr/src and then apply it, like so:
    $ bzip2 -dc patch-kernel-2.4.20-dev-0.6.1.bz2 | patch -p0
4. With a patched kernel, you may now proceed to preparing the source tree
   for the final build:
   $ cd linux-2.4.25-xbox/
   $ make mrproper
   $ cp kernel.config .config
5. We need to load and save the config file to cause some actions to be made
   by the makefile. There are a bunch of ways to do this, the simplest is:
   $ make oldconfig
   If you need to see and change the config options, you need some packages
   installed:
   make menuconfig (curses-based configuration):
   ---------------------------------------------
   ncurses-base, ncurses-bin, ncurses-term, libncurses5 & libncurses5-dev
   make xconfig (graphical-based configuration):
   ---------------------------------------------
   tcl, tk
	  
   Exit from the menu configuration tools and choose YES to save your
   configuration. (This will build the menu configuration utilities and
   refresh the kernel configuration file named .config we previously made
   a default for)
   Now you have a usable kernel tree which you can do your compilations.
6. Compile the kernel and the modules, make sure none of these commands
   abort abnormally with errors. (NOTE: You will need to be root to make
   modules_install):
   $ make dep
   $ make bzImage
   $ make modules
   # make modules_install
The kernel has been compiled and is called `arch/i386/boot/bzImage'. Kernel
modules have been compiled and installed into `/lib/modules/2.4.25-xbox/'.
Kernel compilation complete.
Patch Files:
------------
Patch files will be released to the community based on tagged releases of CVS.
The name of the file will include the base kernel and the project tag version,
for example: patch-kernel-2.4.20-dev-0.6.1.bz2
Clearly, this patch should be applied to 2.4.20, is development quality and
was taken from the CVS tagged version 0.5.2.
 
Template Configuration File: `kernel.config':
---------------------------------------------
A default configuration file has been added with all of the necessary
compile options automatically set. This may save you time and trouble.
Finally (optional):
-------------------
If you've got no use for it, feel free to remove your working copy of the
CVS checkout:
   $ cd ../
   $ rm -rf kernel/
CVS Syncmail:
-------------
CVS is configured to send all repository changes to the xbox-linux-cvs 
mailing list.
The following text is taken from the official sourceforge CVS synmail 
configuration document:
A Warning Regarding Commit Messages:
------------------------------------
When you begin to use syncmail within your project CVS repository, it is 
important to give your developers prior notice. syncmail-generated messages
to your mailing list will contain the commit message used by the developer; 
developers should keep this in mind when entering their commit message 
(not to make inappropriate statements within their commit messages). 
SourceForge.net does not provide the means to remove posts from mailing
list archives; once a commit message appears in list archives, it will always 
appear in those archives. Proceed with caution."
Inside the Xbox Patches:
------------------------
The Xbox has at least the following problems so it doesn't run the Linux
kernel very well:
* the PCI bug: reading from 0:0:1 freezes the machine
* the timer: it is off by 6%
* the shutdown/reboot sequence: it's incompatible
The current kernel detects the Xbox by its 0:0:0 PCI device ID and sets
machine_is_xbox to 1. The PCI, timer and shutdown/reboot patches will
be applied then. This means that a Linux kernel with Xbox support will
still work on a PC without any differences.
Problems:
---------
If you have any problems *ask* (try the IRC channel)
(-) linux-2.4.26/Documentation/input/xpad.txt (+145 lines)
Line 0    Link Here 
xpad - Linux USB driver for Xbox gamepads
------------------------------------------
This driver is work in progress. Although it is already fairly functional,
there are still quite a few things that are not implemented.
See the ToDo-List in drivers/usb/input/xpad.c for details.
0. Status
---------
I believe this driver to have been more or less intensively tested by
xbox-linux users, because it somehow managed it into their CVS [1] ;)
I myself have tested it on just one Linux-Box. This one is running a 2.4.19
kernel with usb-uhci on an amd athlon 600.
Additionally I did receive a few mails from people who have successfully
used the driver on different PC systems and notebooks. I did not yet receive
info on wether it works on PPC or non-i386 hardware.
Version 0.1.0-pre includes Oliver Schwartz' xpad-mouse driver code. This allows
for the xpad to be used as a pointer device (right thumbstick is movement, left
trigger is left mouse button, right one is right). This is not supposed to stay
that way (differs from Oliver's mapping), so don't get too used to it.
The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) reports
14 axes (6 of them are the analog buttons) and 10 buttons (the analog buttons
are mapped as digital ones, too).
Alls 14 axes work, though they all have the same range (-32768..32767)
and the zero-setting is not correct for the triggers and the buttons
(I don't know if that is some limitation of jstest, since the input device
setup should be fine. I didn't have a look at jstest itself yet).
All of the 10 buttons work. The six buttons on the right side (A, B, C [black],
X, Y, Z [white]) are pressure-sensitive and report analog values as 8 bit
unsigned. These are mapped to analog (ABS_HAT1X - ABS_HAT3Y) as well as
digital inputs.
As of version 0.1.0-pre there is EXPERIMENTAL force feedback code. Note that
this is currently just plain stupid (as I have yet to find out all the neat
USB tricks) and is known to have bugs. Specifically, it does not work with the
stock MS controllers. The InterAct device rumbles just fine, though. I am
currently trying to figure out why.
Anyway, USE the stuff AT YOUR OWN RISK, the usual disclaimer applies. It
actually managed to crash my system once (unfortunately not reproducable).
You HAVE BEEN WARNED.
I tested the controller with quake3, and configuration and
in game functionality were OK. However, I find it rather difficult to
play first person shooters with a pad. Your mileage may vary.
1. USB adapter
--------------
Before you can actually use the driver, you need to get yourself an
adapter cable to connect the Xbox controller to your Linux-Box.
Such a cable is pretty easy to build. The Controller itself is a USB compound
device (a hub with three ports for two expansion slots and the controller
device) with the only difference in a nonstandard connector (5 pins vs. 4 on
standard USB connector).
You just need to solder a USB connector onto the cable and keep the
yellow wire unconnected. The other pins have the same order on both
connectors so there is no magic to it. Detailed info on these matters
can be found on the net ([2], [3], [4]).
Thanks to the trip splitter found on the cable you don't even need to cut the
original one. You can buy an extension cable and cut that instead. That way,
you can still use the controller with your Xbox, if you have one ;)
2. driver installation
----------------------
Once you have the adapter cable and the controller is connected, you need
to load your USB subsystem and should cat /proc/bus/usb/devices.
There should be an entry like the one at the end [5].
Currently (as of version 0.1.0), the following three devices are recognized:
 original Microsoft Xbox controller (US), vendor=0x045e, product=0x0202
 original Microsoft Xbox controller (Japan), vendor=0x045e, product=0x0285
 InterAct PowerPad Pro (Germany), vendor=0x05fd, product=0x107a
The driver does feel responsible for the actual USB ids, not the vendor
settings, so other controllers SHOULD work (although they will be reported as
unknown controller). If you have indication of that statement being wrong,
please send me a note.
Also, if you have a controller that is not recognized (but works) and you want
it to be correctly setup, please drop me a line with the appropriate info (that
is, include the name, vendor and product ID; sending the whole dump out of
/proc/bus/usb/devices along would be even better).
If you compiled and installed the driver, test the functionality:
> modprobe xpad
> modprobe joydev
> jstest /dev/js0
There should be 24 inputs (14 axes, 10 buttons), and the values should change
if you move the sticks and push the buttons.
You can test the force feedback functionality by
> modprobe evdev
> fftest /dev/input/event0
You need the Johann Deneux' fftest utility and the evdev module. Note that
the actual event interface number might differ (depends on wether you have the
mouse support included and wether it loads first or not) on your specific setup.
It works? Voila, your done ;)
3. Thanks
---------
I have to thank ITO Takayuki for the detailed info on his site
 http://euc.jp/periphs/xbox-controller.ja.html.
 
His useful info and both the usb-skeleton as well as the iforce input driver
(Greg Kroah-Hartmann; Vojtech Pavlik) helped a lot in rapid prototyping
the basic functionality.
4. References
-------------
1. http://xbox-linux.sourceforge.net
2. http://euc.jp/periphs/xbox-controller.ja.html (ITO Takayuki)
3. http://xpad.xbox-scene.com/
4. http://www.xboxhackz.com/Hackz-Reference.htm
5. /proc/bus/usb/devices - dump from InterAct PowerPad Pro (Germany):
T:  Bus=01 Lev=03 Prnt=04 Port=00 Cnt=01 Dev#=  5 Spd=12  MxCh= 0
D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=32 #Cfgs=  1
P:  Vendor=05fd ProdID=107a Rev= 1.00
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
I:  If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=(none)
E:  Ad=81(I) Atr=03(Int.) MxPS=  32 Ivl= 10ms
E:  Ad=02(O) Atr=03(Int.) MxPS=  32 Ivl= 10ms
-- 
Marko Friedemann <mfr@bmx-chemnitz.de>
2003-01-23
(-) linux-2.4.26/Makefile (-1 / +1 lines)
 Lines 1-7    Link Here 
VERSION = 2
VERSION = 2
PATCHLEVEL = 4
PATCHLEVEL = 4
SUBLEVEL = 26
SUBLEVEL = 26
EXTRAVERSION =
EXTRAVERSION = -xbox
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
(-) linux-2.4.26/arch/i386/boot/compressed/Makefile (+5 lines)
 Lines 34-39    Link Here 
comma	:= ,
comma	:= ,
# we don't know why, but newer (v1.1+) Xbox only boot
ifeq ($(CONFIG_XBOX),y)
 	CFLAGS := -O0 -D__KERNEL__ -I../../../../include -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fomit-frame-pointer -pipe -mpreferred-stack-boundary=2 -march=i386
endif
misc.o: misc.c
misc.o: misc.c
	$(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c misc.c
	$(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c misc.c
(-) linux-2.4.26/arch/i386/config.in (+4 lines)
 Lines 222-227    Link Here 
   bool 'HIGHMEM I/O support' CONFIG_HIGHIO
   bool 'HIGHMEM I/O support' CONFIG_HIGHIO
fi
fi
bool 'Xbox support' CONFIG_XBOX
if [ "$CONFIG_XBOX" = "y" ]; then
   tristate '  Xbox DVD eject fix' CONFIG_XBOX_EJECT
fi
bool 'Math emulation' CONFIG_MATH_EMULATION
bool 'Math emulation' CONFIG_MATH_EMULATION
bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
bool 'Symmetric multi-processing support' CONFIG_SMP
bool 'Symmetric multi-processing support' CONFIG_SMP
(-) linux-2.4.26/arch/i386/kernel/Makefile (+1 lines)
 Lines 43-47    Link Here 
obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
obj-$(CONFIG_EDD)             	+= edd.o
obj-$(CONFIG_EDD)             	+= edd.o
obj-$(CONFIG_XBOX_EJECT)	+= xboxejectfix.o
include $(TOPDIR)/Rules.make
include $(TOPDIR)/Rules.make
(-) linux-2.4.26/arch/i386/kernel/pci-pc.c (+16 lines)
 Lines 183-191    Link Here 
static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* !CONFIG_MULTIQUAD */
static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* !CONFIG_MULTIQUAD */
{
{
	unsigned long flags;
	unsigned long flags;
#ifdef CONFIG_XBOX
	extern int machine_is_xbox;
#endif /* CONFIG_XBOX */
	if (bus > 255 || dev > 31 || fn > 7 || reg > 255)
	if (bus > 255 || dev > 31 || fn > 7 || reg > 255)
		return -EINVAL;
		return -EINVAL;
#ifdef CONFIG_XBOX
	/* Because of a hardware bug in the Xbox (nForce) chipset,
	 * reading from 0:0:1 and 0:0:2 in the PCI configuration
	 * space crashes the machine. */
	if (machine_is_xbox) {
		if (bus > 1)
			return -EINVAL;
		if ((bus == 1) && (dev | fn))
			return -EINVAL;
		if ((bus == 0 && dev == 0) && ((fn == 1) || (fn == 2)))
			return -EINVAL;
	}
#endif /* CONFIG_XBOX */
	spin_lock_irqsave(&pci_config_lock, flags);
	spin_lock_irqsave(&pci_config_lock, flags);
(-) linux-2.4.26/arch/i386/kernel/process.c (+15 lines)
 Lines 50-55    Link Here 
#endif
#endif
#include <asm/apic.h>
#include <asm/apic.h>
#ifdef CONFIG_XBOX
#include <linux/xbox.h>
#endif
#include <linux/irq.h>
#include <linux/irq.h>
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 Lines 412-417    Link Here 
	disable_IO_APIC();
	disable_IO_APIC();
#endif
#endif
#ifdef CONFIG_XBOX
	if (machine_is_xbox) {
		Xbox_reset();
	}
#endif
	if(!reboot_thru_bios) {
	if(!reboot_thru_bios) {
		/* rebooting needs to touch the page at absolute addr 0 */
		/* rebooting needs to touch the page at absolute addr 0 */
		*((unsigned short *)__va(0x472)) = reboot_mode;
		*((unsigned short *)__va(0x472)) = reboot_mode;
 Lines 438-443    Link Here 
void machine_power_off(void)
void machine_power_off(void)
{
{
#ifdef CONFIG_XBOX
	if (machine_is_xbox) {
		Xbox_power_off();
	}
#endif
	if (pm_power_off)
	if (pm_power_off)
		pm_power_off();
		pm_power_off();
}
}
(-) linux-2.4.26/arch/i386/kernel/setup.c (+20 lines)
 Lines 133-138    Link Here 
EXPORT_SYMBOL(mmu_cr4_features);
EXPORT_SYMBOL(mmu_cr4_features);
/*
/*
 * Xbox timer patch
 */
#ifdef CONFIG_XBOX
int CLOCK_TICK_RATE;
int machine_is_xbox = 0;
#endif
/*
 * Bus types ..
 * Bus types ..
 */
 */
#ifdef CONFIG_EISA
#ifdef CONFIG_EISA
 Lines 1203-1208    Link Here 
	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
#endif
#endif
	/* SETUP_ARCH for Xbox */
#ifdef CONFIG_XBOX
	outl(0x80000000, 0xcf8);
	if (inl(0xcfc)==0x02a510de) { /* Xbox PCI 0:0:0 ID 0x10de/0x02a5 */
		machine_is_xbox = 1;
		CLOCK_TICK_RATE = 1125000;
		printk("Xbox detected - enabling Xbox patches.\n");
	} else {
		CLOCK_TICK_RATE = 1193180;
	}
#endif
	setup_memory_region();
	setup_memory_region();
	copy_edd();
	copy_edd();
(-) linux-2.4.26/arch/i386/kernel/xboxejectfix.c (+146 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>
#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 void extsmi_interupt(int i,void *dev,struct pt_regs *r){
	int reason;
	reason=inw(0x8020);
	outw(reason,0x8020); /* ack  IS THIS NEEDED? */
	if(reason&0x2){
		/* wake up thread */
		up(&extsmi_sem);
	}
}
/**
 * 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();
	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 /* |SA_SAMPLE_RANDOM */,
		    "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.4.26/drivers/char/pc_keyb.c (-2 / +15 lines)
 Lines 806-811    Link Here 
	int status;
	int status;
	/*
	/*
	 * This is not really IA-64 specific.  Probably ought to be done on all platforms
	 * that are (potentially) legacy-free.
	 */
	if (kbd_read_status() == 0xff && kbd_read_input() == 0xff) {
		kbd_exists = 0;
		return "No keyboard controller preset";
	}
	/*
	 * Test the keyboard interface.
	 * Test the keyboard interface.
	 * This seems to be the only way to get it going.
	 * This seems to be the only way to get it going.
	 * If the test is successful a x55 is placed in the input buffer.
	 * If the test is successful a x55 is placed in the input buffer.
 Lines 898-908    Link Here 
void __init pckbd_init_hw(void)
void __init pckbd_init_hw(void)
{
{
	if (!kbd_controller_present()) {
/*
 	if (!kbd_controller_present()) {
		kbd_exists = 0;
		kbd_exists = 0;
		return;
		return;
	}
	}
*/
	kbd_request_region();
	kbd_request_region();
	/* Flush any pending input. */
	/* Flush any pending input. */
 Lines 912-917    Link Here 
		char *msg = initialize_kbd();
		char *msg = initialize_kbd();
		if (msg)
		if (msg)
			printk(KERN_WARNING "initialize_kbd: %s\n", msg);
			printk(KERN_WARNING "initialize_kbd: %s\n", msg);
		if (!kbd_exists)
			return;
	}
	}
#if defined CONFIG_PSMOUSE
#if defined CONFIG_PSMOUSE
(-) linux-2.4.26/drivers/i2c/Config.in (+5 lines)
 Lines 63-67    Link Here 
   dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C
   dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C
   dep_tristate 'I2C /proc interface (required for hardware sensors)' CONFIG_I2C_PROC $CONFIG_I2C $CONFIG_SYSCTL
   dep_tristate 'I2C /proc interface (required for hardware sensors)' CONFIG_I2C_PROC $CONFIG_I2C $CONFIG_SYSCTL
   if [ "$CONFIG_XBOX" = "y" ]; then
      dep_tristate 'I2C AMD/XBOX' CONFIG_I2C_AMD756 $CONFIG_I2C
      dep_tristate '  I2C XBOX EXTSMI' CONFIG_I2C_EXTSMI $CONFIG_I2C_AMD756
   fi
fi
fi
endmenu
endmenu
(-) linux-2.4.26/drivers/i2c/Makefile (-1 / +3 lines)
 Lines 6-12    Link Here 
export-objs	:= i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \
export-objs	:= i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \
		   i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \
		   i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \
		   i2c-proc.o
		   i2c-proc.o i2c-amd756.o
obj-$(CONFIG_I2C)		+= i2c-core.o
obj-$(CONFIG_I2C)		+= i2c-core.o
obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
 Lines 25-30    Link Here 
obj-$(CONFIG_I2C_ALGO_SIBYTE)	+= i2c-algo-sibyte.o i2c-sibyte.o
obj-$(CONFIG_I2C_ALGO_SIBYTE)	+= i2c-algo-sibyte.o i2c-sibyte.o
obj-$(CONFIG_I2C_MAX1617)	+= i2c-max1617.o
obj-$(CONFIG_I2C_MAX1617)	+= i2c-max1617.o
obj-$(CONFIG_I2C_ALGO_SGI)	+= i2c-algo-sgi.o
obj-$(CONFIG_I2C_ALGO_SGI)	+= i2c-algo-sgi.o
obj-$(CONFIG_I2C_AMD756)	+= i2c-amd756.o
obj-$(CONFIG_I2C_EXTSMI)	+= extsmi.o
# This is needed for automatic patch generation: sensors code starts here
# This is needed for automatic patch generation: sensors code starts here
# This is needed for automatic patch generation: sensors code ends here
# This is needed for automatic patch generation: sensors code ends here
(-) linux-2.4.26/drivers/i2c/extsmi.c (+269 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
 *
 * Todo: add errorhandling!
 *
 */
#include <linux/kernel.h>
#include <linux/module.h>
/*#include <linux/interrupt.h>*/
#include <linux/init.h>
#include <asm/io.h>
#include <linux/i2c.h>
/* FIXME! -> .h */
#define PIC_ADDRESS 0x10
#define SMC_CMD_TRAY_STATE 0x03
#define SMC_CMD_EJECT 0x0C
#define SMC_CMD_INTERRUPT_REASON 0x11
#define SMC_CMD_RESET_ON_EJECT 0x19
#define SMC_CMD_LED_MODE 0x07
#define SMC_CMD_LED_REGISTER 0x08
#define SMC_SUBCMD_EJECT_EJECT 0x00
#define SMC_SUBCMD_EJECT_LOAD 0x01
#define SMC_SUBCMD_RESET_ON_EJECT_ENABLE 0x00
#define SMC_SUBCMD_RESET_ON_EJECT_DISABLE 0x01
/* interrupt causes */
#define POWERDOWN_MASK (1<<0)
#define TRAYCLOSED_MASK (1<<1)
#define TRAYOPENING_MASK (1<<2)
#define AVPLUGGED_MASK (1<<3)
#define AVUNPLUGGED_MASK (1<<4)
#define TRAYBUTTON_MASK (1<<5)
#define TRAYCLOSING_MASK (1<<6)
#define UNKNOWN_MASK (1<<7)
#define IRQ 12
#define DRIVER_NAME "extsmi"
#ifdef DEBUG
#	define SMI_DEBUG_OUT(a...) printk(a)
#else
#	define SMI_DEBUG_OUT(a...)
#endif
/* just some crap */
static char dev[]="test";
#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 int extsmi_attach_adapter(struct i2c_adapter *adap);
static struct i2c_driver extsmi_driver = {
	.name		= "i2c xbox-extsmi driver",
	.id		= I2C_DRIVERID_I2CDEV,
	.flags		= I2C_DF_DUMMY,
	.attach_adapter	= extsmi_attach_adapter,
};
static struct i2c_adapter *xbox_adap;
static struct i2c_client extsmi_client = {
	.name		= "I2C xbox-extsmi client",
	.id		= 1,
	.flags		= 0,
	.addr		= PIC_ADDRESS,
	.adapter	= NULL,
	.driver		= &extsmi_driver,
};
static int extsmi_attach_adapter(struct i2c_adapter *adap)
{
	int i;
	if ((i = i2c_adapter_id(adap)) < 0) {
		printk("i2c-dev.o: Unknown adapter ?!?\n");
		return -ENODEV;
	}
	/* FIXME! XXX! This is bogus, will break with more than one adaptor */
	if (! xbox_adap) {
		xbox_adap = adap;
		extsmi_client.adapter=adap;
		printk(KERN_INFO DRIVER_NAME ": Using '%s'!\n",adap->name);
	} else {
		/* This is actually a detach_adapter call! */
		xbox_adap=NULL;
	}
	return 0;
}
static void extsmi_interupt(int i,void *dev,struct pt_regs *r){
	int reason;
	reason=inw(0x8020);
	outw(reason,0x8020); /* ack  IS THIS NEEDED? */
	if(reason&0x2){
		SMI_DEBUG_OUT("EXTSMI#\n");
		/* wake up thread */
		up(&extsmi_sem);
		SMI_DEBUG_OUT("Interrupt: 0x%02x\n",reason);
	}
/*
	reason=inw(0x8020);
	SMI_DEBUG_OUT("Interrupt %d 0x%04x\n",hits,reason);
*/
/*	 Stop irq-storm
	if(hits==400){
		free_irq(12,dev);
	}
*/
}
/**
 * Process a event. This is run i process-context.
 */
static void extsmi_process(void){
	int reason;
	
	if(extsmi_client.adapter==NULL){
		printk("bh with no client!?\n");
		return;
	}
	
	reason=i2c_smbus_read_byte_data(&extsmi_client,SMC_CMD_INTERRUPT_REASON);
	if(reason&TRAYBUTTON_MASK){ /* Tray button! Respond to prevent reboot! */
		i2c_smbus_write_byte_data(&extsmi_client,0x0d,0x04);
		i2c_smbus_write_byte_data(&extsmi_client,0x00,0x0c);
		SMI_DEBUG_OUT("Button<tm> pressed\n");
		/* eject? */
#ifndef NO_EJECT
		i2c_smbus_write_byte_data(&extsmi_client, SMC_CMD_RESET_ON_EJECT, SMC_SUBCMD_RESET_ON_EJECT_DISABLE);
		i2c_smbus_write_byte_data(&extsmi_client, SMC_CMD_EJECT, SMC_SUBCMD_EJECT_EJECT);
#endif
	}
	
	SMI_DEBUG_OUT("bh-reason: 0x%02x\n",reason);
}
static int extsmi_thread(void *data){
	daemonize();
	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 res;
	int pid;
	
        pid = kernel_thread(extsmi_thread, NULL,
			    CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
	if (pid < 0) {
		return pid;
	}
	extsmi_pid = pid;
	if ((res = i2c_add_driver(&extsmi_driver))) {
		printk(KERN_ERR DRIVER_NAME ": Driver registration failed, module not inserted.\n");
		/* FIXME! CLEANUP!! */
		return res;
	}
	/* 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);
//	outw(0,0x80d8);  // andy@warmcat.com 2003-02-26  removed as this kills RGB out and serves no other purpose
	outb(1,PM04); /* enable sci interrupts! */
	/* FIXME! retval! */
	request_irq(IRQ,extsmi_interupt,SA_INTERRUPT|SA_SHIRQ /* |SA_SAMPLE_RANDOM */,
		    "xbox_extsmi",dev);
	
	/* LED blinking
	  i2c_smbus_write_byte_data(&i2cxbox_client,SMC_CMD_LED_MODE,1);
	  i2c_smbus_write_byte_data(&i2cxbox_client,SMC_CMD_LED_REGISTER,0xc6);
	*/
	return 0;
}
static void extsmi_exit(void){
	int res;
	free_irq(IRQ,dev);
	/* Kill the thread */
	res = kill_proc(extsmi_pid, SIGTERM, 1);
	wait_for_completion(&extsmi_exited);
	if ((res = i2c_del_driver(&extsmi_driver))) {
		printk(KERN_ERR DRIVER_NAME ": Driver deregistration failed, "
		       "module not removed.\n");
		return;
	}
	
	return;
}
module_init(extsmi_init);
module_exit(extsmi_exit);
MODULE_AUTHOR("Anders Gustafsson <andersg@0x63.nu>");
MODULE_LICENSE("GPL");
(-) linux-2.4.26/drivers/i2c/i2c-amd756.c (+428 lines)
Line 0    Link Here 
/*
    amd756.c - Part of lm_sensors, Linux kernel modules for hardware
              monitoring
    Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org>
    Shamelessly ripped from i2c-piix4.c:
    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
    Philip Edelbrock <phil@netroedge.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
    2002-04-08: Added nForce support. (Csaba Halasz)
    2002-10-03: Fixed nForce PnP I/O port. (Michael Steil)
    2002-12-28: Rewritten into something that resembles a Linux driver (hch)
    2003-11-29: Added back AMD8111 removed by the previous rewrite.
                (Philip Pokorny)
    2004-02-15: Don't register driver to avoid driver conflicts.
                (Daniel Rune Jensen)
*/
/*
   Supports AMD756, AMD766, AMD768, AMD8111 and nVidia nForce
   Note: we assume there can only be one device, with one SMBus interface.
*/
#include <linux/module.h>
#include <linux/pci.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 <asm/io.h>
#include <linux/delay.h>
#define DRV_NAME	"i2c-amd756"
/* AMD756 SMBus address offsets */
#define SMB_ADDR_OFFSET        0xE0
#define SMB_IOSIZE             16
#define SMB_GLOBAL_STATUS      (0x0 + amd756_ioport)
#define SMB_GLOBAL_ENABLE      (0x2 + amd756_ioport)
#define SMB_HOST_ADDRESS       (0x4 + amd756_ioport)
#define SMB_HOST_DATA          (0x6 + amd756_ioport)
#define SMB_HOST_COMMAND       (0x8 + amd756_ioport)
#define SMB_HOST_BLOCK_DATA    (0x9 + amd756_ioport)
#define SMB_HAS_DATA           (0xA + amd756_ioport)
#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport)
#define SMB_HAS_HOST_ADDRESS   (0xE + amd756_ioport)
#define SMB_SNOOP_ADDRESS      (0xF + amd756_ioport)
/* PCI Address Constants */
/* address of I/O space */
#define SMBBA     0x058		/* mh */
#define SMBBANFORCE     0x014
/* general configuration */
#define SMBGCFG   0x041		/* mh */
/* silicon revision code */
#define SMBREV    0x008
/* Other settings */
#define MAX_TIMEOUT 500
/* AMD756 constants */
#define AMD756_QUICK        0x00
#define AMD756_BYTE         0x01
#define AMD756_BYTE_DATA    0x02
#define AMD756_WORD_DATA    0x03
#define AMD756_PROCESS_CALL 0x04
#define AMD756_BLOCK_DATA   0x05
static unsigned short amd756_ioport = 0;
/* 
  SMBUS event = I/O 28-29 bit 11
     see E0 for the status bits and enabled in E2
     
*/
#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_HCYC_STS (1 << 4)
#define GS_TO_STS (1 << 5)
#define GS_SMB_STS (1 << 11)
#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)
static int amd756_transaction(void)
{
	int temp;
	int result = 0;
	int timeout = 0;
	pr_debug(DRV_NAME
	       ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
	       inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
	       inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
	/* Make sure the SMBus host is ready to start transmitting */
	if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
		pr_debug(DRV_NAME ": SMBus busy (%04x). Waiting... \n", temp);
		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) {
			pr_debug(DRV_NAME ": Busy wait timeout (%04x)\n", temp);
			goto abort;
		}
		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! */
	do {
		udelay(100);
		temp = inw_p(SMB_GLOBAL_STATUS);
	} while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT));
	/* If the SMBus is still busy, we give up */
	if (timeout >= MAX_TIMEOUT) {
		pr_debug(DRV_NAME ": Completion timeout!\n");
		goto abort;
	}
	if (temp & GS_PRERR_STS) {
		result = -1;
		pr_debug(DRV_NAME ": SMBus Protocol error (no response)!\n");
	}
	if (temp & GS_COL_STS) {
		result = -1;
		printk(KERN_WARNING DRV_NAME ": SMBus collision!\n");
	}
	if (temp & GS_TO_STS) {
		result = -1;
		pr_debug(DRV_NAME ": SMBus protocol timeout!\n");
	}
	if (temp & GS_HCYC_STS)
		pr_debug(DRV_NAME ": SMBus protocol success!\n");
	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
#ifdef DEBUG
	if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
		pr_debug(DRV_NAME
		         ": Failed reset at end of transaction (%04x)\n", temp);
	}
	pr_debug(DRV_NAME
		 ": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
		 inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
		 inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
#endif
	return result;
 abort:
	printk(KERN_WARNING DRV_NAME ": Sending abort.\n");
	outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
	udelay(100);
	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
	return -1;
}
/* Return -1 on error. */
static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
		  unsigned short flags, char read_write,
		  u8 command, int size, union i2c_smbus_data * data)
{
	int i, len;
	/** TODO: Should I supporte the 10-bit transfers? */
	switch (size) {
	/* TODO: proc call is supported, I'm just not sure what to do here... */
	case I2C_SMBUS_QUICK:
		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
		       SMB_HOST_ADDRESS);
		size = AMD756_QUICK;
		break;
	case I2C_SMBUS_BYTE:
		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
		       SMB_HOST_ADDRESS);
		if (read_write == I2C_SMBUS_WRITE)
			outb_p(command, SMB_HOST_DATA);
		size = AMD756_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 = AMD756_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 = AMD756_WORD_DATA;
		break;
	case I2C_SMBUS_BLOCK_DATA:
		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
		       SMB_HOST_ADDRESS);
		outb_p(command, SMB_HOST_COMMAND);
		if (read_write == I2C_SMBUS_WRITE) {
			len = data->block[0];
			if (len < 0)
				len = 0;
			if (len > 32)
				len = 32;
			outw_p(len, SMB_HOST_DATA);
			/* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
			for (i = 1; i <= len; i++)
				outb_p(data->block[i],
				       SMB_HOST_BLOCK_DATA);
		}
		size = AMD756_BLOCK_DATA;
		break;
	default:
		printk
		    (KERN_WARNING "i2c-amd756.o: Unsupported transaction %d\n", size);
		return -1;
	}
	/* How about enabling interrupts... */
	outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
	if (amd756_transaction())	/* Error in transaction */
		return -1;
	if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
		return 0;
	switch (size) {
	case AMD756_BYTE:
		data->byte = inw_p(SMB_HOST_DATA);
		break;
	case AMD756_BYTE_DATA:
		data->byte = inw_p(SMB_HOST_DATA);
		break;
	case AMD756_WORD_DATA:
		data->word = inw_p(SMB_HOST_DATA);	/* TODO: endian???? */
		break;
	case AMD756_BLOCK_DATA:
		data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f;
		if(data->block[0] > 32)
			data->block[0] = 32;
		/* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
		for (i = 1; i <= data->block[0]; i++)
			data->block[i] = inb_p(SMB_HOST_BLOCK_DATA);
		break;
	}
	return 0;
}
static u32 amd756_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;
}
static struct i2c_algorithm smbus_algorithm = {
	.name		= "Non-I2C SMBus adapter",
	.id		= I2C_ALGO_SMBUS,
	.smbus_xfer	= amd756_access,
	.functionality	= amd756_func,
};
static struct i2c_adapter amd756_adapter = {
	"unset",
	I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756,
	&smbus_algorithm,
};
enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 };
static struct pci_device_id amd756_ids[] __devinitdata = {
	{PCI_VENDOR_ID_AMD, 0x740B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD756 },
	{PCI_VENDOR_ID_AMD, 0x7413, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD766 },
	{PCI_VENDOR_ID_AMD, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768 },
	{PCI_VENDOR_ID_AMD, 0x746B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD8111 },
	{PCI_VENDOR_ID_NVIDIA, 0x01B4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE },
	{ 0, }
};
static int __devinit amd756_probe(struct pci_dev *pdev,
				  const struct pci_device_id *id)
{
	int nforce = (id->driver_data == NFORCE);
	int error;
	u8 temp;
	
	if (amd756_ioport) {
		printk(KERN_ERR DRV_NAME ": Only one device supported. "
		       "(you have a strange motherboard, btw..)\n");
		return -ENODEV;
	}
	if (nforce) {
		if (PCI_FUNC(pdev->devfn) != 1)
			return -ENODEV;
		pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport);
		amd756_ioport &= 0xfffc;
	} else { /* amd */
		if (PCI_FUNC(pdev->devfn) != 3)
			return -ENODEV;
		pci_read_config_byte(pdev, SMBGCFG, &temp);
		if ((temp & 128) == 0) {
			printk(KERN_ERR DRV_NAME
			       ": Error: SMBus controller I/O not enabled!\n");
			return -ENODEV;
		}
		/* Determine the address of the SMBus areas */
		/* Technically it is a dword but... */
		pci_read_config_word(pdev, SMBBA, &amd756_ioport);
		amd756_ioport &= 0xff00;
		amd756_ioport += SMB_ADDR_OFFSET;
	}
	if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) {
		printk(KERN_ERR DRV_NAME
		       ": SMB region 0x%x already in use!\n", amd756_ioport);
		return -ENODEV;
	}
#ifdef DEBUG
	pci_read_config_byte(pdev, SMBREV, &temp);
	printk(KERN_DEBUG DRV_NAME ": SMBREV = 0x%X\n", temp);
	printk(KERN_DEBUG DRV_NAME ": AMD756_smba = 0x%X\n", amd756_ioport);
#endif
	sprintf(amd756_adapter.name,
		"SMBus AMD756 adapter at %04x", amd756_ioport);
	error = i2c_add_adapter(&amd756_adapter);
	if (error) {
		printk(KERN_ERR DRV_NAME
		       ": Adapter registration failed, module not inserted.\n");
		goto out_err;
	}
	return 0;
 out_err:
	release_region(amd756_ioport, SMB_IOSIZE);
	return error;
}
int __init i2c_amd756_init(void)
{
	struct pci_dev *dev;
	const struct pci_device_id *id;
	printk(KERN_INFO "i2c-amd756.o version 2.8.6\n");
 	pci_for_each_dev(dev) {
		id = pci_match_device(amd756_ids, dev);
		if (id && amd756_probe(dev, id) >= 0)
			return 0; 
	}
	return -ENODEV;
}
void __exit i2c_amd756_exit(void)
{
	i2c_del_adapter(&amd756_adapter);
	release_region(amd756_ioport, SMB_IOSIZE);
}
EXPORT_SYMBOL(i2c_amd756_init);
#ifdef MODULE
MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
MODULE_LICENSE("GPL");
module_init(i2c_amd756_init)
module_exit(i2c_amd756_exit)
#endif
(-) linux-2.4.26/drivers/ide/ide-cd.c (+93 lines)
 Lines 308-313    Link Here 
#include <linux/cdrom.h>
#include <linux/cdrom.h>
#include <linux/ide.h>
#include <linux/ide.h>
#include <linux/completion.h>
#include <linux/completion.h>
#include <linux/xbox.h>
#include <asm/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/io.h>
 Lines 317-322    Link Here 
#include "ide-cd.h"
#include "ide-cd.h"
#ifdef CONFIG_XBOX
/* 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_XBOX */
/****************************************************************************
/****************************************************************************
 * Generic packet command support and error handling routines.
 * Generic packet command support and error handling routines.
 */
 */
 Lines 1986-1991    Link Here 
	if (sense == NULL)
	if (sense == NULL)
		sense = &my_sense;
		sense = &my_sense;
#ifdef CONFIG_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_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 2033-2038    Link Here 
	if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
	if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
		return 0;
		return 0;
#ifdef CONFIG_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
	memset(&pc, 0, sizeof (pc));
	memset(&pc, 0, sizeof (pc));
	pc.sense = sense;
	pc.sense = sense;
 Lines 2922-2927    Link Here 
	CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 0;
	CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 0;
	CDROM_CONFIG_FLAGS(drive)->audio_play = 0;
	CDROM_CONFIG_FLAGS(drive)->audio_play = 0;
	CDROM_CONFIG_FLAGS(drive)->close_tray = 1;
	CDROM_CONFIG_FLAGS(drive)->close_tray = 1;
	CDROM_CONFIG_FLAGS(drive)->xbox_drive = 0;
	CDROM_CONFIG_FLAGS(drive)->xbox_eject = 0;
	
	
	/* limit transfer size per interrupt. */
	/* limit transfer size per interrupt. */
	CDROM_CONFIG_FLAGS(drive)->limit_nframes = 0;
	CDROM_CONFIG_FLAGS(drive)->limit_nframes = 0;
 Lines 2988-2993    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;
	}
	}
	/* 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;
	}
	/* Is an Xbox drive detected? */
	if (CDROM_CONFIG_FLAGS(drive)->xbox_drive) {
		/* 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_XBOX
		if (!machine_is_xbox) {
#endif /* CONFIG_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_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 /* CONFIG_XBOX */
	}
#endif /* not STANDARD_ATAPI */
#endif /* not STANDARD_ATAPI */
	info->toc		= NULL;
	info->toc		= NULL;
(-) linux-2.4.26/drivers/ide/ide-cd.h (-1 / +3 lines)
 Lines 85-91    Link Here 
	__u8 audio_play		: 1; /* can do audio related commands */
	__u8 audio_play		: 1; /* can do audio related commands */
	__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 reserved		: 3;
	__u8 xbox_drive		: 1; /* drive is an Xbox drive */
	__u8 xbox_eject		: 1; /* use Xbox SMC eject mechanism */
	__u8 reserved		: 1;
	byte max_speed;		     /* Max speed of the drive */
	byte max_speed;		     /* Max speed of the drive */
};
};
#define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags))
#define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags))
(-) linux-2.4.26/drivers/pci/pci.ids (+1 lines)
 Lines 2754-2759    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 - 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.4.26/drivers/sound/ac97_codec.c (+1 lines)
 Lines 179-184    Link Here 
	{0x83847666, "SigmaTel STAC9750T",	&sigmatel_9744_ops},
	{0x83847666, "SigmaTel STAC9750T",	&sigmatel_9744_ops},
	{0x83847684, "SigmaTel STAC9783/84?",	&null_ops},
	{0x83847684, "SigmaTel STAC9783/84?",	&null_ops},
	{0x57454301, "Winbond 83971D",		&null_ops},
	{0x57454301, "Winbond 83971D",		&null_ops},
	{0x574d4c09, "nVidia Xbox",             &null_ops},
};
};
static const char *ac97_stereo_enhancements[] =
static const char *ac97_stereo_enhancements[] =
(-) linux-2.4.26/drivers/sound/i810_audio.c (-1 / +5 lines)
 Lines 2744-2750    Link Here 
		set_current_state(TASK_UNINTERRUPTIBLE);
		set_current_state(TASK_UNINTERRUPTIBLE);
		schedule_timeout(HZ/20);
		schedule_timeout(HZ/20);
	} 
	} 
	return i;
#ifdef CONFIG_XBOX
        return 1;
#else
        return i;
#endif
}
}
/**
/**
(-) linux-2.4.26/drivers/usb/Config.in (+7 lines)
 Lines 58-63    Link Here 
   fi
   fi
   dep_tristate '  Aiptek 6000U/8000U tablet support' CONFIG_USB_AIPTEK $CONFIG_USB $CONFIG_INPUT
   dep_tristate '  Aiptek 6000U/8000U tablet support' CONFIG_USB_AIPTEK $CONFIG_USB $CONFIG_INPUT
   dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
   dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
   dep_tristate '  Xbox controller ("Xpad") support (EXPERIMENTAL)' CONFIG_USB_XPAD $CONFIG_USB $CONFIG_INPUT $CONFIG_EXPERIMENTAL
   dep_mbool '    Xbox controller mouse emulation support (EXPERIMENTAL)' CONFIG_USB_XPAD_MOUSE $CONFIG_USB $CONFIG_INPUT $CONFIG_EXPERIMENTAL $CONFIG_USB_XPAD
   dep_tristate '  Xbox Infrared DVD dongle for LIRC support (EXPERIMENTAL)' CONFIG_USB_XIR $CONFIG_USB $CONFIG_EXPERIMENTAL
   if [ "$CONFIG_USB_XIR" == "n" ]; then
      dep_tristate '  Xbox Infrared DVD dongle support (EXPERIMENTAL)' CONFIG_USB_XBOXIR $CONFIG_USB $CONFIG_INPUT $CONFIG_USB_KBD $CONFIG_EXPERIMENTAL
   fi
     
   dep_tristate '  KB Gear JamStudio tablet support' CONFIG_USB_KBTAB $CONFIG_USB $CONFIG_INPUT
   dep_tristate '  KB Gear JamStudio tablet support' CONFIG_USB_KBTAB $CONFIG_USB $CONFIG_INPUT
   dep_tristate '  Griffin Technology PowerMate support' CONFIG_USB_POWERMATE $CONFIG_USB $CONFIG_INPUT
   dep_tristate '  Griffin Technology PowerMate support' CONFIG_USB_POWERMATE $CONFIG_USB $CONFIG_INPUT
(-) linux-2.4.26/drivers/usb/Makefile (-2 / +13 lines)
 Lines 10-24    Link Here 
# Objects that export symbols.
# Objects that export symbols.
export-objs		:= hcd.o usb.o ov511.o pwc-uncompress.o
export-objs		:= hcd.o usb.o ov511.o pwc-uncompress.o xir.o
# Multipart objects.
# Multipart objects.
list-multi		:= usbcore.o hid.o pwc.o
list-multi		:= usbcore.o hid.o pwc.o xpad.o
usbcore-objs		:= usb.o usb-debug.o hub.o
usbcore-objs		:= usb.o usb-debug.o hub.o
hid-objs		:= hid-core.o
hid-objs		:= hid-core.o
pwc-objs		:= pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o
pwc-objs		:= pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o
auerswald-objs		:= auerbuf.o auerchain.o auerchar.o auermain.o
auerswald-objs		:= auerbuf.o auerchain.o auerchar.o auermain.o
xpad-objs		:= xpad-core.o
# Optional parts of multipart objects.
# Optional parts of multipart objects.
 Lines 40-45    Link Here 
endif
endif
endif
endif
ifeq ($(CONFIG_USB_XPAD_MOUSE),y)
	xpad-objs	+= xpad-mouse.o
endif
# Object file lists.
# Object file lists.
obj-y	:=
obj-y	:=
 Lines 87-92    Link Here 
obj-$(CONFIG_USB_WACOM)		+= wacom.o
obj-$(CONFIG_USB_WACOM)		+= wacom.o
obj-$(CONFIG_USB_KBTAB)		+= kbtab.o
obj-$(CONFIG_USB_KBTAB)		+= kbtab.o
obj-$(CONFIG_USB_POWERMATE)	+= powermate.o
obj-$(CONFIG_USB_POWERMATE)	+= powermate.o
obj-$(CONFIG_USB_XBOXIR)	+= usb-xboxir.o
obj-$(CONFIG_USB_SCANNER)	+= scanner.o
obj-$(CONFIG_USB_SCANNER)	+= scanner.o
obj-$(CONFIG_USB_ACM)		+= acm.o
obj-$(CONFIG_USB_ACM)		+= acm.o
 Lines 120-125    Link Here 
obj-$(CONFIG_USB_USBNET)	+= usbnet.o
obj-$(CONFIG_USB_USBNET)	+= usbnet.o
obj-$(CONFIG_USB_AUERSWALD)	+= auerswald.o
obj-$(CONFIG_USB_AUERSWALD)	+= auerswald.o
obj-$(CONFIG_USB_BRLVGER)	+= brlvger.o
obj-$(CONFIG_USB_BRLVGER)	+= brlvger.o
obj-$(CONFIG_USB_XPAD)		+= xpad.o
obj-$(CONFIG_USB_XIR)		+= xir.o
obj-$(CONFIG_USB_LCD)		+= usblcd.o
obj-$(CONFIG_USB_LCD)		+= usblcd.o
obj-$(CONFIG_USB_SPEEDTOUCH)	+= speedtch.o
obj-$(CONFIG_USB_SPEEDTOUCH)	+= speedtch.o
 Lines 152-154    Link Here 
auerswald.o: $(auerswald-objs)
auerswald.o: $(auerswald-objs)
	$(LD) -r -o $@ $(auerswald-objs)
	$(LD) -r -o $@ $(auerswald-objs)
xpad.o: $(xpad-objs)
	$(LD) -r -o $@ $(xpad-objs)
(-) linux-2.4.26/drivers/usb/hub.c (-6 / +11 lines)
 Lines 534-542    Link Here 
	return ret;
	return ret;
}
}
#define HUB_RESET_TRIES		5
#define HUB_RESET_TRIES		10	/* Formerly 5 */
#define HUB_PROBE_TRIES		2
#define HUB_PROBE_TRIES		20	/* Formerly 2 */
#define HUB_SHORT_RESET_TIME	10
#define HUB_SHORT_RESET_TIME	15	/* Formerly 10 */
#define HUB_LONG_RESET_TIME	200
#define HUB_LONG_RESET_TIME	200
#define HUB_RESET_TIMEOUT	500
#define HUB_RESET_TIMEOUT	500
 Lines 599-604    Link Here 
	for (i = 0; i < HUB_RESET_TRIES; i++) {
	for (i = 0; i < HUB_RESET_TRIES; i++) {
		usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
		usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
		wait_ms(10);
		/* return on disconnect or reset */
		/* return on disconnect or reset */
		status = usb_hub_port_wait_reset(hub, port, dev, delay);
		status = usb_hub_port_wait_reset(hub, port, dev, delay);
		if (status != -1) {
		if (status != -1) {
 Lines 642-649    Link Here 
 * every 100ms for transient disconnects to restart the delay.
 * every 100ms for transient disconnects to restart the delay.
 */
 */
#define HUB_DEBOUNCE_TIMEOUT	400
#define HUB_DEBOUNCE_TIMEOUT	600	/* Formerly 400 */
#define HUB_DEBOUNCE_STEP	100
#define HUB_DEBOUNCE_STEP	200	/* Formerly 100 */
/* return: -1 on error, 0 on success, 1 on disconnect.  */
/* return: -1 on error, 0 on success, 1 on disconnect.  */
static int usb_hub_port_debounce(struct usb_device *hub, int port)
static int usb_hub_port_debounce(struct usb_device *hub, int port)
 Lines 678-683    Link Here 
	struct usb_device *dev;
	struct usb_device *dev;
	unsigned int delay = HUB_SHORT_RESET_TIME;
	unsigned int delay = HUB_SHORT_RESET_TIME;
	int i;
	int i;
/*	int delay;*/
	dbg("port %d, portstatus %x, change %x, %s",
	dbg("port %d, portstatus %x, change %x, %s",
		port + 1, portstatus, portchange, portspeed (portstatus));
		port + 1, portstatus, portchange, portspeed (portstatus));
 Lines 704-709    Link Here 
	}
	}
	down(&usb_address0_sem);
	down(&usb_address0_sem);
/*	delay = HUB_SHORT_RESET_TIME;*/
	for (i = 0; i < HUB_PROBE_TRIES; i++) {
	for (i = 0; i < HUB_PROBE_TRIES; i++) {
		struct usb_device *pdev;
		struct usb_device *pdev;
 Lines 759-764    Link Here 
			dev->bus->bus_name, dev->devpath, dev->devnum);
			dev->bus->bus_name, dev->devpath, dev->devnum);
		/* Run it through the hoops (find a driver, etc) */
		/* Run it through the hoops (find a driver, etc) */
		wait_ms(HUB_SHORT_RESET_TIME);
		if (!usb_new_device(dev)) {
		if (!usb_new_device(dev)) {
			hub->children[port] = dev;
			hub->children[port] = dev;
			goto done;
			goto done;
 Lines 1057-1063    Link Here 
	ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor,
	ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor,
			sizeof(*descriptor));
			sizeof(*descriptor));
	if (ret < 0) {
	if (ret < 0) {
		kfree(descriptor);
/*		kfree(descriptor);*/
		return ret;
		return ret;
	}
	}
(-) linux-2.4.26/drivers/usb/readme.txt (+33 lines)
Line 0    Link Here 
 *
 *  WARNING: The author does not have a USB keyboard to test with. Expect bugs.
 *
 *  XBOX DVD dongle infrared device driver for the input driver suite.
 *
 *  This work was derived from the usbkbd.c kernel module.
 *
 *  Purpose:
 *
 *  The goal of this driver is to accept and translate the IR messages
 *  from an XBOX DVD dongle, pushing them into the kernel HID layer
 *  as normal keyboard events.
 *
 *  Conclusion:
 *
 *  The keybdev.o module is capable of receiving these
 *  events and pushing them into the appropriate keyboard layers
 *  for interaction with userland applications. You are now able
 *  to use the XBOX remote control to drive userland applications.
 *
 *  TODO (next release):
 *  - Rename /proc/xboxir to /proc/xbox/ir
 *  - Investigate whether the IR eye is capable of receiving NON XBOX RC codes (ala Pronto)
 *  - Integrate into the kernel build process
 *  - Add ioctls to allow codes to be added and removed dynamically.
 *  - Add an ioctl to restore the driver to it's default configuration state.
 *
 *  The "ult" configuration tool needs to communicate to the xbox ir drivers using a character
 *  device MAJOR 180, MINOR 240. Create this device as follows:
 *
 *  mknod /dev/xboxir c 180 240
 *  chmod 600 /dev/xboxir
(-) linux-2.4.26/drivers/usb/storage/README (+83 lines)
Line 0    Link Here 
 usb-storage driver patched to accept Xbox Memory Units
--------------------------------------------------------
BEFORE using this driver, consider the following:
1) this is EXPERIMENTAL
2) this is KNOWN to HAVE BUGS
3) this has NOT been extensively TESTED
4) this is NOT SUPPORTED well
5) this CANNOT be used to WRITE onto the thing
Still there? OK. Some further notes:
 Author
--------
Credits belong to Paul Bartholomew who found out what is needed to get those
units accepted. He sent a message containing the whole subtree (precompiled)
to the xbox-linux-devel mailing list.
I made a diff against a vanilla kernel and sent that to the ml a day or two
later (patches are smaller and it is a lot easier to identify the changes).
Because of that, people misunderstood me as the author, which is not correct.
Credit where credit is due.
While testing the thing I noticed that it tried to detect all luns (you can
setup the kernel do to that). Because it detected 8 luns but only 4 worked
(and those were all just mirrors of the data) AND the other 4 caused timeouts
I added a line to suppress luns > 0.
 writing
---------
While reading from the device worked fine, writing was and is an unresolved
issue. I did indeed mess the thing up when I mounted it read/write and
added a file. After unmounting it was not valid FATX anymore. The Xbox insisted
on formatting it. Having a previously generated dump at hand I decided to
write that onto the thing in raw mode. While that recreated the directory
structures (even the Xbox displayed all the savegames with icons and the
funky stuff) from the looks of it the files themselves were not there (or, to
be precise here, were all filled with 0xFF). I did not investigate on this
further yet. Any volunteers?
IF you REALLY intend to write onto an Xbox Memory Unit (because, for instance,
you are eager to fire up 007:auf with that "boot-linux-savegame"), PLEASE
consider the following:
 
Do NOT mount the device itself writeable! That will almost certainly screw
it up.
Do NOT expect it to WORK AT ALL. Or you're screwed up when it fulfills my
prophecy.
Do NOT come to the list whining about its (not-working) state or about loss
of data or the like. It's EXPERIMENTAL, remember? You have been warned.
You are encouraged, however, to contribute to the effort with testing,
reporting success/failures and even code. It's open source, after all. If you
do contribute, xbox-linux-devel@lists.sourceforge.net should be where you post
anything.
OK, so you ignored my previous statements and want to write onto the thing.
In that case, please, at least TRY it this way:
1) dump the device contents into a file
   #> dd if=/path/to/device of=/path/to/file
2) (optional, recommended) make a backup copy of that dump
3) (optional) verify the file (should be of size 8MB and start with "FATX")
4) mount that file loopback
   #> mount -t fatx -o loop /path/to/file /path/to/mountpoint
5) edit/copy/add/delete files inside the mountpoint directory
6) umount the file
   #> umount /path/to/mountpoint
7) (optional) remount the file and check for errors
8) write the file back onto the device (do NOT hold your breath!)
   #> dd if=/path/to/file of=/path/to/device
9) (prohibited) curse the driver author and/or linux folk because it did not
   work (DON'T DO THAT! You have been warned.)
-- 
Marko Friedemann
12.05.2003
(-) linux-2.4.26/drivers/usb/storage/protocol.c (-1 / +89 lines)
 Lines 1-6    Link Here 
/* Driver for USB Mass Storage compliant devices
/* Driver for USB Mass Storage compliant devices
 *
 *
 * $Id: protocol.c,v 1.13 2002/02/25 00:34:56 mdharm Exp $
 * $Id: protocol.c,v 1.3 2003/11/28 23:51:52 aothieno Exp $
 *
 *
 * Current development and maintenance by:
 * Current development and maintenance by:
 *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
 *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
 Lines 399-401    Link Here 
	}
	}
}
}
#ifdef US_SC_XBMEM
unsigned char	Xbmem_fake_inquiry_data[] = {
	0x20, 0x80, 0x02, 0x02, 0x1F, 0x00, 0x00, 0x00,
	
	0x4D, 0x53, 0x46, 0x54, 0x20, 0x20, 0x20, 0x20,	// VendorName
	0x58, 0x42, 0x4D, 0x45, 0x4D, 0x20, 0x20, 0x20,	// ProductName
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
	0x30, 0x31, 0x30, 0x30,				// Version
};
unsigned char	Xbmem_fake_mode_sense_data[] = {
	0x03, 0x00, 0x00, 0x00,
};
void usb_stor_xbmem_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
{
	unsigned char	*fake_resp_data;
	int fake_resp_len;
	unsigned int	fake_resp_result;
	int	i;
	struct scatterlist *sg;
	int len;
	int transferred;
	int amt;
	warn("usb_stor_xbmem_scsi_command: cmd=0x%x\n", srb->cmnd[0]);
	fake_resp_len = -1;
	fake_resp_data = NULL;
	fake_resp_result = (GOOD << 1);
	switch(srb->cmnd[0]) {
	case INQUIRY:
		warn("XBMEM: fake INQUIRY\n");
		fake_resp_data = Xbmem_fake_inquiry_data;
		fake_resp_len = sizeof(Xbmem_fake_inquiry_data);
		fake_resp_result = (GOOD << 1);
		break;
	case TEST_UNIT_READY:
		warn("XBMEM: fake TEST_UNIT_READY\n");
		fake_resp_len = 0;
		fake_resp_result = (GOOD << 1);
		break;
	case MODE_SENSE:
		warn("XBMEM: fake MODE_SENSE\n");
		fake_resp_data = Xbmem_fake_mode_sense_data;
		fake_resp_len = sizeof(Xbmem_fake_mode_sense_data);
		fake_resp_result = (GOOD << 1);
		break;
	case START_STOP:
		warn("XBMEM: fake START_STOP\n");
		fake_resp_len = 0;
		fake_resp_result = (GOOD << 1);
		break;
	case ALLOW_MEDIUM_REMOVAL:
		warn("XBMEM: fake ALLOW_MEDIUM_REMOVAL\n");
		fake_resp_len = 0;
		fake_resp_result = (GOOD << 1);
		break;
	default:
		break;
	}
	if (fake_resp_len != -1) {
		len = (us->srb->request_bufflen > fake_resp_len) ? 
			fake_resp_len : us->srb->request_bufflen;
		if (us->srb->use_sg) {
			warn("XBMEM: use_sg is TRUE\n");
			sg = (struct scatterlist *)us->srb->request_buffer;
			for (i = 0; i < us->srb->use_sg; i++) {
				memset(sg[0].address, 0, sg[i].length);
			}
			for (i = 0, transferred = 0;
				i < us->srb->use_sg && (transferred < len); i++) {
				amt = sg[i].length > (len-transferred) ?
					(len-transferred) : sg[i].length;
				memcpy(sg[i].address, fake_resp_data+transferred, amt);
				transferred -= amt;
			}
		} else {
			warn("XBMEM: use_sg is FALSE\n");
			memset(us->srb->request_buffer, 0, us->srb->request_bufflen);
			memcpy(us->srb->request_buffer, fake_resp_data, len);
		}
		us->srb->result = fake_resp_result;
	} else {
		usb_stor_transparent_scsi_command(srb, us);
	}
}
#endif
(-) linux-2.4.26/drivers/usb/storage/protocol.h (-4 / +8 lines)
 Lines 1-7    Link Here 
/* Driver for USB Mass Storage compliant devices
/* Driver for USB Mass Storage compliant devices
 * Protocol Functions Header File
 * Protocol Functions Header File
 *
 *
 * $Id: protocol.h,v 1.4 2001/02/13 07:10:03 mdharm Exp $
 * $Id: protocol.h,v 1.3 2003/10/15 15:27:58 aothieno Exp $
 *
 *
 * Current development and maintenance by:
 * Current development and maintenance by:
 *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
 *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
 Lines 54-61    Link Here 
#define US_SC_8070	0x05		/* Removable media */
#define US_SC_8070	0x05		/* Removable media */
#define US_SC_SCSI	0x06		/* Transparent */
#define US_SC_SCSI	0x06		/* Transparent */
#define US_SC_ISD200    0x07            /* ISD200 ATA */
#define US_SC_ISD200    0x07            /* ISD200 ATA */
#define US_SC_MIN	US_SC_RBC
#define US_SC_XBMEM	0x42		/* Xbox memory unit */
#define US_SC_MAX	US_SC_ISD200
#define US_SC_MIN	US_SC_RBC	/* paulb: added   - Xbox memory unit */
#define US_SC_MAX	US_SC_XBMEM 	/* paulb: changed - Xbox memory unit */
//#define US_SC_MAX	US_SC_ISD200	/* paulb: old setting */
#define US_SC_DEVICE	0xff		/* Use device's value */
#define US_SC_DEVICE	0xff		/* Use device's value */
 Lines 63-67    Link Here 
extern void usb_stor_qic157_command(Scsi_Cmnd*, struct us_data*);
extern void usb_stor_qic157_command(Scsi_Cmnd*, struct us_data*);
extern void usb_stor_ufi_command(Scsi_Cmnd*, struct us_data*);
extern void usb_stor_ufi_command(Scsi_Cmnd*, struct us_data*);
extern void usb_stor_transparent_scsi_command(Scsi_Cmnd*, struct us_data*);
extern void usb_stor_transparent_scsi_command(Scsi_Cmnd*, struct us_data*);
#ifdef US_SC_XBMEM
extern void usb_stor_xbmem_scsi_command(Scsi_Cmnd*, struct us_data*);
#endif
#endif
#endif
(-) linux-2.4.26/drivers/usb/storage/usb.c (-5 / +33 lines)
 Lines 1-6    Link Here 
/* Driver for USB Mass Storage compliant devices
/* Driver for USB Mass Storage compliant devices
 *
 *
 * $Id: usb.c,v 1.73 2002/01/27 09:02:15 mdharm Exp $
 * $Id: usb.c,v 1.4 2004/02/18 23:45:58 aothieno Exp $
 *
 *
 * Current development and maintenance by:
 * Current development and maintenance by:
 *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
 *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
 Lines 155-161    Link Here 
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) },
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) },
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) },
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) },
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
#ifdef US_SC_XBMEM
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_XBMEM, US_PR_BULK) },
#endif
	/* Terminating entry */
	/* Terminating entry */
	{ }
	{ }
};
};
 Lines 230-236    Link Here 
	  useTransport: US_PR_BULK},
	  useTransport: US_PR_BULK},
	{ useProtocol: US_SC_SCSI,
	{ useProtocol: US_SC_SCSI,
	  useTransport: US_PR_BULK},
	  useTransport: US_PR_BULK},
#ifdef US_SC_XBMEM
	{ useProtocol: US_SC_XBMEM,
	  useTransport: US_PR_BULK},
#endif
	/* Terminating entry */
	/* Terminating entry */
	{ 0 }
	{ 0 }
};
};
 Lines 319-324    Link Here 
	 */
	 */
	exit_files(current);
	exit_files(current);
	current->files = init_task.files;
	current->files = init_task.files;
	//current->flags |= PF_IOTHREAD;		/* paulb? */
	atomic_inc(&current->files->count);
	atomic_inc(&current->files->count);
	daemonize();
	daemonize();
	reparent_to_init();
	reparent_to_init();
 Lines 440-450    Link Here 
					unsigned char data_ptr[36] = {
					unsigned char data_ptr[36] = {
					    0x00, 0x80, 0x02, 0x02,
					    0x00, 0x80, 0x02, 0x02,
					    0x1F, 0x00, 0x00, 0x00};
					    0x1F, 0x00, 0x00, 0x00};
warn("Fake INQUIRY command\n");
					US_DEBUGP("Faking INQUIRY command\n");
					US_DEBUGP("Faking INQUIRY command\n");
					fill_inquiry_response(us, data_ptr, 36);
					fill_inquiry_response(us, data_ptr, 36);
					us->srb->result = GOOD << 1;
					us->srb->result = GOOD << 1;
				} else if ((us->srb->cmnd[0] == START_STOP) &&
				    (us->flags & US_FL_START_CHECK)) {
					unsigned char saved_cdb[6];
					/* Handle those devices which fake
					 * START_STOP on us, this confuses
					 * the hell out of media check code. */
warn("Converting START_STOP cmd\n");
					US_DEBUGP("Convering START_STOP command\n");
					memcpy(saved_cdb, us->srb->cmnd, 6);
					memset(us->srb->cmnd, 0, 6);
					us->srb->cmnd[0] = TEST_UNIT_READY;
					US_DEBUG(usb_stor_show_command(us->srb));
					us->proto_handler(us->srb, us);
					memcpy(us->srb->cmnd, saved_cdb, 6);
				} else {
				} else {
warn("USB SCSI command: 0x%x\n", us->srb->cmnd[0]);
					/* we've got a command, let's do it! */
					/* we've got a command, let's do it! */
					US_DEBUG(usb_stor_show_command(us->srb));
					US_DEBUG(usb_stor_show_command(us->srb));
					us->proto_handler(us->srb, us);
					us->proto_handler(us->srb, us);
 Lines 952-958    Link Here 
			ss->protocol_name = "Transparent SCSI";
			ss->protocol_name = "Transparent SCSI";
			ss->proto_handler = usb_stor_transparent_scsi_command;
			ss->proto_handler = usb_stor_transparent_scsi_command;
			break;
			break;
#ifdef US_SC_XBMEM
		case US_SC_XBMEM:
			ss->protocol_name = "Xbox Mem card";
			ss->proto_handler = usb_stor_xbmem_scsi_command;
                        ss->max_lun = 0;  /* fix: ignore all luns > 0 */
			break;
#endif
		case US_SC_UFI:
		case US_SC_UFI:
			ss->protocol_name = "Uniform Floppy Interface (UFI)";
			ss->protocol_name = "Uniform Floppy Interface (UFI)";
			ss->proto_handler = usb_stor_ufi_command;
			ss->proto_handler = usb_stor_ufi_command;
(-) linux-2.4.26/drivers/usb/storage/usb.h (-1 / +2 lines)
 Lines 1-7    Link Here 
/* Driver for USB Mass Storage compliant devices
/* Driver for USB Mass Storage compliant devices
 * Main Header File
 * Main Header File
 *
 *
 * $Id: usb.h,v 1.18 2001/07/30 00:27:59 mdharm Exp $
 * $Id: usb.h,v 1.3 2003/09/13 20:36:11 huceke Exp $
 *
 *
 * Current development and maintenance by:
 * Current development and maintenance by:
 *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
 *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
 Lines 99-104    Link Here 
#define US_FL_SINGLE_LUN      0x00000001 /* allow access to only LUN 0	    */
#define US_FL_SINGLE_LUN      0x00000001 /* allow access to only LUN 0	    */
#define US_FL_MODE_XLATE      0x00000002 /* translate _6 to _10 commands for
#define US_FL_MODE_XLATE      0x00000002 /* translate _6 to _10 commands for
						    Win/MacOS compatibility */
						    Win/MacOS compatibility */
#define US_FL_START_CHECK     0x00000008 /* START_STOP => TEST UNIT READY */
#define US_FL_IGNORE_SER      0x00000010 /* Ignore the serial number given  */
#define US_FL_IGNORE_SER      0x00000010 /* Ignore the serial number given  */
#define US_FL_SCM_MULT_TARG   0x00000020 /* supports multiple targets */
#define US_FL_SCM_MULT_TARG   0x00000020 /* supports multiple targets */
#define US_FL_FIX_INQUIRY     0x00000040 /* INQUIRY response needs fixing */
#define US_FL_FIX_INQUIRY     0x00000040 /* INQUIRY response needs fixing */
(-) linux-2.4.26/drivers/usb/ult.c (+264 lines)
Line 0    Link Here 
/*
 * 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
 * 
 */
/*
 *  $Id: ult.c,v 1.1 2002/09/02 00:56:47 steventoth Exp $
 *
 *  Copyright (c) 2002 Steven Toth <steve@toth.demon.co.uk>
 *
 *  This tool is a user space usb-xboxir.o configuration tool.
 *
 *  History:
 *
 *  2002_09_02 - 0.1 - Initial release
 *
 */
/*
 * Compile with:
 * gcc ult.c -o ult -I/usr/src/linux-2.4.19-XBOX-toths1/include -I/usr/src/linux-2.4.19-XBOX-toths1/drivers/usb
 */
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <usb-xboxir.h>
#define PROGNAME "ult"
#define PROCNAME "/proc/xboxir"
#define VERSION  "0.1"
int fh,verbose=0;
struct t_rc_kbd_matrix entry;
char *src_name;
char *tgt_name;
char * get_rc_name_by_code(unsigned char c);
char * get_hid_name_by_code(unsigned int c);
void write_entry();
void usage(void);
void dump_proc(void);
unsigned int get_hid_key_by_name(char *n);
unsigned char get_rc_key_by_name(char *n);
void dump_keys(void);
char * get_rc_name_by_code(unsigned char c);
char * get_hid_name_by_code(unsigned int c);
void write_entry() {
	if (verbose) printf("Configuring driver: XBOX key %s generates kernel key %s\n", src_name, tgt_name);	
	if( (ioctl(fh,XBOXIR_IOCSQSET, &entry)) == -1) {
		printf("Error, unable to configure driver table\n");
		exit(1);
	}
}
void usage(void) {
	printf("Description: %s, a user space tool for configuring the xbox ir driver key codes.\n",PROGNAME);
	printf("Usage: %s [-hkq] -d /dev/name -s <src key> -t <target key>\n",PROGNAME);
	printf(" -h  help\n");
	printf(" -v  verbose\n");
	printf(" -V  version\n");
	printf(" -k  list key codes\n");
	printf(" -q  query current settings\n");
	printf(" -d  device name\n");
	printf(" -s  source keyname (XBOX)\n");
	printf(" -t  target keyname (KERNEL)\n\n");
	printf("Example: To remap the xbox INFO key to the HID stopcd KEY\n");
	printf("     do: %s -d /dev/xboxir -s RC_KEY_INFO -t KEY_STOPCD\n\n",PROGNAME);
}
void dump_proc(void) {
	struct t_rc_kbd_matrix entry;
	FILE *in;
	char line[80];
	int ret=0;
	
	in=fopen(PROCNAME,"rb");
	if (!in) {
		perror("fopen");
		exit(1);
	}
	printf("#XBOX key -> HID key\n");
	while(!feof(in)) {
		memset(&line,0,sizeof(line));
		fgets(&line[0],sizeof(line)-1,in);
		if(line[0] == '0') {
			ret=sscanf(line,"0x%02x:0x%04x",&entry.rc_code,&entry.kbd_code);
			//printf("ret=%d\n",ret);
			printf("%s -> %s\n",get_rc_name_by_code(entry.rc_code), get_hid_name_by_code(entry.kbd_code) );
		}
	}
	fclose(in);
}
/* For a given hid KEY_NAME, find it in the structures and return the unique code */
unsigned int get_hid_key_by_name(char *n) {
	int i=1; /* Start at 1 as 0 = reserved */
	while( hidkeys[i].code != 0 ) {
		if( strcmp(hidkeys[i].name,n) == 0) {
			return(hidkeys[i].code);
		}
		i++;
	}
	return 0;
}
void dump_keys(void) {
	int i=0;
	int w=0;
	printf("XBOX KEY NAME (CODE):\n");
	while( rckeys[i].code != 0 ) {
		printf("   %s (0x%x)\n",rckeys[i].name,rckeys[i].code);
		i++;
	}
	i=1; /* start from 1 as 0 is RESERVED */
	printf("HID KEY NAME (CODE):\n");
	while( hidkeys[i].code != 0 ) {
		printf("   %s (0x%x)\n",hidkeys[i].name,hidkeys[i].code);
		i++;
	}
}
/* For a given xbox KEY_NAME, find it in the structures and return the unique code */
unsigned char get_rc_key_by_name(char *n) {
	int i=0;
	while( rckeys[i].code != 0 ) {
		if( strcmp(rckeys[i].name,n) == 0) {
			return(rckeys[i].code);
		}
		i++;
	}
	return 0;
}
/* For a given xbox KEY_CODE, find it in the structures and return the name */
char * get_rc_name_by_code(unsigned char c) {
	int i=0;
	while( rckeys[i].code != 0 ) {
		if(rckeys[i].code == c) return(rckeys[i].name);
		i++;
	}
	return 0;
}
/* For a given hid KEY_CODE, find it in the structures and return the name */
char * get_hid_name_by_code(unsigned int c) {
	int i=1; /* Start at 1, 0 = reserved */
	while( hidkeys[i].code != 0 ) {
		if(hidkeys[i].code == c) return(hidkeys[i].name);
		i++;
	}
	return 0;
}
int main(int argc, char **argv[]) {
	extern char *optarg;
	extern int optind, opterr, optopt;
	int dflg=0,tflg=0,sflg=0,c=0;
	char dev[128],srckey[32],tgtkey[32];
	while ((c=getopt(argc,argv,"d:s:t:qvkhV")) != -1 ) {
		switch(c) {
			case 'V':
				printf("Version: %s\n", VERSION);
				exit(0);
				break;
			case 'h':
				usage();
				exit(0);
				break;
			case 'k':
				dump_keys();
				exit(0);
				break;
			case 'q':
				dump_proc();
				exit(0);
				break;
			case 'v':
				verbose++;
				break;
			case 'd':
				dflg++;
				strcpy(dev,optarg);
				break;
			case 's':
				sflg++;
				if( (entry.rc_code = get_rc_key_by_name(optarg)) == 0) {
					printf("Error, invalid XBOX KEY_NAME\n");
					exit(1);
				}	
				src_name=optarg;
				break;
			case 't':
				tflg++;
				//entry.kbd_code = atoi(optarg);
				if( (entry.kbd_code = get_hid_key_by_name(optarg)) == 0) {
					printf("Error, invalid HID KEY_NAME\n");
					exit(1);
				}
				tgt_name=optarg;
				break;
			default:
				usage();
				exit(1);
		}
	}
	if(! ((dflg) && (sflg) && (tflg)) ) {
		usage();
		exit(1);
	}
	if (verbose) printf("Opening device driver named %s\n",dev);
	if( (fh=open(dev,O_RDWR)) == -1) {
		perror("open");
		exit(1);
	}
	write_entry();
	close(fh);
	if (verbose) printf("Closed device driver\n");
}
/*
#!/bin/sh
cat /usr/src/linux/include/linux/input.h | grep "#define" | grep "KEY_" | \
awk '{ print " {\"" $2 "\", " $2 "}," }'
*/
(-) linux-2.4.26/drivers/usb/usb-xboxir.c (+383 lines)
Line 0    Link Here 
/*
 * 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
 * 
 */
/*
 *  $Id: usb-xboxir.c,v 1.4 2003/12/10 00:18:28 aothieno Exp $
 *
 *  Copyright (c) 2002 Steven Toth <steve@toth.demon.co.uk>
 *
 *  XBOX DVD dongle infrared device driver for the input driver suite.
 *
 *  This work was derived from the usbkbd.c kernel module.
 *
 *  History:
 *
 *  2002_08_31 - 0.1 - Initial release
 *  2002_09_02 - 0.2 - Added IOCTL support enabling user space administration
 *                     of the translation matrix.
 *
 */
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <asm/uaccess.h>
#include "usb-xboxir.h"
#ifndef MODULE
#define MODULE
#endif
#define DRIVER_VERSION		"0.2"
#define DRIVER_AUTHOR			"Steven Toth <steve@toth.demon.co.uk>"
#define DRIVER_DESC				"USB HID XBOX IR driver"
#define PROC_FILE_NAME		"xboxir"
#define PROC_FILE_PERMS		S_IFREG | S_IRUGO
#define XBOXIR_MINOR			240
#ifdef dbg
#undef dbg
#define dbg(format, arg...) do { if(xboxir_debug) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg); } while (0)
unsigned int xboxir_debug = 0;
struct proc_dir_entry *proc_file_ent;
/*  Dump the contents of the translation table in ASCII to the /proc file */
static int usb_xboxir_read_proc_ir( char *buf, char **start, off_t offset, int count, int *eof, void *data)
{
	int i=0, len=0;
	if(count>=512) {
	
		len += sprintf(buf+len,"XBOX:HID\n");
		while(rc_kbd_matrix[i].rc_code != 0) {
			len += sprintf(buf+len,"0x%02x:0x%04x\n"
				,rc_kbd_matrix[i].rc_code
				,rc_kbd_matrix[i].kbd_code);
			i++;
		}
	} else {
		dbg("user attemped to read /proc but user bufferlen was < 512 chars, not big enough, increase");
	}
	*eof = 1;
	return len;
}
/* Perform an lookup for xbox rc_code in the table, return the kbd_code. */
static unsigned int get_kdb_code(unsigned char c)
{
	int i=0;
	/* the table is order so we can take a short cut for invalid code numbers */
	while(rc_kbd_matrix[i].rc_code != 0) {
		if(rc_kbd_matrix[i].rc_code > c) return 0; /* wasn't in list */
		if(rc_kbd_matrix[i].rc_code == c)
			return rc_kbd_matrix[i].kbd_code;
		i++;
	}
	return 0;
}
/* Perform an lookup for xbox rc_code in the table, set the kbd_code. */
static unsigned int set_kdb_code(unsigned char c, unsigned int new_code)
{
	int i=0;
	/* the table is order so we can take a short cut for invalid code numbers */
	while(rc_kbd_matrix[i].rc_code != 0) {
		if(rc_kbd_matrix[i].rc_code > c) return 0; /* wasn't in list */
		if(rc_kbd_matrix[i].rc_code == c) {
			dbg("Changing translation from HID event 0x%X to 0x%X",rc_kbd_matrix[i].kbd_code, new_code);
			rc_kbd_matrix[i].kbd_code = new_code;
			return 1;
		}
		i++;
	}
	return 0;
}
/* Start of IOCTL specifics */
static int usb_xboxir_ioc_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	struct t_rc_kbd_matrix input;
	int err=0;
	int ret=0;
	if (_IOC_TYPE(cmd) != XBOXIR_IOC_MAGIC) return -ENOTTY;
	if (_IOC_NR(cmd) > XBOXIR_IOC_MAXNR) return -ENOTTY;
	/* Check that the user space addresses are valid - we don't want an exception */
	if (_IOC_DIR(cmd) & _IOC_READ)
		err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
	else if (_IOC_DIR(cmd) & _IOC_WRITE)
		err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
	if (err) return -EFAULT;
	switch(cmd) {
		case XBOXIR_IOCSQSET:	/* user performing an update */
			if (copy_from_user(&input, (int *)arg, sizeof(input))) return -EFAULT;
			dbg("user sent struct containing rc_code=%X, kbd_code=%X",input.rc_code,input.kbd_code);
			if( (input.kbd_code = set_kdb_code( input.rc_code, input.kbd_code )) == 0 ) {
				ret = -1;
			} else {
				ret = 0;
			}
			break;
		case XBOXIR_IOCSQGET:	/* User is performing a query */
			if (copy_from_user(&input, (int *)arg, sizeof(input))) return -EFAULT;
			dbg("user sent struct containing rc_code=%X, kbd_code=%X",input.rc_code,input.kbd_code);
			if( (input.kbd_code = get_kdb_code( input.rc_code )) == 0 ) {
				ret = -1;
			} else {
				/* Return the structure to the user */
				dbg("we return containing rc_code=%X, kbd_code=%X",input.rc_code,input.kbd_code);
				if (copy_to_user((int *)arg, &input, sizeof(input))) return -EFAULT;
				ret = 0;
			}
			break;
		default:
			return -ENOTTY;
	}
	return ret;
}
static int usb_xboxir_ioc_open (struct inode *inode, struct file *file)
{
	return 0;
}
/* End of IOCTL specifics */
/*  USB callback completion handler
 *  Code in transfer_buffer is received as six unsigned chars
 *  Example PLAY=00 06 ea 0a 40 00
 *  The command is located in byte[2], the rest are ignored.
 *  Key position is byte[4] bit0 (7-0 format) 0=down, 1=up
 *  All other bits are unknown / now required.
 */
static void usb_xboxir_irq(struct urb *urb)
{
	struct usb_xboxir *xir = urb->context;
	unsigned int kbd_code=0;
	unsigned int key_direction=0; // 0=down, 1=up
	if (urb->status) return;
	if (urb->actual_length < 6) return;
	/* Messy/unnecessary, fix this */
	memcpy(xir->irpkt, urb->transfer_buffer, 6);
	if ( (kbd_code = get_kdb_code( xir->irpkt[2] )) == 0) return;
	/* Set the key action based in the sent action */
	key_direction =  ( xir->irpkt[4] & 1 ? 0 : 1) ;
	if(xir->previous_kbd_code) {
		input_report_key(&xir->dev, xir->previous_kbd_code, 0);
	}
	input_report_key(&xir->dev, kbd_code, key_direction);
	xir->previous_kbd_code=kbd_code;
	dbg("usb_xboxir_irq: actual_length=%d",urb->actual_length);
	dbg("%02x %02x %02x %02x %02x %02x"
		,xir->irpkt[0],xir->irpkt[1],xir->irpkt[2],xir->irpkt[3],xir->irpkt[4],xir->irpkt[5]);
}
static int usb_xboxir_open(struct input_dev *dev)
{
	struct usb_xboxir *xir = dev->private;
	if (xir->open++)
		return 0;
	xir->irq.dev = xir->usbdev;
	if (usb_submit_urb(&xir->irq))
		return -EIO;
	return 0;
}
static void usb_xboxir_close(struct input_dev *dev)
{
	struct usb_xboxir *xir = dev->private;
	if (!--xir->open)
		usb_unlink_urb(&xir->irq);
}
static void *usb_xboxir_probe(struct usb_device *dev, unsigned int ifnum,
			   const struct usb_device_id *id)
{
	struct usb_interface *iface;
	struct usb_interface_descriptor *interface;
	struct usb_endpoint_descriptor *endpoint;
	struct usb_xboxir *xir;
	int i, pipe, maxp;
	char *buf;
	dbg("usb_xboxir_probe");
	iface = &dev->actconfig->interface[ifnum];
	interface = &iface->altsetting[iface->act_altsetting];
	if (interface->bNumEndpoints != 1) return NULL;
	endpoint = interface->endpoint + 0;
	if (!(endpoint->bEndpointAddress & 0x80)) return NULL;
	if ((endpoint->bmAttributes & 3) != 3) return NULL;
	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
	usb_set_protocol(dev, interface->bInterfaceNumber, 0);
	usb_set_idle(dev, interface->bInterfaceNumber, 0, 0);
	if (!(xir = kmalloc(sizeof(struct usb_xboxir), GFP_KERNEL))) return NULL;
	memset(xir, 0, sizeof(struct usb_xboxir));
	xir->usbdev = dev;
	// The kinds of events we can send (keyboard)
	xir->dev.evbit[0] = BIT(EV_KEY);
	i=0;
	while(rc_kbd_matrix[i].rc_code != 0) {
		set_bit(rc_kbd_matrix[i++].kbd_code, xir->dev.keybit);
	}
	clear_bit(0, xir->dev.keybit);
	
	xir->dev.private = xir;
	xir->dev.event = NULL;
	xir->dev.open = usb_xboxir_open;
	xir->dev.close = usb_xboxir_close;
	FILL_INT_URB(&xir->irq, dev, pipe, xir->irpkt, maxp > 8 ? 8 : maxp,
		usb_xboxir_irq, xir, endpoint->bInterval);
	xir->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
	xir->dr.bRequest = USB_REQ_SET_REPORT;
	xir->dr.wValue = 0x200;
	xir->dr.wIndex = interface->bInterfaceNumber;
	xir->dr.wLength = 1;
	xir->dev.name = xir->name;
	xir->dev.idbus = BUS_USB;
	xir->dev.idvendor = dev->descriptor.idVendor;
	xir->dev.idproduct = dev->descriptor.idProduct;
	xir->dev.idversion = dev->descriptor.bcdDevice;
	if (!(buf = kmalloc(63, GFP_KERNEL))) {
		kfree(xir);
		return NULL;
	}
	if (dev->descriptor.iManufacturer &&
		usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0)
			strcat(xir->name, buf);
	
	if (dev->descriptor.iProduct &&
		usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
			sprintf(xir->name, "%s %s", xir->name, buf);
	if (!strlen(xir->name))
		sprintf(xir->name, "USB HID XBOX IR %04x:%04x",
			xir->dev.idvendor, xir->dev.idproduct);
	kfree(buf);
	input_register_device(&xir->dev);
	dbg("input%d: %s on usb%d:%d.%d", xir->dev.number, xir->name, dev->bus->busnum, dev->devnum, ifnum);
	return xir;
}
static void usb_xboxir_disconnect(struct usb_device *dev, void *ptr)
{
	struct usb_xboxir *xir = ptr;
	usb_unlink_urb(&xir->irq);
	input_unregister_device(&xir->dev);
	kfree(xir);
}
static struct usb_device_id usb_xboxir_id_table [] = {
	{ USB_DEVICE(0x045e, 0x0284) }, /* Microsoft, DVD dongle */
	{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, usb_xboxir_id_table);
static struct file_operations usb_xboxir_fops =
{
	.owner	= THIS_MODULE,
	.ioctl	= usb_xboxir_ioc_ioctl,
	.open	= usb_xboxir_ioc_open,
};
static struct usb_driver usb_xboxir_driver = {
	.name		= "usb-xboxir",
	.probe		= usb_xboxir_probe,
	.disconnect	= usb_xboxir_disconnect,
	.id_table	= usb_xboxir_id_table,
	.fops		= &usb_xboxir_fops,
	.minor		= XBOXIR_MINOR,
};
static int __init usb_xboxir_init(void)
{
	usb_register(&usb_xboxir_driver);
	proc_file_ent = create_proc_read_entry(PROC_FILE_NAME,
			PROC_FILE_PERMS, NULL, usb_xboxir_read_proc_ir, NULL);
	dbg("%s:%s", DRIVER_VERSION, DRIVER_DESC);
	return 0;
}
static void __exit usb_xboxir_exit(void)
{
	if (proc_file_ent)
		remove_proc_entry(PROC_FILE_NAME, NULL);
	usb_deregister(&usb_xboxir_driver);
}
module_init(usb_xboxir_init);
module_exit(usb_xboxir_exit);
MODULE_PARM(xboxir_debug, "i");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
#undef dbg
#endif
(-) linux-2.4.26/drivers/usb/usb-xboxir.h (+372 lines)
Line 0    Link Here 
/*
 *  $Id: usb-xboxir.h,v 1.3 2002/12/02 23:04:58 oliverschwartz Exp $
 *
 *  Copyright (c) 2002 Steven Toth 
 *
 */
/*
 * 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
 * 
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <steve@toth.demon.co.uk>.
 */
#ifndef USB_XBOX_IR_H
#define USB_XBOX_IR_H
/*  These are all the XBOX remote control keys (and their unique codes).
 *  These are stored in a lookup table and translated into HID keyboard events
 */
#define RC_KEY_SELECT		0x0b
#define RC_KEY_UP				0xa6
#define RC_KEY_DOWN			0xa7
#define RC_KEY_RIGHT		0xa8
#define RC_KEY_LEFT			0xa9
#define RC_KEY_INFO			0xc3
#define RC_KEY_9				0xc6
#define RC_KEY_8				0xc7
#define RC_KEY_7				0xc8
#define RC_KEY_6				0xc9
#define RC_KEY_5				0xca
#define RC_KEY_4				0xcb
#define RC_KEY_3				0xcc
#define RC_KEY_2				0xcd
#define RC_KEY_1				0xce
#define RC_KEY_0				0xcf
#define RC_KEY_DISPLAY	0xd5
#define RC_KEY_BACK			0xd8
#define RC_KEY_SKIPF		0xdd
#define RC_KEY_SKIPB		0xdf
#define RC_KEY_STOP			0xe0
#define RC_KEY_REW			0xe2
#define RC_KEY_FWD			0xe3
#define RC_KEY_TITLE		0xe5
#define RC_KEY_PAUSE		0xe6
#define RC_KEY_PLAY			0xea
#define RC_KEY_MENU			0xf7
struct t_rc_kbd_matrix {
  unsigned char rc_code;
  unsigned int  kbd_code;
};
#ifdef MODULE
/*  An ORDERED table (rc_code) to enabling XBOX codes to be translated into HID keyboard codes */
static struct {
	unsigned char	rc_code;
	unsigned int	kbd_code;
} rc_kbd_matrix[] = {
	{ RC_KEY_SELECT,	KEY_ENTER },
	{ RC_KEY_UP,			KEY_UP },
	{ RC_KEY_DOWN,		KEY_DOWN },
	{ RC_KEY_RIGHT,		KEY_RIGHT },
	{ RC_KEY_LEFT,		KEY_LEFT },
	{ RC_KEY_INFO,		KEY_HELP },
	{ RC_KEY_9,				KEY_9 },
	{ RC_KEY_8,				KEY_8 },
	{ RC_KEY_7,				KEY_7 },
	{ RC_KEY_6,				KEY_6 },
	{ RC_KEY_5,				KEY_5 },
	{ RC_KEY_4,				KEY_4 },
	{ RC_KEY_3,				KEY_3 },
	{ RC_KEY_2,				KEY_2 },
	{ RC_KEY_1,				KEY_1 },
	{ RC_KEY_0,				KEY_0 },
	{ RC_KEY_DISPLAY,	KEY_HELP },
	{ RC_KEY_BACK,		KEY_BACK },
	{ RC_KEY_SKIPF,		KEY_PREVIOUSSONG },
	{ RC_KEY_SKIPB,		KEY_NEXTSONG },
	{ RC_KEY_STOP,		KEY_STOPCD },
	{ RC_KEY_REW,			KEY_REWIND },
	{ RC_KEY_FWD,			KEY_FORWARD },
	{ RC_KEY_TITLE,		KEY_MENU },
	{ RC_KEY_PAUSE,		KEY_PAUSECD },
	{ RC_KEY_PLAY,		KEY_PLAYCD },
	{ RC_KEY_MENU,		KEY_MENU },
	{ 0,0 }
};
struct usb_xboxir {
	struct input_dev dev;
	struct usb_device *usbdev;
	unsigned char irpkt[8];
	unsigned int previous_kbd_code;
	struct urb irq;
	struct usb_ctrlrequest dr;
	char name[128];
	int open;
};
#endif
/* Configure the ioctl stuff */
#define XBOXIR_IOC_MAGIC 's'
#define XBOXIR_IOCRESET _IO(XBOXIR_IOC_MAGIC, 0)
#define XBOXIR_IOCSQSET	_IOW(XBOXIR_IOC_MAGIC, 1, int)	// userland writes to device
#define XBOXIR_IOCSQGET	_IOR(XBOXIR_IOC_MAGIC, 2, int)	// userland reads from device
#define XBOXIR_IOC_MAXNR 2
struct {
	char *name;
	unsigned char code;
} rckeys[] = {
 {"RC_KEY_SELECT", RC_KEY_SELECT},
 {"RC_KEY_UP", RC_KEY_UP},
 {"RC_KEY_DOWN", RC_KEY_DOWN},
 {"RC_KEY_RIGHT", RC_KEY_RIGHT},
 {"RC_KEY_LEFT", RC_KEY_LEFT},
 {"RC_KEY_INFO", RC_KEY_INFO},
 {"RC_KEY_9", RC_KEY_9},
 {"RC_KEY_8", RC_KEY_8},
 {"RC_KEY_7", RC_KEY_7},
 {"RC_KEY_6", RC_KEY_6},
 {"RC_KEY_5", RC_KEY_5},
 {"RC_KEY_4", RC_KEY_4},
 {"RC_KEY_3", RC_KEY_3},
 {"RC_KEY_2", RC_KEY_2},
 {"RC_KEY_1", RC_KEY_1},
 {"RC_KEY_0", RC_KEY_0},
 {"RC_KEY_DISPLAY", RC_KEY_DISPLAY},
 {"RC_KEY_BACK", RC_KEY_BACK},
 {"RC_KEY_SKIPF", RC_KEY_SKIPF},
 {"RC_KEY_SKIPB", RC_KEY_SKIPB},
 {"RC_KEY_STOP", RC_KEY_STOP},
 {"RC_KEY_REW", RC_KEY_REW},
 {"RC_KEY_FWD", RC_KEY_FWD},
 {"RC_KEY_TITLE", RC_KEY_TITLE},
 {"RC_KEY_PAUSE", RC_KEY_PAUSE},
 {"RC_KEY_PLAY", RC_KEY_PLAY},
 {"RC_KEY_MENU", RC_KEY_MENU},
 {NULL, 0},
};
struct t_ult_hidkeys {
	char *name;
	unsigned int code;
} hidkeys[] = {
 {"KEY_RESERVED", KEY_RESERVED},
 {"KEY_ESC", KEY_ESC},
 {"KEY_1", KEY_1},
 {"KEY_2", KEY_2},
 {"KEY_3", KEY_3},
 {"KEY_4", KEY_4},
 {"KEY_5", KEY_5},
 {"KEY_6", KEY_6},
 {"KEY_7", KEY_7},
 {"KEY_8", KEY_8},
 {"KEY_9", KEY_9},
 {"KEY_0", KEY_0},
 {"KEY_MINUS", KEY_MINUS},
 {"KEY_EQUAL", KEY_EQUAL},
 {"KEY_BACKSPACE", KEY_BACKSPACE},
 {"KEY_TAB", KEY_TAB},
 {"KEY_Q", KEY_Q},
 {"KEY_W", KEY_W},
 {"KEY_E", KEY_E},
 {"KEY_R", KEY_R},
 {"KEY_T", KEY_T},
 {"KEY_Y", KEY_Y},
 {"KEY_U", KEY_U},
 {"KEY_I", KEY_I},
 {"KEY_O", KEY_O},
 {"KEY_P", KEY_P},
 {"KEY_LEFTBRACE", KEY_LEFTBRACE},
 {"KEY_RIGHTBRACE", KEY_RIGHTBRACE},
 {"KEY_ENTER", KEY_ENTER},
 {"KEY_LEFTCTRL", KEY_LEFTCTRL},
 {"KEY_A", KEY_A},
 {"KEY_S", KEY_S},
 {"KEY_D", KEY_D},
 {"KEY_F", KEY_F},
 {"KEY_G", KEY_G},
 {"KEY_H", KEY_H},
 {"KEY_J", KEY_J},
 {"KEY_K", KEY_K},
 {"KEY_L", KEY_L},
 {"KEY_SEMICOLON", KEY_SEMICOLON},
 {"KEY_APOSTROPHE", KEY_APOSTROPHE},
 {"KEY_GRAVE", KEY_GRAVE},
 {"KEY_LEFTSHIFT", KEY_LEFTSHIFT},
 {"KEY_BACKSLASH", KEY_BACKSLASH},
 {"KEY_Z", KEY_Z},
 {"KEY_X", KEY_X},
 {"KEY_C", KEY_C},
 {"KEY_V", KEY_V},
 {"KEY_B", KEY_B},
 {"KEY_N", KEY_N},
 {"KEY_M", KEY_M},
 {"KEY_COMMA", KEY_COMMA},
 {"KEY_DOT", KEY_DOT},
 {"KEY_SLASH", KEY_SLASH},
 {"KEY_RIGHTSHIFT", KEY_RIGHTSHIFT},
 {"KEY_KPASTERISK", KEY_KPASTERISK},
 {"KEY_LEFTALT", KEY_LEFTALT},
 {"KEY_SPACE", KEY_SPACE},
 {"KEY_CAPSLOCK", KEY_CAPSLOCK},
 {"KEY_F1", KEY_F1},
 {"KEY_F2", KEY_F2},
 {"KEY_F3", KEY_F3},
 {"KEY_F4", KEY_F4},
 {"KEY_F5", KEY_F5},
 {"KEY_F6", KEY_F6},
 {"KEY_F7", KEY_F7},
 {"KEY_F8", KEY_F8},
 {"KEY_F9", KEY_F9},
 {"KEY_F10", KEY_F10},
 {"KEY_NUMLOCK", KEY_NUMLOCK},
 {"KEY_SCROLLLOCK", KEY_SCROLLLOCK},
 {"KEY_KP7", KEY_KP7},
 {"KEY_KP8", KEY_KP8},
 {"KEY_KP9", KEY_KP9},
 {"KEY_KPMINUS", KEY_KPMINUS},
 {"KEY_KP4", KEY_KP4},
 {"KEY_KP5", KEY_KP5},
 {"KEY_KP6", KEY_KP6},
 {"KEY_KPPLUS", KEY_KPPLUS},
 {"KEY_KP1", KEY_KP1},
 {"KEY_KP2", KEY_KP2},
 {"KEY_KP3", KEY_KP3},
 {"KEY_KP0", KEY_KP0},
 {"KEY_KPDOT", KEY_KPDOT},
 {"KEY_103RD", KEY_103RD},
 {"KEY_F13", KEY_F13},
 {"KEY_102ND", KEY_102ND},
 {"KEY_F11", KEY_F11},
 {"KEY_F12", KEY_F12},
 {"KEY_F14", KEY_F14},
 {"KEY_F15", KEY_F15},
 {"KEY_F16", KEY_F16},
 {"KEY_F17", KEY_F17},
 {"KEY_F18", KEY_F18},
 {"KEY_F19", KEY_F19},
 {"KEY_F20", KEY_F20},
 {"KEY_KPENTER", KEY_KPENTER},
 {"KEY_RIGHTCTRL", KEY_RIGHTCTRL},
 {"KEY_KPSLASH", KEY_KPSLASH},
 {"KEY_SYSRQ", KEY_SYSRQ},
 {"KEY_RIGHTALT", KEY_RIGHTALT},
 {"KEY_LINEFEED", KEY_LINEFEED},
 {"KEY_HOME", KEY_HOME},
 {"KEY_UP", KEY_UP},
 {"KEY_PAGEUP", KEY_PAGEUP},
 {"KEY_LEFT", KEY_LEFT},
 {"KEY_RIGHT", KEY_RIGHT},
 {"KEY_END", KEY_END},
 {"KEY_DOWN", KEY_DOWN},
 {"KEY_PAGEDOWN", KEY_PAGEDOWN},
 {"KEY_INSERT", KEY_INSERT},
 {"KEY_DELETE", KEY_DELETE},
 {"KEY_MACRO", KEY_MACRO},
 {"KEY_MUTE", KEY_MUTE},
 {"KEY_VOLUMEDOWN", KEY_VOLUMEDOWN},
 {"KEY_VOLUMEUP", KEY_VOLUMEUP},
 {"KEY_POWER", KEY_POWER},
 {"KEY_KPEQUAL", KEY_KPEQUAL},
 {"KEY_KPPLUSMINUS", KEY_KPPLUSMINUS},
 {"KEY_PAUSE", KEY_PAUSE},
 {"KEY_F21", KEY_F21},
 {"KEY_F22", KEY_F22},
 {"KEY_F23", KEY_F23},
 {"KEY_F24", KEY_F24},
 {"KEY_KPCOMMA", KEY_KPCOMMA},
 {"KEY_LEFTMETA", KEY_LEFTMETA},
 {"KEY_RIGHTMETA", KEY_RIGHTMETA},
 {"KEY_COMPOSE", KEY_COMPOSE},
 {"KEY_STOP", KEY_STOP},
 {"KEY_AGAIN", KEY_AGAIN},
 {"KEY_PROPS", KEY_PROPS},
 {"KEY_UNDO", KEY_UNDO},
 {"KEY_FRONT", KEY_FRONT},
 {"KEY_COPY", KEY_COPY},
 {"KEY_OPEN", KEY_OPEN},
 {"KEY_PASTE", KEY_PASTE},
 {"KEY_FIND", KEY_FIND},
 {"KEY_CUT", KEY_CUT},
 {"KEY_HELP", KEY_HELP},
 {"KEY_MENU", KEY_MENU},
 {"KEY_CALC", KEY_CALC},
 {"KEY_SETUP", KEY_SETUP},
 {"KEY_SLEEP", KEY_SLEEP},
 {"KEY_WAKEUP", KEY_WAKEUP},
 {"KEY_FILE", KEY_FILE},
 {"KEY_SENDFILE", KEY_SENDFILE},
 {"KEY_DELETEFILE", KEY_DELETEFILE},
 {"KEY_XFER", KEY_XFER},
 {"KEY_PROG1", KEY_PROG1},
 {"KEY_PROG2", KEY_PROG2},
 {"KEY_WWW", KEY_WWW},
 {"KEY_MSDOS", KEY_MSDOS},
 {"KEY_COFFEE", KEY_COFFEE},
 {"KEY_DIRECTION", KEY_DIRECTION},
 {"KEY_CYCLEWINDOWS", KEY_CYCLEWINDOWS},
 {"KEY_MAIL", KEY_MAIL},
 {"KEY_BOOKMARKS", KEY_BOOKMARKS},
 {"KEY_COMPUTER", KEY_COMPUTER},
 {"KEY_BACK", KEY_BACK},
 {"KEY_FORWARD", KEY_FORWARD},
 {"KEY_CLOSECD", KEY_CLOSECD},
 {"KEY_EJECTCD", KEY_EJECTCD},
 {"KEY_EJECTCLOSECD", KEY_EJECTCLOSECD},
 {"KEY_NEXTSONG", KEY_NEXTSONG},
 {"KEY_PLAYPAUSE", KEY_PLAYPAUSE},
 {"KEY_PREVIOUSSONG", KEY_PREVIOUSSONG},
 {"KEY_STOPCD", KEY_STOPCD},
 {"KEY_RECORD", KEY_RECORD},
 {"KEY_REWIND", KEY_REWIND},
 {"KEY_PHONE", KEY_PHONE},
 {"KEY_ISO", KEY_ISO},
 {"KEY_CONFIG", KEY_CONFIG},
 {"KEY_HOMEPAGE", KEY_HOMEPAGE},
 {"KEY_REFRESH", KEY_REFRESH},
 {"KEY_EXIT", KEY_EXIT},
 {"KEY_MOVE", KEY_MOVE},
 {"KEY_EDIT", KEY_EDIT},
 {"KEY_SCROLLUP", KEY_SCROLLUP},
 {"KEY_SCROLLDOWN", KEY_SCROLLDOWN},
 {"KEY_KPLEFTPAREN", KEY_KPLEFTPAREN},
 {"KEY_KPRIGHTPAREN", KEY_KPRIGHTPAREN},
 {"KEY_INTL1", KEY_INTL1},
 {"KEY_INTL2", KEY_INTL2},
 {"KEY_INTL3", KEY_INTL3},
 {"KEY_INTL4", KEY_INTL4},
 {"KEY_INTL5", KEY_INTL5},
 {"KEY_INTL6", KEY_INTL6},
 {"KEY_INTL7", KEY_INTL7},
 {"KEY_INTL8", KEY_INTL8},
 {"KEY_INTL9", KEY_INTL9},
 {"KEY_LANG1", KEY_LANG1},
 {"KEY_LANG2", KEY_LANG2},
 {"KEY_LANG3", KEY_LANG3},
 {"KEY_LANG4", KEY_LANG4},
 {"KEY_LANG5", KEY_LANG5},
 {"KEY_LANG6", KEY_LANG6},
 {"KEY_LANG7", KEY_LANG7},
 {"KEY_LANG8", KEY_LANG8},
 {"KEY_LANG9", KEY_LANG9},
 {"KEY_PLAYCD", KEY_PLAYCD},
 {"KEY_PAUSECD", KEY_PAUSECD},
 {"KEY_PROG3", KEY_PROG3},
 {"KEY_PROG4", KEY_PROG4},
 {"KEY_SUSPEND", KEY_SUSPEND},
 {"KEY_CLOSE", KEY_CLOSE},
 {"KEY_UNKNOWN", KEY_UNKNOWN},
 {"KEY_BRIGHTNESSDOWN", KEY_BRIGHTNESSDOWN},
 {"KEY_BRIGHTNESSUP", KEY_BRIGHTNESSUP},
 {"KEY_MAX", KEY_MAX},
 {NULL, 0},
};
#endif
(-) linux-2.4.26/drivers/usb/xir.c (+364 lines)
Line 0    Link Here 
/*
 * Xbox DVD Playback Kit receiver driver for Linux - v0.0.2
 *
 * Copyright (c)  2004  Marko Friedemann <mfr@bmx-chemnitz.de>
 *
 *	Contributors:
 *		Steven Toth <steve@toth.demon.co.uk>,
 *		Christoph Bartelmus <lirc@bartelmus.de>,
 *		Wayne Hogue <w_hogue@hotmail.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:
 *  - usb-xboxir	by Steven Toth (keyboard emu for the remote)
 *  - xpad driver	notes there apply
 *
 * Thanks to:
 *  - Christoph Bartelmus - essential info about the data from USB receiver
 *  - Wayne Hogue	  - tests with various remotes, error reports + fixes
 *
 * TODO:
 *  - implement event queue to notify LIRC
 *
 * 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/devfs_fs_kernel.h>
#include <linux/proc_fs.h>
#include <linux/usb.h>
#include <linux/version.h>
#include <linux/timer.h>
#include <asm/uaccess.h>
#define __USB_XIR
#include "xir.h"
#undef __USB_XIR
/* some debug output macros */
#undef warn
#define warn(format, arg...) (xir_verbosity > 0) && printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg)
#undef info
#define info(format, arg...) (xir_verbosity > 1) && printk(KERN_INFO __FILE__ ": " format "\n" , ## arg)
#undef dbg
#define dbg(format, arg...) (xir_verbosity > 2) && printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
int xir_verbosity = 0;
MODULE_PARM(xir_verbosity, "i");
MODULE_PARM_DESC(xir_verbosity, "\nverbosity level, default: errors only (=0)\n"
			    "  +warnings: 1\n"
			    "  +info: 2\n"
	                    "  +all: 3+");
/* FIXME: avoid this static */
static struct usb_xir *__xir = NULL;
static struct xir_device xir_device[] = {
	/* please keep those ordered wrt. vendor/product ids
	  vendor, product, dvd-dongle, name                  */
	{ 0x040b, 0x6521, "Gamester Xbox DVD Movie Playback Kit IR" },
	{ 0x045e, 0x0284, "Microsoft Xbox DVD Movie Playback Kit IR" },
	{ 0x0000, 0x0000, "nothing detected - FAIL" }
};
static struct usb_device_id xir_table [] = {
	{ USB_INTERFACE_INFO('X', 'B', 0) },	/* Xbox USB-IF not approved class */
	{ }
};
MODULE_DEVICE_TABLE(usb, xir_table);
static unsigned char xir_get_keycode(int byteNum)
{
	unsigned char retval;
	
	if (__xir == NULL)
		return 0;
	if (byteNum > XIR_CODE_BYTES-1) {
		err("BUG: cannot get byte %d from %d byte keycode",
		    byteNum, XIR_CODE_BYTES-1);
		return 0;
	}
	/* CHECKME: shouldn't be no sync neccessary here, should there? */
	if (0 == CIRC_CNT(__xir->rx.head, __xir->rx.tail,
			  XIR_RXBUF_LEN))
		return 0;
	retval = (unsigned char)__xir->rx.buf[
		__xir->rx.head*XIR_CODE_BYTES + byteNum];
	
	if (byteNum == XIR_CODE_BYTES-1)
		XIR_RXBUF_INC(__xir->rx.head);
	
	return retval;
}
/**
 *	xir_lirc_open
 *
 *	Called from lirc_xir upon usage by lircd.
 */
static int xir_lirc_open(void)
{
	if (__xir == NULL) {
		warn("device not initialized");
		return -ENODEV;
	}
	
	if (__xir->open_count)
		return 0;
		
	info("opening device");
	
	__xir->irq_in->dev = __xir->udev;
	if (usb_submit_urb(__xir->irq_in)) {
		err("open input urb failed");
		return -EIO;
	}
	
	++__xir->open_count;
	return 0;
}
/**
 *	xir_lirc_close
 *
 *	Called from lirc_xir upon close event from lircd.
 */
static void xir_lirc_close(void)
{
	if (__xir == NULL)
		return;
	if (!--__xir->open_count) {
		info("closing device");
		usb_unlink_urb(__xir->irq_in);
	}
}
EXPORT_SYMBOL(xir_get_keycode);
EXPORT_SYMBOL(xir_lirc_open);
EXPORT_SYMBOL(xir_lirc_close);
/**
 *	xir_process_packet
 *
 *	Completes a request by converting the data into events
 *	for the input subsystem.
 */
static void xir_process_packet(struct usb_xir *xir, u16 cmd, unsigned char *data)
{
	unsigned int _3nibbles = 0;
	if (xir == NULL)
		return;
	
	dbg("irpp: %02x %02x %02x %02x %02x %02x", data[0], data[1],
		data[2], data[3], data[4], data[5]);
	
	/* RCA (RC-5/-6?) codes use 6 nibbles, 3 of which are the complement
	    of the others, we therefore cannot allow for data[3] to be > 0x0F
	   since lirc cannot handle 0x00 as a data byte (used as end marker)
	    we cannot allow for 0x0F even, because a code of 0x0F 0xF0 would
	    translate to 0x00FFF0, which makes lirc choke */
	if (data[3] > 0x0E) {
		warn("cannot handle bad IR data 0x%01X%02X, key ignored",
		     data[3], data[2]);
		return;
	}
	/* CHECKME: shouldn't be no sync neccessary here, should there? */
	if (0 == CIRC_SPACE(xir->rx.head, xir->rx.tail,
			   XIR_RXBUF_LEN))
	{
		warn("no space left in buffer: keypress lost");
		return;
	}
	
	/* the dongle removes the IR redundancy
	 * to stay compatible with RCA codes (which the remote sends)
	 *  we simply recreate it */
	_3nibbles = ((data[3] & 0x0f) << 8) + data[2];
	
	xir->rx.buf[xir->rx.tail*XIR_CODE_BYTES] = (~_3nibbles & 0xfff) >> 4;
	xir->rx.buf[xir->rx.tail*XIR_CODE_BYTES+1] = ((~_3nibbles & 0x0f) << 4)
						     + (_3nibbles >> 8);
	xir->rx.buf[xir->rx.tail*XIR_CODE_BYTES+2] = data[2];
	
	XIR_RXBUF_INC(xir->rx.tail);
}
/**
 *	xir_irq_in
 *
 *	Completion handler for interrupt in transfers (user input).
 *	Just calls xir_process_packet which does then emit input events.
 */
static void xir_irq_in(struct urb *urb)
{
	struct usb_xir *xir = urb->context;
	
	if (urb->status) {
		warn("urb status");
		return;
	}
	
	xir_process_packet(xir, 0, xir->idata);
}
/**
 *	xir_probe
 *
 *	Called upon device detection to find a suitable driver.
 *	Must return NULL when no xir is found, else setup everything.
 */
static void * xir_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
{
        int i;
	int probedDevNum = -1;	/* this takes the index into the known devices
				   array for the recognized device */
	
	struct usb_xir *xir = NULL;
	struct usb_endpoint_descriptor *ep_irq_in;
	
	// try to detect the device we are called for
	for (i = 0; xir_device[i].idVendor; ++i) {
		if ((udev->descriptor.idVendor == xir_device[i].idVendor) &&
		    (udev->descriptor.idProduct == xir_device[i].idProduct)) {
			probedDevNum = i;
			break;
		}
	}
	
	// sanity check, did we recognize this device? if not, fail
	if ((probedDevNum == -1) || (!xir_device[probedDevNum].idVendor &&
				     !xir_device[probedDevNum].idProduct))
		return NULL;
		
	if ((xir = kmalloc (sizeof(struct usb_xir), GFP_KERNEL)) == NULL) {
		err("cannot allocate memory for new IR receiver");
		return NULL;
	}
	memset(xir, 0, sizeof(struct usb_xir));
	
	xir->udev = udev;
	ep_irq_in = udev->actconfig->interface[ifnum].altsetting[0].endpoint + 0;
	
	/* setup input interrupt pipe (button and axis state) */
	xir->irq_in = usb_alloc_urb(0);
        if (!xir->irq_in) {
		err("cannot allocate memory for new IR receiver irq urb");
                kfree(xir);
                return NULL;
	}
	
	/* init input URB for USB INT transfer from device */
	FILL_INT_URB(xir->irq_in, udev,
		     usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
		     xir->idata, XIR_PKT_LEN,
		     xir_irq_in, xir, ep_irq_in->bInterval);
	
	// XIR_CODE_BYTES bytes per key!
	xir->rx.buf = kmalloc(XIR_RXBUF_LEN * XIR_CODE_BYTES, GFP_KERNEL);
	if (xir->rx.buf == NULL) {
		err("cannot allocate memory for new IR input buffer");
		return NULL;
	}
	memset(xir->rx.buf, 0, XIR_RXBUF_LEN * XIR_CODE_BYTES);
	
	info("%s", xir_device[probedDevNum].name);
	
	__xir = xir;
	return xir;
}
/**
 *	xir_disconnect
 *
 *	Called upon device disconnect to dispose of the structures and
 *	close the USB connections.
 */
static void xir_disconnect(struct usb_device *udev, void *ptr)
{
	struct usb_xir *xir = ptr;
	if (xir != __xir)
		err("BUG: usb dev != lirc dev, possible memory leak");
	
	info( "disconnecting device" );
	
	usb_unlink_urb(xir->irq_in);
	usb_free_urb(xir->irq_in);
	
	kfree(xir->rx.buf);
	kfree(xir);
	
	__xir = NULL;
}
/******************* Linux driver framework specific stuff ************/
static struct usb_driver xir_driver = {
	.name		= "xir",
	.probe		= xir_probe,
	.disconnect	= xir_disconnect,
	.id_table	= xir_table,
};
/**
 * driver init entry point
 */
static int __init usb_xir_init(void)
{
	int result = usb_register(&xir_driver);
	if (result == 0)
		info(DRIVER_DESC " " DRIVER_VERSION);
	return result;
}
/**
 * driver exit entry point
 */
static void __exit usb_xir_exit(void)
{
	usb_deregister(&xir_driver);
}
module_init(usb_xir_init);
module_exit(usb_xir_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/*
 *  driver history
 * ----------------
 *
 * 2002-06-27 - 0.0.1 : first version, just said "XBOX HID controller"
 */
(-) linux-2.4.26/drivers/usb/xir.h (+71 lines)
Line 0    Link Here 
/*
 * Xbox DVD Playback Kit receiver driver for Linux - v0.0.2
 *
 * Copyright (c)  2004  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 __XIR_h
#define __XIR_h
/************************* driver internals ***************************/
#ifdef __KERNEL__
#ifndef __USB_XIR
 extern unsigned char xir_get_keycode(int byteNum);
 extern int xir_lirc_open(void);
 extern void xir_lirc_close(void);
#endif
#include <linux/input.h>
#include <linux/circ_buf.h>
/****************** driver description and version ********************/
#define DRIVER_VERSION		"v0.0.2"
#define DRIVER_AUTHOR		"Marko Friedemann <mfr@bmx-chemnitz.de>"
#define DRIVER_DESC		"driver for Xbox DVD Playback Kit receiver"
/****************************** constants *****************************/
#define XIR_PKT_LEN		6	/* input packet size */
#define XIR_CODE_BYTES		3
#define XIR_RXBUF_LEN	   	30
#define XIR_RXBUF_INC(var)	(var) += 1; (var) %= XIR_RXBUF_LEN
/************************* the device struct **************************/
struct usb_xir {
	struct usb_device *udev;		/* usb device */
	
	struct urb *irq_in;			/* urb for int. in report */
	unsigned char idata[XIR_PKT_LEN];	/* input data */
	
	int open_count;				/* reference count */
	
	struct circ_buf rx;			/* ring buffer for IR input */
};
/* for the list of know devices */
struct xir_device {
	u16 idVendor;
	u16 idProduct;
	char *name;
};
#endif /* __KERNEL__ */
#endif /* __XIR_h */
(-) linux-2.4.26/drivers/usb/xpad-core.c (+728 lines)
Line 0    Link Here 
/*
 * Xbox input device driver for Linux - v0.1.5
 *
 * 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/devfs_fs_kernel.h>
#include <linux/proc_fs.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 */
};
/* these have no analogue inputs and only 10 buttons */
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 (d-pad) as axes */
	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);
static struct usb_xpad *xpad_units[XPAD_MAX_DEVICES];
static struct proc_dir_entry *xpad_procdir_units = NULL;
/***************** Linux /proc filesystem specific functions **********/
/**
 *	xpad_proc_read_info
 *
 *	Used to display general driver information in a /proc fs entry.
 *	Called when /proc/driver/xpad/info is read from userspace.
 */
static int xpad_proc_read_info(char *buf, char **start, off_t offset, int count, int *eof, void *data)
{
	int len=0, i;
//	struct usb_xpad *xpad = (struct usb_xpad *)data;
	len += sprintf( buf+len, "xpad driver %s\n", DRIVER_VERSION );
	
	len += sprintf( buf+len, "\ndetected units (up to %d devices supported):\n", XPAD_MAX_DEVICES );
	for (i=0; i<XPAD_MAX_DEVICES; ++i) {
		len += sprintf( buf+len, "\t%d:\t", i );
		if (xpad_units[i] == NULL)
			len += sprintf( buf+len, "not connected\n" );
		else
			len += sprintf( buf+len, "%s\n", xpad_units[i]->dev.name );
	}
	
	len += sprintf( buf+len, "\njoystick support available:\tyes\n\n" );
	
	xpad_mouse_proc_read_info(buf, start, offset, count, eof, data, &len);
	xpad_rumble_proc_read_info(buf, start, offset, count, eof, data, &len);
	
	*eof = 1;
	return len;
}
/**
 *	xpad_proc_read_unit_info
 *
 *	Called when an application reads /proc/driver/xpad/units/<unitnumber>.
 *	Reports some device data.
 */
static int xpad_proc_read_unit_info(char *buf, char **start, off_t offset, int count, int *eof, void *data)
{
	int len=0;
	struct usb_xpad *xpad = (struct usb_xpad *)data;
	
	len += sprintf( buf+len, "device name:\t%s\n", xpad->dev.name );
	xpad_mouse_proc_read_unit_info(buf, start, offset, count, eof, data, &len);
	xpad_rumble_proc_read_unit_info(buf, start, offset, count, eof, data, &len);
	
	*eof = 1;
	return len;
}
/**
 *	xpad_proc_create
 *
 *	Called upon driver initialization to create the entries for the
 *	/proc file system and clear out the array of known devices.
 */
static int xpad_proc_create(void)
{
	struct proc_dir_entry *entry;
	
	/* world readable directory */
	int i, flags = S_IFDIR | S_IRUGO | S_IXUGO;
	
	for (i=0; i<XPAD_MAX_DEVICES; ++i)
		xpad_units[i] = NULL;
	
	entry = create_proc_entry( "xpad", flags, proc_root_driver );
	xpad_procdir_units = create_proc_entry( "units",  flags, entry );
	
	/* world readable file */
	flags = S_IFREG | S_IRUGO;
	
	entry = create_proc_entry( "info", flags, entry );
	entry->read_proc = xpad_proc_read_info;
	
	return 0;
}
/**
 *	xpad_proc_unit_create
 *
 *	Called upon device connect to create the unit's entry in the
 *	/proc file system (underneath the driver/xpad/units subdir).
 */
static void xpad_proc_unit_create(struct usb_xpad *xpad)
{
	char name[5];
	//struct proc_dir_entry *entry;
	struct proc_dir_entry *proc[3];
	
	/* world readable directory */
	int flags = S_IFDIR | S_IRUGO | S_IXUGO;
	
	enum { UNIT, FEATRS, INFO };
	
	xpad_units[xpad->number] = xpad;
	snprintf(name, 5, "%d", xpad->number);
	/* directory entries for the unit and it's 'features' subdir */
	proc[UNIT] = create_proc_entry(name, flags, xpad_procdir_units);
	proc[FEATRS] = create_proc_entry("features", flags, proc[UNIT]);
	
	/* world readable file */
	flags = S_IFREG | S_IRUGO;
	
	proc[INFO] = create_proc_entry("info", flags, proc[UNIT]);
	proc[INFO]->data = xpad;
	proc[INFO]->read_proc = xpad_proc_read_unit_info;
	/* MemoryCard1
	entry = create_proc_entry("memorycard1", flags, proc[FEATRS]);
	entry->data = xpad;
	entry->read_proc = xpad_proc_read_stub; */
	/* MemoryCard2
	entry = create_proc_entry("memorycard2", flags, proc[FEATRS]);
	entry->data = xpad;
	entry->read_proc = xpad_proc_read_stub; */
	
	xpad_mouse_proc_unit_create(xpad, proc[FEATRS]);
	xpad_rumble_proc_unit_create(xpad, proc[FEATRS]);
}
/**
 *	xpad_proc_remove
 *
 *	Called upon driver unloading to get rid of the /proc file entries.
 *	Note that those are _not_ updated as long as an application has one
 *	of the subdirectories open.
 *	Clears the array of known devices, too.
 */
static void xpad_proc_remove(void)
{
	int i;
	xpad_procdir_units = NULL;
	for (i=0; i<XPAD_MAX_DEVICES; ++i)
		xpad_units[i] = NULL;
	remove_proc_entry( "xpad", proc_root_driver );
}
/**
 *	xpad_proc_unit_remove
 *
 *	Called upon device disconnect to dispose of the
 *	device /proc entries.
 */
static void xpad_proc_unit_remove(struct usb_xpad *xpad)
{
	char proc_name[5];
	snprintf( proc_name, 5, "%d", xpad->number );
	xpad_units[xpad->number] = NULL;
	remove_proc_entry( proc_name, xpad_procdir_units );
}
/*********************** the actual xpad functions ********************/
/**
 *	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 input_dev *dev = &xpad->dev;
	/* digital pad: 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/back buttons and stick press left/right */
	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: 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);
	
	/* buttons 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]);
	
	/* 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 usb_xpad *xpad = urb->context;
	
	if (urb->status) {
		err("urb status");
		return;
	}
	
	xpad_process_packet(xpad, 0, xpad->idata);
}
/*	xpad_init_urb
 *
 *	initialize the input urb
 *	this is to be called when joystick or mouse device are opened
 */
static 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))) {
		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;
}
static 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_ioctl
 *
 *	Called via ioctl to change driver parameters (toggle mouse/ff support).
 *	Note that this relies on some unofficial changes to the input subsystem.
 */ 
static int xpad_ioctl(struct input_dev *dev, unsigned int cmd, unsigned long arg)
{
	/* check magic and max number */
	if (_IOC_TYPE(cmd) != USB_XPAD_IOC_MAGIC) return -ENOTTY;
	if (_IOC_NR(cmd) > USB_XPAD_IOC_MAXNR) return -ENOTTY;
	switch (cmd) {
		case USB_XPAD_IOCSMOUSE:
		case USB_XPAD_IOCGMOUSE:
			return xpad_mouse_ioctl(dev, cmd, arg);
		case USB_XPAD_IOCSRUMBLE:
		case USB_XPAD_IOCGRUMBLE:
			return xpad_rumble_ioctl(dev, cmd, arg);
		default:
			return -ENOTTY;
	}
}
/**	xpad_init_input_device
 *
 *	setup the input device for the kernel
 */
static void xpad_init_input_device(struct usb_device *udev, struct usb_xpad *xpad, int probedDevNum)
{
	int i;
	
	xpad->dev.idbus = BUS_USB;
	xpad->dev.idvendor = udev->descriptor.idVendor;
	xpad->dev.idproduct = udev->descriptor.idProduct;
	xpad->dev.idversion = udev->descriptor.bcdDevice;
	xpad->dev.private = xpad;
	xpad->dev.name = xpad_device[probedDevNum].name;
	xpad->dev.open = xpad_open;
	xpad->dev.close = xpad_close;
	
	/* 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);
	info("%s", xpad->dev.name);
}
/**
 *	xpad_probe
 *
 *	Called upon device detection to find a suitable driver.
 *	Must return NULL when no xpad is found, else setup everything.
 */
static void * xpad_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
{
        int i;
	int probedDevNum = -1;	/* this takes the index into the known devices
				   array for the recognized device */
	
	struct usb_xpad *xpad = NULL;
	struct usb_endpoint_descriptor *ep_irq_in;
	
	// 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].idVendor == 0))
		return NULL;
		
	if ((xpad = kmalloc (sizeof(struct usb_xpad), GFP_KERNEL)) == NULL) {
		err("cannot allocate memory for new pad");
		return NULL;
	}
	memset(xpad, 0, sizeof(struct usb_xpad));
	
	/* find next unused device slot */
	for (i=0; (i<XPAD_MAX_DEVICES && xpad_units[i] != NULL); ++i);
	if (i == XPAD_MAX_DEVICES) {
		err( "no more than %d devices supported", XPAD_MAX_DEVICES );
		return NULL;
	}
	
	xpad->udev = udev;
	xpad->number = i;
	xpad->isMat = xpad_device[probedDevNum].isMat;
	xpad_proc_unit_create(xpad);
	
	/* setup input interrupt pipe (button and axis state) */
	ep_irq_in = udev->actconfig->interface[ifnum].altsetting[0].endpoint + 0;
	xpad->irq_in = usb_alloc_urb(0);
        if (!xpad->irq_in) {
		err("cannot allocate memory for new pad irq urb");
                kfree(xpad);
                return NULL;
	}
	
	/* init input URB for USB INT transfer from device */
	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_init_input_device(udev, xpad, probedDevNum);
	xpad_mouse_init_input_device(udev, xpad, probedDevNum);
	return xpad;
}
/**
 *	xpad_disconnect
 *
 *	Called upon device disconnect to dispose of the structures and
 *	close the USB connections.
 */
static void xpad_disconnect(struct usb_device *udev, void *ptr)
{
	struct usb_xpad *xpad = ptr;
	
	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_rumble_disconnect(xpad);
	// disconnect mouse interface
	xpad_mouse_cleanup(xpad);
	
	xpad_proc_unit_remove(xpad);
	kfree(xpad);
}
/******************* Linux driver framework specific stuff ************/
static struct usb_driver xpad_driver = {
	.name		= "xpad",
	.probe		= xpad_probe,
	.disconnect	= xpad_disconnect,
	.id_table	= xpad_table
};
/**
 * driver init entry point
 */
static int __init usb_xpad_init(void)
{
	xpad_proc_create();
	usb_register(&xpad_driver);
	info(DRIVER_DESC " " DRIVER_VERSION);
	return 0;
}
/**
 * driver exit entry point
 */
static void __exit usb_xpad_exit(void)
{
	usb_deregister(&xpad_driver);
	xpad_proc_remove();
}
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.4.26/drivers/usb/xpad-mouse.c (+318 lines)
Line 0    Link Here 
/*
 * Xbox input device driver for Linux - v0.1.5
 *
 *	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
extern struct xpad_device xpad_device[];
extern int xpad_start_urb(struct usb_xpad *xpad);
extern void xpad_stop_urb(struct usb_xpad *xpad);
static int mouse_on_load = 1;
MODULE_PARM( mouse_on_load, "i" );
MODULE_PARM_DESC( mouse_on_load, "set to 0 [off] to deactivate mouse support on insmod (default 1 [on])" );
/*static*/ void xpad_mouse_proc_read_info(char *buf, char **start, off_t offset, int count, int *eof, struct usb_xpad *xpad, int *len)
{
	*len += sprintf( buf+*len, "mouse support available:\tyes\n" );
	*len += sprintf( buf+*len, "    automatically activated:\t%s\n\n",
		mouse_on_load ? "yes" : "no" );
}
/*static*/ void xpad_mouse_proc_read_unit_info(char *buf, char **start, off_t offset, int count, int *eof, struct usb_xpad *xpad, int *len)
{
	*len += sprintf( buf+*len, "mouse enabled:\t%s\n", xpad->mouse_enabled ? "yes" : "no" );
}
static int xpad_mouse_proc_read_feature_info(char *buf, char **start, off_t offset, int count, int *eof, void *data)
{
	int len = 0;
	struct usb_xpad *xpad = (struct usb_xpad *)data;
	
	len += sprintf( buf+len, "%d", xpad->mouse_enabled );
	*eof = 1;
	
	return len;
}
/*static*/ void xpad_mouse_proc_unit_create(struct usb_xpad *xpad, struct proc_dir_entry *entry)
{
	struct proc_dir_entry *tmp;
	
	/* world readable file */
	int flags = S_IFREG | S_IRUGO;
	tmp = create_proc_entry("mouse", flags, entry);
	tmp->data = xpad;
	tmp->read_proc = xpad_mouse_proc_read_feature_info;
}
/**
 *	xpad_removedeadzone
 *
 *	Franz? Please clarify and correct.
 *
 *	Removes the deadzone for mouse operation.
 *	Allows for better handling near the stick's center.
 */   
int xpad_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;
}
/*static*/ 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_removedeadzone(left_joy_x,0x1500,JOY_DeadZone_fast));
		xpad->rel_y = -(xpad_removedeadzone(left_joy_y,0x1500,JOY_DeadZone_fast));
		xyspeed = 2;
		//printk("%d:",xpad->rel_y);
	} else {
		// Ultra Slow Mode                                                 
		xpad->rel_x =  (xpad_removedeadzone(left_joy_x,0x3500,JOY_DeadZone_slow));
		xpad->rel_y = -(xpad_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_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);
}
/**
 *	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); 
	
		/*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);
}
/*static*/ int xpad_mouse_init_input_device(struct usb_device *udev, struct usb_xpad *xpad, int probedDevNum)
{
	/* the mouse device struct for the kernel (mouse emulation) */
	xpad->dev_mouse.idbus = BUS_USB;
	xpad->dev_mouse.idvendor = udev->descriptor.idVendor;
	xpad->dev_mouse.idproduct = udev->descriptor.idProduct;
	xpad->dev_mouse.idversion = udev->descriptor.bcdDevice;
	xpad->dev_mouse.private = xpad;
	xpad->dev_mouse.name = xpad_device[probedDevNum].name;
	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);
	info("Mouse Emulation %s@ %s", (mouse_on_load ? "" : "(disabled) "),
		xpad->dev_mouse.name);
}
void xpad_mouse_cleanup(struct usb_xpad *xpad)
{
	del_timer(&xpad->timer);
	input_unregister_device(&xpad->dev_mouse);
}
/**
 *	xpad_ioctl
 *
 *	Called via ioctl to change driver parameters (toggle mouse/ff support).
 *	Note that this relies on some unofficial changes to the input subsystem.
 */ 
/*static*/ int xpad_mouse_ioctl(struct input_dev *dev, unsigned int cmd, unsigned long arg)
{
	struct usb_xpad *xpad = (struct usb_xpad *) dev->private;
	switch (cmd) {
		case USB_XPAD_IOCSMOUSE:
			return get_user( xpad->mouse_enabled, (int *) arg );
		case USB_XPAD_IOCGMOUSE:
			return put_user( xpad->mouse_enabled, (int *) arg );
		default:
			return -ENOTTY;
	}
}
(-) linux-2.4.26/drivers/usb/xpad.h (+177 lines)
Line 0    Link Here 
/*
 * Xbox Controller driver for Linux - v0.1.5
 *
 *	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.5"
#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 {
	int number;
	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[XPAD_PKT_LEN];	/* input data */
	
	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;
};
/************************ mouse function stubs ************************/
#ifndef CONFIG_USB_XPAD_MOUSE
 #define mouse_open_count open_count
 #define xpad_mouse_proc_read_info(buf, start, offset, count, eof, xpad, len) {\
	*len += sprintf( buf+*len, "mouse support available:\tno\n\n" ); }
 #define xpad_mouse_proc_read_unit_info(buf, start, offset, count, eof, xpad, len) {}
 #define xpad_mouse_proc_unit_create(xpad, entry) {}
 #define xpad_mouse_process_packet(xpad, cmd, data) {}
 #define xpad_mouse_init_input_device(udev, xpad, probedDevNum) {}
 #define xpad_mouse_cleanup(xpad) {}
 #define xpad_mouse_ioctl(dev, cmd, arg) -ENOTTY
#else /* CONFIG_USB_XPAD_MOUSE */
 #ifndef __USB_XPAD_MOUSE
  extern void xpad_mouse_proc_read_info(char *buf, char **start, off_t offset, int count, int *eof, struct usb_xpad *xpad, int *len);
  extern void xpad_mouse_proc_read_unit_info(char *buf, char **start, off_t offset, int count, int *eof, struct usb_xpad *xpad, int *len);
  extern void xpad_mouse_proc_unit_create(struct usb_xpad *xpad, struct proc_dir_entry *entry);
  extern void xpad_mouse_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data);
  extern void xpad_mouse_init_input_device(struct usb_device *udev, struct usb_xpad *xpad, int probedDevNum);
  extern void xpad_mouse_cleanup(struct usb_xpad *xpad);
  extern int  xpad_mouse_ioctl(struct input_dev *dev, unsigned int cmd, unsigned long arg);
 #endif /* __USB_XPAD_MOUSE */
#endif /* CONFIG_USB_XPAD_MOUSE */
/************************ rumble function stubs ***********************/
#ifndef CONFIG_USB_XPAD_RUMBLE
 #define xpad_rumble_proc_read_info(buf, start, offset, count, eof, xpad, len) {\
	*len += sprintf( buf+*len, "rumble support available:\tno\n\n" ); }
 #define xpad_rumble_proc_read_unit_info(buf, start, offset, count, eof, xpad, len) {}
 #define xpad_rumble_proc_unit_create(xpad, entry) {}
 #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 void xpad_rumble_proc_read_info(char *buf, char **start, off_t offset, int count, int *eof, struct usb_xpad *xpad, int *len);
  extern void xpad_rumble_proc_read_unit_info(char *buf, char **start, off_t offset, int count, int *eof, struct usb_xpad *xpad, int *len);
  extern void xpad_rumble_proc_unit_create(struct usb_xpad *xpad, struct proc_dir_entry *entry);
  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.4.26/drivers/video/Config.in (-6 / +12 lines)
 Lines 12-17    Link Here 
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
      if [ "$CONFIG_PCI" = "y" ]; then
      if [ "$CONFIG_PCI" = "y" ]; then
         tristate '  nVidia Riva support (EXPERIMENTAL)' CONFIG_FB_RIVA
         tristate '  nVidia Riva support (EXPERIMENTAL)' CONFIG_FB_RIVA
         dep_tristate '  Xbox (nVidia) support (EXPERIMENTAL)' CONFIG_FB_XBOX $CONFIG_I2C_AMD756
      fi
      fi
      if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then
      if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then
	 tristate '  Cirrus Logic support (EXPERIMENTAL)' CONFIG_FB_CLGEN
	 tristate '  Cirrus Logic support (EXPERIMENTAL)' CONFIG_FB_CLGEN
 Lines 312-318    Link Here 
	   "$CONFIG_FB_TX3912" = "y" -o \
	   "$CONFIG_FB_TX3912" = "y" -o \
	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \
	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \
	   "$CONFIG_FB_STI" = "y" -o "$CONFIG_FB_HP300" = "y" -o \
	   "$CONFIG_FB_STI" = "y" -o "$CONFIG_FB_HP300" = "y" -o \
	   "$CONFIG_FB_INTEL" = "y" ]; then
	   "$CONFIG_FB_INTEL" = "y" -o "$CONFIG_FB_XBOX" = "y" ]; then
	 define_tristate CONFIG_FBCON_CFB8 y
	 define_tristate CONFIG_FBCON_CFB8 y
      else
      else
	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
 Lines 335-341    Link Here 
	      "$CONFIG_FB_RADEON" = "m" -o "$CONFIG_FB_INTEL" = "m" -o \
	      "$CONFIG_FB_RADEON" = "m" -o "$CONFIG_FB_INTEL" = "m" -o \
	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" -o \
	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" -o \
	      "$CONFIG_FB_STI" = "m" -o "$CONFIG_FB_INTEL" = "m" ]; then
	      "$CONFIG_FB_STI" = "m" -o "$CONFIG_FB_INTEL" = "m" -o \
	      "$CONFIG_FB_XBOX" = "m" ]; then
	    define_tristate CONFIG_FBCON_CFB8 m
	    define_tristate CONFIG_FBCON_CFB8 m
	 fi
	 fi
      fi
      fi
 Lines 354-360    Link Here 
	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
	   "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_INTEL" = "y" ]; then
	   "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_INTEL" = "y" -o \
	   "$CONFIG_FB_XBOX" = "y" ]; then
	 define_tristate CONFIG_FBCON_CFB16 y
	 define_tristate CONFIG_FBCON_CFB16 y
      else
      else
	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
 Lines 372-378    Link Here 
	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
	      "$CONFIG_FB_INTEL" = "m" -o \
	      "$CONFIG_FB_INTEL" = "m" -o \
	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
	      "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_INTEL" = "m" ]; then
	      "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_INTEL" = "m" -o \
	      "$CONFIG_FB_XBOX" = "m" ]; then
	    define_tristate CONFIG_FBCON_CFB16 m
	    define_tristate CONFIG_FBCON_CFB16 m
	 fi
	 fi
      fi
      fi
 Lines 405-411    Link Here 
	   "$CONFIG_FB_INTEL" = "y" -o \
	   "$CONFIG_FB_INTEL" = "y" -o \
	   "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" -o \
	   "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" -o \
	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
	   "$CONFIG_FB_STI" = "y"  -o "$CONFIG_FB_INTEL" = "y" ]; then
	   "$CONFIG_FB_STI" = "y"  -o "$CONFIG_FB_INTEL" = "y" -o \
	   "$CONFIG_FB_XBOX" = "y" ]; then
	 define_tristate CONFIG_FBCON_CFB32 y
	 define_tristate CONFIG_FBCON_CFB32 y
      else
      else
	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
 Lines 419-425    Link Here 
	      "$CONFIG_FB_INTEL" = "m" -o \
	      "$CONFIG_FB_INTEL" = "m" -o \
	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_STI" = "m" ]; then
	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_STI" = "m" -o \
	      "$CONFIG_FB_XBOX" = "m" ]; then
	    define_tristate CONFIG_FBCON_CFB32 m
	    define_tristate CONFIG_FBCON_CFB32 m
	 fi
	 fi
      fi
      fi
(-) linux-2.4.26/drivers/video/Makefile (+5 lines)
 Lines 114-119    Link Here 
obj-y				  += riva/rivafb.o
obj-y				  += riva/rivafb.o
endif
endif
subdir-$(CONFIG_FB_XBOX)	  += xbox
ifeq ($(CONFIG_FB_XBOX),y)
obj-y				  += xbox/xboxfb.o
endif
subdir-$(CONFIG_FB_SIS)		  += sis
subdir-$(CONFIG_FB_SIS)		  += sis
ifeq ($(CONFIG_FB_SIS),y)
ifeq ($(CONFIG_FB_SIS),y)
obj-y				  += sis/sisfb.o
obj-y				  += sis/sisfb.o
(-) linux-2.4.26/drivers/video/fbmem.c (+5 lines)
 Lines 114-119    Link Here 
extern int sun3fb_setup(char *);
extern int sun3fb_setup(char *);
extern int sgivwfb_init(void);
extern int sgivwfb_init(void);
extern int sgivwfb_setup(char*);
extern int sgivwfb_setup(char*);
extern int xboxfb_init(void);
extern int xboxfb_setup(char*);
extern int rivafb_init(void);
extern int rivafb_init(void);
extern int rivafb_setup(char*);
extern int rivafb_setup(char*);
extern int tdfxfb_init(void);
extern int tdfxfb_init(void);
 Lines 203-208    Link Here 
#ifdef CONFIG_FB_RIVA
#ifdef CONFIG_FB_RIVA
	{ "riva", rivafb_init, rivafb_setup },
	{ "riva", rivafb_init, rivafb_setup },
#endif
#endif
#ifdef CONFIG_FB_XBOX
	{ "xbox", xboxfb_init, xboxfb_setup },
#endif
#ifdef CONFIG_FB_RADEON
#ifdef CONFIG_FB_RADEON
	{ "radeon", radeonfb_init, radeonfb_setup },
	{ "radeon", radeonfb_init, radeonfb_setup },
#endif
#endif
(-) linux-2.4.26/drivers/video/xbox/Makefile (+15 lines)
Line 0    Link Here 
#
# Makefile for the Xbox framebuffer driver
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := xboxfb.o
obj-y    := fbdev.o riva_hw.o accel.o encoder-i2c.o encoder.o conexant.o focus.o xlb.o
obj-m    := $(O_TARGET)
include $(TOPDIR)/Rules.make
(-) linux-2.4.26/drivers/video/xbox/accel.c (+429 lines)
Line 0    Link Here 
/*
 * linux/drivers/video/accel.c - nVidia RIVA 128/TNT/TNT2 fb driver
 *
 * Copyright 2000 Jindrich Makovicka, Ani Joshi
 *
 * 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.
 */
#include "xboxfb.h"
/* acceleration routines */
inline void wait_for_idle(struct rivafb_info *rinfo)
{
	while (rinfo->riva.Busy(&rinfo->riva));
}
/* set copy ROP, no mask */
static void riva_setup_ROP(struct rivafb_info *rinfo)
{
	RIVA_FIFO_FREE(rinfo->riva, Patt, 5);
	rinfo->riva.Patt->Shape = 0;
	rinfo->riva.Patt->Color0 = 0xffffffff;
	rinfo->riva.Patt->Color1 = 0xffffffff;
	rinfo->riva.Patt->Monochrome[0] = 0xffffffff;
	rinfo->riva.Patt->Monochrome[1] = 0xffffffff;
	RIVA_FIFO_FREE(rinfo->riva, Rop, 1);
	rinfo->riva.Rop->Rop3 = 0xCC;
}
void riva_setup_accel(struct rivafb_info *rinfo)
{
	RIVA_FIFO_FREE(rinfo->riva, Clip, 2);
	rinfo->riva.Clip->TopLeft     = 0x0;
	rinfo->riva.Clip->WidthHeight = 0x80008000;
	riva_setup_ROP(rinfo);
	wait_for_idle(rinfo);
}
static void riva_rectfill(struct rivafb_info *rinfo, int sy,
			  int sx, int height, int width, u_int color)
{
	RIVA_FIFO_FREE(rinfo->riva, Bitmap, 1);
	rinfo->riva.Bitmap->Color1A = color;
	RIVA_FIFO_FREE(rinfo->riva, Bitmap, 2);
	rinfo->riva.Bitmap->UnclippedRectangle[0].TopLeft     = (sx << 16) | sy; 
	rinfo->riva.Bitmap->UnclippedRectangle[0].WidthHeight = (width << 16) | height;
}
static void fbcon_riva_bmove(struct display *p, int sy, int sx, int dy, int dx,
			    int height, int width)
{
	struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
	sx *= fontwidth(p);
	sy *= fontheight(p);
	dx *= fontwidth(p);
	dy *= fontheight(p);
	width *= fontwidth(p);
	height *= fontheight(p);
	RIVA_FIFO_FREE(rinfo->riva, Blt, 3);
	rinfo->riva.Blt->TopLeftSrc  = (sy << 16) | sx;
	rinfo->riva.Blt->TopLeftDst  = (dy << 16) | dx;
	rinfo->riva.Blt->WidthHeight = (height  << 16) | width;
	wait_for_idle(rinfo);
}
static void riva_clear_margins(struct vc_data *conp, struct display *p,
				int bottom_only, u32 bgx)
{
	struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
	unsigned int right_start = conp->vc_cols*fontwidth(p);
	unsigned int bottom_start = conp->vc_rows*fontheight(p);
	unsigned int right_width, bottom_width;
	if (!bottom_only && (right_width = p->var.xres - right_start))
		riva_rectfill(rinfo, 0, right_start, p->var.yres_virtual,
			      right_width, bgx);
	if ((bottom_width = p->var.yres - bottom_start))
		riva_rectfill(rinfo, p->var.yoffset + bottom_start, 0,
			      bottom_width, right_start, bgx);
}
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 fbcon_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];
}
static void fbcon_riva_writechr(struct vc_data *conp, struct display *p,
			        int c, int fgx, int bgx, int yy, int xx)
{
	u8 *cdat;
	struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
	int w, h;
	volatile u32 *d;
	u32 cdat2;
	int i, j, cnt;
	w = fontwidth(p);
	h = fontheight(p);
	if (w <= 8)
		cdat = p->fontdata + (c & p->charmask) * h;
	else
		cdat = p->fontdata + ((c & p->charmask) * h << 1);
        RIVA_FIFO_FREE(rinfo->riva, Bitmap, 7);
        rinfo->riva.Bitmap->ClipE.TopLeft     = (yy << 16) | (xx & 0xFFFF);
        rinfo->riva.Bitmap->ClipE.BottomRight = ((yy+h) << 16) | ((xx+w) & 0xffff);
        rinfo->riva.Bitmap->Color0E           = bgx;
        rinfo->riva.Bitmap->Color1E           = fgx;
        rinfo->riva.Bitmap->WidthHeightInE  = (h << 16) | 32;
        rinfo->riva.Bitmap->WidthHeightOutE = (h << 16) | 32;
        rinfo->riva.Bitmap->PointE          = (yy << 16) | (xx & 0xFFFF);
	
	d = &rinfo->riva.Bitmap->MonochromeData01E;
	for (i = h; i > 0; i-=16) {
		if (i >= 16)
			cnt = 16;
		else
			cnt = i;
		RIVA_FIFO_FREE(rinfo->riva, Bitmap, cnt);
		for (j = 0; j < cnt; j++) {
			if (w <= 8) 
				cdat2 = *cdat++;
			else
				cdat2 = *((u16*)cdat)++;
			fbcon_reverse_order(&cdat2);
			d[j] = cdat2;
		}
	}
}
#ifdef FBCON_HAS_CFB8
void fbcon_riva8_setup(struct display *p)
{
    p->next_line = p->line_length ? p->line_length : p->var.xres_virtual;
    p->next_plane = 0;
}
static void fbcon_riva8_clear(struct vc_data *conp, struct display *p, int sy,
			     int sx, int height, int width)
{
	u32 bgx;
	struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
	bgx = attr_bgcol_ec(p, conp);
	sx *= fontwidth(p);
	sy *= fontheight(p);
	width *= fontwidth(p);
	height *= fontheight(p);
	riva_rectfill(rinfo, sy, sx, height, width, bgx);
}
static void fbcon_riva8_putc(struct vc_data *conp, struct display *p, int c,
			    int yy, int xx)
{
	u32 fgx,bgx;
	fgx = attr_fgcol(p,c);
	bgx = attr_bgcol(p,c);
	
	xx *= fontwidth(p);
	yy *= fontheight(p);
	fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
}
static void fbcon_riva8_putcs(struct vc_data *conp, struct display *p,
			     const unsigned short *s, int count, int yy,
			     int xx)
{
	u16 c;
	u32 fgx,bgx;
	xx *= fontwidth(p);
	yy *= fontheight(p);
	c = scr_readw(s);
	fgx = attr_fgcol(p, c);
	bgx = attr_bgcol(p, c);
	while (count--) {
		c = scr_readw(s++);
		fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
		xx += fontwidth(p);
	}
}
static void fbcon_riva8_revc(struct display *p, int xx, int yy)
{
	struct rivafb_info *rinfo = (struct rivafb_info *) (p->fb_info);
	xx *= fontwidth(p);
	yy *= fontheight(p);
	RIVA_FIFO_FREE(rinfo->riva, Rop, 1);
	rinfo->riva.Rop->Rop3 = 0x66; // XOR
	riva_rectfill(rinfo, yy, xx, fontheight(p), fontwidth(p), 0x0f);
	RIVA_FIFO_FREE(rinfo->riva, Rop, 1);
	rinfo->riva.Rop->Rop3 = 0xCC; // back to COPY
}
static void fbcon_riva8_clear_margins(struct vc_data *conp, struct display *p,
				       int bottom_only)
{
	riva_clear_margins(conp, p, bottom_only, attr_bgcol_ec(p, conp));
}
struct display_switch fbcon_riva8 = {
	.setup		= fbcon_riva8_setup,
	.bmove		= fbcon_riva_bmove,
	.clear		= fbcon_riva8_clear,
	.putc		= fbcon_riva8_putc,
	.putcs		= fbcon_riva8_putcs,
	.revc		= fbcon_riva8_revc,
	.clear_margins	= fbcon_riva8_clear_margins,
	.fontwidthmask	= FONTWIDTHRANGE(4, 16)
};
#endif
#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
static void fbcon_riva1632_revc(struct display *p, int xx, int yy)
{
	struct rivafb_info *rinfo = (struct rivafb_info *) (p->fb_info);
	xx *= fontwidth(p);
	yy *= fontheight(p);
	RIVA_FIFO_FREE(rinfo->riva, Rop, 1);
	rinfo->riva.Rop->Rop3 = 0x66; // XOR
	riva_rectfill(rinfo, yy, xx, fontheight(p), fontwidth(p), 0xffffffff);
	RIVA_FIFO_FREE(rinfo->riva, Rop, 1);
	rinfo->riva.Rop->Rop3 = 0xCC; // back to COPY
}
#endif
#ifdef FBCON_HAS_CFB16
void fbcon_riva16_setup(struct display *p)
{
    p->next_line = p->line_length ? p->line_length : p->var.xres_virtual<<1;
    p->next_plane = 0;
}
static void fbcon_riva16_clear(struct vc_data *conp, struct display *p, int sy,
			     int sx, int height, int width)
{
	u32 bgx;
	struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
	bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
	sx *= fontwidth(p);
	sy *= fontheight(p);
	width *= fontwidth(p);
	height *= fontheight(p);
	riva_rectfill(rinfo, sy, sx, height, width, bgx);
}
static inline void convert_bgcolor_16(u32 *col)
{
	*col = ((*col & 0x00007C00) << 9)
             | ((*col & 0x000003E0) << 6)
             | ((*col & 0x0000001F) << 3)
             |          0xFF000000;
}
static void fbcon_riva16_putc(struct vc_data *conp, struct display *p, int c,
			    int yy, int xx)
{
	u32 fgx,bgx;
	fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p,c)];
	bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p,c)];
	if (p->var.green.length == 6)
		convert_bgcolor_16(&bgx);
	xx *= fontwidth(p);
	yy *= fontheight(p);
	fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
}
static void fbcon_riva16_putcs(struct vc_data *conp, struct display *p,
			     const unsigned short *s, int count, int yy,
			     int xx)
{
	u16 c;
	u32 fgx,bgx;
	xx *= fontwidth(p);
	yy *= fontheight(p);
	c = scr_readw(s);
	fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
	bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
	if (p->var.green.length == 6)
		convert_bgcolor_16(&bgx);
	while (count--) {
		c = scr_readw(s++);
		fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
		xx += fontwidth(p);
	}
}
static void fbcon_riva16_clear_margins(struct vc_data *conp, struct display *p,
				       int bottom_only)
{
	riva_clear_margins(conp, p, bottom_only, ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]);
}
struct display_switch fbcon_riva16 = {
	.setup		= fbcon_riva16_setup,
	.bmove		= fbcon_riva_bmove,
	.clear		= fbcon_riva16_clear,
	.putc		= fbcon_riva16_putc,
	.putcs		= fbcon_riva16_putcs,
	.revc		= fbcon_riva1632_revc,
	.clear_margins	= fbcon_riva16_clear_margins,
	.fontwidthmask	= FONTWIDTHRANGE(4, 16)
};
#endif
#ifdef FBCON_HAS_CFB32
void fbcon_riva32_setup(struct display *p)
{
    p->next_line = p->line_length ? p->line_length : p->var.xres_virtual<<2;
    p->next_plane = 0;
}
static void fbcon_riva32_clear(struct vc_data *conp, struct display *p, int sy,
			     int sx, int height, int width)
{
	u32 bgx;
	struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
	bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
	sx *= fontwidth(p);
	sy *= fontheight(p);
	width *= fontwidth(p);
	height *= fontheight(p);
	riva_rectfill(rinfo, sy, sx, height, width, bgx);
}
static void fbcon_riva32_putc(struct vc_data *conp, struct display *p, int c,
			    int yy, int xx)
{
	u32 fgx,bgx;
	fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p,c)];
	bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p,c)];
	xx *= fontwidth(p);
	yy *= fontheight(p);
	fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
}
static void fbcon_riva32_putcs(struct vc_data *conp, struct display *p,
			     const unsigned short *s, int count, int yy,
			     int xx)
{
	u16 c;
	u32 fgx,bgx;
	xx *= fontwidth(p);
	yy *= fontheight(p);
	c = scr_readw(s);
	fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)];
	bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
	while (count--) {
		c = scr_readw(s++);
		fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
		xx += fontwidth(p);
	}
}
static void fbcon_riva32_clear_margins(struct vc_data *conp, struct display *p,
				       int bottom_only)
{
	riva_clear_margins(conp, p, bottom_only, ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]);
}
struct display_switch fbcon_riva32 = {
	.setup		= fbcon_riva32_setup,
	.bmove		= fbcon_riva_bmove,
	.clear		= fbcon_riva32_clear,
	.putc		= fbcon_riva32_putc,
	.putcs		= fbcon_riva32_putcs,
	.revc		= fbcon_riva1632_revc,
	.clear_margins	= fbcon_riva32_clear_margins,
	.fontwidthmask	= FONTWIDTHRANGE(4, 16)
};
#endif
(-) linux-2.4.26/drivers/video/xbox/conexant.c (+642 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,
	int dotClock,
	unsigned char * regs
){
	unsigned char pll_int = (unsigned char)((double)dotClock * 6.0 / 13.5e3 + 0.5);
			
	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,
	int dotClock,
	unsigned char * regs
){
	unsigned char pll_int = (unsigned char)((double)dotClock * 6.0 / 13.5e3 + 0.5);
	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.4.26/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, int dotClock, unsigned char * mode_out);
int conexant_calc_hdtv_mode(xbox_hdtv_mode hdtv_mode, int dotClock, unsigned char * mode_out);
#endif
(-) linux-2.4.26/drivers/video/xbox/encoder-i2c.c (+229 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>
#include <linux/xbox.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_amd756_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_amd756_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_read_block(unsigned char adr, unsigned char *data) {
	if (!xlb_client.adapter) {
		printk(KERN_ERR DRIVER_NAME " : No XLB client attached.\n");
		return -1;
	}
	udelay(500);
	return i2c_smbus_read_block_data(&xlb_client, adr, data);
}
int xlb_i2c_write_block(unsigned char adr, unsigned char *data, int len) {
	if (!xlb_client.adapter) {
		printk(KERN_ERR DRIVER_NAME " : No XLB client attached.\n");
		return -1;
	}
	udelay(500);
	return i2c_smbus_write_block_data(&xlb_client, adr, len, data);
}
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);
}
int pic_i2c_write_reg(unsigned char adr, unsigned char value) {
	if (!pic_client.adapter) {
		printk(KERN_ERR DRIVER_NAME " : No pic client attached.\n");
		return -1;
	}
	udelay(500);
	i2c_smbus_write_byte_data(&pic_client, adr, value);
	udelay(500);
}
unsigned char set_led(unsigned char mode, unsigned char color) {
	pic_i2c_write_reg(SMC_CMD_LED_MODE,mode);
        return pic_i2c_write_reg(SMC_CMD_LED_REGISTER,color);
}
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.4.26/drivers/video/xbox/encoder-i2c.h (+33 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_read_block(unsigned char adr, unsigned char *data);
int xlb_i2c_write_block(unsigned char adr, unsigned char *data, int len);
unsigned char pic_i2c_read_reg(unsigned char adr);
unsigned char set_led(unsigned char mode, unsigned char color);
unsigned char eeprom_i2c_read(unsigned char adr);
#endif
(-) linux-2.4.26/drivers/video/xbox/encoder.c (+195 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 "xcalibur.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(0x01);
	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;
	unsigned char data[4];
	
	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:
			switch(get_tv_encoding()) {
				case TV_ENC_PALBDGHI:
					for(n = 0; n < sizeof(xlb_regs); n++) {
						memset(data, 0x00, 0x04);
						memcpy(data, &XCal_Vals_PAL[n], 0x04);
						xlb_i2c_write_block(xlb_regs[n], data, 0x04);
					}
					break;
				case TV_ENC_NTSC:
				default:	// Default to NTSC
					for(n = 0; n < sizeof(xlb_regs); n++) {
						memset(data, 0x00, 0x04);
						memcpy(data, &XCal_Vals_NTSC[n], 0x04);
						xlb_i2c_write_block(xlb_regs[n], data, 0x04);
					}
					break;
			}
			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) {
	if (eeprom_value == 0x80) {
		enc = TV_ENC_PALBDGHI;
	}
	else {
		enc = TV_ENC_NTSC;
	}
	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.4.26/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.4.26/drivers/video/xbox/fbdev.c (+2635 lines)
Line 0    Link Here 
/*
 * linux/drivers/video/xbox/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver
 *
 * Maintained by Oliver Schwartz <Oliver.Schwartz@gmx.de>
 *
 * 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
 *
 * 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
 *	option 'noaccel' has no effect
 */
#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/selection.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>
#include <linux/console.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.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"
#ifndef CONFIG_PCI		/* sanity check */
#error This driver requires PCI support.
#endif
/* version number of this driver */
#define RIVAFB_VERSION "0.9.6-xbox"
/* ------------------------------------------------------------------------- *
 *
 * 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 DEFAULT_CURSOR_BLINK_RATE	(40)
#define CURSOR_HIDE_DELAY		(20)
#define CURSOR_SHOW_DELAY		(3)
#define CURSOR_COLOR		0x7fff
#define TRANSPARENT_COLOR	0x0000
#define MAX_CURS		32
/* ------------------------------------------------------------------------- *
 *
 * prototypes
 *
 * ------------------------------------------------------------------------- */
static void rivafb_blank(int blank, struct fb_info *info);
extern void riva_setup_accel(struct rivafb_info *rinfo);
extern inline void wait_for_idle(struct rivafb_info *rinfo);
/* ------------------------------------------------------------------------- *
 *
 * card identification
 *
 * ------------------------------------------------------------------------- */
enum xbox_chips {
	CH_GEFORCE3_XBOX
};
/* directly indexed by xbox_chips enum, above */
static struct riva_chip_info {
	const char *name;
	unsigned arch_rev;
} riva_chip_info[] __devinitdata = {
	{ "GeForce3-Xbox", NV_ARCH_20}
};
static struct pci_device_id rivafb_pci_tbl[] __devinitdata = {
        { PCI_VENDOR_ID_NVIDIA, 0x2a0,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_XBOX },
	{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);
/* ------------------------------------------------------------------------- *
 *
 * framebuffer related structures
 *
 * ------------------------------------------------------------------------- */
#ifdef FBCON_HAS_CFB8
extern struct display_switch fbcon_riva8;
#endif
#ifdef FBCON_HAS_CFB16
extern struct display_switch fbcon_riva16;
#endif
#ifdef FBCON_HAS_CFB32
extern struct display_switch fbcon_riva32;
#endif
#if 0
/* describes the state of a Riva board */
struct rivafb_par {
	struct riva_regs state;	/* state of hw board */
	__u32 visual;		/* FB_VISUAL_xxx */
	unsigned depth;		/* bpp of current mode */
};
#endif
struct riva_cursor {
	int enable;
	int on;
	int vbl_cnt;
	int last_move_delay;
	int blink_rate;
	struct {
		u16 x, y;
	} pos, size;
	unsigned short image[MAX_CURS*MAX_CURS];
	struct timer_list *timer;
};
/* ------------------------------------------------------------------------- *
 *
 * global variables
 *
 * ------------------------------------------------------------------------- */
struct rivafb_info *riva_boards = NULL;
/* command line data, set in xboxfb_setup() */
static char fontname[40] __initdata = { 0 };
static char noaccel __initdata = 0;
static char nomove = 0;
static char nohwcursor __initdata = 1;
static char noblink = 0;
static unsigned long fb_start __initdata = 0;
static unsigned long fb_size __initdata = 0;
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;
//#ifdef MODULE
//static char *fb_mem = NULL;
//static char *tv = NULL;
//#endif
#ifdef CONFIG_MTRR
static char nomtrr __initdata = 0;
#endif
static char *mode_option __initdata = NULL;
static struct fb_var_screeninfo xboxfb_mode_640x480 = {
	.xres		= 640,
	.yres		= 480,
	.xres_virtual	= 640,
	.yres_virtual	= 480,
	.xoffset	= 0,
	.yoffset	= 0,
	.bits_per_pixel	= 8,
	.grayscale	= 0,
	.red		= {0, 6, 0},
	.green		= {0, 6, 0},
	.blue		= {0, 6, 0},
	.transp		= {0, 0, 0},
	.nonstd		= 0,
	.activate	= 0,
	.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,
	.sync		= 0,
	.vmode		= FB_VMODE_NONINTERLACED
};
static struct fb_var_screeninfo xboxfb_mode_800x600 = {
	.xres		= 800,
	.yres		= 600,
	.xres_virtual	= 800,
	.yres_virtual	= 600,
	.xoffset	= 0,
	.yoffset	= 0,
	.bits_per_pixel	= 16,
	.grayscale	= 0,
	.red		= {0, 5, 10},
	.green		= {0, 5, 5},
	.blue		= {0, 5, 0},
	.transp		= {0, 0, 0},
	.nonstd		= 0,
	.activate	= 0,
	.height		= -1,
	.width		= -1,
	.accel_flags	= FB_ACCELF_TEXT,
	.pixclock	= 22000,
	.left_margin	= 135,
	.right_margin	= 124,
	.upper_margin	= 55,
	.lower_margin	= 27,
	.hsync_len	= 136,
	.vsync_len	= 84,
	.sync		= 0,
	.vmode		= FB_VMODE_NONINTERLACED
};
static struct fb_var_screeninfo xboxfb_mode_480p = {
	.xres		= 720,
	.yres		= 480,
	.xres_virtual	= 720,
	.yres_virtual	= 480,
	.xoffset	= 0,
	.yoffset	= 0,
	.bits_per_pixel	= 32,
	.grayscale	= 0,
	.red		= {0, 8, 16},
	.green		= {0, 8, 8},
	.blue		= {0, 8, 0},
	.transp		= {0, 0, 0},
	.nonstd		= 0,
	.activate	= 0,
	.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,
	.sync		= 0,
	.vmode		= FB_VMODE_NONINTERLACED
};
static struct fb_var_screeninfo xboxfb_mode_720p = {
	.xres		= 1280,
	.yres		= 720,
	.xres_virtual	= 1280,
	.yres_virtual	= 720,
	.xoffset	= 0,
	.yoffset	= 0,
	.bits_per_pixel	= 8,
	.grayscale	= 0,
	.red		= {0, 6, 0},
	.green		= {0, 6, 0},
	.blue		= {0, 6, 0},
	.transp		= {0, 0, 0},
	.nonstd		= 0,
	.activate	= 0,
	.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,
	.sync		= 0,
	.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 */
};
static const struct riva_regs xlbRegs[] = {
{
	{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	/* ATTR */
	 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
	 0x41, 0x01, 0x0F, 0x00, 0x00},
	 
	{0x5d ,0x4f ,0x4f ,0x9c ,0x54 ,0x35 ,0x0b ,0x3e ,0x00 ,0x40 , // NTSC
	0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0xe9 ,0x0e ,0xdf ,0x40 ,
	0x00 ,0xdf ,0x0c ,0xe3 ,0xff ,0x30 ,0x3a ,0x05 ,0x00 ,0x00 ,
	0x00 ,0x03 ,0x29 ,0xfe ,0x9b ,0xa1 ,0x80 ,0x10 ,0x14 ,0xd3 ,
	0x83 ,0x00 ,0x00 ,0x7d ,0x9c ,0xe0 ,0x00 ,0x00 ,0x00 ,0x00 ,
	0x00 ,0x11 ,0x02 ,0x02 ,0x21 ,0x30 ,0x00 ,0xff ,0xf3 ,0xdf ,
	0xef ,0x00 ,0x23 ,0x30 ,0x00 ,
	},
	
	{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,	/* GRA  */
	 0xFF},
	{0x03, 0x01, 0x0F, 0x00, 0x0E},				/* SEQ  */
	0xEB							/* MISC */
},
{
	{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	/* ATTR */
	 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
	 0x41, 0x01, 0x0F, 0x00, 0x00},
	 {0x5f ,0x4f ,0x4f ,0x80 ,0x55 ,0xb9 ,0x06 ,0x3e ,0x00 ,0x40 ,	//PAL
	0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0xeb ,0x0e ,0xdf ,0x40 ,
	0x00 ,0xdf ,0x0c ,0xe3 ,0xff ,0x30 ,0x3a ,0x05 ,0x00 ,0x00 ,
	0x00 ,0x03 ,0x29 ,0xfe ,0xdb ,0xa1 ,0x00 ,0x10 ,0x20 ,0xd3 ,
	0x83 ,0x00 ,0x00 ,0x7d ,0x9c ,0xe0 ,0x00 ,0x00 ,0x00 ,0x00 ,
	0x00 ,0x11 ,0x02 ,0x02 ,0x21 ,0x30 ,0x00 ,0xff ,0xf3 ,0xcf ,
	0xef ,0x00 ,0x23 ,0x30 ,0x00 ,
	 },
	{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 rivafb_info *rinfo, unsigned char index,
			   unsigned char val)
{
	VGA_WR08(rinfo->riva.PCIO, 0x3d4, index);
	VGA_WR08(rinfo->riva.PCIO, 0x3d5, val);
}
static inline unsigned char CRTCin(struct rivafb_info *rinfo,
				   unsigned char index)
{
	VGA_WR08(rinfo->riva.PCIO, 0x3d4, index);
	return (VGA_RD08(rinfo->riva.PCIO, 0x3d5));
}
static inline void GRAout(struct rivafb_info *rinfo, unsigned char index,
			  unsigned char val)
{
	VGA_WR08(rinfo->riva.PVIO, 0x3ce, index);
	VGA_WR08(rinfo->riva.PVIO, 0x3cf, val);
}
static inline unsigned char GRAin(struct rivafb_info *rinfo,
				  unsigned char index)
{
	VGA_WR08(rinfo->riva.PVIO, 0x3ce, index);
	return (VGA_RD08(rinfo->riva.PVIO, 0x3cf));
}
static inline void SEQout(struct rivafb_info *rinfo, unsigned char index,
			  unsigned char val)
{
	VGA_WR08(rinfo->riva.PVIO, 0x3c4, index);
	VGA_WR08(rinfo->riva.PVIO, 0x3c5, val);
}
static inline unsigned char SEQin(struct rivafb_info *rinfo,
				  unsigned char index)
{
	VGA_WR08(rinfo->riva.PVIO, 0x3c4, index);
	return (VGA_RD08(rinfo->riva.PVIO, 0x3c5));
}
static inline void ATTRout(struct rivafb_info *rinfo, unsigned char index,
			   unsigned char val)
{
	VGA_WR08(rinfo->riva.PCIO, 0x3c0, index);
	VGA_WR08(rinfo->riva.PCIO, 0x3c0, val);
}
static inline unsigned char ATTRin(struct rivafb_info *rinfo,
				   unsigned char index)
{
	VGA_WR08(rinfo->riva.PCIO, 0x3c0, index);
	return (VGA_RD08(rinfo->riva.PCIO, 0x3c1));
}
static inline void MISCout(struct rivafb_info *rinfo, unsigned char val)
{
	VGA_WR08(rinfo->riva.PVIO, 0x3c2, val);
}
static inline unsigned char MISCin(struct rivafb_info *rinfo)
{
	return (VGA_RD08(rinfo->riva.PVIO, 0x3cc));
}
/* ------------------------------------------------------------------------- *
 *
 * cursor stuff
 *
 * ------------------------------------------------------------------------- */
/**
 * riva_cursor_timer_handler - blink timer
 * @dev_addr: pointer to rivafb_info object containing info for current riva board
 *
 * DESCRIPTION:
 * Cursor blink timer.
 */
static void riva_cursor_timer_handler(unsigned long dev_addr)
{
	struct rivafb_info *rinfo = (struct rivafb_info *)dev_addr;
	if (!rinfo->cursor) return;
	if (!rinfo->cursor->enable) goto out;
	if (rinfo->cursor->last_move_delay < 1000)
		rinfo->cursor->last_move_delay++;
	if (rinfo->cursor->vbl_cnt && --rinfo->cursor->vbl_cnt == 0) {
		rinfo->cursor->on ^= 1;
		if (rinfo->cursor->on)
			*(rinfo->riva.CURSORPOS) = (rinfo->cursor->pos.x & 0xFFFF)
						   | (rinfo->cursor->pos.y << 16);
		rinfo->riva.ShowHideCursor(&rinfo->riva, rinfo->cursor->on);
		if (!noblink)
			rinfo->cursor->vbl_cnt = rinfo->cursor->blink_rate;
	}
out:
	rinfo->cursor->timer->expires = jiffies + (HZ / 100);
	add_timer(rinfo->cursor->timer);
}
/**
 * rivafb_init_cursor - allocates cursor structure and starts blink timer
 * @rinfo: pointer to rivafb_info object containing info for current riva board
 *
 * DESCRIPTION:
 * Allocates cursor structure and starts blink timer.
 *
 * RETURNS:
 * Pointer to allocated cursor structure.
 *
 * CALLED FROM:
 * rivafb_init_one()
 */
static struct riva_cursor * __init rivafb_init_cursor(struct rivafb_info *rinfo)
{
	struct riva_cursor *cursor;
	cursor = kmalloc(sizeof(struct riva_cursor), GFP_KERNEL);
	if (!cursor) return 0;
	memset(cursor, 0, sizeof(*cursor));
	cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL);
	if (!cursor->timer) {
		kfree(cursor);
		return 0;
	}
	memset(cursor->timer, 0, sizeof(*cursor->timer));
	cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
	init_timer(cursor->timer);
	cursor->timer->expires = jiffies + (HZ / 100);
	cursor->timer->data = (unsigned long)rinfo;
	cursor->timer->function = riva_cursor_timer_handler;
	add_timer(cursor->timer);
	return cursor;
}
/**
 * rivafb_exit_cursor - stops blink timer and releases cursor structure
 * @rinfo: pointer to rivafb_info object containing info for current riva board
 *
 * DESCRIPTION:
 * Stops blink timer and releases cursor structure.
 *
 * CALLED FROM:
 * rivafb_init_one()
 * rivafb_remove_one()
 */
static void rivafb_exit_cursor(struct rivafb_info *rinfo)
{
	struct riva_cursor *cursor = rinfo->cursor;
	if (cursor) {
		if (cursor->timer) {
			del_timer_sync(cursor->timer);
			kfree(cursor->timer);
		}
		kfree(cursor);
		rinfo->cursor = 0;
	}
}
/**
 * rivafb_download_cursor - writes cursor shape into card registers
 * @rinfo: pointer to rivafb_info object containing info for current riva board
 *
 * DESCRIPTION:
 * Writes cursor shape into card registers.
 *
 * CALLED FROM:
 * riva_load_video_mode()
 */
static void rivafb_download_cursor(struct rivafb_info *rinfo)
{
	int i, save;
	int *image;
	
	if (!rinfo->cursor) return;
	image = (int *)rinfo->cursor->image;
	save = rinfo->riva.ShowHideCursor(&rinfo->riva, 0);
	for (i = 0; i < (MAX_CURS*MAX_CURS*2)/sizeof(int); i++)
		writel(image[i], rinfo->riva.CURSOR + i);
	rinfo->riva.ShowHideCursor(&rinfo->riva, save);
}
/**
 * rivafb_create_cursor - sets rectangular cursor
 * @rinfo: pointer to rivafb_info object containing info for current riva board
 * @width: cursor width in pixels
 * @height: cursor height in pixels
 *
 * DESCRIPTION:
 * Sets rectangular cursor.
 *
 * CALLED FROM:
 * rivafb_set_font()
 * rivafb_set_var()
 */
static void rivafb_create_cursor(struct rivafb_info *rinfo, int width, int height)
{
	struct riva_cursor *c = rinfo->cursor;
	int i, j, idx;
	if (c) {
		if (width <= 0 || height <= 0) {
			width = 8;
			height = 16;
		}
		if (width > MAX_CURS) width = MAX_CURS;
		if (height > MAX_CURS) height = MAX_CURS;
		c->size.x = width;
		c->size.y = height;
		
		idx = 0;
		for (i = 0; i < height; i++) {
			for (j = 0; j < width; j++,idx++)
				c->image[idx] = CURSOR_COLOR;
			for (j = width; j < MAX_CURS; j++,idx++)
				c->image[idx] = TRANSPARENT_COLOR;
		}
		for (i = height; i < MAX_CURS; i++)
			for (j = 0; j < MAX_CURS; j++,idx++)
				c->image[idx] = TRANSPARENT_COLOR;
	}</