From: Fredrik H. <hu...@hu...> - 2002-01-22 19:41:36
|
This is a patch against the current (Jan 22 2002) linuxsh tree. Some of the highlights include: o All Maple devices are probed o Lightgun Support included o Drivers may support one or more functions o Multiple drivers per device possible (But only one per function) o Uses DMA interrupt when possible My next goal is to impelement a VMU MTD or block device. I have also written a small tool for calibrating the Lightgun device(s) which can be downloaded from: http://fredrik.hubbe.net/xguncalibrate.tar.gz Please let me know if there are any problems with this patch. -----------------------------8<-------------------------------- diff -C3 -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,324 **** --- 319,325 ---- 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 -C3 -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,183 **** --- 178,184 ---- 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 -C3 -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,31 **** }; ! static void dc_pad_callback(struct mapleq *mq) { unsigned short buttons; ! struct maple_device *mapledev = mq->dev; ! struct dc_pad *pad = mapledev->private_data; struct input_dev *dev = &pad->dev; unsigned char *res = mq->recvbuf; --- 21,31 ---- }; ! static void dc_pad_callback(struct maple_driver_data *data) { unsigned short buttons; ! struct mapleq *mq=&data->mq; ! struct dc_pad *pad = data->private_data; struct input_dev *dev = &pad->dev; unsigned char *res = mq->recvbuf; *************** *** 73,82 **** } ! static int dc_pad_connect(struct maple_device *dev) { int i; ! unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); struct dc_pad *pad; const short btn_bit[32] = { --- 73,82 ---- } ! static int dc_pad_connect(struct maple_driver_data *d) { int i; ! unsigned long data = d->function_data; struct dc_pad *pad; const short btn_bit[32] = { *************** *** 97,103 **** return -1; memset(pad, 0, sizeof(struct dc_pad)); ! dev->private_data = pad; for (i=0; i<32; i++) if (data&(1<<i) && btn_bit[i]>=0) --- 97,103 ---- return -1; memset(pad, 0, sizeof(struct dc_pad)); ! d->private_data = pad; for (i=0; i<32; i++) if (data&(1<<i) && btn_bit[i]>=0) *************** *** 132,144 **** pad->dev.close = dc_pad_close; pad->dev.event = NULL; ! pad->dev.name = 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); --- 132,142 ---- pad->dev.close = dc_pad_close; pad->dev.event = NULL; ! pad->dev.name = d->dev->product_name; pad->dev.idbus = BUS_MAPLE; input_register_device(&pad->dev); printk(KERN_INFO "input%d: controller(0x%lx): %s\n", pad->dev.number, data, pad->dev.name); *************** *** 148,156 **** } ! static void dc_pad_disconnect(struct maple_device *dev) { ! struct dc_pad *pad = dev->private_data; input_unregister_device(&pad->dev); --- 146,154 ---- } ! static void dc_pad_disconnect(struct maple_driver_data *d) { ! struct dc_pad *pad = d->private_data; input_unregister_device(&pad->dev); *************** *** 165,170 **** --- 163,170 ---- name: "Dreamcast controller", connect: dc_pad_connect, disconnect: dc_pad_disconnect, + reply: dc_pad_callback, + vblank: maple_getcond_vblank_callback, }; diff -C3 -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,95 **** } ! static void dc_kbd_callback(struct mapleq *mq) { ! 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); ! } } --- 80,93 ---- } ! static void dc_kbd_callback(struct maple_driver_data *data) { ! 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,124 **** } ! static int dc_kbd_connect(struct maple_device *dev) { int i; ! unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); 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; kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); --- 106,122 ---- } ! static int dc_kbd_connect(struct maple_driver_data *d) { int i; ! 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)); ! d->private_data = kbd; kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); *************** *** 131,143 **** kbd->dev.close = dc_kbd_close; kbd->dev.event = NULL; ! kbd->dev.name = 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); --- 129,139 ---- kbd->dev.close = dc_kbd_close; kbd->dev.event = NULL; ! kbd->dev.name = d->dev->product_name; kbd->dev.idbus = BUS_MAPLE; input_register_device(&kbd->dev); printk(KERN_INFO "input%d: keyboard(0x%lx): %s\n", kbd->dev.number, data, kbd->dev.name); *************** *** 147,155 **** } ! static void dc_kbd_disconnect(struct maple_device *dev) { ! struct dc_kbd *kbd = dev->private_data; input_unregister_device(&kbd->dev); --- 143,151 ---- } ! static void dc_kbd_disconnect(struct maple_driver_data *d) { ! struct dc_kbd *kbd = d->private_data; input_unregister_device(&kbd->dev); *************** *** 164,169 **** --- 160,167 ---- name: "Dreamcast keyboard", connect: dc_kbd_connect, disconnect: dc_kbd_disconnect, + reply: dc_kbd_callback, + vblank: maple_getcond_vblank_callback, }; diff -C3 -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 **** --- 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 -C3 -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,31 **** }; ! static void dc_mouse_callback(struct mapleq *mq) { int buttons, relx, rely, relz; ! struct maple_device *mapledev = mq->dev; ! struct dc_mouse *mouse = mapledev->private_data; struct input_dev *dev = &mouse->dev; unsigned char *res = mq->recvbuf; --- 21,31 ---- }; ! static void dc_mouse_callback(struct maple_driver_data *data) { int buttons, relx, rely, relz; ! struct mapleq *mq=& data->mq; ! struct dc_mouse *mouse = data->private_data; struct input_dev *dev = &mouse->dev; unsigned char *res = mq->recvbuf; *************** *** 58,73 **** } ! static int dc_mouse_connect(struct maple_device *dev) { ! unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); 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; 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); --- 58,73 ---- } ! static int dc_mouse_connect(struct maple_driver_data *d) { ! 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)); ! 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,90 **** mouse->dev.close = dc_mouse_close; mouse->dev.event = NULL; ! mouse->dev.name = 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); --- 78,88 ---- mouse->dev.close = dc_mouse_close; mouse->dev.event = NULL; ! mouse->dev.name = d->dev->product_name; mouse->dev.idbus = BUS_MAPLE; input_register_device(&mouse->dev); printk(KERN_INFO "input%d: mouse(0x%lx): %s\n", mouse->dev.number, data, mouse->dev.name); *************** *** 94,102 **** } ! static void dc_mouse_disconnect(struct maple_device *dev) { ! struct dc_mouse *mouse = dev->private_data; input_unregister_device(&mouse->dev); --- 92,100 ---- } ! static void dc_mouse_disconnect(struct maple_driver_data *d) { ! struct dc_mouse *mouse = d->private_data; input_unregister_device(&mouse->dev); *************** *** 111,116 **** --- 109,116 ---- name: "Dreamcast mouse", connect: dc_mouse_connect, disconnect: dc_mouse_disconnect, + reply: dc_mouse_callback, + vblank: maple_getcond_vblank_callback, }; diff -C3 -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,26 **** --- 17,59 ---- #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,106 **** #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; ! struct timer_list maple_timer; ! unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; ! unsigned long maple_pnp_time; ! static struct maple_driver maple_dummy_driver = { ! function: 0, ! name: "Dummy", ! }; ! ! static void maple_dump_devinfo(struct maple_devinfo *devinfo) { ! 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)); } ! void maple_register_driver(struct maple_driver *driver) ! { ! struct list_head *lh = (void *)driver; ! list_add(lh, &maple_driver_list); ! ! MOD_INC_USE_COUNT; ! printk(KERN_INFO "maple: registered driver: %s (function 0x%lx)\n", ! driver->name, driver->function); ! } ! void maple_unregister_driver(struct maple_driver *driver) { ! struct list_head *lh = (void *)driver; ! list_del(lh); ! ! MOD_DEC_USE_COUNT; ! printk(KERN_INFO "maple: unregistered driver: %s (function 0x%lx)\n", ! driver->name, driver->function); } - 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); return mq; } --- 64,137 ---- #define MAPLE_DMA_SIZE (1<<MAPLE_DMA_ORDER) #define MAPLE_DMA_PAGES ((MAPLE_DMA_ORDER > PAGE_SHIFT) ? MAPLE_DMA_ORDER-PAGE_SHIFT : 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; ! /*** Heleper functions ***/ ! static void maple_detect_callback(struct mapleq *); ! static int maple_dma_done(void) { ! return (ctrl_inl(MAPLE_STATE) & 1) == 0; } ! #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. ! */ ! unsigned long *maple_sendbuf, *maple_sendptr; + static LIST_HEAD(maple_waitq); + static LIST_HEAD(maple_sentq); ! void maple_init_mq(struct mapleq *mq) { ! unsigned long buf; ! 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) { struct mapleq *mq; mq = kmalloc(sizeof(*mq), GFP_KERNEL); if (!mq) return NULL; ! maple_init_mq(mq); return mq; } *************** *** 114,206 **** kfree(mq); } ! static struct maple_device *maple_alloc_dev(int port, int unit) { ! struct maple_device *dev; ! dev = kmalloc(sizeof(*dev), GFP_KERNEL); ! if (!dev) ! return NULL; ! memset(dev, 0, sizeof(*dev)); ! dev->port = port; ! dev->unit = unit; ! dev->mq = maple_allocq(dev); ! if (!dev->mq) { ! kfree(dev); ! return NULL; } ! return dev; } ! static void maple_free_dev(struct maple_device *dev) { ! if (!dev) return; ! if (dev->mq) ! maple_freeq(dev->mq); ! kfree(dev); ! } ! static void maple_register_dev(struct maple_device *dev) ! { ! struct list_head *lh = (void *)dev; ! list_add_tail(lh, &maple_dev_list); ! } ! static void maple_unregister_dev(struct maple_device *dev) ! { ! struct list_head *lh = (void *)dev; ! list_del(lh); ! } - 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; } int maple_add_packet(struct mapleq *mq) { unsigned long flags; save_and_cli(flags); ! list_add((struct list_head *)mq, &maple_waitq); restore_flags(flags); ! return 0; } - 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; } } ! list_for_each(lh, &maple_waitq) { if (mq == (struct mapleq *)lh) list_del(lh); --- 145,379 ---- kfree(mq); } + static unsigned long last_gun_data; ! static void maple_dma_irq(int irq, void *dev, struct pt_regs *fp) { ! struct mapleq *mq; ! struct list_head *lh, tmph; ! DCOLOR(0x0000ff); ! IRQ_DPRINTK("MAPLE DMA IRQ BEGIN\n"); ! POLL_DPRINTK("Maple DMA finished %d, %d.\n", ! list_empty(&maple_sentq), !maple_dma_done()); ! if (list_empty(&maple_sentq) || !maple_dma_done()) return; ! #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 ! 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"); } ! ! ! /* Call this after one or more calls to maple_add_packet */ ! /* FIXME: implement scheduling */ ! static void low_maple_send(int vblank) { ! 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 (list_empty(&maple_waitq) || !maple_dma_done()) { ! restore_flags(flags); ! return; ! } ! 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; ! 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; ! 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_send(void) + { + low_maple_send(0); + } int maple_add_packet(struct mapleq *mq) { + int ret=0; unsigned long flags; save_and_cli(flags); ! 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 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 -EBUSY; } } ! list_for_each(lh, &maple_waitq) { if (mq == (struct mapleq *)lh) list_del(lh); *************** *** 211,453 **** return 0; } ! ! static int maple_dma_done(void) { ! return (ctrl_inl(MAPLE_STATE) & 1) == 0; ! } ! 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; - 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); ! printk(KERN_INFO "maple(%d,%d): Connected(function 0x%lx)\n", ! dev->port, dev->unit, function); ! list_for_each(lh, &maple_driver_list) { ! driver = (struct maple_driver *)lh; ! if (function & driver->function) { ! if (!driver->connect(dev)) { ! dev->driver = driver; ! break; ! } ! } } ! 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; } } ! ! static void maple_detach_driver(struct maple_device *dev) { ! printk(KERN_INFO "maple(%d,%d): Disconnected\n", ! dev->port, dev->unit); ! dev->driver->disconnect(dev); ! dev->driver = NULL; } ! static void maple_dma_irq(void) { ! struct mapleq *mq; ! struct maple_device *dev; ! struct list_head *lh, tmph; ! char *recvbuf; ! int code, need_wakeup = 0; - 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; ! recvbuf = mq->recvbuf; ! code = recvbuf[0]; ! switch (code) { ! case MAPLE_RESPONSE_NONE: ! case MAPLE_RESPONSE_DEVINFO: ! maple_getcond_callback(dev, NULL, 0, 0); ! dev->event = code; ! need_wakeup = 1; ! break; - case MAPLE_RESPONSE_DATATRF: - if (dev->callback) - dev->callback(mq); - break; ! default: ! break; ! } ! } ! ! INIT_LIST_HEAD(&maple_sentq); ! if (need_wakeup) ! wake_up(&kmapled_wait); } ! static void maple_build_block(struct mapleq *mq) { ! int port, unit, from, to, len; ! unsigned long *lsendbuf = mq->sendbuf; ! port = mq->dev->port & 3; ! unit = mq->dev->unit; ! len = mq->length; ! from = port<<6; ! to = (port<<6) | (unit>0 ? (1<<(unit-1))&0x1f : 0x20); ! *maple_lastptr &= 0x7fffffff; ! maple_lastptr = maple_sendptr; ! *maple_sendptr++ = (port<<16) | len | 0x80000000; ! *maple_sendptr++ = PHYSADDR(mq->recvbuf); ! *maple_sendptr++ = mq->command | (to<<8) | (from<<16) | (len<<24); ! while (len-->0) { ! *maple_sendptr++ = *lsendbuf++; ! } ! } ! void maple_send(void) ! { ! int i; ! int maple_packets; ! struct mapleq *mq; ! struct list_head *lh, tmph; ! if (!list_empty(&maple_sentq)) ! return; - if (list_empty(&maple_waitq) || !maple_dma_done()) - return; ! maple_packets = 0; ! maple_sendptr = maple_lastptr = maple_sendbuf; ! 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) break; } ! 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); } ! } ! static void maple_timer_handler(unsigned long dummy) { struct list_head *lh; ! struct maple_device *dev; ! /* If DMA is done, dispatch callback functions */ ! maple_dma_irq(); ! /* 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); } } ! else { ! if (jiffies>=maple_pnp_time) { ! dev->mq->command = MAPLE_COMMAND_DEVINFO; ! dev->mq->length = 0; ! maple_add_packet(dev->mq); } } - } ! if (jiffies>=maple_pnp_time) ! maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; ! ! /* Scan list and build sending block */ ! maple_send(); ! /* Schedule next timer event */ ! mod_timer(&maple_timer, jiffies + MAPLE_SCANHZ); } ! static void maple_pnp_events(void) { ! struct maple_device *dev; ! struct list_head *lh; ! list_for_each(lh, &maple_dev_list) { ! dev = (struct maple_device *)lh; ! switch(dev->event) { ! case MAPLE_RESPONSE_NONE: ! if (dev->driver) ! maple_detach_driver(dev); ! break; ! case MAPLE_RESPONSE_DEVINFO: ! if (!dev->driver) ! maple_attach_driver(dev); ! break; ! } ! dev->event = 0; } } static int kmapled_thread(void *hoge) { lock_kernel(); --- 384,758 ---- return 0; } ! void maple_set_gunmode(int port, void (cb)(void *,int,int),void *data) { ! #if 1 ! unsigned long flags; + save_and_cli(flags); ! if( (!ports[port].gunmode) ^ (!cb) ) { ! maple_active_guns += (cb ? 1 : -1); ! if(cb) maple_gunport=port; ! } ! ports[port].gunmode = cb; ! ports[port].gunmode_data = data; ! restore_flags(flags); ! printk("Setting gunmode for port %d to %p(%p) (active guns = %d)\n",port,cb,data,maple_active_guns); ! #endif ! } ! 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(); ! /* 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 exit_maple_low(void) { ! free_irq(HW_EVENT_MAPLE_DMA, 0); ! ! /* twiddle */ ! while(!maple_dma_done()); ! if (maple_sendbuf) ! free_pages((unsigned long)maple_sendbuf, MAPLE_DMA_PAGES); } ! ! /*** 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) { ! 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)); ! } ! void maple_register_driver(struct maple_driver *driver) ! { ! struct list_head *lh = (void *)driver; ! list_add(lh, &maple_driver_list); ! MOD_INC_USE_COUNT; ! printk(KERN_INFO "maple: registered driver: %s (function 0x%lx)\n", ! driver->name, driver->function); ! } ! void maple_unregister_driver(struct maple_driver *driver) ! { ! struct list_head *lh = (void *)driver; ! list_del(lh); ! MOD_DEC_USE_COUNT; ! printk(KERN_INFO "maple: unregistered driver: %s (function 0x%lx)\n", ! driver->name, driver->function); } ! static struct maple_device *maple_alloc_dev(int port, int unit) { ! unsigned long flags; ! struct maple_device *dev; ! SETUP_DPRINTK("Maple, Allocating unit %d, %d\n",port, unit); ! dev = kmalloc(sizeof(*dev), GFP_KERNEL); ! if (!dev) ! return NULL; ! memset(dev, 0, sizeof(*dev)); ! dev->port = port; ! dev->unit = unit; ! dev->lock = 0; ! CHECKALLP(); + save_and_cli(flags); + ports[port].dev[unit]=dev; + ports[port].known_units |= unitcodes[unit]; + restore_flags(flags); ! CHECKALLP(); ! return dev; ! } ! 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 ); ! } ! } ! 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(! driver->connect(data)) { ! save_and_cli(flags); ! list_add((struct list_head *)data, &maple_data_list); ! restore_flags(flags); ! return 0; } ! kfree( data ); + CHECKALLP(); ! return 1; ! } ! ! static void maple_attach_driver(int port, int unit) { struct list_head *lh; ! struct maple_driver *driver; ! unsigned long function, bits_left; ! char *p, *recvbuf = maple_detector.recvbuf; ! struct maple_device *dev=maple_alloc_dev(port, unit); ! 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; } ! ! /* 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; ! ! } } } ! 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; ! check_more_bits: ; ! } ! ! CHECKALLP(); } ! static void maple_detach_driver(int port, int unit) { ! unsigned long flags; ! struct list_head *lh, tmph; ! struct maple_device *dev=ports[port].dev[unit]; ! if(!dev) ! return; ! printk(KERN_INFO "maple(%d,%d): Disconnected (%d,%d)\n", ! dev->port, dev->unit, port, unit); ! 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); ! 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,463 **** strcpy(current->comm, "kmapled"); do { ! maple_pnp_events(); interruptible_sleep_on(&kmapled_wait); } while(!signal_pending(current)); --- 762,804 ---- strcpy(current->comm, "kmapled"); do { ! /*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,495 **** complete_and_exit(&kmapled_exited, 0); } ! static int __init maple_init(void) { ! struct maple_device *dev; ! int i; ! 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); ! /* Register dummy maple driver */ ! maple_register_driver(&maple_dummy_driver); ! /* 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); } /* Start kernel thread */ kmapled_pid = kernel_thread(kmapled_thread, NULL, --- 807,958 ---- 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; + } ! ! /* ! * 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) { ! int p=maple_detector.port; ! int u=maple_detector.unit; ! /* SETUP_DPRINTK("Detector callback.\n"); */ ! CHECKALLP(); ! 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; ! 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,517 **** 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); return 0; --- 960,970 ---- if (kmapled_pid==0) goto cleanup; ! 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,549 **** { /* XXX: Must do proper clean-up */ 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); } module_init(maple_init); module_exit(maple_exit); EXPORT_SYMBOL(maple_add_packet); EXPORT_SYMBOL(maple_del_packet); EXPORT_SYMBOL(maple_register_driver); EXPORT_SYMBOL(maple_unregister_driver); ! EXPORT_SYMBOL(maple_getcond_callback); /* * Local variables: --- 979,1007 ---- { /* XXX: Must do proper clean-up */ + free_irq(HW_EVENT_VSYNC, 0); + kill_proc(kmapled_pid, SIGTERM, 1); wait_for_completion(&kmapled_exited); ! 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_vblank_callback); /* * Local variables: diff -C3 -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,1057 **** return -EINVAL; } ! if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0, "pvr2 VBL handler", ¤tpar)) { DPRINTK("couldn't register VBL int\n"); return -EBUSY; --- 1051,1057 ---- return -EINVAL; } ! if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, SA_SHIRQ, "pvr2 VBL handler", ¤tpar)) { DPRINTK("couldn't register VBL int\n"); return -EBUSY; diff -C3 -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,70 **** #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! */ --- 64,69 ---- *************** *** 80,127 **** struct maple_driver; struct maple_device; struct mapleq { struct list_head list; ! struct maple_device *dev; ! void *sendbuf, *recvbuf; ! unsigned char command, length; 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; struct maple_devinfo devinfo; ! unsigned char port, unit; char product_name[32]; char product_license[64]; }; struct maple_driver { struct list_head list; ! unsigned long function; const char *name; ! int (*connect)(struct maple_device *dev); ! void (*disconnect)(struct maple_device *dev); }; 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_callback(struct maple_device *dev, - void (*callback)(struct mapleq *mq), - unsigned long interval, unsigned long function); /* * Local variables: --- 79,159 ---- struct maple_driver; struct maple_device; + + #define MAPLEQ_LENGTH_GUN (1<<9) + struct mapleq { struct list_head list; ! 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 { ! unsigned char port; ! unsigned char unit; ! short lock; ! ! unsigned long function; /* Little endian */ struct maple_devinfo devinfo; ! 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; /* One or more bits */ const char *name; ! ! 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 */ /* * Local variables: |