From: M. R. B. <mr...@us...> - 2002-10-29 21:38:16
|
Update of /cvsroot/linuxdc/linux-sh-dc/drivers/input/joystick In directory usw-pr-cvs1:/tmp/cvs-serv25716/drivers/input/joystick Added Files: Config.in Makefile maplecontrol.c purupuru.c Log Message: drivers/input/ changeover/update --- NEW FILE: Config.in --- # # Joystick driver configuration # bool 'Joysticks' CONFIG_INPUT_JOYSTICK dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_JOYSTICK_ANALOG $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Assasin 3D and MadCatz Panther devices' CONFIG_JOYSTICK_A3D $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Logitech ADI digital joysticks and gamepads' CONFIG_JOYSTICK_ADI $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_JOYSTICK_COBRA $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_JOYSTICK_GF2K $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOYSTICK_GRIP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Gravis GrIP MultiPort' CONFIG_JOYSTICK_GRIP_MP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Guillemot joysticks and gamepads' CONFIG_JOYSTICK_GUILLEMOT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_JOYSTICK_INTERACT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_JOYSTICK_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOYSTICK_TMDC $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT source drivers/input/joystick/iforce/Config.in dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_JOYSTICK_WARRIOR $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controllers' CONFIG_JOYSTICK_MAGELLAN $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controllers' CONFIG_JOYSTICK_SPACEORB $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO dep_tristate ' SpaceTec SpaceBall 6dof controllers' CONFIG_JOYSTICK_SPACEBALL $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO dep_tristate ' Gravis Stinger gamepad' CONFIG_JOYSTICK_STINGER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO dep_tristate ' Twiddler as a joystick' CONFIG_JOYSTICK_TWIDDLER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_JOYSTICK_DB9 $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_JOYSTICK_GAMECON $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_JOYSTICK_TURBOGRAFX $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT if [ "$CONFIG_AMIGA" = "y" ]; then dep_tristate ' Amiga joysticks' CONFIG_JOYSTICK_AMIGA $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK fi if [ "$CONFIG_MAPLE" != "n" ]; then dep_tristate ' Dreamcast Maple Bus controllers' CONFIG_JOYSTICK_MAPLE_CONTROL $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK dep_tristate ' Dreamcast Maple Bug lightguns' CONFIG_JOYSTICK_MAPLE_GUN $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK fi dep_tristate ' Gameport data dumper' CONFIG_INPUT_JOYDUMP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK --- NEW FILE: Makefile --- # # Makefile for the input core drivers. # # Each configuration option enables a list of files. obj-$(CONFIG_JOYSTICK_A3D) += a3d.o obj-$(CONFIG_JOYSTICK_ADI) += adi.o obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o obj-$(CONFIG_JOYSTICK_DB9) += db9.o obj-$(CONFIG_JOYSTICK_GAMECON) += gamecon.o obj-$(CONFIG_JOYSTICK_GF2K) += gf2k.o obj-$(CONFIG_JOYSTICK_GRIP) += grip.o obj-$(CONFIG_JOYSTICK_GRIP_MP) += grip_mp.o obj-$(CONFIG_JOYSTICK_GUILLEMOT) += guillemot.o obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o obj-$(CONFIG_JOYSTICK_MAPLE_CONTROL) += maplecontrol.o obj-$(CONFIG_JOYSTICK_MAPLE_GUN) += maple_lg.o obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o obj-$(CONFIG_JOYSTICK_SPACEORB) += spaceorb.o obj-$(CONFIG_JOYSTICK_STINGER) += stinger.o obj-$(CONFIG_JOYSTICK_TMDC) += tmdc.o obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o obj-$(CONFIG_JOYSTICK_TWIDJOY) += twidjoy.o obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o obj-$(CONFIG_JOYSTICK_IFORCE) += iforce/ # The global Rules.make. include $(TOPDIR)/Rules.make --- NEW FILE: maplecontrol.c --- /* * $Id: maplecontrol.c,v 1.1 2002/10/29 21:38:13 mrbrown Exp $ * SEGA Dreamcast controller driver * Based on drivers/usb/iforce.c */ #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> MODULE_AUTHOR("YAEGASHI Takeshi <t...@ke...>"); MODULE_DESCRIPTION("SEGA Dreamcast controller driver"); struct dc_pad { struct input_dev dev; int open; }; 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; buttons = ~*(unsigned short *)(res+8); input_report_abs(dev, ABS_HAT0Y, (buttons&0x0010?-1:0)+(buttons&0x0020?+1:0)); input_report_abs(dev, ABS_HAT0X, (buttons&0x0040?-1:0)+(buttons&0x0080?+1:0)); input_report_abs(dev, ABS_HAT1Y, (buttons&0x1000?-1:0)+(buttons&0x2000?+1:0)); input_report_abs(dev, ABS_HAT1X, (buttons&0x4000?-1:0)+(buttons&0x8000?+1:0)); input_report_key(dev, BTN_C, buttons&0x0001); input_report_key(dev, BTN_B, buttons&0x0002); input_report_key(dev, BTN_A, buttons&0x0004); input_report_key(dev, BTN_START, buttons&0x0008); input_report_key(dev, BTN_Z, buttons&0x0100); input_report_key(dev, BTN_Y, buttons&0x0200); input_report_key(dev, BTN_X, buttons&0x0400); input_report_key(dev, BTN_SELECT, buttons&0x0800); input_report_abs(dev, ABS_GAS, res[10]); input_report_abs(dev, ABS_BRAKE, res[11]); input_report_abs(dev, ABS_X, res[12]); input_report_abs(dev, ABS_Y, res[13]); input_report_abs(dev, ABS_RX, res[14]); input_report_abs(dev, ABS_RY, res[15]); } static int dc_pad_open(struct input_dev *dev) { struct dc_pad *pad = dev->private; pad->open++; return 0; } static void dc_pad_close(struct input_dev *dev) { struct dc_pad *pad = dev->private; pad->open--; } 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] = { BTN_C, BTN_B, BTN_A, BTN_START, -1, -1, -1, -1, BTN_Z, BTN_Y, BTN_X, BTN_SELECT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; const short abs_bit[32] = { -1, -1, -1, -1, ABS_HAT0Y, ABS_HAT0Y, ABS_HAT0X, ABS_HAT0X, -1, -1, -1, -1, ABS_HAT1Y, ABS_HAT1Y, ABS_HAT1X, ABS_HAT1X, ABS_GAS, ABS_BRAKE, ABS_X, ABS_Y, ABS_RX, ABS_RY, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; if (!(pad = kmalloc(sizeof(struct dc_pad), GFP_KERNEL))) 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) pad->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(btn_bit[i]); if (pad->dev.keybit[LONG(BTN_JOYSTICK)]) pad->dev.evbit[0] |= BIT(EV_KEY); for (i=0; i<32; i++) if (data&(1<<i) && abs_bit[i]>=0) pad->dev.absbit[0] |= BIT(abs_bit[i]); if (pad->dev.absbit[0]) pad->dev.evbit[0] |= BIT(EV_ABS); for (i=ABS_X; i<=ABS_BRAKE; i++) { pad->dev.absmax[i] = 255; pad->dev.absmin[i] = 0; pad->dev.absfuzz[i] = 0; pad->dev.absflat[i] = 0; } for (i=ABS_HAT0X; i<=ABS_HAT3Y; i++) { pad->dev.absmax[i] = 1; pad->dev.absmin[i] = -1; pad->dev.absfuzz[i] = 0; pad->dev.absflat[i] = 0; } pad->dev.private = pad; pad->dev.open = dc_pad_open; 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); MOD_INC_USE_COUNT; return 0; } static void dc_pad_disconnect(struct maple_driver_data *d) { struct dc_pad *pad = d->private_data; input_unregister_device(&pad->dev); kfree(pad); MOD_DEC_USE_COUNT; } static struct maple_driver dc_pad_driver = { function: MAPLE_FUNC_CONTROLLER, name: "Dreamcast controller", connect: dc_pad_connect, disconnect: dc_pad_disconnect, reply: dc_pad_callback, vblank: maple_getcond_vblank_callback, }; static int __init dc_pad_init(void) { maple_register_driver(&dc_pad_driver); return 0; } static void __exit dc_pad_exit(void) { maple_unregister_driver(&dc_pad_driver); } module_init(dc_pad_init); module_exit(dc_pad_exit); /* * Local variables: * c-basic-offset: 8 * End: */ --- NEW FILE: purupuru.c --- /* * Purupuru driver * for SEGA Dreamcast * Copyright (c) Adrian McMenamin, 2002 * * Licenced under the terms * of the Free Software Foundation * General Public Licence * Version 2 * See http://www.gnu.org * * Based on pre-existing Maple device coding * Copyright MR Brown, YAEGASHI Takeshi and others * * */ /* * First posted 18 February 2002 * * Multiple device support fixed 7 March 2002 * * Hot plugging bug fixed 14 March 2002 * */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/module.h> #include <linux/init.h> #include <linux/timer.h> #include <linux/maple.h> #include <linux/list.h> #include <asm/uaccess.h> #include <linux/mm.h> #include <asm/atomic.h> #include <linux/interrupt.h> #define PURU_MINOR_BASE 64 #define PPP_VERSION 2 /*#define _DEBUG_*/ #ifdef _DEBUG_ #define DEBGM(fmt, args...) (printk(KERN_ERR fmt, ##args)) #else #define DEBGM(fmt, args...) ((void) 0) #endif #define CHECKFUNC EVIOCGBIT(EV_FF, 16) static int last_minor; static unsigned long last_jiffies = -1; /* one list shared through all devices */ LIST_HEAD(effects_list); /* may be more than one puru puru attached */ LIST_HEAD(devices_list); static int use_count = 0; struct dc_puru_effect { int length_of_time; u16 sid; struct list_head list; }; struct dc_purupuru { struct input_dev dev; struct maple_driver_data *data; struct list_head list; int minor; atomic_t active; int timeleft; }; static struct input_handle *purupuru_connect(struct input_handler *handler, struct input_dev *dev); static struct input_handler purupuru_handler; static int dc_puru_open(struct input_dev *dev) { return 0; } static void dc_puru_close(struct input_dev *dev) { } static int dc_purupuru_connect(struct maple_driver_data *d) { /*unsigned long data = d->function_data; */ struct dc_purupuru *puru; if (!(puru = kmalloc(sizeof(struct dc_purupuru), GFP_KERNEL))) { DEBGM("Memory allocation failure\n"); return -ENOMEM; } memset(puru, 0, sizeof(struct dc_purupuru)); puru->data = d; d->private_data = puru; puru->dev.private = puru; puru->dev.open = dc_puru_open; puru->dev.close = dc_puru_close; puru->dev.name = d->dev->product_name; puru->dev.event = NULL; puru->dev.idbus = BUS_MAPLE; input_register_device(&puru->dev); if (use_count == 0) input_register_handler(&purupuru_handler); use_count++; return 0; } static void dc_purupuru_disconnect(struct maple_driver_data *d) { struct dc_purupuru *puru = d->private_data; input_unregister_device(&puru->dev); DEBGM("In dc_purupuru_disconnect\n"); use_count--; if (use_count < 0) use_count = 0; if (use_count == 0) input_unregister_handler(&purupuru_handler); } /* static void dc_purupuru_callback(struct maple_driver_data *data) */ /* { */ /* struct mapleq *mq = &data->mq; */ /* int res = mq->recvbuf[0]; */ /* printk */ /* ("Maple reply (%d, %d) cmd=%d => %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", */ /* mq->port, mq->unit, mq->command, res, mq->recvbuf[1], */ /* mq->recvbuf[2], mq->recvbuf[3], mq->recvbuf[4], */ /* mq->recvbuf[5], mq->recvbuf[6], mq->recvbuf[7], */ /* mq->recvbuf[8], mq->recvbuf[9], mq->recvbuf[10], */ /* mq->recvbuf[11]); */ /* } */ static int effect_number = 0; static int puru_ioctl(struct inode *inode, struct file *filip, unsigned int cmd, unsigned long arg) { struct ff_effect *ff_upload; struct ff_replay ff_time; struct dc_puru_effect *new_effect, *entry; struct list_head *ptr; switch (cmd) { case EVIOCGVERSION: return put_user(PPP_VERSION, (int *) arg); case CHECKFUNC: return put_user(FF_RUMBLE | FF_CONSTANT, (int *) arg); case EVIOCGEFFECTS: return put_user(1, (int *) arg); /* Save a FF effect */ case EVIOCSFF: /* * Currently * only supports: * length * */ ff_upload = kmalloc(sizeof(struct ff_effect), GFP_KERNEL); if (ff_upload == NULL) return -ENOMEM; copy_from_user(ff_upload, (void *) arg, sizeof(struct ff_effect)); /* Now get the length */ ff_time = ff_upload->replay; new_effect = kmalloc(sizeof(struct dc_puru_effect), GFP_KERNEL); if (new_effect == NULL) { kfree(ff_upload); return -ENOMEM; } new_effect->length_of_time = ff_time.length; new_effect->sid = effect_number++; list_add_tail(&new_effect->list, &effects_list); /* report the effect number back to the caller */ ff_upload->id = new_effect->sid; copy_to_user(arg, ff_upload, sizeof(struct ff_effect)); kfree(ff_upload); return 0; case EVIOCRMFF: if (list_empty(&effects_list)) return -EINVAL; /* walk through the list */ u16 find_id = (u16) arg; for (ptr = effects_list.next; ptr != &effects_list; ptr = ptr->next) { entry = list_entry(ptr, struct dc_puru_effect, list); if (entry->sid == find_id) { list_del(&entry->list); kfree(entry); return 0; } } return -EINVAL; default: return -1; } } static int puru_open(struct inode *inode, struct file *file) { file->private_data = MINOR(inode->i_rdev); return 0; } static void halt_puru(struct dc_purupuru *puru) { /* Halt the puru device immediately */ struct mapleq *halt = &(puru->data->mq); halt->command = 14; halt->length = 2; ((unsigned long *) (halt->recvbuf))[0] = cpu_to_be32(MAPLE_FUNC_PURUPURU); ((unsigned long *) (halt->recvbuf))[1] = 0x00; halt->sendbuf = halt->recvbuf; if (maple_add_packet(halt) != 0) DEBGM("Could not add packet\n"); } static void play_puru(struct dc_purupuru *puru) { /* Halt the puru device immediately */ struct mapleq *play = &(puru->data->mq); play->command = 14; play->length = 2; ((unsigned long *) (play->recvbuf))[0] = cpu_to_be32(MAPLE_FUNC_PURUPURU); ((unsigned long *) (play->recvbuf))[1] = 0x0000ffff; play->sendbuf = play->recvbuf; if (maple_add_packet(play) != 0) DEBGM("Could not add packet\n"); } /* 'Write' routine to play effects */ static ssize_t puru_play(struct file *file, const char *buffer, size_t count, loff_t * pos) { last_minor = file->private_data; /* buffer is a pointer to an input event */ struct input_event *play = kmalloc(sizeof(struct input_event), GFP_KERNEL); if (play == NULL) return -ENOMEM; memset(play, 0, sizeof(struct input_event)); copy_from_user(play, buffer, sizeof(struct input_event)); if (play->type != EV_FF) { kfree(play); return -EINVAL; } /* Which purupuru device are we playing with? */ struct dc_purupuru *select_me, *puru = NULL; struct list_head *ptr; for (ptr = devices_list.next; ptr != &devices_list; ptr = ptr->next) { select_me = list_entry(ptr, struct dc_purupuru, list); if (select_me->minor == last_minor) { puru = select_me; break; } } if (puru == NULL) { kfree(play); return -ENODEV; } /* Stop? In which case halt the Puru Puru immediately */ if (play->value == 0) { halt_puru(puru); kfree(play); return 0; } /* Walk through the list looking for the desired effect */ u16 find_id = play->code; struct dc_puru_effect *entry; for (ptr = effects_list.next; ptr != &effects_list; ptr = ptr->next) { entry = list_entry(ptr, struct dc_puru_effect, list); if (entry->sid == find_id) { play_puru(puru); /* Set up the timing measurements */ atomic_set(&puru->active, 1); puru->timeleft = entry->length_of_time; kfree(play); return 0; } } kfree(play); return -EINVAL; } /* vblank interrupt handling */ void switchoff_puru(unsigned long x) { int gap; if (time_before(jiffies, last_jiffies)) { gap = ((jiffies + (0xffffffff - last_jiffies)) * 1000) / HZ; } else gap = ((jiffies - last_jiffies) * 1000) / HZ; last_jiffies = jiffies; /* which Puru Puru packs are active? */ struct dc_purupuru *select_me; struct list_head *ptr; for (ptr = devices_list.next; ptr != &devices_list; ptr = ptr->next) { select_me = list_entry(ptr, struct dc_purupuru, list); if (atomic_read(&select_me->active) == 1) { select_me->timeleft -= gap; if (select_me->timeleft <= 0) { atomic_set(&select_me->active, 0); halt_puru(select_me); } } } return; } DECLARE_TASKLET(switchoff_tasklet, switchoff_puru, (unsigned long) 0); void dc_purupuru_wake(struct maple_driver_data *data) { if (last_jiffies == -1) { last_jiffies = jiffies; return; } tasklet_schedule(&switchoff_tasklet); } /* * Link the maple, input and fops * functions of this driver */ static struct maple_driver dc_purupuru_driver = { function:MAPLE_FUNC_PURUPURU, name:"Puru Puru Pack", connect:dc_purupuru_connect, disconnect:dc_purupuru_disconnect, /* reply:dc_purupuru_callback, */ vblank:dc_purupuru_wake, }; static struct file_operations puru_ops = { owner:THIS_MODULE, ioctl:puru_ioctl, write:puru_play, open:puru_open, }; static struct input_handle *purupuru_connect(struct input_handler *handler, struct input_dev *dev) { struct input_handle *handle; struct list_head *lst; struct dc_purupuru *device; /* tasklet_enable(&switchoff_tasklet); */ /* Is this a Puru Puru device? */ if (dev->open != dc_puru_open) { DEBGM("Attempted to connect non-PP device\n"); return NULL; } /* Have we already added this device? */ list_for_each(lst, &devices_list) { device = list_entry(lst, struct dc_purupuru, list); if (device->minor == (PURU_MINOR_BASE + dev->number)) { DEBGM ("Attempting to connect already connected PP\n"); return device->dev.handle; } } if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) return NULL; memset(handle, 0, sizeof(struct input_handle)); handle->dev = dev; handle->handler = handler; input_open_device(handle); printk(KERN_INFO "purupuru.c: adding Puru Puru Pack input%d\n", dev->number); handler->minor = PURU_MINOR_BASE + dev->number; /* Add to list */ struct dc_purupuru *dcp = dev->private; dcp->minor = handler->minor; list_add_tail(&dcp->list, &devices_list); return handle; } static void purupuru_disconnect(struct input_handle *handle) { /* Remove from list of devices */ struct list_head *ptr = NULL; struct list_head *nxt = NULL; struct dc_purupuru *device; list_for_each_safe(ptr, nxt, &devices_list) { device = list_entry(ptr, struct dc_purupuru, list); if (device->minor == handle->handler->minor) { DEBGM("Disconnection: removing from list\n"); list_del(&device->list); } } input_close_device(handle); kfree(handle); kfree(device); } static struct input_handler purupuru_handler = { connect:purupuru_connect, disconnect:purupuru_disconnect, fops:&puru_ops, minor:PURU_MINOR_BASE, }; static int __init dc_purupuru_init(void) { maple_register_driver(&dc_purupuru_driver); printk("Puru Puru Pack driver for Dreamcast Linux version 0.2\n"); /* tasklet_disable(&switchoff_tasklet); */ return 0; } static void __exit dc_purupuru_exit(void) { struct list_head *ptr = NULL; struct list_head *nxt = NULL; struct dc_puru_effect *effect; maple_unregister_driver(&dc_purupuru_driver); if (!list_empty(&effects_list)) { list_for_each_safe(ptr, nxt, &effects_list) { effect = list_entry(ptr, struct dc_puru_effect, list); if (effect) { list_del(&(effect->list)); kfree(effect); } } } } module_init(dc_purupuru_init); module_exit(dc_purupuru_exit); MODULE_AUTHOR("Adrian McMenamin <ad...@mc...>"); MODULE_DESCRIPTION("SEGA Dreamcast purupuru driver"); |