From: Fredrik H. <hu...@hu...> - 2002-01-22 23:56:30
|
As per request, here is the maple patch in unified diff format: --------------------------------8<---------------------- diff -U3 -N -r --exclude=CVS --exclude *~ ../linux-sh-orig/arch/sh/config.in ./arch/sh/config.in --- ../linux-sh-orig/arch/sh/config.in Fri Nov 2 16:52:47 2001 +++ ./arch/sh/config.in Mon Jan 7 22:22:18 2002 @@ -319,6 +319,7 @@ if [ "$CONFIG_INPUT" != "n" ]; then dep_tristate ' Maple Bus keyboard support' CONFIG_MAPLE_KEYBOARD $CONFIG_INPUT dep_tristate ' Maple Bus mouse support' CONFIG_MAPLE_MOUSE $CONFIG_INPUT + dep_tristate ' Maple Light Gun support' CONFIG_MAPLE_LIGHTGUN $CONFIG_INPUT else comment 'Input core support is required for Maple input peripherals' fi diff -U3 -N -r --exclude=CVS --exclude *~ ../linux-sh-orig/drivers/char/Makefile ./drivers/char/Makefile --- ../linux-sh-orig/drivers/char/Makefile Fri Nov 30 15:03:52 2001 +++ ./drivers/char/Makefile Mon Jan 7 22:19:27 2002 @@ -178,6 +178,7 @@ obj-$(CONFIG_MAPLE_KEYBOARD) += maple_keyb.o obj-$(CONFIG_MAPLE_MOUSE) += maplemouse.o +obj-$(CONFIG_MAPLE_LIGHTGUN) += maple_lg.o obj-$(CONFIG_BUSMOUSE) += busmouse.o obj-$(CONFIG_DTLK) += dtlk.o diff -U3 -N -r --exclude=CVS --exclude *~ ../linux-sh-orig/drivers/char/joystick/maplecontrol.c ./drivers/char/joystick/maplecontrol.c --- ../linux-sh-orig/drivers/char/joystick/maplecontrol.c Mon Oct 15 13:44:59 2001 +++ ./drivers/char/joystick/maplecontrol.c Tue Jan 15 05:17:29 2002 @@ -21,11 +21,11 @@ }; -static void dc_pad_callback(struct mapleq *mq) +static void dc_pad_callback(struct maple_driver_data *data) { unsigned short buttons; - struct maple_device *mapledev = mq->dev; - struct dc_pad *pad = mapledev->private_data; + struct mapleq *mq=&data->mq; + struct dc_pad *pad = data->private_data; struct input_dev *dev = &pad->dev; unsigned char *res = mq->recvbuf; @@ -73,10 +73,10 @@ } -static int dc_pad_connect(struct maple_device *dev) +static int dc_pad_connect(struct maple_driver_data *d) { int i; - unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); + unsigned long data = d->function_data; struct dc_pad *pad; const short btn_bit[32] = { @@ -97,7 +97,7 @@ return -1; memset(pad, 0, sizeof(struct dc_pad)); - dev->private_data = pad; + d->private_data = pad; for (i=0; i<32; i++) if (data&(1<<i) && btn_bit[i]>=0) @@ -132,13 +132,11 @@ pad->dev.close = dc_pad_close; pad->dev.event = NULL; - pad->dev.name = dev->product_name; + pad->dev.name = d->dev->product_name; pad->dev.idbus = BUS_MAPLE; input_register_device(&pad->dev); - maple_getcond_callback(dev, dc_pad_callback, 1, MAPLE_FUNC_CONTROLLER); - printk(KERN_INFO "input%d: controller(0x%lx): %s\n", pad->dev.number, data, pad->dev.name); @@ -148,9 +146,9 @@ } -static void dc_pad_disconnect(struct maple_device *dev) +static void dc_pad_disconnect(struct maple_driver_data *d) { - struct dc_pad *pad = dev->private_data; + struct dc_pad *pad = d->private_data; input_unregister_device(&pad->dev); @@ -165,6 +163,8 @@ name: "Dreamcast controller", connect: dc_pad_connect, disconnect: dc_pad_disconnect, + reply: dc_pad_callback, + vblank: maple_getcond_vblank_callback, }; diff -U3 -N -r --exclude=CVS --exclude *~ ../linux-sh-orig/drivers/char/maple_keyb.c ./drivers/char/maple_keyb.c --- ../linux-sh-orig/drivers/char/maple_keyb.c Thu Dec 6 07:23:03 2001 +++ ./drivers/char/maple_keyb.c Wed Jan 16 00:44:16 2002 @@ -80,16 +80,14 @@ } -static void dc_kbd_callback(struct mapleq *mq) +static void dc_kbd_callback(struct maple_driver_data *data) { - struct maple_device *mapledev = mq->dev; - struct dc_kbd *kbd = mapledev->private_data; - unsigned long *buf = mq->recvbuf; - - if (buf[1] == mapledev->function) { - memcpy(kbd->new, buf+2, 8); - dc_scan_kbd(kbd); - } + struct mapleq *mq=& data->mq; + struct dc_kbd *kbd = data->private_data; + unsigned long *buf = (unsigned long *)mq->recvbuf; + + memcpy(kbd->new, buf+2, 8); + dc_scan_kbd(kbd); } @@ -108,17 +106,17 @@ } -static int dc_kbd_connect(struct maple_device *dev) +static int dc_kbd_connect(struct maple_driver_data *d) { int i; - unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); + unsigned long data = d->function_data; struct dc_kbd *kbd; if (!(kbd = kmalloc(sizeof(struct dc_kbd), GFP_KERNEL))) return -1; memset(kbd, 0, sizeof(struct dc_kbd)); - dev->private_data = kbd; + d->private_data = kbd; kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); @@ -131,13 +129,11 @@ kbd->dev.close = dc_kbd_close; kbd->dev.event = NULL; - kbd->dev.name = dev->product_name; + kbd->dev.name = d->dev->product_name; kbd->dev.idbus = BUS_MAPLE; input_register_device(&kbd->dev); - maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD); - printk(KERN_INFO "input%d: keyboard(0x%lx): %s\n", kbd->dev.number, data, kbd->dev.name); @@ -147,9 +143,9 @@ } -static void dc_kbd_disconnect(struct maple_device *dev) +static void dc_kbd_disconnect(struct maple_driver_data *d) { - struct dc_kbd *kbd = dev->private_data; + struct dc_kbd *kbd = d->private_data; input_unregister_device(&kbd->dev); @@ -164,6 +160,8 @@ name: "Dreamcast keyboard", connect: dc_kbd_connect, disconnect: dc_kbd_disconnect, + reply: dc_kbd_callback, + vblank: maple_getcond_vblank_callback, }; diff -U3 -N -r --exclude=CVS --exclude *~ ../linux-sh-orig/drivers/char/maple_lg.c ./drivers/char/maple_lg.c --- ../linux-sh-orig/drivers/char/maple_lg.c Wed Dec 31 16:00:00 1969 +++ ./drivers/char/maple_lg.c Tue Jan 22 11:39:07 2002 @@ -0,0 +1,271 @@ +/* + * $Id: maple_lg.c,v 1.1.1.1 2001/10/15 20:44:57 hubbe 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: + */ diff -U3 -N -r --exclude=CVS --exclude *~ ../linux-sh-orig/drivers/char/maplemouse.c ./drivers/char/maplemouse.c --- ../linux-sh-orig/drivers/char/maplemouse.c Mon Oct 15 13:44:57 2001 +++ ./drivers/char/maplemouse.c Tue Jan 15 05:18:22 2002 @@ -21,11 +21,11 @@ }; -static void dc_mouse_callback(struct mapleq *mq) +static void dc_mouse_callback(struct maple_driver_data *data) { int buttons, relx, rely, relz; - struct maple_device *mapledev = mq->dev; - struct dc_mouse *mouse = mapledev->private_data; + struct mapleq *mq=& data->mq; + struct dc_mouse *mouse = data->private_data; struct input_dev *dev = &mouse->dev; unsigned char *res = mq->recvbuf; @@ -58,16 +58,16 @@ } -static int dc_mouse_connect(struct maple_device *dev) +static int dc_mouse_connect(struct maple_driver_data *d) { - unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); + unsigned long data = d->function_data; struct dc_mouse *mouse; if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL))) return -1; memset(mouse, 0, sizeof(struct dc_mouse)); - dev->private_data = mouse; + d->private_data = mouse; mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); @@ -78,13 +78,11 @@ mouse->dev.close = dc_mouse_close; mouse->dev.event = NULL; - mouse->dev.name = dev->product_name; + mouse->dev.name = d->dev->product_name; mouse->dev.idbus = BUS_MAPLE; input_register_device(&mouse->dev); - maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE); - printk(KERN_INFO "input%d: mouse(0x%lx): %s\n", mouse->dev.number, data, mouse->dev.name); @@ -94,9 +92,9 @@ } -static void dc_mouse_disconnect(struct maple_device *dev) +static void dc_mouse_disconnect(struct maple_driver_data *d) { - struct dc_mouse *mouse = dev->private_data; + struct dc_mouse *mouse = d->private_data; input_unregister_device(&mouse->dev); @@ -111,6 +109,8 @@ name: "Dreamcast mouse", connect: dc_mouse_connect, disconnect: dc_mouse_disconnect, + reply: dc_mouse_callback, + vblank: maple_getcond_vblank_callback, }; diff -U3 -N -r --exclude=CVS --exclude *~ ../linux-sh-orig/drivers/maple/maple.c ./drivers/maple/maple.c --- ../linux-sh-orig/drivers/maple/maple.c Mon Oct 15 13:44:59 2001 +++ ./drivers/maple/maple.c Tue Jan 22 11:20:04 2002 @@ -17,10 +17,43 @@ #include <asm/page.h> #include <asm/io.h> +#include <asm/dc_sysasic.h> #include <linux/maple.h> +/* + * Significantly rewritten by Fredrik Hubinette <hu...@hu...> 2002 + */ + +#if 0 #define DPRINTK(format, args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format, args...) +#endif + +#if 0 +#define POLL_DPRINTK(format, args...) printk(KERN_INFO format,##args) +#else +#define POLL_DPRINTK(format, args...) +#endif + +#if 0 +#define IRQ_DPRINTK(format, args...) printk(KERN_INFO format,##args) +#else +#define IRQ_DPRINTK(format, args...) +#endif + +#if 0 +#define SETUP_DPRINTK(format, args...) printk(KERN_DEBUG format,##args) +#else +#define SETUP_DPRINTK(format, args...) +#endif + +#if 0 +#define DCOLOR(X) ((*(unsigned long *)0xa05f8040)=(X)) +#else +#define DCOLOR(X) +#endif #define MAPLE_PORTS 4 #define MAPLE_SCANHZ (HZ/100) @@ -31,76 +64,74 @@ #define MAPLE_DMA_SIZE (1<<MAPLE_DMA_ORDER) #define MAPLE_DMA_PAGES ((MAPLE_DMA_ORDER > PAGE_SHIFT) ? MAPLE_DMA_ORDER-PAGE_SHIFT : 0) -static LIST_HEAD(maple_dev_list); -static LIST_HEAD(maple_driver_list); -static LIST_HEAD(maple_waitq); -static LIST_HEAD(maple_sentq); -static DECLARE_WAIT_QUEUE_HEAD(kmapled_wait); -static DECLARE_COMPLETION(kmapled_exited); -static int kmapled_pid = 0; +/* Maple units: + * 0 = primary + * 1-5 = secondaries + */ +static int unitcodes[MAPLE_MAX_UNITS] = { 32, 1, 2, 4, 8, 16 }; + +static struct maple_port ports[MAPLE_PORTS]; +static int maple_active_guns; +static int maple_gunport; +static int maple_active_gunport; -struct timer_list maple_timer; +/*** Heleper functions ***/ -unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; -unsigned long maple_pnp_time; +static void maple_detect_callback(struct mapleq *); -static struct maple_driver maple_dummy_driver = { - function: 0, - name: "Dummy", -}; - -static void maple_dump_devinfo(struct maple_devinfo *devinfo) +static int maple_dma_done(void) { - DPRINTK(" function: 0x%08x\n", be32_to_cpu(devinfo->function)); - DPRINTK(" data[0]: 0x%08x\n", be32_to_cpu(devinfo->function_data[0])); - DPRINTK(" data[1]: 0x%08x\n", be32_to_cpu(devinfo->function_data[1])); - DPRINTK(" data[2]: 0x%08x\n", be32_to_cpu(devinfo->function_data[2])); - DPRINTK(" area code: %d\n", devinfo->area_code); - DPRINTK(" direction: %d\n", devinfo->connector_direction); - DPRINTK(" name: \"%-30.30s\"\n", devinfo->product_name); - DPRINTK(" license: \"%-60.60s\"\n", devinfo->product_license); - DPRINTK(" stanby power: %d\n", le16_to_cpu(devinfo->standby_power)); - DPRINTK(" max power: %d\n", le16_to_cpu(devinfo->max_power)); + return (ctrl_inl(MAPLE_STATE) & 1) == 0; } -void maple_register_driver(struct maple_driver *driver) -{ - struct list_head *lh = (void *)driver; - list_add(lh, &maple_driver_list); - - MOD_INC_USE_COUNT; +#define MCP(P,U) do{ \ + if( !(ports[(P)].dev[(U)]) != \ + !(ports[(P)].known_units & unitcodes[(U)]) ) { \ + unsigned long flags; \ + printk(KERN_INFO "MF: %d (%d,%d) u=%x\n",__LINE__,(P),(U),ports[(P)].known_units); \ + save_and_cli(flags); \ + while(1); \ + } \ +}while(0) + +#define CHECKALLP() do{ \ + int P,U; \ + for(P=0;P<4;P++) for(U=0;U<MAPLE_MAX_UNITS;U++) MCP(P,U); \ +}while(0) + + +/*** Low-level maple functions *** + * + * This section only handles data transfers and callbacks, + * it does not handle any devices, auto-detection or + * timing. See the next section for that. + */ - printk(KERN_INFO "maple: registered driver: %s (function 0x%lx)\n", - driver->name, driver->function); -} +unsigned long *maple_sendbuf, *maple_sendptr; +static LIST_HEAD(maple_waitq); +static LIST_HEAD(maple_sentq); -void maple_unregister_driver(struct maple_driver *driver) +void maple_init_mq(struct mapleq *mq) { - struct list_head *lh = (void *)driver; - list_del(lh); - - MOD_DEC_USE_COUNT; + unsigned long buf; - printk(KERN_INFO "maple: unregistered driver: %s (function 0x%lx)\n", - driver->name, driver->function); + mq->done = 1; + buf = (unsigned long)mq->buf; + buf = (buf + 31) & ~31; + mq->recvbuf = (void *)P2SEGADDR(buf); } - static struct mapleq *maple_allocq(struct maple_device *dev) { - unsigned long buf; struct mapleq *mq; mq = kmalloc(sizeof(*mq), GFP_KERNEL); if (!mq) return NULL; - mq->dev = dev; - buf = (unsigned long)mq->buf; - buf = (buf + 31) & ~31; - mq->recvbuf = (void *)P2SEGADDR(buf); + maple_init_mq(mq); return mq; } @@ -114,93 +145,235 @@ kfree(mq); } +static unsigned long last_gun_data; -static struct maple_device *maple_alloc_dev(int port, int unit) +static void maple_dma_irq(int irq, void *dev, struct pt_regs *fp) { - struct maple_device *dev; + struct mapleq *mq; + struct list_head *lh, tmph; - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; + DCOLOR(0x0000ff); + IRQ_DPRINTK("MAPLE DMA IRQ BEGIN\n"); - memset(dev, 0, sizeof(*dev)); + POLL_DPRINTK("Maple DMA finished %d, %d.\n", + list_empty(&maple_sentq), !maple_dma_done()); - dev->port = port; - dev->unit = unit; - dev->mq = maple_allocq(dev); + if (list_empty(&maple_sentq) || !maple_dma_done()) return; - if (!dev->mq) { - kfree(dev); - return NULL; +#if 1 + if(maple_active_gunport >= 0) { + int x,y; + unsigned long tmp=*(unsigned long *)0xA05F80C4; + if(last_gun_data != tmp) { + y=tmp>>16; + x=tmp&0xffff; + POLL_DPRINTK("Maple gunport reply for port %d: " + "%04x %04x\n", + maple_active_gunport, + x,y); + ports[maple_active_gunport].gunmode( + ports[maple_active_gunport].gunmode_data,x,y); + maple_active_gunport=-1; + } } +#endif - return dev; + list_for_each(lh, &maple_sentq) { + tmph = *lh; + + mq = (struct mapleq *)lh; + mq->done=1; + POLL_DPRINTK("Maple reply (%d,%d) cmd=%d => %d\n", + mq->port, mq->unit, + mq->command, mq->recvbuf[0]); + + if(mq->recvbuf[0] == MAPLE_RESPONSE_NONE) + maple_detect_callback(mq); + else if(mq->callback) + mq->callback(mq); + + lh = &tmph; + + } + + INIT_LIST_HEAD(&maple_sentq); + maple_send(); + + IRQ_DPRINTK("MAPLE DMA IRQ END\n"); } -static void maple_free_dev(struct maple_device *dev) + + +/* Call this after one or more calls to maple_add_packet */ +/* FIXME: implement scheduling */ +static void low_maple_send(int vblank) { - if (!dev) + int i; + int maple_packets; + struct mapleq *mq; + struct list_head *lh, tmph; + unsigned long *maple_lastptr; + unsigned long flags; + + /* Major-league dodgy */ + save_and_cli(flags); + + if (!list_empty(&maple_sentq) || + (maple_active_gunport != -1 && !vblank) ) { + restore_flags(flags); return; + } - if (dev->mq) - maple_freeq(dev->mq); + if (list_empty(&maple_waitq) || !maple_dma_done()) { + restore_flags(flags); + return; + } - kfree(dev); -} + maple_packets = 0; + maple_sendptr = maple_lastptr = maple_sendbuf; + maple_active_gunport=-1; + list_for_each(lh, &maple_waitq) { + int port, unit, from, to, len; + unsigned long *lsendbuf; -static void maple_register_dev(struct maple_device *dev) -{ - struct list_head *lh = (void *)dev; - list_add_tail(lh, &maple_dev_list); -} + mq = (struct mapleq *)lh; + + port = mq->port; + unit = mq->unit; + len = mq->length & 0xff; + + if(ports[port].dev[unit] && + ports[port].dev[unit]->lock) + { + if(vblank) ports[port].dev[unit]->lock--; + continue; + } + tmph = *lh; -static void maple_unregister_dev(struct maple_device *dev) -{ - struct list_head *lh = (void *)dev; - list_del(lh); -} + list_del(lh); + list_add_tail(lh, &maple_sentq); + lsendbuf = mq->sendbuf; + + POLL_DPRINTK("Maple sending (%d,%d) cmd=%d len=%d\n", + mq->port, mq->unit, mq->command, len); + + from = port<<6; + to = (port<<6) | unitcodes[unit]; + + maple_lastptr = maple_sendptr; + + *maple_sendptr++ = (port<<16) | len; + *maple_sendptr++ = PHYSADDR(mq->recvbuf); + *maple_sendptr++ = mq->command | (to<<8) | + (from<<16) | (len<<24); + +#if 1 + while (len-->0) { + *maple_sendptr++ = *lsendbuf++; + } +#else + if(len > 0) + { + memcpy((char *)maple_sendptr, + (char *)lsendbuf, + sizeof(*maple_sendptr) * (len - 1)); + + maple_sendptr+=len; + } +#endif + if(mq->length & MAPLEQ_LENGTH_GUN) { +/* printk("Setting GUN MODE!\n"); */ + maple_lastptr = maple_sendptr; + *maple_sendptr++ = (port<<16) | 0x200; + maple_active_gunport = port; + break; + } + + lh = &tmph; + if (maple_packets++ > MAPLE_MAXPACKETS) + break; + } + +#if 0 + *maple_lastptr |= 0x80000000; /* Set 'last' bit */ +#else + switch(maple_active_guns) + { + case 0: + maple_active_gunport=-1; + *maple_lastptr |= 0x80000000; /* Set 'last' bit */ + break; + + default: + do { + if(++maple_gunport == MAPLE_PORTS) + maple_gunport=0; + } while( ! ports[maple_gunport].gunmode); + + /* FALL THROUGH */ + case 1: + maple_active_gunport=maple_gunport; + *maple_sendptr++ = (maple_gunport <<16) | 0x80000200; + POLL_DPRINTK("Active gunport = %d\n", + maple_active_gunport); + } +#endif + + if (maple_packets>0) { + for (i=0; i<(1<<MAPLE_DMA_PAGES); i++) + dma_cache_wback_inv(maple_sendbuf+i*PAGE_SIZE, PAGE_SIZE); + POLL_DPRINTK("Maple, starting DMA packets=%d\n",maple_packets); + ctrl_outl(1, MAPLE_STATE); + DCOLOR(0x00ffff); + } + + restore_flags(flags); -void maple_getcond_callback(struct maple_device *dev, - void (*callback)(struct mapleq *mq), - unsigned long interval, unsigned long function) -{ - dev->callback = callback; - dev->interval = interval; - dev->function = cpu_to_be32(function); - dev->when = 0; } +void maple_send(void) +{ + low_maple_send(0); +} int maple_add_packet(struct mapleq *mq) { + int ret=0; unsigned long flags; save_and_cli(flags); - list_add((struct list_head *)mq, &maple_waitq); + if(mq->done) { + mq->done=0; + list_add_tail((struct list_head *)mq, &maple_waitq); + }else{ + DPRINTK("Maple, rejecting package (to %d,%d, cmd=%d)\n", + mq->port, mq->unit, + mq->command); + ret=-EINPROGRESS; + } restore_flags(flags); - return 0; + return ret; } - int maple_del_packet(struct mapleq *mq) { struct list_head *lh; unsigned long flags; save_and_cli(flags); - + list_for_each(lh, &maple_sentq) { if (mq == (struct mapleq *)lh) { restore_flags(flags); - return -1; + return -EBUSY; } } - + list_for_each(lh, &maple_waitq) { if (mq == (struct mapleq *)lh) list_del(lh); @@ -211,243 +384,375 @@ return 0; } - -static int maple_dma_done(void) +void maple_set_gunmode(int port, void (cb)(void *,int,int),void *data) { - return (ctrl_inl(MAPLE_STATE) & 1) == 0; -} +#if 1 + unsigned long flags; + save_and_cli(flags); -static void maple_attach_driver(struct maple_device *dev) -{ - struct list_head *lh; - struct maple_driver *driver; - unsigned long function; - char *p, *recvbuf = dev->mq->recvbuf; + if( (!ports[port].gunmode) ^ (!cb) ) { + maple_active_guns += (cb ? 1 : -1); + if(cb) maple_gunport=port; + } - memcpy(&dev->devinfo, recvbuf+4, sizeof(dev->devinfo)); - memcpy(dev->product_name, dev->devinfo.product_name, 30); - memcpy(dev->product_license, dev->devinfo.product_license, 60); - dev->product_name[30] = 0; - dev->product_license[60] = 0; + ports[port].gunmode = cb; + ports[port].gunmode_data = data; - for (p=dev->product_name+29; dev->product_name<=p; p--) - if (*p==' ') *p = 0; else break; - - for (p=dev->product_license+59; dev->product_license<=p; p--) - if (*p==' ') *p = 0; else break; - function = be32_to_cpu(dev->devinfo.function); + restore_flags(flags); - printk(KERN_INFO "maple(%d,%d): Connected(function 0x%lx)\n", - dev->port, dev->unit, function); + printk("Setting gunmode for port %d to %p(%p) (active guns = %d)\n",port,cb,data,maple_active_guns); +#endif +} - list_for_each(lh, &maple_driver_list) { - driver = (struct maple_driver *)lh; - if (function & driver->function) { - if (!driver->connect(dev)) { - dev->driver = driver; - break; - } - } +static int init_maple_low(void) +{ + int p, u; + + printk(KERN_INFO "SEGA Dreamcast MAPLE Bus drivers\n"); + + /* Allocate DMA buffer */ + maple_sendbuf = (void *)__get_dma_pages(GFP_KERNEL, MAPLE_DMA_PAGES); + if (maple_sendbuf == NULL) + return -ENOMEM; + memset(maple_sendbuf, 0, MAPLE_DMA_SIZE); + + for(p=0;p<MAPLE_PORTS;p++) + { + ports[p].port=p; + ports[p].known_units=0; + ports[p].units=0; + ports[p].gunmode=0; + + for(u=0;u<MAPLE_MAX_UNITS;u++) + ports[p].dev[u]=NULL; } + CHECKALLP(); - if (dev->driver==NULL) { - printk(KERN_INFO "maple(%d,%d): No proper driver.\n", - dev->port, dev->unit); - maple_dump_devinfo(&dev->devinfo); - dev->driver = &maple_dummy_driver; + /* Initialize hardware */ + ctrl_outl(MAPLE_MAGIC, MAPLE_RESET); + ctrl_outl(0, MAPLE_RESET2); + ctrl_outl(MAPLE_2MBPS|MAPLE_TIMEOUT(50000), MAPLE_SPEED); + ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR); + ctrl_outl(1, MAPLE_ENABLE); + + + if (request_irq(HW_EVENT_MAPLE_DMA, maple_dma_irq, 0, + "Maple BUS DMA", 0)) { + DPRINTK("couldn't register DMA int\n"); + goto cleanup; } + return 0; + cleanup: + printk(KERN_INFO "maple: Register failed\n"); + return -ENOMEM; } - -static void maple_detach_driver(struct maple_device *dev) +static void exit_maple_low(void) { - printk(KERN_INFO "maple(%d,%d): Disconnected\n", - dev->port, dev->unit); + free_irq(HW_EVENT_MAPLE_DMA, 0); + + /* twiddle */ + while(!maple_dma_done()); - dev->driver->disconnect(dev); - dev->driver = NULL; + if (maple_sendbuf) + free_pages((unsigned long)maple_sendbuf, MAPLE_DMA_PAGES); } -static void maple_dma_irq(void) + +/*** Maple Device interface *** + * + * This section provides the interface for individual + * drivers and handles device state polling and auto-detection. + */ + +static LIST_HEAD(maple_data_list); +static LIST_HEAD(maple_driver_list); +static DECLARE_WAIT_QUEUE_HEAD(kmapled_wait); +static DECLARE_COMPLETION(kmapled_exited); +static int kmapled_pid = 0; + + +static int maple_detector_counter; +static struct mapleq maple_detector; +static int detector_new_dev; + + +static void maple_dump_devinfo(struct maple_devinfo *devinfo) { - struct mapleq *mq; - struct maple_device *dev; - struct list_head *lh, tmph; - char *recvbuf; - int code, need_wakeup = 0; + DPRINTK(" function: 0x%08x\n", be32_to_cpu(devinfo->function)); + DPRINTK(" data[0]: 0x%08x\n", be32_to_cpu(devinfo->function_data[0])); + DPRINTK(" data[1]: 0x%08x\n", be32_to_cpu(devinfo->function_data[1])); + DPRINTK(" data[2]: 0x%08x\n", be32_to_cpu(devinfo->function_data[2])); + DPRINTK(" area code: %d\n", devinfo->area_code); + DPRINTK(" direction: %d\n", devinfo->connector_direction); + DPRINTK(" name: \"%-30.30s\"\n", devinfo->product_name); + DPRINTK(" license: \"%-60.60s\"\n", devinfo->product_license); + DPRINTK(" stanby power: %d\n", le16_to_cpu(devinfo->standby_power)); + DPRINTK(" max power: %d\n", le16_to_cpu(devinfo->max_power)); +} - if (list_empty(&maple_sentq) || !maple_dma_done()) return; - list_for_each(lh, &maple_sentq) { - mq = (struct mapleq *)lh; - dev = mq->dev; - tmph = *lh; - lh = &tmph; +void maple_register_driver(struct maple_driver *driver) +{ + struct list_head *lh = (void *)driver; + list_add(lh, &maple_driver_list); - recvbuf = mq->recvbuf; - code = recvbuf[0]; + MOD_INC_USE_COUNT; - switch (code) { - case MAPLE_RESPONSE_NONE: - case MAPLE_RESPONSE_DEVINFO: - maple_getcond_callback(dev, NULL, 0, 0); - dev->event = code; - need_wakeup = 1; - break; + printk(KERN_INFO "maple: registered driver: %s (function 0x%lx)\n", + driver->name, driver->function); +} - case MAPLE_RESPONSE_DATATRF: - if (dev->callback) - dev->callback(mq); - break; - default: - break; - } +void maple_unregister_driver(struct maple_driver *driver) +{ + struct list_head *lh = (void *)driver; + list_del(lh); - } - - INIT_LIST_HEAD(&maple_sentq); + MOD_DEC_USE_COUNT; - if (need_wakeup) - wake_up(&kmapled_wait); + printk(KERN_INFO "maple: unregistered driver: %s (function 0x%lx)\n", + driver->name, driver->function); } -static void maple_build_block(struct mapleq *mq) +static struct maple_device *maple_alloc_dev(int port, int unit) { - int port, unit, from, to, len; - unsigned long *lsendbuf = mq->sendbuf; + unsigned long flags; + struct maple_device *dev; - port = mq->dev->port & 3; - unit = mq->dev->unit; - len = mq->length; + SETUP_DPRINTK("Maple, Allocating unit %d, %d\n",port, unit); - from = port<<6; - to = (port<<6) | (unit>0 ? (1<<(unit-1))&0x1f : 0x20); + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; - *maple_lastptr &= 0x7fffffff; - maple_lastptr = maple_sendptr; + memset(dev, 0, sizeof(*dev)); - *maple_sendptr++ = (port<<16) | len | 0x80000000; - *maple_sendptr++ = PHYSADDR(mq->recvbuf); - *maple_sendptr++ = mq->command | (to<<8) | (from<<16) | (len<<24); + dev->port = port; + dev->unit = unit; + dev->lock = 0; - while (len-->0) { - *maple_sendptr++ = *lsendbuf++; - } -} + CHECKALLP(); + save_and_cli(flags); + ports[port].dev[unit]=dev; + ports[port].known_units |= unitcodes[unit]; + restore_flags(flags); -void maple_send(void) -{ - int i; - int maple_packets; - struct mapleq *mq; - struct list_head *lh, tmph; + CHECKALLP(); - if (!list_empty(&maple_sentq)) - return; + return dev; +} - if (list_empty(&maple_waitq) || !maple_dma_done()) - return; - maple_packets = 0; - maple_sendptr = maple_lastptr = maple_sendbuf; +void maple_getcond_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] = + cpu_to_be32(data->driver->function); + data->mq.sendbuf = data->mq.recvbuf; + + POLL_DPRINTK("queueing GETCOND for %d,%d,%lx (%s)\n", + data->mq.port, + data->mq.unit, + data->driver->function, + data->driver->name); + + maple_add_packet(& data->mq ); + } +} - list_for_each(lh, &maple_waitq) { - mq = (struct mapleq *)lh; - tmph = *lh; - list_del(lh); - list_add(lh, &maple_sentq); - maple_build_block(mq); - lh = &tmph; - if (maple_packets++ > MAPLE_MAXPACKETS) +static void maple_driver_cmd_callback(struct mapleq *mq) +{ + struct maple_driver_data *data=(struct maple_driver_data *)mq->mq_privdata; + if(data->driver->reply) + data->driver->reply(data); +} + +static int maple_connect(struct maple_device *dev, + struct maple_driver *driver) +{ + unsigned long flags, func; + int tmp; + struct maple_driver_data *data; + data = kmalloc(sizeof(*data), GFP_KERNEL); + + if(!data) return -ENOMEM; + data->driver=driver; + data->dev=dev; + data->private_data=0; + + /* Init mq as much as possible */ + maple_init_mq(& data->mq ); + data->mq.mq_privdata=data; + data->mq.port=dev->port; + data->mq.unit=dev->unit; + data->mq.callback=maple_driver_cmd_callback; + + for(func=data->dev->function, tmp=0;;tmp++) { + func &= func-1; + if(data->driver->function > func) break; } + data->function_data=be32_to_cpu(dev->devinfo.function_data[tmp]); + SETUP_DPRINTK("Function data: %lx\n",data->function_data); - if (maple_packets>0) { - for (i=0; i<(1<<MAPLE_DMA_PAGES); i++) - dma_cache_wback_inv(maple_sendbuf+i*PAGE_SIZE, PAGE_SIZE); - ctrl_outl(1, MAPLE_STATE); + if(! driver->connect(data)) { + save_and_cli(flags); + list_add((struct list_head *)data, &maple_data_list); + restore_flags(flags); + return 0; } -} + kfree( data ); + CHECKALLP(); -static void maple_timer_handler(unsigned long dummy) + return 1; +} + +static void maple_attach_driver(int port, int unit) { struct list_head *lh; - struct maple_device *dev; + struct maple_driver *driver; + unsigned long function, bits_left; + char *p, *recvbuf = maple_detector.recvbuf; - /* If DMA is done, dispatch callback functions */ - maple_dma_irq(); + struct maple_device *dev=maple_alloc_dev(port, unit); - /* Do task for each device */ - list_for_each (lh, &maple_dev_list) { - dev = (struct maple_device *)lh; - if (dev->event) - continue; - if (dev->interval>0) { - if (jiffies>dev->when) { - dev->when = jiffies + dev->interval; - dev->mq->command = MAPLE_COMMAND_GETCOND; - dev->mq->sendbuf = &dev->function; - dev->mq->length = 1; - maple_add_packet(dev->mq); + memcpy(&dev->devinfo, recvbuf+4, sizeof(dev->devinfo)); + + memcpy(dev->product_name, dev->devinfo.product_name, 30); + memcpy(dev->product_license, dev->devinfo.product_license, 60); + dev->product_name[30] = 0; + dev->product_license[60] = 0; + + for (p=dev->product_name+29; dev->product_name<=p; p--) + if (*p==' ') *p = 0; else break; + + for (p=dev->product_license+59; dev->product_license<=p; p--) + if (*p==' ') *p = 0; else break; + + function = be32_to_cpu(dev->devinfo.function); + dev->function=function; + + printk(KERN_INFO "maple(%d,%d): Connected(function 0x%lx)\n", + dev->port, dev->unit, function); + + /* First, try all functions of this device */ + for(bits_left=function;bits_left;) { + int best_bits=0; + + /* Find out the maximum number of functions we can get + * from one driver. + */ + list_for_each(lh, &maple_driver_list) { + unsigned long bits, tmp; + + driver = (struct maple_driver *)lh; + if(driver->function & ~bits_left) continue; + tmp=bits_left & driver->function; + bits=0; + while(tmp) + { + tmp = tmp & (tmp -1); + bits++; } + if(bits > best_bits) + best_bits=bits; } - else { - if (jiffies>=maple_pnp_time) { - dev->mq->command = MAPLE_COMMAND_DEVINFO; - dev->mq->length = 0; - maple_add_packet(dev->mq); + + /* Now, first try the best drivers, + * then the second best, etc. + */ + for(;best_bits>0;best_bits--) { + list_for_each(lh, &maple_driver_list) { + unsigned long bits, tmp; + + driver = (struct maple_driver *)lh; + if(driver->function & ~bits_left) continue; + tmp=bits_left & driver->function; + bits=0; + while(tmp) { + tmp = tmp & (tmp -1); + bits++; + } + if(bits == best_bits && + !maple_connect(dev,driver)) { + bits_left=bits_left & + ~driver->function; + goto check_more_bits; + + } } } - } - if (jiffies>=maple_pnp_time) - maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; - - /* Scan list and build sending block */ - maple_send(); + printk(KERN_INFO "maple(%d,%d): No driver for function(s): %lx.\n", + dev->port, dev->unit, bits_left); + maple_dump_devinfo(&dev->devinfo); + break; - /* Schedule next timer event */ - mod_timer(&maple_timer, jiffies + MAPLE_SCANHZ); + check_more_bits: ; + } + + CHECKALLP(); } -static void maple_pnp_events(void) +static void maple_detach_driver(int port, int unit) { - struct maple_device *dev; - struct list_head *lh; + unsigned long flags; - list_for_each(lh, &maple_dev_list) { + struct list_head *lh, tmph; + struct maple_device *dev=ports[port].dev[unit]; - dev = (struct maple_device *)lh; + if(!dev) + return; - switch(dev->event) { - case MAPLE_RESPONSE_NONE: - if (dev->driver) - maple_detach_driver(dev); - break; + printk(KERN_INFO "maple(%d,%d): Disconnected (%d,%d)\n", + dev->port, dev->unit, port, unit); - case MAPLE_RESPONSE_DEVINFO: - if (!dev->driver) - maple_attach_driver(dev); - break; - } + list_for_each(lh, &maple_data_list) { + struct maple_driver_data *data; + data=(struct maple_driver_data *)lh; + if(data->dev == dev) { + save_and_cli(flags); + tmph=*lh; + list_del(lh); + restore_flags(flags); + + data->driver->disconnect(data); - dev->event = 0; + while( maple_del_packet( & data->mq ) < 0) + /* yield() */; + kfree(lh); + lh=&tmph; + } } + + save_and_cli(flags); + ports[port].dev[unit]=0; + ports[port].known_units &=~ unitcodes[unit]; + restore_flags(flags); + + CHECKALLP(); + + kfree(dev); } + +/* kmapled */ static int kmapled_thread(void *hoge) { lock_kernel(); @@ -457,7 +762,43 @@ strcpy(current->comm, "kmapled"); do { - maple_pnp_events(); + /*Yawn*/ + /* Time to see if there are any new devices */ + + SETUP_DPRINTK("kmapled: *yawn*\n"); + CHECKALLP(); + + int p, u; + + /* maple_detector contains devinfo for a new device ? */ + if(detector_new_dev) { + maple_attach_driver(maple_detector.port, + maple_detector.unit); + detector_new_dev=0; + maple_detector.done=1; /* allow more autodetects */ + } + + for(p=0;p<MAPLE_PORTS;p++) { + if(!(ports[p].known_units & ~ports[p].units)) + continue; + + SETUP_DPRINTK("Maple, port[%d] units=%x known_units=%x\n", + p, + ports[p].units, + ports[p].known_units); + + for(u=0;u<MAPLE_MAX_UNITS;u++) { + if(unitcodes[u] & + ports[p].known_units & + ~ports[p].units) { + maple_detach_driver(p,u); + } + } + } + + CHECKALLP(); + + /* Wait for another event */ interruptible_sleep_on(&kmapled_wait); } while(!signal_pending(current)); @@ -466,30 +807,152 @@ complete_and_exit(&kmapled_exited, 0); } +/* + * If there is an unconfigure device on this port, + * send a DEVINFO request to it. + */ +static int maple_detect_resend(void) +{ + int u,p; + if(! maple_detector.done ) return 0; + + CHECKALLP(); + + p=maple_detector.port; + if(ports[p].units & ~ports[p].known_units) { + for(u=0;u<MAPLE_MAX_UNITS;u++) { + if(unitcodes[u] & + ports[p].units & + ~ports[p].known_units) { + SETUP_DPRINTK("Detector resender, sending devinfo to unit 0 on port %d\n",p); + maple_detector.command=MAPLE_COMMAND_DEVINFO; + maple_detector.port = p; + maple_detector.unit = u; + maple_detector.length = 0; + maple_add_packet(& maple_detector); + return 1; + } + } + } + return 0; +} -static int __init maple_init(void) + +/* + * Autodetect DMA callback. + * 1) Wake up kmapled when we receive a MAPLE_RESPONSE_DEVINFO + * for an unconfigured device. + * 2) Wake up kmapled if devices have been removed. + */ +static void maple_detect_callback(struct mapleq *mq) { - struct maple_device *dev; - int i; + int p=maple_detector.port; + int u=maple_detector.unit; - printk(KERN_INFO "SEGA Dreamcast MAPLE Bus drivers\n"); +/* SETUP_DPRINTK("Detector callback.\n"); */ - /* Allocate DMA buffer */ - maple_sendbuf = (void *)__get_dma_pages(GFP_KERNEL, MAPLE_DMA_PAGES); - if (maple_sendbuf == NULL) - return -ENOMEM; - memset(maple_sendbuf, 0, MAPLE_DMA_SIZE); + CHECKALLP(); - /* Register dummy maple driver */ - maple_register_driver(&maple_dummy_driver); + switch(mq->recvbuf[0]) { + case MAPLE_RESPONSE_DEVINFO: + SETUP_DPRINTK("Detector reply DEVINFO (%d, %d), units = %x.\n",p,u,mq->recvbuf[2] & 0x3f); + if(!u) + ports[p].units = mq->recvbuf[2] & 0x3f; + else + ports[p].units |= unitcodes[u]; + + if(!ports[p].dev[u]) { + maple_detector.done=0; + detector_new_dev=1; + SETUP_DPRINTK("Kmapled, wakie wakie (new device) ... "); + wake_up(&kmapled_wait); + return; + } + break; - /* Register basic port devices */ - for (i=0; i<MAPLE_PORTS; i++) { - dev = maple_alloc_dev(i, 0); - if (!dev) - goto cleanup; - maple_register_dev(dev); + case MAPLE_RESPONSE_NONE: + SETUP_DPRINTK("Detector reply NONE (%d,%d)\n",p,u); + if(!u) + ports[p].units = 0; + else + ports[p].units &=~ unitcodes[u]; + break; + } + maple_detect_resend(); + + /* Devices are gone */ + if(ports[p].known_units & ~ports[p].units) { + SETUP_DPRINTK("Kmapled, wakie wakie (device gone) ... "); + wake_up(&kmapled_wait); } +} + +/* + * Autodetect vertical blank callback + * Check if there are subdevices to configure. + * If not, check if it is time to send a COMMAND_DEVINFO + * to a primary device on a port. + */ +static void maple_detect_vblank(void) +{ + int p; + + CHECKALLP(); + + if(! maple_detector.done ) return; + if( maple_detect_resend() ) return; + + maple_detector_counter++; + if(maple_detector_counter & 0xf) return; + p = (maple_detector_counter >> 4 ) & 3; + + SETUP_DPRINTK("Detector, sending devinfo to unit 0 on port %d\n",p); + + maple_detector.command=MAPLE_COMMAND_DEVINFO; + maple_detector.port = p; + maple_detector.unit = 0; + maple_detector.length = 0; + maple_detector.callback = maple_detect_callback; + maple_add_packet(& maple_detector); +} + +static void maple_vblank_interupt(int irq, void *dev, struct pt_regs *fp) +{ + struct list_head *lh; + struct maple_driver_data *data; + + IRQ_DPRINTK("MAPLE VBLANK IRQ BEGIN\n"); + DCOLOR(0xff00ff); + + /* Dodgyness, damn maple! */ + if(maple_active_gunport >=0) maple_dma_irq(0,0,0); + + + maple_detect_vblank(); + + + /* Do task for each device */ + list_for_each (lh, &maple_data_list) { + data = (struct maple_driver_data *)lh; + if(data->driver->vblank) + data->driver->vblank(data); + } + + /* Scan list and build sending block */ + low_maple_send(1); + + IRQ_DPRINTK("MAPLE VBLANK IRQ END\n"); +} + + +static int __init maple_init(void) +{ + int i; + + if((i=init_maple_low())) + return i; + + maple_init_mq(& maple_detector ); /* Start kernel thread */ kmapled_pid = kernel_thread(kmapled_thread, NULL, @@ -497,21 +960,11 @@ if (kmapled_pid==0) goto cleanup; - /* Start to scan ports */ - maple_pnp_time = 0; - - /* Initialize hardware */ - ctrl_outl(MAPLE_MAGIC, MAPLE_RESET); - ctrl_outl(0, MAPLE_RESET2); - ctrl_outl(MAPLE_2MBPS|MAPLE_TIMEOUT(50000), MAPLE_SPEED); - ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR); - ctrl_outl(1, MAPLE_ENABLE); - - /* Initialize timer */ - init_timer(&maple_timer); - maple_timer.expires = jiffies + MAPLE_SCANHZ; - maple_timer.function = maple_timer_handler; - add_timer(&maple_timer); + if (request_irq(HW_EVENT_VSYNC, maple_vblank_interupt, SA_SHIRQ, + "Maple BUS", 0)) { + DPRINTK("couldn't register VBL int\n"); + goto cleanup; + } return 0; @@ -526,24 +979,29 @@ { /* XXX: Must do proper clean-up */ + free_irq(HW_EVENT_VSYNC, 0); + kill_proc(kmapled_pid, SIGTERM, 1); wait_for_completion(&kmapled_exited); - if (maple_sendbuf) - free_pages((unsigned long)maple_sendbuf, MAPLE_DMA_PAGES); - - del_timer(&maple_timer); + exit_maple_low(); } module_init(maple_init); module_exit(maple_exit); +EXPORT_SYMBOL(maple_init_mq); +EXPORT_SYMBOL(maple_allocq); +EXPORT_SYMBOL(maple_freeq); EXPORT_SYMBOL(maple_add_packet); EXPORT_SYMBOL(maple_del_packet); +EXPORT_SYMBOL(maple_send); +EXPORT_SYMBOL(maple_set_gunmode); + EXPORT_SYMBOL(maple_register_driver); EXPORT_SYMBOL(maple_unregister_driver); -EXPORT_SYMBOL(maple_getcond_callback); +EXPORT_SYMBOL(maple_getcond_vblank_callback); /* * Local variables: diff -U3 -N -r --exclude=CVS --exclude *~ ../linux-sh-orig/drivers/video/pvr2fb.c ./drivers/video/pvr2fb.c --- ../linux-sh-orig/drivers/video/pvr2fb.c Mon Oct 15 13:45:05 2001 +++ ./drivers/video/pvr2fb.c Tue Jan 8 01:17:00 2002 @@ -1051,7 +1051,7 @@ return -EINVAL; } - if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0, + if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, SA_SHIRQ, "pvr2 VBL handler", ¤tpar)) { DPRINTK("couldn't register VBL int\n"); return -EBUSY; diff -U3 -N -r --exclude=CVS --exclude *~ ../linux-sh-orig/include/linux/maple.h ./include/linux/maple.h --- ../linux-sh-orig/include/linux/maple.h Mon Oct 15 13:45:12 2001 +++ ./include/linux/maple.h Tue Jan 22 11:36:22 2002 @@ -64,7 +64,6 @@ #define MAPLE_FUNC_PURUPURU 0x100 #define MAPLE_FUNC_MOUSE 0x200 - struct maple_devinfo { unsigned long function; /* big endian! */ unsigned long function_data[3]; /* big endian! */ @@ -80,48 +79,81 @@ struct maple_driver; struct maple_device; + +#define MAPLEQ_LENGTH_GUN (1<<9) + struct mapleq { struct list_head list; - struct maple_device *dev; - void *sendbuf, *recvbuf; - unsigned char command, length; + void *mq_privdata; + void *sendbuf; + char *recvbuf; /* points to ->buf, but 32-byte aligned */ + + unsigned char port, unit; + unsigned char command; + unsigned char done; + int length; + + void (*callback)(struct mapleq *mq); unsigned char buf[1024+32]; }; struct maple_device { - struct list_head list; - struct maple_driver *driver; - struct mapleq *mq; - void *private_data; - void (*callback)(struct mapleq *mq); - unsigned long when, interval, function; - int event; + unsigned char port; + unsigned char unit; + short lock; + + unsigned long function; /* Little endian */ struct maple_devinfo devinfo; - unsigned char port, unit; + char product_name[32]; char product_license[64]; }; +/* Max devices per port */ +#define MAPLE_MAX_UNITS 6 + +struct maple_port { + unsigned char port; + unsigned char known_units; /* connected units */ + unsigned char units; /* units to connect/disconnect */ + void (*gunmode)(void *,int,int); + void *gunmode_data; + struct maple_device *dev[MAPLE_MAX_UNITS]; +}; + +struct maple_driver_data { + struct list_head list; + struct maple_driver *driver; + struct maple_device *dev; + void *private_data; + unsigned long function_data; + struct mapleq mq; +}; struct maple_driver { struct list_head list; - unsigned long function; + unsigned long function; /* One or more bits */ const char *name; - int (*connect)(struct maple_device *dev); - void (*disconnect)(struct maple_device *dev); + + void (*vblank)(struct maple_driver_data *dev); + void (*reply)(struct maple_driver_data *dev); + int (*connect)(struct maple_driver_data *dev); + void (*disconnect)(struct maple_driver_data *dev); }; +/* Prototypes begin here */ +void maple_send(void); int maple_add_packet(struct mapleq *mq); int maple_del_packet(struct mapleq *mq); - void maple_register_driver(struct maple_driver *driver); void maple_unregister_driver(struct maple_driver *driver); +void maple_getcond_vblank_callback(struct maple_driver_data *data); +void maple_set_gunmode(int, void (*)(void *,int,int), void *); +void maple_init_mq(struct mapleq *mq); +/* Prototypes end here */ -void maple_getcond_callback(struct maple_device *dev, - void (*callback)(struct mapleq *mq), - unsigned long interval, unsigned long function); /* * Local variables: |