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: */ |