Re: Some coordination

Free The Cube <[email protected]>
Newsgroups gmane.linux.ports.game-cube.devel
Message-ID <[email protected]>
Michael Steil wrote:
> On 23.01.2004, at 09:49, Free The Cube wrote:
> 
>> You're right :) !!!! But the "temporary" driver is written :), it need 
>> more tests (it's a port of the GCLIB driver so it should work 
>> correclty (i hope) :)
>> I will work on the SI driver...
> 
> 
> Great. Jut send a kernel patch (preferably 2.6.1) to the mailing list 
> and we'll put it in the CVS for everyone to see it.
> ...and you need an SF CVS account yourself then.
> 

I can't send you a patch against 2.6.1, I'm at my work office ;) (no 
kernel sources, and can't spend time to download, test, ...) but I can 
send you the source file tested with linux 2.4.XX :) !

In my version, there are 2 parts :
  - the GCPAD driver
  - some functions (not finished) to test it with my 86 box...
I removed the last one in the attached file.

We still must adjust some values such as 'gcpad[i].dev.absmin' 
'gcpad[i].dev.absmax' !!! If i remember correctly, the trigger values go 
from -32767 to 32768, it is not really what we want (0 to 32768).

This driver (if it works :) ) is not really good :
  - the active loop wastes CPU time, even if i didn't feel this into my 
x86 box.
  - it doesn't use the SI layer
  - and the worst : it is not tested :) !

let us not be so pessimistic : it uses the standart input layer :D...

Free The Cube.
gcpad.c (text/x-csrc, 8.4 KB)
/*
 * Based on GCLIB (Free GameCube SDK Libraries) by costis
 * GC_PAD.c by CrowTRobo and tmbinc
 */
/*
 * Based on the PSX gamepad driver for Linux
 * gamecon.c Copyright (c) 1999-2001 Vojtech Pavlik
 */
/*
 * Ported by Free The Cube <[email protected]>
 * GameCube joystick device driver for the input driver suite.
 */

/*
 * 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 <[email protected]>
 */

#include <linux/config.h> //CONFIG_*
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h> //module_init(), module_exit()
#include <linux/ioport.h> //struct resource
#include <linux/errno.h> //EBUSY
#include <linux/delay.h> //udelay()
#include <linux/slab.h> //kmalloc(), kfree()
#include <linux/input.h>

#ifdef CONFIG_SMP
#define __SMP__
#endif //CONFIG_SMP

#define GCPAD_LEFT        0x0001
#define GCPAD_RIGHT       0x0002
#define GCPAD_DOWN        0x0004
#define GCPAD_UP          0x0008
#define GCPAD_Z           0x0010
#define GCPAD_R           0x0020
#define GCPAD_L           0x0040
#define GCPAD_A           0x0100
#define GCPAD_B           0x0200
#define GCPAD_X           0x0400
#define GCPAD_Y           0x0800
#define GCPAD_START       0x1000

#define GCPAD_SI_BASE	(0xCC006400)
#define GCPAD_CHANNEL(chan)	(GCPAD_SI_BASE+(chan*12))
#define GCPAD_REFRESH_TIME	HZ/50

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GameCube joystick device driver");
MODULE_SUPPORTED_DEVICE("Simple controller");

static void gcpad_timer(unsigned long private);
static int gcpad_open(struct input_dev *dev);
static void gcpad_close(struct input_dev *dev);

struct gcpad_dev
{
	struct input_dev dev;
	short number;
	struct timer_list timer;
	int count;
};

static struct gcpad_dev *gcpad;

static short gcpad_btn[] = { BTN_A, BTN_B,
			     BTN_X, BTN_Y, BTN_Z,
			     BTN_TL, BTN_TR,
			     BTN_START
			    };
static short gcpad_abs[] = { ABS_X, ABS_Y, // Main joystick
			     ABS_RX, ABS_RY, // C-stick
			     ABS_HAT0X, ABS_HAT0Y, // Trigger left and right
			     ABS_HAT1X ,ABS_HAT1Y // Digital axes
			    };

