|
From: M. R. B. <mr...@us...> - 2002-10-29 16:53:07
|
Update of /cvsroot/linuxdc/linux-sh-dc/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv28721
Added Files:
Tag: 1.2
maple_lg.c
Log Message:
Moved.
--- NEW FILE: maple_lg.c ---
/*
* $Id: maple_lg.c,v 1.2 2002/10/29 16:53:04 mrbrown Exp $
* SEGA Dreamcast light gun driver
* Based on drivers/maple/maplemouse.c
*
* Written by Fredrik Hubinette <hu...@hu...>, 2002
*
* You may want to download xguncalibrate from
* http://fredrik.hubbe.net/xguncalibrate.tar.gz to
* calibrate your Lightgun.
*
*/
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/maple.h>
#include <linux/interrupt.h>
#include <asm/dc_sysasic.h>
MODULE_AUTHOR("Fredrik Hubinette <hu...@hu...>");
MODULE_DESCRIPTION("SEGA Dreamcast light gun driver");
#ifdef CONFIG_MAPLE_LG_DEBUG
# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
# define DPRINTK(fmt, args...)
#endif
/* outx = inx * mult - sub */
struct dc_lg_axis_param {
int mult;
int sub;
int max;
};
struct dc_lightgun {
struct maple_driver_data *data;
struct input_dev dev;
int open;
struct mapleq gun;
struct dc_lg_axis_param xparam, yparam;
};
static void dc_lightgun_callback(struct maple_driver_data *data)
{
unsigned short buttons;
struct mapleq *mq=&data->mq;
struct dc_lightgun *lg = data->private_data;
struct input_dev *dev = &lg->dev;
unsigned char *res = mq->recvbuf;
buttons = ~*(unsigned short *)(res+8);
input_report_key(dev, BTN_LEFT, buttons&4);
input_report_key(dev, BTN_MIDDLE, buttons&8);
input_report_key(dev, BTN_RIGHT, buttons&2);
input_report_key(dev, KEY_UP, buttons&0x0010);
input_report_key(dev, KEY_DOWN, buttons&0x0020);
input_report_key(dev, KEY_LEFT, buttons&0x0040);
input_report_key(dev, KEY_RIGHT,buttons&0x0080);
}
static void dc_lightgun_pos_callback(void *privdata, int x, int y)
{
struct dc_lightgun *lg = (struct dc_lightgun *) privdata;
/* printk("\033\r Lightgun: %04x %04x \n",x,y);
printk(" Lightgun: %04x %04x \n",x,y); */
x=x * lg->xparam.mult - lg->xparam.sub;
if(x<0) x=0;
if(x >= lg->xparam.max) x = lg->xparam.max -1;
input_report_abs(& lg->dev, ABS_X, x);
y=y * lg->yparam.mult - lg->yparam.sub;
if(y<0) y=0;
if(y >= lg->yparam.max) y = lg->yparam.max -1;
input_report_abs(& lg->dev, ABS_Y, y);
}
static int dc_lightgun_open(struct input_dev *dev)
{
struct dc_lightgun *lg = dev->private;
if( lg->open++ == 0) {
/* Enable lightgun functionality */
maple_set_gunmode(lg->data->dev->port,
dc_lightgun_pos_callback, lg);
}
return 0;
}
static void dc_lightgun_close(struct input_dev *dev)
{
struct dc_lightgun *lg = dev->private;
if( --lg->open == 0) {
maple_set_gunmode(lg->data->dev->port, 0, 0);
}
}
void dc_lightgun_vblank_callback(struct maple_driver_data *data)
{
if( data->mq.done )
{
data->mq.command = MAPLE_COMMAND_GETCOND;
data->mq.length = 1;
((unsigned long *)data->mq.recvbuf)[0] = MAPLE_FUNC_CONTROLLER;
data->mq.sendbuf = data->mq.recvbuf;
DPRINTK("queueing GETCOND for %d,%d,%x (%s)\n",
data->mq.port,
data->mq.unit,
data->driver->function,
data->driver->name);
maple_add_packet(& data->mq );
}
}
static int dc_lightgun_event(struct input_dev *dev,
unsigned int type,
unsigned int code,
int value)
{
struct dc_lightgun *lg = dev->private;
struct dc_lg_axis_param *tmp;
#if 0
printk(KERN_DEBUG " LGEV: %d %d %d\n",type,code,value);
#endif
if(type != EV_FF) return -1;
switch(code & 0xf0)
{
default: return -2;
case 0: tmp = & lg->xparam; break;
case 1: tmp = & lg->yparam; break;
}
switch(code & 0xf)
{
default: return -3;
case 0: tmp->mult=value; break;
case 1: tmp->sub=value; break;
case 2: tmp->max=value; break;
}
return 0;
}
static int dc_lightgun_connect(struct maple_driver_data *d)
{
unsigned long data = d->function_data;
struct dc_lightgun *lg;
if (!(lg = kmalloc(sizeof(struct dc_lightgun), GFP_KERNEL)))
return -1;
memset(lg, 0, sizeof(struct dc_lightgun));
lg->data=d;
lg->xparam.mult=1;
lg->xparam.sub =0xc8;
lg->xparam.max =640;
lg->yparam.mult=1;
lg->yparam.sub =0x35;
lg->yparam.max =480;
d->private_data = lg;
lg->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF);
lg->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
lg->dev.keybit[LONG(KEY_UP)] |= BIT(KEY_UP);
lg->dev.keybit[LONG(KEY_DOWN)] |= BIT(KEY_DOWN);
lg->dev.keybit[LONG(KEY_LEFT)] |= BIT(KEY_LEFT);
lg->dev.keybit[LONG(KEY_RIGHT)] |= BIT(KEY_RIGHT);
lg->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y);
/* FIXME: what should the max values really be? */
lg->dev.absmax[ABS_X] = 640;
lg->dev.absmin[ABS_X] = 0;
lg->dev.absfuzz[ABS_X]= 20;
lg->dev.absflat[ABS_X]= 0;
lg->dev.absmax[ABS_Y] = 480;
lg->dev.absmin[ABS_Y] = 0;
lg->dev.absfuzz[ABS_Y]= 20;
lg->dev.absflat[ABS_Y]= 0;
lg->dev.private = lg;
lg->dev.open = dc_lightgun_open;
lg->dev.close = dc_lightgun_close;
lg->dev.event = dc_lightgun_event;
lg->dev.name = d->dev->product_name;
lg->dev.idbus = BUS_MAPLE;
input_register_device(&lg->dev);
printk(KERN_INFO "input%d: lightgun(0x%lx): %s\n",
lg->dev.number, data, lg->dev.name);
MOD_INC_USE_COUNT;
return 0;
}
static void dc_lightgun_disconnect(struct maple_driver_data *d)
{
struct dc_lightgun *lg = d->private_data;
while( maple_del_packet( & lg->gun) < 0)
/* yield */;
input_unregister_device(&lg->dev);
kfree(lg);
MOD_DEC_USE_COUNT;
}
static struct maple_driver dc_lightgun_driver = {
function: MAPLE_FUNC_LIGHTGUN | MAPLE_FUNC_CONTROLLER,
name: "Dreamcast light gun",
connect: dc_lightgun_connect,
disconnect: dc_lightgun_disconnect,
reply: dc_lightgun_callback,
vblank: dc_lightgun_vblank_callback,
};
static int __init dc_lightgun_init(void)
{
maple_register_driver(&dc_lightgun_driver);
return 0;
}
static void __exit dc_lightgun_exit(void)
{
maple_unregister_driver(&dc_lightgun_driver);
}
module_init(dc_lightgun_init);
module_exit(dc_lightgun_exit);
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
|