// Memory map for joypad (TODO : confirmations needed !) :
// Lower = 0xCC006400
// Upper = 0xCC006480
static struct resource gcpad_resource = {
	"gcpad",
	0xCC006400,
	0xCC006480,
	IORESOURCE_MEM|IORESOURCE_BUSY
};

static int __init gcpad_init(void)
{
	int i,j;

	// Get the memory where pads are mapped
	if(request_resource(&iomem_resource, &gcpad_resource) < 0) {
		printk(KERN_WARNING "gcpad : resource busy\n");
		return -EBUSY;
	}

	gcpad = kmalloc(4*sizeof(struct gcpad_dev), GFP_KERNEL);
	if(gcpad == NULL)
		return -ENOMEM;
	memset(gcpad, 0, 4*sizeof(struct gcpad_dev));

	// For each pads
	for (i = 0; i < 4; i++) {
		// Initalize callbacks and private data.
		gcpad[i].number = i;
		gcpad[i].dev.private = &gcpad[i];
		gcpad[i].dev.open = gcpad_open;
		gcpad[i].dev.close = gcpad_close;

		// Declare avaible events.
		set_bit(EV_KEY, gcpad[i].dev.evbit);
		set_bit(EV_ABS, gcpad[i].dev.evbit);

		// Declare avaible buttons.
		for(j = 0; j < 8; j++)
			set_bit(gcpad_btn[j], gcpad[i].dev.keybit);

		// Initialize and declare avaible axes.
		for(j = 0; j < 8; j++) {
			set_bit(gcpad_abs[j], gcpad[i].dev.absbit);
			switch(j) {
				case 0:
				case 1: // Main joystick
				case 2:
				case 3 : // C-stick
					gcpad[i].dev.absmin[gcpad_abs[j]] = -128;
					gcpad[i].dev.absmax[gcpad_abs[j]] = 127;
					gcpad[i].dev.absfuzz[gcpad_abs[j]] = 0;
					gcpad[i].dev.absflat[gcpad_abs[j]] = 0;
					break;
				case 4:
				case 5: // Trigger left and right
					gcpad[i].dev.absmin[gcpad_abs[j]] = 0;
					gcpad[i].dev.absmax[gcpad_abs[j]] = 255;
					gcpad[i].dev.absfuzz[gcpad_abs[j]] = 0;
					gcpad[i].dev.absflat[gcpad_abs[j]] = 0;
					break;
				case 6:
				case 7: //Digital axes
					gcpad[i].dev.absmin[gcpad_abs[j]] = -1;
					gcpad[i].dev.absmax[gcpad_abs[j]] = 1;
					gcpad[i].dev.absfuzz[gcpad_abs[j]] = 0;
					gcpad[i].dev.absflat[gcpad_abs[j]] = 0;
					break;
			}
		}
		input_register_device(&gcpad[i].dev);

		init_timer(&gcpad[i].timer);
		gcpad[i].timer.data = (long)&gcpad[i];
		gcpad[i].timer.function = gcpad_timer;
	}

	// Taken directly from tmbinc's IPL replacement code.
	// Initializes all controllers!
	// 32bits access
	*(volatile unsigned long*)0xCC006430 = 0x00000000;
	*(volatile unsigned long*)0xCC006438 = 0x80000000;
	*(volatile unsigned long*)0xCC006430 = 0x00f70200;
	*(volatile unsigned long*)0xCC006438 = 0x80000000;
	*(volatile unsigned long*)0xCC006480 = 0x00000000;
	*(volatile unsigned long*)0xCC006434 = 0xc0010301;
	*(volatile unsigned long*)0xCC006438 = 0x00000000;

	(void)*(volatile unsigned long*)0xCC006434;

	*(volatile unsigned long*)0xCC006430 |= 0xF0; // enable all four controller ports

	*(volatile unsigned long*)0xCC006400  = 0x00400300;
	*(volatile unsigned long*)0xCC00640C  = 0x00400300;
	*(volatile unsigned long*)0xCC006418  = 0x00400300;
	*(volatile unsigned long*)0xCC006424  = 0x00400300;

	udelay(1000);

	*(volatile unsigned long*)0xCC006430 = 0x00000000;
	*(volatile unsigned long*)0xCC006438 = 0x80000000;
	*(volatile unsigned long*)0xCC006430 = 0x00f70200;
	*(volatile unsigned long*)0xCC006438 = 0x80000000;
	*(volatile unsigned long*)0xCC006480 = 0x00000000;
	*(volatile unsigned long*)0xCC006434 = 0xc0010301;
	*(volatile unsigned long*)0xCC006438 = 0x00000000;

	(void)*(volatile unsigned long*)0xCC006434;

	*(volatile unsigned long*)0xCC006430 |= 0xF0; // enable all four controller ports

	*(volatile unsigned long*)0xCC006400  = 0x00400300;
	*(volatile unsigned long*)0xCC00640C  = 0x00400300;
	*(volatile unsigned long*)0xCC006418  = 0x00400300;
	*(volatile unsigned long*)0xCC006424  = 0x00400300;

	return 0;
}


static void __exit gcpad_cleanup(void)
{
	int i;

	for (i = 0; i < 4; i++)
		input_unregister_device(&gcpad[i].dev);

	kfree(gcpad);
	release_resource(&gcpad_resource);

	return;
}


static void gcpad_timer(unsigned long private)
{
	struct gcpad_dev *pad = (void *) private;
	unsigned long pdata;
	short chan = pad->number;
	u16 button;

	// TODO : Does it need a delay between two read ?

	// Get the button and control stick values
	pdata = *(volatile unsigned long *)(GCPAD_CHANNEL(chan)+4);

	button = pdata >> 16;
	if(button & GCPAD_LEFT) input_report_abs(&pad->dev, ABS_HAT0X, -1);
	if(button & GCPAD_RIGHT) input_report_abs(&pad->dev, ABS_HAT0X, 1);
	if(button & GCPAD_UP) input_report_abs(&pad->dev, ABS_HAT0Y, 1);
	if(button & GCPAD_DOWN) input_report_abs(&pad->dev, ABS_HAT0Y, -1);

	input_report_key(&pad->dev, BTN_TL, button & GCPAD_L);
	input_report_key(&pad->dev, BTN_TR, button & GCPAD_R);
	input_report_key(&pad->dev, BTN_A, button & GCPAD_A);
	input_report_key(&pad->dev, BTN_B, button & GCPAD_B);
	input_report_key(&pad->dev, BTN_X, button & GCPAD_X);
	input_report_key(&pad->dev, BTN_Y, button & GCPAD_Y);
	input_report_key(&pad->dev, BTN_Z, button & GCPAD_Z);
	input_report_key(&pad->dev, BTN_START, button & GCPAD_START);

	input_report_abs(&pad->dev, ABS_X, 128 + ((pdata >> 8) & 0xff));
	input_report_abs(&pad->dev, ABS_Y, 128 - (pdata & 0xff));

	// Get the c-stick and trigger values

	pdata = *(volatile unsigned long *)(GCPAD_CHANNEL(chan)+8);

	input_report_abs(&pad->dev, ABS_RX, 128 + (pdata >> 24));
	input_report_abs(&pad->dev, ABS_RX, 128 - ((pdata >> 16) & 0xff));
	input_report_abs(&pad->dev, ABS_HAT0X, (pdata >> 8) & 0xff);
	input_report_abs(&pad->dev, ABS_HAT0Y, pdata & 0xff);

	mod_timer(&pad->timer, jiffies + GCPAD_REFRESH_TIME);
}


static int gcpad_open(struct input_dev *dev)
{
	struct gcpad_dev *pad = dev->private;

	if (!pad->count++)
		mod_timer(&pad->timer, jiffies + GCPAD_REFRESH_TIME);
	return 0;
}

static void gcpad_close(struct input_dev *dev)
{
	struct gcpad_dev *pad = dev->private;
	if (!--pad->count)
		del_timer(&pad->timer);
}

module_init(gcpad_init);
module_exit(gcpad_cleanup);
Makefile (application/x-java-vm, 559 B) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.