Commit e21a85a7 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linux-input.bkbits.net/linux-input

into home.transmeta.com:/home/torvalds/v2.5/linux
parents d1de9834 382b8d8d
......@@ -64,6 +64,18 @@ CONFIG_INPUT_JOYDEV
The module will be called joydev.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_INPUT_TSDEV
Say Y here if you have an application that only can understand the
Compaq touchscreen protocol for absolute pointer data. This is
useful namely for embedded configurations.
If unsure, say N.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called tsdev.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_INPUT_EVDEV
Say Y here if you want your input device events be accessible
under char device 13:64+ - /dev/input/eventX in a generic way.
......@@ -72,3 +84,17 @@ CONFIG_INPUT_EVDEV
inserted in and removed from the running kernel whenever you want).
The module will be called evdev.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_INPUT_EVBUG
Say Y here if you have a problem with the input subsystem and
want all events (keypresses, mouse movements), to be output to
the system log. While this is useful for debugging, it's also
a security threat - your keypresses include your passwords, of
course.
If unsure, say N.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called joydev.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
......@@ -6,20 +6,34 @@ mainmenu_option next_comment
comment 'Input device support'
tristate 'Input core support' CONFIG_INPUT
comment 'Userland interfaces'
dep_tristate ' Keyboard interface' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
dep_tristate ' Mouse interface' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
dep_mbool ' Provide legacy /dev/psaux device' CONFIG_INPUT_MOUSEDEV_PSAUX $CONFIG_INPUT
if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
fi
dep_tristate ' Joystick interface' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
dep_tristate ' Touchscreen interface' CONFIG_INPUT_TSDEV $CONFIG_INPUT
if [ "$CONFIG_INPUT_TSDEV" != "n" ]; then
int ' Horizontal screen resolution' CONFIG_INPUT_TSDEV_SCREEN_X 240
int ' Vertical screen resolution' CONFIG_INPUT_TSDEV_SCREEN_Y 320
fi
dep_tristate ' Event interface' CONFIG_INPUT_EVDEV $CONFIG_INPUT
dep_tristate ' Event debugging' CONFIG_INPUT_EVBUG $CONFIG_INPUT
comment 'Input I/O drivers'
source drivers/input/gameport/Config.in
source drivers/input/serio/Config.in
comment 'Input Device Drivers'
if [ "$CONFIG_INPUT" != "n" ]; then
source drivers/input/keyboard/Config.in
source drivers/input/mouse/Config.in
source drivers/input/joystick/Config.in
source drivers/input/touchscreen/Config.in
fi
endmenu
......@@ -13,8 +13,14 @@ obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
obj-$(CONFIG_INPUT_TSDEV) += tsdev.o
obj-$(CONFIG_INPUT_POWER) += power.o
obj-$(CONFIG_INPUT_EVBUG) += evbug.o
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
obj-$(CONFIG_INPUT_MOUSE) += mouse/
obj-$(CONFIG_INPUT_JOYSTICK) += joystick/
obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
# The global Rules.make.
......
/*
* $Id: evbug.c,v 1.10 2001/09/25 10:12:07 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
/*
* Input driver event debug module - dumps all events into syslog
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/init.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input driver event debug module");
MODULE_LICENSE("GPL");
static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value);
}
static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
{
struct input_handle *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_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys);
return handle;
}
static void evbug_disconnect(struct input_handle *handle)
{
printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
input_close_device(handle);
kfree(handle);
}
static struct input_device_id evbug_ids[] = {
{ driver_info: 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
MODULE_DEVICE_TABLE(input, evbug_ids);
static struct input_handler evbug_handler = {
event: evbug_event,
connect: evbug_connect,
disconnect: evbug_disconnect,
name: "evbug",
id_table: evbug_ids,
};
int __init evbug_init(void)
{
input_register_handler(&evbug_handler);
return 0;
}
void __exit evbug_exit(void)
{
input_unregister_handler(&evbug_handler);
}
module_init(evbug_init);
module_exit(evbug_exit);
/*
* $Id: evdev.c,v 1.42 2002/01/02 11:59:56 vojtech Exp $
* $Id: evdev.c,v 1.48 2002/05/26 14:28:26 jdeneux Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
......@@ -40,7 +40,6 @@
struct evdev {
int exist;
int open;
int open_for_write;
int minor;
char name[16];
struct input_handle handle;
......@@ -91,7 +90,9 @@ static int evdev_fasync(int fd, struct file *file, int on)
static int evdev_flush(struct file * file)
{
return input_flush_device(&((struct evdev_list*)file->private_data)->evdev->handle, file);
struct evdev_list *list = (struct evdev_list*)file->private_data;
if (!list->evdev->exist) return -ENODEV;
return input_flush_device(&list->evdev->handle, file);
}
static int evdev_release(struct inode * inode, struct file * file)
......@@ -158,6 +159,8 @@ static ssize_t evdev_write(struct file * file, const char * buffer, size_t count
struct input_event event;
int retval = 0;
if (!list->evdev->exist) return -ENODEV;
while (retval < count) {
if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
......@@ -232,6 +235,8 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
struct input_dev *dev = evdev->handle.dev;
int retval, t, u;
if (!evdev->exist) return -ENODEV;
switch (cmd) {
case EVIOCGVERSION:
......@@ -284,11 +289,11 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
int err;
if (copy_from_user((void*)(&effect), (void*)arg, sizeof(effect))) {
return -EINVAL;
return -EFAULT;
}
err = dev->upload_effect(dev, &effect);
if (put_user(effect.id, &(((struct ff_effect*)arg)->id))) {
return -EINVAL;
return -EFAULT;
}
return err;
}
......@@ -301,7 +306,8 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
else return -ENOSYS;
case EVIOCGEFFECTS:
put_user(dev->ff_effects_max, (int*) arg);
if ((retval = put_user(dev->ff_effects_max, (int*) arg)))
return retval;
return 0;
default:
......
......@@ -43,13 +43,13 @@ CONFIG_GAMEPORT_EMU10K1
The module will be called emu10k1-gp.o. If you want to compile it as
a module, say M here and read <file:Documentation/modules.txt>.
CONFIG_GAMEPORT_PCIGAME
Say Y here if you have an Aureal Vortex 1 or 2 or a Trident
4DWave NX or DX card and want to use its gameport.
CONFIG_GAMEPORT_VORTEX
Say Y here if you have an Aureal Vortex 1 or 2 card and want
to use its gameport.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called pcigame.o. If you want to compile it as a
The module will be called vortex.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_GAMEPORT_CS461X
......
......@@ -14,6 +14,6 @@ fi
dep_tristate ' Classic ISA and PnP gameport support' CONFIG_GAMEPORT_NS558 $CONFIG_GAMEPORT
dep_tristate ' PDPI Lightning 4 gamecard support' CONFIG_GAMEPORT_L4 $CONFIG_GAMEPORT
dep_tristate ' SB Live and Audigy gameport support' CONFIG_INPUT_EMU10K1 $CONFIG_GAMEPORT
dep_tristate ' Aureal Vortex, Vortex 2 and Trident 4DWave NX/DX gameport support' CONFIG_GAMEPORT_PCIGAME $CONFIG_GAMEPORT
dep_tristate ' Aureal Vortex, Vortex 2 gameport support' CONFIG_GAMEPORT_VORTEX $CONFIG_GAMEPORT
dep_tristate ' ForteMedia FM801 gameport support' CONFIG_GAMEPORT_FM801 $CONFIG_GAMEPORT
dep_tristate ' Crystal SoundFusion gameport support' CONFIG_GAMEPORT_CS461x $CONFIG_GAMEPORT
......@@ -11,9 +11,10 @@ export-objs := gameport.o
obj-$(CONFIG_GAMEPORT) += gameport.o
obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o
obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o
obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o
obj-$(CONFIG_GAMEPORT_L4) += lightning.o
obj-$(CONFIG_GAMEPORT_NS558) += ns558.o
obj-$(CONFIG_GAMEPORT_PCIGAME) += pcigame.o
obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o
# The global Rules.make.
......
/*
* FM801 gameport driver for Linux
*
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/gameport.h>
#define PCI_VENDOR_ID_FORTEMEDIA 0x1319
#define PCI_DEVICE_ID_FM801_GP 0x0802
#define HAVE_COOKED
struct fm801_gp {
struct gameport gameport;
struct resource *res_port;
char phys[32];
char name[32];
};
#ifdef HAVE_COOKED
static int fm801_gp_cooked_read(struct gameport *gameport, int *axes, int *buttons)
{
unsigned short w;
w = inw(gameport->io + 2);
*buttons = (~w >> 14) & 0x03;
axes[0] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
w = inw(gameport->io + 4);
axes[1] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
w = inw(gameport->io + 6);
*buttons |= ((~w >> 14) & 0x03) << 2;
axes[2] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
w = inw(gameport->io + 8);
axes[3] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
outw(0xff, gameport->io); /* reset */
return 0;
}
#endif
static int fm801_gp_open(struct gameport *gameport, int mode)
{
switch (mode) {
#ifdef HAVE_COOKED
case GAMEPORT_MODE_COOKED:
return 0;
#endif
case GAMEPORT_MODE_RAW:
return 0;
default:
return -1;
}
return 0;
}
static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id)
{
struct fm801_gp *gp;
if (! (gp = kmalloc(sizeof(*gp), GFP_KERNEL))) {
printk("cannot malloc for fm801-gp\n");
return -1;
}
memset(gp, 0, sizeof(*gp));
gp->gameport.open = fm801_gp_open;
#ifdef HAVE_COOKED
gp->gameport.cooked_read = fm801_gp_cooked_read;
#endif
pci_enable_device(pci);
gp->gameport.io = pci_resource_start(pci, 0);
if ((gp->res_port = request_region(gp->gameport.io, 0x10, "FM801 GP")) == NULL) {
kfree(gp);
printk("unable to grab region 0x%x-0x%x\n", gp->gameport.io, gp->gameport.io + 0x0f);
return -1;
}
gp->gameport.phys = gp->phys;
gp->gameport.name = gp->name;
gp->gameport.idbus = BUS_PCI;
gp->gameport.idvendor = pci->vendor;
gp->gameport.idproduct = pci->device;
pci_set_drvdata(pci, gp);
outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */
gameport_register_port(&gp->gameport);
printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n",
pci->name, pci->slot_name, gp->gameport.speed);
return 0;
}
static void __devexit fm801_gp_remove(struct pci_dev *pci)
{
struct fm801_gp *gp = pci_get_drvdata(pci);
if (gp) {
gameport_unregister_port(&gp->gameport);
release_resource(gp->res_port);
kfree(gp);
}
}
static struct pci_device_id fm801_gp_id_table[] __devinitdata = {
{ PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0 }
};
static struct pci_driver fm801_gp_driver = {
name: "FM801 GP",
id_table: fm801_gp_id_table,
probe: fm801_gp_probe,
remove: fm801_gp_remove,
};
int __init fm801_gp_init(void)
{
return pci_module_init(&fm801_gp_driver);
}
void __exit fm801_gp_exit(void)
{
pci_unregister_driver(&fm801_gp_driver);
}
module_init(fm801_gp_init);
module_exit(fm801_gp_exit);
MODULE_DEVICE_TABLE(pci, fm801_gp_id_table);
MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
MODULE_LICENSE("GPL");
......@@ -54,16 +54,36 @@ EXPORT_SYMBOL(gameport_cooked_read);
static struct gameport *gameport_list;
static struct gameport_dev *gameport_dev;
#ifdef __i386__
#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180/HZ:0))
#define GET_TIME(x) do { x = get_time_pit(); } while (0)
static unsigned int get_time_pit(void)
{
extern spinlock_t i8253_lock;
unsigned long flags;
unsigned int count;
spin_lock_irqsave(&i8253_lock, flags);
outb_p(0x00, 0x43);
count = inb_p(0x40);
count |= inb_p(0x40) << 8;
spin_unlock_irqrestore(&i8253_lock, flags);
return count;
}
#endif
/*
* gameport_measure_speed() measures the gameport i/o speed.
*/
static int gameport_measure_speed(struct gameport *gameport)
{
#if defined(__i386__) || defined(__x86_64__)
#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0))
#ifdef __i386__
unsigned int i, t, t1, t2, t3, tx;
unsigned long flags;
......
/*
* $Id: pcigame.c,v 1.10 2001/04/26 10:24:46 vojtech Exp $
* $Id: vortex.c,v 1.5 2002/07/01 15:39:30 vojtech Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik
*
* Based on the work of:
* Raymond Ingles
*
* Sponsored by SuSE
*/
/*
......@@ -29,8 +27,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <asm/io.h>
......@@ -44,74 +42,61 @@
#include <linux/slab.h>
#include <linux/gameport.h>
#define PCI_VENDOR_ID_AUREAL 0x12eb
#define PCIGAME_DATA_WAIT 20 /* 20 ms */
#define PCIGAME_4DWAVE 0
#define PCIGAME_VORTEX 1
#define PCIGAME_VORTEX2 2
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver");
MODULE_LICENSE("GPL");
struct pcigame_data {
int gcr; /* Gameport control register */
int legacy; /* Legacy port location */
int axes; /* Axes start */
int axsize; /* Axis field size */
int axmax; /* Axis field max value */
int adcmode; /* Value to enable ADC mode in GCR */
};
#define VORTEX_GCR 0x0c /* Gameport control register */
#define VORTEX_LEG 0x08 /* Legacy port location */
#define VORTEX_AXD 0x10 /* Axes start */
#define VORTEX_DATA_WAIT 20 /* 20 ms */
static struct pcigame_data pcigame_data[] __devinitdata =
{{ 0x00030, 0x00031, 0x00034, 2, 0xffff, 0x80 },
{ 0x1100c, 0x11008, 0x11010, 4, 0x1fff, 0x40 },
{ 0x2880c, 0x28808, 0x28810, 4, 0x1fff, 0x40 },
{ 0 }};
struct pcigame {
struct vortex {
struct gameport gameport;
struct pci_dev *dev;
unsigned char *base;
struct pcigame_data *data;
unsigned char *io;
char phys[32];
};
static unsigned char pcigame_read(struct gameport *gameport)
static unsigned char vortex_read(struct gameport *gameport)
{
struct pcigame *pcigame = gameport->private;
return readb(pcigame->base + pcigame->data->legacy);
struct vortex *vortex = gameport->driver;
return readb(vortex->io + VORTEX_LEG);
}
static void pcigame_trigger(struct gameport *gameport)
static void vortex_trigger(struct gameport *gameport)
{
struct pcigame *pcigame = gameport->private;
writeb(0xff, pcigame->base + pcigame->data->legacy);
struct vortex *vortex = gameport->driver;
writeb(0xff, vortex->io + VORTEX_LEG);
}
static int pcigame_cooked_read(struct gameport *gameport, int *axes, int *buttons)
static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
{
struct pcigame *pcigame = gameport->private;
struct vortex *vortex = gameport->driver;
int i;
*buttons = (~readb(pcigame->base + pcigame->data->legacy) >> 4) & 0xf;
*buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
for (i = 0; i < 4; i++) {
axes[i] = readw(pcigame->base + pcigame->data->axes + i * pcigame->data->axsize);
if (axes[i] == pcigame->data->axmax) axes[i] = -1;
axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
if (axes[i] == 0x1fff) axes[i] = -1;
}
return 0;
}
static int pcigame_open(struct gameport *gameport, int mode)
static int vortex_open(struct gameport *gameport, int mode)
{
struct pcigame *pcigame = gameport->private;
struct vortex *vortex = gameport->driver;
switch (mode) {
case GAMEPORT_MODE_COOKED:
writeb(pcigame->data->adcmode, pcigame->base + pcigame->data->gcr);
wait_ms(PCIGAME_DATA_WAIT);
writeb(0x40, vortex->io + VORTEX_GCR);
wait_ms(VORTEX_DATA_WAIT);
return 0;
case GAMEPORT_MODE_RAW:
writeb(0, pcigame->base + pcigame->data->gcr);
writeb(0x00, vortex->io + VORTEX_GCR);
return 0;
default:
return -1;
......@@ -120,28 +105,33 @@ static int pcigame_open(struct gameport *gameport, int mode)
return 0;
}
static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_id *id)
static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
struct pcigame *pcigame;
struct vortex *vortex;
int i;
if (!(pcigame = kmalloc(sizeof(struct pcigame), GFP_KERNEL)))
if (!(vortex = kmalloc(sizeof(struct vortex), GFP_KERNEL)))
return -1;
memset(pcigame, 0, sizeof(struct pcigame));
memset(vortex, 0, sizeof(struct vortex));
pcigame->data = pcigame_data + id->driver_data;
vortex->dev = dev;
sprintf(vortex->phys, "pci%s/gameport0", dev->slot_name);
pcigame->dev = dev;
pci_set_drvdata(dev, pcigame);
pci_set_drvdata(dev, vortex);
pcigame->gameport.private = pcigame;
pcigame->gameport.fuzz = 64;
vortex->gameport.driver = vortex;
vortex->gameport.fuzz = 64;
pcigame->gameport.read = pcigame_read;
pcigame->gameport.trigger = pcigame_trigger;
pcigame->gameport.cooked_read = pcigame_cooked_read;
pcigame->gameport.open = pcigame_open;
vortex->gameport.read = vortex_read;
vortex->gameport.trigger = vortex_trigger;
vortex->gameport.cooked_read = vortex_cooked_read;
vortex->gameport.open = vortex_open;
vortex->gameport.name = dev->name;
vortex->gameport.phys = vortex->phys;
vortex->gameport.idbus = BUS_PCI;
vortex->gameport.idvendor = dev->vendor;
vortex->gameport.idproduct = dev->device;
for (i = 0; i < 6; i++)
if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
......@@ -149,51 +139,47 @@ static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_
pci_enable_device(dev);
pcigame->base = ioremap(pci_resource_start(pcigame->dev, i),
pci_resource_len(pcigame->dev, i));
vortex->base = ioremap(pci_resource_start(vortex->dev, i),
pci_resource_len(vortex->dev, i));
vortex->io = vortex->base + id->driver_data;
gameport_register_port(&pcigame->gameport);
gameport_register_port(&vortex->gameport);
printk(KERN_INFO "gameport%d: %s at pci%02x:%02x.%x speed %d kHz\n",
pcigame->gameport.number, dev->name, dev->bus->number,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), pcigame->gameport.speed);
printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n",
dev->name, dev->slot_name, vortex->gameport.speed);
return 0;
}
static void __devexit pcigame_remove(struct pci_dev *dev)
static void __devexit vortex_remove(struct pci_dev *dev)
{
struct pcigame *pcigame = pci_get_drvdata(dev);
gameport_unregister_port(&pcigame->gameport);
iounmap(pcigame->base);
kfree(pcigame);
struct vortex *vortex = pci_get_drvdata(dev);
gameport_unregister_port(&vortex->gameport);
iounmap(vortex->base);
kfree(vortex);
}
static struct pci_device_id pcigame_id_table[] __devinitdata =
{{ PCI_VENDOR_ID_TRIDENT, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE },
{ PCI_VENDOR_ID_TRIDENT, 0x2001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE },
{ PCI_VENDOR_ID_AUREAL, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX },
{ PCI_VENDOR_ID_AUREAL, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX2 },
static struct pci_device_id vortex_id_table[] __devinitdata =
{{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
{ 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
{ 0 }};
static struct pci_driver pcigame_driver = {
name: "pcigame",
id_table: pcigame_id_table,
probe: pcigame_probe,
remove: __devexit_p(pcigame_remove),
static struct pci_driver vortex_driver = {
name: "vortex",
id_table: vortex_id_table,
probe: vortex_probe,
remove: vortex_remove,
};
int __init pcigame_init(void)
int __init vortex_init(void)
{
return pci_module_init(&pcigame_driver);
return pci_module_init(&vortex_driver);
}
void __exit pcigame_exit(void)
void __exit vortex_exit(void)
{
pci_unregister_driver(&pcigame_driver);
pci_unregister_driver(&vortex_driver);
}
module_init(pcigame_init);
module_exit(pcigame_exit);
MODULE_LICENSE("GPL");
module_init(vortex_init);
module_exit(vortex_exit);
......@@ -61,8 +61,6 @@ static struct input_dev *input_dev;
static struct input_handler *input_handler;
static struct input_handler *input_table[8];
static devfs_handle_t input_devfs_handle;
static int input_number;
static long input_devices[NBITS(INPUT_DEVICES)];
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_bus_input_dir;
......@@ -454,17 +452,8 @@ void input_register_device(struct input_dev *dev)
* Add the device.
*/
if (input_number >= INPUT_DEVICES) {
printk(KERN_WARNING "input: ran out of input device numbers!\n");
dev->number = input_number;
} else {
dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES);
set_bit(dev->number, input_devices);
}
dev->next = input_dev;
input_dev = dev;
input_number++;
/*
* Notify handlers.
......@@ -493,7 +482,6 @@ void input_register_device(struct input_dev *dev)
input_devices_state++;
wake_up(&input_devices_poll_wait);
#endif
}
void input_unregister_device(struct input_dev *dev)
......@@ -509,7 +497,6 @@ void input_unregister_device(struct input_dev *dev)
if (dev->pm_dev)
pm_unregister(dev->pm_dev);
/*
* Kill any pending repeat timers.
*/
......@@ -540,7 +527,6 @@ void input_unregister_device(struct input_dev *dev)
*/
input_find_and_remove(struct input_dev, input_dev, dev, next);
input_number--;
/*
* Notify /proc.
*/
......
/*
* $Id: joydev.c,v 1.38 2001/12/27 10:37:41 vojtech Exp $
* $Id: joydev.c,v 1.43 2002/04/09 23:59:01 jsimmons Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
* Copyright (c) 1999 Colin Van Dyke
......@@ -49,7 +49,7 @@ MODULE_SUPPORTED_DEVICE("input/js");
MODULE_LICENSE("GPL");
#define JOYDEV_MINOR_BASE 0
#define JOYDEV_MINORS 32
#define JOYDEV_MINORS 16
#define JOYDEV_BUFFER_SIZE 64
#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
......@@ -254,6 +254,10 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
while (list->head == list->tail) {
if (!joydev->exist) {
retval = -ENODEV;
break;
}
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
break;
......@@ -325,6 +329,8 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct input_dev *dev = joydev->handle.dev;
int i;
if (!joydev->exist) return -ENODEV;
switch (cmd) {
case JS_SET_CAL:
......
......@@ -67,6 +67,15 @@ CONFIG_JOYSTICK_GRIP
The module will be called grip.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_JOYSTICK_GUILLEMOT
Say Y here if you have a Guillemot joystick using a digital
protocol over the PC gameport.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called guillemot.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_JOYSTICK_INTERACT
Say Y here if you have an InterAct gameport or joystick
communicating digitally over the gameport.
......@@ -158,6 +167,15 @@ CONFIG_JOYSTICK_STINGER
The module will be called stinger.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_JOYSTICK_TWIDDLER
Say Y here if you have a Handykey Twiddler connected to your
computer's serial port and want to use it as a joystick.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called twidjoy.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_JOYSTICK_DB9
Say Y here if you have a Sega Master System gamepad, Sega Genesis
gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
......
......@@ -10,6 +10,7 @@ dep_tristate ' Logitech ADI digital joysticks and gamepads' CONFIG_JOYSTICK_ADI
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 ' 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
......@@ -21,6 +22,7 @@ dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controllers' CONFIG_JOYSTICK_
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 as 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
......
......@@ -31,8 +31,9 @@ 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_IFORCE) += iforce.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_SIDEWINDER) += sidewinder.o
obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o
......@@ -40,8 +41,11 @@ 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
......@@ -426,10 +426,10 @@ static void adi_init_input(struct adi *adi, struct adi_port *port, int half)
adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++)
set_bit(adi->abs[i], &adi->dev.absbit);
set_bit(adi->abs[i], adi->dev.absbit);
for (i = 0; i < adi->buttons; i++)
set_bit(adi->key[i], &adi->dev.keybit);
set_bit(adi->key[i], adi->dev.keybit);
}
static void adi_init_center(struct adi *adi)
......
/*
* $Id: db9.c,v 1.12 2002/01/22 20:27:05 vojtech Exp $
* $Id: db9.c,v 1.13 2002/04/07 20:13:37 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
......@@ -199,7 +199,7 @@ static void db9_timer(unsigned long private)
data=parport_read_data(port);
input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
input_report_key(dev, BTN_X, ~data & DB9_FIRE2);
input_report_key(dev, BTN_START, ~data & DB9_FIRE2);
parport_write_control(port, DB9_NOSELECT); /* 2 */
udelay(DB9_GENESIS6_DELAY);
......@@ -209,10 +209,10 @@ static void db9_timer(unsigned long private)
udelay(DB9_GENESIS6_DELAY);
data=parport_read_data(port);
input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
input_report_key(dev, BTN_Z, ~data & DB9_DOWN);
input_report_key(dev, BTN_MODE, ~data & DB9_UP);
input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
input_report_key(dev, BTN_X, ~data & DB9_LEFT);
input_report_key(dev, BTN_Y, ~data & DB9_DOWN);
input_report_key(dev, BTN_Z, ~data & DB9_UP);
input_report_key(dev, BTN_MODE, ~data & DB9_RIGHT);
parport_write_control(port, DB9_NORMAL);
udelay(DB9_GENESIS6_DELAY);
......
/*
* $Id: gamecon.c,v 1.21 2002/01/22 20:27:27 vojtech Exp $
* $Id: gamecon.c,v 1.22 2002/07/01 15:42:25 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
......@@ -398,8 +398,8 @@ static void gc_timer(unsigned long private)
case GC_PSX_RUMBLE:
input_report_key(dev + i, BTN_THUMB, ~data[0] & 0x04);
input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
input_report_key(dev + i, BTN_THUMBL, ~data[0] & 0x04);
input_report_key(dev + i, BTN_THUMBR, ~data[0] & 0x02);
case GC_PSX_NEGCON:
case GC_PSX_ANALOG:
......
/*
* $Id: guillemot.c,v 1.10 2002/01/22 20:28:12 vojtech Exp $
*
* Copyright (c) 2001 Vojtech Pavlik
*/
/*
* Guillemot Digital Interface Protocol driver for Linux
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/input.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Guillemot Digital joystick driver");
MODULE_LICENSE("GPL");
#define GUILLEMOT_MAX_START 600 /* 600 us */
#define GUILLEMOT_MAX_STROBE 60 /* 60 us */
#define GUILLEMOT_MAX_LENGTH 17 /* 17 bytes */
#define GUILLEMOT_REFRESH_TIME HZ/50 /* 20 ms */
static short guillemot_abs_pad[] =
{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 };
static short guillemot_btn_pad[] =
{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_MODE, BTN_SELECT, -1 };
static struct {
int x;
int y;
} guillemot_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
struct guillemot_type {
unsigned char id;
short *abs;
short *btn;
int hat;
char *name;
};
struct guillemot {
struct gameport *gameport;
struct input_dev dev;
struct timer_list timer;
int used;
int bads;
int reads;
struct guillemot_type *type;
unsigned char length;
char phys[32];
};
static struct guillemot_type guillemot_type[] = {
{ 0x00, guillemot_abs_pad, guillemot_btn_pad, 1, "Guillemot Pad" },
{ 0 }};
/*
* guillemot_read_packet() reads Guillemot joystick data.
*/
static int guillemot_read_packet(struct gameport *gameport, u8 *data)
{
unsigned long flags;
unsigned char u, v;
unsigned int t, s;
int i;
for (i = 0; i < GUILLEMOT_MAX_LENGTH; i++)
data[i] = 0;
i = 0;
t = gameport_time(gameport, GUILLEMOT_MAX_START);
s = gameport_time(gameport, GUILLEMOT_MAX_STROBE);
__save_flags(flags);
__cli();
gameport_trigger(gameport);
v = gameport_read(gameport);
while (t > 0 && i < GUILLEMOT_MAX_LENGTH * 8) {
t--;
u = v; v = gameport_read(gameport);
if (v & ~u & 0x10) {
data[i >> 3] |= ((v >> 5) & 1) << (i & 7);
i++;
t = s;
}
}
__restore_flags(flags);
return i;
}
/*
* guillemot_timer() reads and analyzes Guillemot joystick data.
*/
static void guillemot_timer(unsigned long private)
{
struct guillemot *guillemot = (struct guillemot *) private;
struct input_dev *dev = &guillemot->dev;
u8 data[GUILLEMOT_MAX_LENGTH];
int i;
guillemot->reads++;
if (guillemot_read_packet(guillemot->gameport, data) != GUILLEMOT_MAX_LENGTH * 8 ||
data[0] != 0x55 || data[16] != 0xaa) {
guillemot->bads++;
} else {
for (i = 0; i < 6 && guillemot->type->abs[i] >= 0; i++)
input_report_abs(dev, guillemot->type->abs[i], data[i + 5]);
if (guillemot->type->hat) {
input_report_abs(dev, ABS_HAT0X, guillemot_hat_to_axis[data[4] >> 4].x);
input_report_abs(dev, ABS_HAT0Y, guillemot_hat_to_axis[data[4] >> 4].y);
}
for (i = 0; i < 16 && guillemot->type->btn[i] >= 0; i++)
input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1);
}
mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
}
/*
* guillemot_open() is a callback from the input open routine.
*/
static int guillemot_open(struct input_dev *dev)
{
struct guillemot *guillemot = dev->private;
if (!guillemot->used++)
mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
return 0;
}
/*
* guillemot_close() is a callback from the input close routine.
*/
static void guillemot_close(struct input_dev *dev)
{
struct guillemot *guillemot = dev->private;
if (!--guillemot->used)
del_timer(&guillemot->timer);
}
/*
* guillemot_connect() probes for Guillemot joysticks.
*/
static void guillemot_connect(struct gameport *gameport, struct gameport_dev *dev)
{
struct guillemot *guillemot;
u8 data[GUILLEMOT_MAX_LENGTH];
int i, t;
if (!(guillemot = kmalloc(sizeof(struct guillemot), GFP_KERNEL)))
return;
memset(guillemot, 0, sizeof(struct guillemot));
gameport->private = guillemot;
guillemot->gameport = gameport;
init_timer(&guillemot->timer);
guillemot->timer.data = (long) guillemot;
guillemot->timer.function = guillemot_timer;
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
goto fail1;
i = guillemot_read_packet(gameport, data);
if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa)
goto fail2;
for (i = 0; guillemot_type[i].name; i++)
if (guillemot_type[i].id == data[11])
break;
if (!guillemot_type[i].name) {
printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n",
gameport->phys, data[12], data[13], data[11], data[14], data[15]);
goto fail2;
}
sprintf(guillemot->phys, "%s/input0", gameport->phys);
guillemot->type = guillemot_type + i;
guillemot->dev.private = guillemot;
guillemot->dev.open = guillemot_open;
guillemot->dev.close = guillemot_close;
guillemot->dev.name = guillemot_type[i].name;
guillemot->dev.phys = guillemot->phys;
guillemot->dev.idbus = BUS_GAMEPORT;
guillemot->dev.idvendor = GAMEPORT_ID_VENDOR_GUILLEMOT;
guillemot->dev.idproduct = guillemot_type[i].id;
guillemot->dev.idversion = (int)data[14] << 8 | data[15];
guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) {
set_bit(t, guillemot->dev.absbit);
guillemot->dev.absmin[t] = 0;
guillemot->dev.absmax[t] = 255;
}
if (guillemot->type->hat)
for (i = 0; i < 2; i++) {
t = ABS_HAT0X + i;
set_bit(t, guillemot->dev.absbit);
guillemot->dev.absmin[t] = -1;
guillemot->dev.absmax[t] = 1;
}
for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++)
set_bit(t, guillemot->dev.keybit);
input_register_device(&guillemot->dev);
printk(KERN_INFO "input: %s ver %d.%02d on %s\n",
guillemot->type->name, data[14], data[15], gameport->phys);
return;
fail2: gameport_close(gameport);
fail1: kfree(guillemot);
}
static void guillemot_disconnect(struct gameport *gameport)
{
struct guillemot *guillemot = gameport->private;
printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys);
input_unregister_device(&guillemot->dev);
gameport_close(gameport);
kfree(guillemot);
}
static struct gameport_dev guillemot_dev = {
connect: guillemot_connect,
disconnect: guillemot_disconnect,
};
int __init guillemot_init(void)
{
gameport_register_device(&guillemot_dev);
return 0;
}
void __exit guillemot_exit(void)
{
gameport_unregister_device(&guillemot_dev);
}
module_init(guillemot_init);
module_exit(guillemot_exit);
This diff is collapsed.
#
# Makefile for the I-Force driver
#
# I-Force may need both USB and RS-232
CONFIG_JOYSTICK_IFORCE := n
ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
CONFIG_JOYSTICK_IFORCE := y
endif
endif
ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m)
CONFIG_JOYSTICK_IFORCE := m
endif
ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m)
CONFIG_JOYSTICK_IFORCE := m
endif
obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o
# The global Rules.make.
include $(TOPDIR)/Rules.make
# iforce.o is a multipart module.
IFORCEOBJS = iforce-ff.o iforce-main.o iforce-packets.o
ifneq ($(CONFIG_JOYSTICK_IFORCE_232),)
IFORCEOBJS += iforce-serio.o
endif
ifneq ($(CONFIG_JOYSTICK_IFORCE_USB),)
IFORCEOBJS += iforce-usb.o
endif
iforce.o: $(IFORCEOBJS)
$(LD) -i $(IFORCEOBJS) -o $@
This diff is collapsed.
This diff is collapsed.
/*
* $Id: iforce-packets.c,v 1.15 2002/06/09 11:08:04 jdeneux Exp $
*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
*
* USB/RS232 I-Force joysticks and wheels.
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include "iforce.h"
static struct {
__s32 x;
__s32 y;
} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data)
{
int i;
printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd);
for (i = 0; i < LO(cmd); i++)
printk("%02x ", data[i]);
printk(")\n");
}
/*
* Send a packet of bytes to the device
*/
int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
{
/* Copy data to buffer */
int n = LO(cmd);
int c;
int empty;
int head, tail;
unsigned long flags;
/*
* Update head and tail of xmit buffer
*/
spin_lock_irqsave(&iforce->xmit_lock, flags);
head = iforce->xmit.head;
tail = iforce->xmit.tail;
if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) {
printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n");
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
return -1;
}
empty = head == tail;
XMIT_INC(iforce->xmit.head, n+2);
/*
* Store packet in xmit buffer
*/
iforce->xmit.buf[head] = HI(cmd);
XMIT_INC(head, 1);
iforce->xmit.buf[head] = LO(cmd);
XMIT_INC(head, 1);
c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE);
if (n < c) c=n;
memcpy(&iforce->xmit.buf[head],
data,
c);
if (n != c) {
memcpy(&iforce->xmit.buf[0],
data + c,
n - c);
}
XMIT_INC(head, n);
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
/*
* If necessary, start the transmission
*/
switch (iforce->bus) {
#ifdef IFORCE_232
case IFORCE_232:
if (empty)
iforce_serial_xmit(iforce);
break;
#endif
#ifdef IFORCE_USB
case IFORCE_USB:
if (iforce->usbdev && empty &&
!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
iforce_usb_xmit(iforce);
}
break;
#endif
}
return 0;
}
/* Start or stop an effect */
int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value)
{
unsigned char data[3];
printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value);
data[0] = LO(id);
data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
data[2] = LO(value);
return iforce_send_packet(iforce, FF_CMD_PLAY, data);
}
/* Mark an effect that was being updated as ready. That means it can be updated
* again */
static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
{
int i;
for (i=0; i<iforce->dev.ff_effects_max; ++i) {
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
(iforce->core_effects[i].mod1_chunk.start == addr ||
iforce->core_effects[i].mod2_chunk.start == addr)) {
clear_bit(FF_CORE_UPDATE, iforce->core_effects[i].flags);
return 0;
}
}
printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr);
return -1;
}
void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
{
struct input_dev *dev = &iforce->dev;
int i;
static int being_used = 0;
if (being_used)
printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used);
being_used++;
#ifdef IFORCE_232
if (HI(iforce->expect_packet) == HI(cmd)) {
iforce->expect_packet = 0;
iforce->ecmd = cmd;
memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
if (waitqueue_active(&iforce->wait))
wake_up(&iforce->wait);
}
#endif
if (!iforce->type) {
being_used--;
return;
}
switch (HI(cmd)) {
case 0x01: /* joystick position data */
case 0x03: /* wheel position data */
if (HI(cmd) == 1) {
input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit))
input_report_abs(dev, ABS_RUDDER, (__s8)data[7]);
} else {
input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0]));
input_report_abs(dev, ABS_GAS, 255 - data[2]);
input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
}
input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
for (i = 0; iforce->type->btn[i] >= 0; i++)
input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7)));
/* If there are untouched bits left, interpret them as the second hat */
if (i <= 8) {
int btns = data[6];
if (test_bit(ABS_HAT1X, dev->absbit)) {
if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1);
else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1);
else input_report_abs(dev, ABS_HAT1X, 0);
}
if (test_bit(ABS_HAT1Y, dev->absbit)) {
if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1);
else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1);
else input_report_abs(dev, ABS_HAT1Y, 0);
}
}
break;
case 0x02: /* status report */
input_report_key(dev, BTN_DEAD, data[0] & 0x02);
/* Check if an effect was just started or stopped */
i = data[1] & 0x7f;
if (data[1] & 0x80) {
if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
/* Report play event */
input_report_ff_status(dev, i, FF_STATUS_PLAYING);
}
}
else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
/* Report stop event */
input_report_ff_status(dev, i, FF_STATUS_STOPPED);
}
if (LO(cmd) > 3) {
int j;
for (j=3; j<LO(cmd); j+=2) {
mark_core_as_ready(iforce, data[j] | (data[j+1]<<8));
}
}
break;
}
being_used--;
}
int iforce_get_id_packet(struct iforce *iforce, char *packet)
{
DECLARE_WAITQUEUE(wait, current);
int timeout = HZ; /* 1 second */
switch (iforce->bus) {
case IFORCE_USB:
#ifdef IFORCE_USB
iforce->cr.bRequest = packet[0];
iforce->ctrl->dev = iforce->usbdev;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&iforce->wait, &wait);
if (usb_submit_urb(iforce->ctrl, GFP_KERNEL)) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&iforce->wait, &wait);
return -1;
}
while (timeout && iforce->ctrl->status == -EINPROGRESS)
timeout = schedule_timeout(timeout);
set_current_state(TASK_RUNNING);
remove_wait_queue(&iforce->wait, &wait);
if (!timeout) {
usb_unlink_urb(iforce->ctrl);
return -1;
}
#else
printk(KERN_ERR "iforce_get_id_packet: iforce->bus = USB!\n");
#endif
break;
case IFORCE_232:
#ifdef IFORCE_232
iforce->expect_packet = FF_CMD_QUERY;
iforce_send_packet(iforce, FF_CMD_QUERY, packet);
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&iforce->wait, &wait);
while (timeout && iforce->expect_packet)
timeout = schedule_timeout(timeout);
set_current_state(TASK_RUNNING);
remove_wait_queue(&iforce->wait, &wait);
if (!timeout) {
iforce->expect_packet = 0;
return -1;
}
#else
printk(KERN_ERR "iforce_get_id_packet: iforce->bus = SERIO!\n");
#endif
break;
default:
printk(KERN_ERR "iforce_get_id_packet: iforce->bus = %d\n",
iforce->bus);
break;
}
return -(iforce->edata[0] != packet[0]);
}
/*
* $Id: iforce-serio.c,v 1.4 2002/01/28 22:45:00 jdeneux Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001 Johann Deneux <deneux@ifrance.com>
*
* USB/RS232 I-Force joysticks and wheels.
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include "iforce.h"
void iforce_serial_xmit(struct iforce *iforce)
{
unsigned char cs;
int i;
unsigned long flags;
if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags);
return;
}
spin_lock_irqsave(&iforce->xmit_lock, flags);
again:
if (iforce->xmit.head == iforce->xmit.tail) {
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
return;
}
cs = 0x2b;
serio_write(iforce->serio, 0x2b);
serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
cs ^= iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
cs ^= iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
}
serio_write(iforce->serio, cs);
if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
goto again;
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
}
static void iforce_serio_write_wakeup(struct serio *serio)
{
iforce_serial_xmit((struct iforce *)serio->private);
}
static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags)
{
struct iforce* iforce = serio->private;
if (!iforce->pkt) {
if (data != 0x2b) {
return;
}
iforce->pkt = 1;
return;
}
if (!iforce->id) {
if (data > 3 && data != 0xff) {
iforce->pkt = 0;
return;
}
iforce->id = data;
return;
}
if (!iforce->len) {
if (data > IFORCE_MAX_LENGTH) {
iforce->pkt = 0;
iforce->id = 0;
return;
}
iforce->len = data;
return;
}
if (iforce->idx < iforce->len) {
iforce->csum += iforce->data[iforce->idx++] = data;
return;
}
if (iforce->idx == iforce->len) {
iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
iforce->pkt = 0;
iforce->id = 0;
iforce->len = 0;
iforce->idx = 0;
iforce->csum = 0;
}
}
static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev)
{
struct iforce *iforce;
if (serio->type != (SERIO_RS232 | SERIO_IFORCE))
return;
if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return;
memset(iforce, 0, sizeof(struct iforce));
iforce->bus = IFORCE_232;
iforce->serio = serio;
serio->private = iforce;
if (serio_open(serio, dev)) {
kfree(iforce);
return;
}
if (iforce_init_device(iforce)) {
serio_close(serio);
kfree(iforce);
return;
}
}
static void iforce_serio_disconnect(struct serio *serio)
{
struct iforce* iforce = serio->private;
input_unregister_device(&iforce->dev);
serio_close(serio);
kfree(iforce);
}
struct serio_dev iforce_serio_dev = {
write_wakeup: iforce_serio_write_wakeup,
interrupt: iforce_serio_irq,
connect: iforce_serio_connect,
disconnect: iforce_serio_disconnect,
};
/*
* $Id: iforce-usb.c,v 1.16 2002/06/09 11:08:04 jdeneux Exp $
*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
*
* USB/RS232 I-Force joysticks and wheels.
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include "iforce.h"
void iforce_usb_xmit(struct iforce *iforce)
{
int n, c;
unsigned long flags;
spin_lock_irqsave(&iforce->xmit_lock, flags);
if (iforce->xmit.head == iforce->xmit.tail) {
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
return;
}
((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
n = iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
iforce->out->transfer_buffer_length = n + 1;
iforce->out->dev = iforce->usbdev;
/* Copy rest of data then */
c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE);
if (n < c) c=n;
memcpy(iforce->out->transfer_buffer + 1,
&iforce->xmit.buf[iforce->xmit.tail],
c);
if (n != c) {
memcpy(iforce->out->transfer_buffer + 1 + c,
&iforce->xmit.buf[0],
n-c);
}
XMIT_INC(iforce->xmit.tail, n);
if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
printk(KERN_WARNING "iforce-usb.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n);
}
/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
* As long as the urb completion handler is not called, the transmiting
* is considered to be running */
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
}
static void iforce_usb_irq(struct urb *urb)
{
struct iforce *iforce = urb->context;
if (urb->status) return;
iforce_process_packet(iforce,
(iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
}
static void iforce_usb_out(struct urb *urb)
{
struct iforce *iforce = urb->context;
if (urb->status) {
printk(KERN_DEBUG "iforce_usb_out: urb->status %d, exiting", urb->status);
return;
}
iforce_usb_xmit(iforce);
if (waitqueue_active(&iforce->wait))
wake_up(&iforce->wait);
}
static void iforce_usb_ctrl(struct urb *urb)
{
struct iforce *iforce = urb->context;
if (urb->status) return;
iforce->ecmd = 0xff00 | urb->actual_length;
if (waitqueue_active(&iforce->wait))
wake_up(&iforce->wait);
}
static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
{
struct usb_endpoint_descriptor *epirq, *epout;
struct iforce *iforce;
epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1;
if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL)))
goto fail;
memset(iforce, 0, sizeof(struct iforce));
if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL))) {
goto fail;
}
if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL))) {
goto fail;
}
if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) {
goto fail;
}
iforce->bus = IFORCE_USB;
iforce->usbdev = dev;
iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
iforce->cr.wIndex = 0;
iforce->cr.wLength = 16;
usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
usb_fill_bulk_urb(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
iforce + 1, 32, iforce_usb_out, iforce);
usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
(void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce);
if (iforce_init_device(iforce)) goto fail;
return iforce;
fail:
if (iforce) {
if (iforce->irq) usb_free_urb(iforce->irq);
if (iforce->out) usb_free_urb(iforce->out);
if (iforce->ctrl) usb_free_urb(iforce->ctrl);
kfree(iforce);
}
return NULL;
}
/* Called by iforce_delete() */
void iforce_usb_delete(struct iforce* iforce)
{
usb_unlink_urb(iforce->irq);
/* Is it ok to unlink those ? */
usb_unlink_urb(iforce->out);
usb_unlink_urb(iforce->ctrl);
usb_free_urb(iforce->irq);
usb_free_urb(iforce->out);
usb_free_urb(iforce->ctrl);
}
static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
{
struct iforce *iforce = ptr;
int open = iforce->dev.handle->open;
iforce->usbdev = NULL;
input_unregister_device(&iforce->dev);
if (!open) {
iforce_delete_device(iforce);
kfree(iforce);
}
}
static struct usb_device_id iforce_usb_ids [] = {
{ USB_DEVICE(0x044f, 0xa01c) }, /* Thrustmaster Motor Sport GT */
{ USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */
{ USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */
{ USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */
{ USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */
{ USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */
{ USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */
{ USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
{ USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, iforce_usb_ids);
struct usb_driver iforce_usb_driver = {
owner: THIS_MODULE,
name: "iforce",
probe: iforce_usb_probe,
disconnect: iforce_usb_disconnect,
id_table: iforce_usb_ids,
};
/*
* $Id: iforce.h,v 1.12 2002/06/09 11:08:04 jdeneux Exp $
*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
*
* USB/RS232 I-Force joysticks and wheels.
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
#include <linux/serio.h>
#include <linux/config.h>
#include <linux/circ_buf.h>
#include <asm/semaphore.h>
/* FF: This module provides arbitrary resource management routines.
* I use it to manage the device's memory.
* Despite the name of this module, I am *not* going to access the ioports.
*/
#include <linux/ioport.h>
#define IFORCE_MAX_LENGTH 16
#if defined(CONFIG_JOYSTICK_IFORCE_232)
#define IFORCE_232 1
#endif
#if defined(CONFIG_JOYSTICK_IFORCE_USB)
#define IFORCE_USB 2
#endif
#define FALSE 0
#define TRUE 1
#define FF_EFFECTS_MAX 32
/* Each force feedback effect is made of one core effect, which can be
* associated to at most to effect modifiers
*/
#define FF_MOD1_IS_USED 0
#define FF_MOD2_IS_USED 1
#define FF_CORE_IS_USED 2
#define FF_CORE_IS_PLAYED 3 /* Effect is currently being played */
#define FF_CORE_SHOULD_PLAY 4 /* User wants the effect to be played */
#define FF_CORE_UPDATE 5 /* Effect is being updated */
#define FF_MODCORE_MAX 5
#define CHECK_OWNERSHIP(i, iforce) \
((i) < FF_EFFECTS_MAX && i >= 0 && \
test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \
(current->pid == 0 || \
(iforce)->core_effects[(i)].owner == current->pid))
struct iforce_core_effect {
/* Information about where modifiers are stored in the device's memory */
struct resource mod1_chunk;
struct resource mod2_chunk;
unsigned long flags[NBITS(FF_MODCORE_MAX)];
pid_t owner;
/* Used to keep track of parameters of an effect. They are needed
* to know what parts of an effect changed in an update operation.
* We try to send only parameter packets if possible, as sending
* effect parameter requires the effect to be stoped and restarted
*/
struct ff_effect effect;
};
#define FF_CMD_EFFECT 0x010e
#define FF_CMD_ENVELOPE 0x0208
#define FF_CMD_MAGNITUDE 0x0303
#define FF_CMD_PERIOD 0x0407
#define FF_CMD_CONDITION 0x050a
#define FF_CMD_AUTOCENTER 0x4002
#define FF_CMD_PLAY 0x4103
#define FF_CMD_ENABLE 0x4201
#define FF_CMD_GAIN 0x4301
#define FF_CMD_QUERY 0xff01
/* Buffer for async write */
#define XMIT_SIZE 256
#define XMIT_INC(var, n) (var)+=n; (var)&= XMIT_SIZE -1
/* iforce::xmit_flags */
#define IFORCE_XMIT_RUNNING 0
#define IFORCE_XMIT_AGAIN 1
struct iforce_device {
u16 idvendor;
u16 idproduct;
char *name;
signed short *btn;
signed short *abs;
signed short *ff;
};
struct iforce {
struct input_dev dev; /* Input device interface */
struct iforce_device *type;
int bus;
unsigned char data[IFORCE_MAX_LENGTH];
unsigned char edata[IFORCE_MAX_LENGTH];
u16 ecmd;
u16 expect_packet;
#ifdef IFORCE_232
struct serio *serio; /* RS232 transfer */
int idx, pkt, len, id;
unsigned char csum;
#endif
#ifdef IFORCE_USB
struct usb_device *usbdev; /* USB transfer */
struct urb *irq, *out, *ctrl;
struct usb_ctrlrequest cr;
#endif
spinlock_t xmit_lock;
/* Buffer used for asynchronous sending of bytes to the device */
struct circ_buf xmit;
unsigned char xmit_data[XMIT_SIZE];
long xmit_flags[1];
/* Force Feedback */
wait_queue_head_t wait;
struct resource device_memory;
struct iforce_core_effect core_effects[FF_EFFECTS_MAX];
struct semaphore mem_mutex;
};
/* Get hi and low bytes of a 16-bits int */
#define HI(a) ((unsigned char)((a) >> 8))
#define LO(a) ((unsigned char)((a) & 0xff))
/* For many parameters, it seems that 0x80 is a special value that should
* be avoided. Instead, we replace this value by 0x7f
*/
#define HIFIX80(a) ((unsigned char)(((a)<0? (a)+255 : (a))>>8))
/* Encode a time value */
#define TIME_SCALE(a) (a)
/* Public functions */
/* iforce-serio.c */
void iforce_serial_xmit(struct iforce *iforce);
/* iforce-usb.c */
void iforce_usb_xmit(struct iforce *iforce);
void iforce_usb_delete(struct iforce *iforce);
/* iforce-main.c */
int iforce_init_device(struct iforce *iforce);
void iforce_delete_device(struct iforce *iforce);
/* iforce-packets.c */
int iforce_control_playback(struct iforce*, u16 id, unsigned int);
void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data);
int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data);
void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ;
int iforce_get_id_packet(struct iforce *iforce, char *packet);
/* iforce-ff.c */
int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update);
int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update);
int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update);
/* Public variables */
extern struct serio_dev iforce_serio_dev;
extern struct usb_driver iforce_usb_driver;
......@@ -156,7 +156,7 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev)
magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (i = 0; i < 9; i++)
set_bit(magellan_buttons[i], &magellan->dev.keybit);
set_bit(magellan_buttons[i], magellan->dev.keybit);
for (i = 0; i < 6; i++) {
t = magellan_axes[i];
......
/*
* $Id: twidjoy.c,v 1.5 2002/01/22 20:31:53 vojtech Exp $
*
* derived from CVS-ID "stinger.c,v 1.5 2001/05/29 12:57:18 vojtech Exp"
*
* Copyright (c) 2001 Arndt Schoenewald
* Copyright (c) 2000-2001 Vojtech Pavlik
* Copyright (c) 2000 Mark Fletcher
*
* Sponsored by Quelltext AG (http://www.quelltext-ag.de), Dortmund, Germany
*/
/*
* Driver to use Handykey's Twiddler (the first edition, i.e. the one with
* the RS232 interface) as a joystick under Linux
*
* The Twiddler is a one-handed chording keyboard featuring twelve buttons on
* the front, six buttons on the top, and a built-in tilt sensor. The buttons
* on the front, which are grouped as four rows of three buttons, are pressed
* by the four fingers (this implies only one button per row can be held down
* at the same time) and the buttons on the top are for the thumb. The tilt
* sensor delivers X and Y axis data depending on how the Twiddler is held.
* Additional information can be found at http://www.handykey.com.
*
* This driver does not use the Twiddler for its intended purpose, i.e. as
* a chording keyboard, but as a joystick: pressing and releasing a button
* immediately sends a corresponding button event, and tilting it generates
* corresponding ABS_X and ABS_Y events. This turns the Twiddler into a game
* controller with amazing 18 buttons :-)
*
* Note: The Twiddler2 (the successor of the Twiddler that connects directly
* to the PS/2 keyboard and mouse ports) is NOT supported by this driver!
*
* For questions or feedback regarding this driver module please contact:
* Arndt Schoenewald <arndt@quelltext.com>
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
/*
* Constants.
*/
#define TWIDJOY_MAX_LENGTH 5
static char *twidjoy_name = "Handykey Twiddler";
static struct twidjoy_button_spec {
int bitshift;
int bitmask;
int buttons[3];
}
twidjoy_buttons[] = {
{ 0, 3, { BTN_A, BTN_B, BTN_C } },
{ 2, 3, { BTN_X, BTN_Y, BTN_Z } },
{ 4, 3, { BTN_TL, BTN_TR, BTN_TR2 } },
{ 6, 3, { BTN_SELECT, BTN_START, BTN_MODE } },
{ 8, 1, { BTN_BASE5 } },
{ 9, 1, { BTN_BASE } },
{ 10, 1, { BTN_BASE3 } },
{ 11, 1, { BTN_BASE4 } },
{ 12, 1, { BTN_BASE2 } },
{ 13, 1, { BTN_BASE6 } },
{ 0, 0, { 0 } }
};
/*
* Per-Twiddler data.
*/
struct twidjoy {
struct input_dev dev;
int idx;
unsigned char data[TWIDJOY_MAX_LENGTH];
char phys[32];
};
/*
* twidjoy_process_packet() decodes packets the driver receives from the
* Twiddler. It updates the data accordingly.
*/
static void twidjoy_process_packet(struct twidjoy *twidjoy)
{
if (twidjoy->idx == TWIDJOY_MAX_LENGTH) {
struct input_dev *dev = &twidjoy->dev;
unsigned char *data = twidjoy->data;
struct twidjoy_button_spec *bp;
int button_bits, abs_x, abs_y;
button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f);
for (bp = twidjoy_buttons; bp->bitmask; bp++) {
int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift;
int i;
for (i = 0; i < bp->bitmask; i++)
input_report_key(dev, bp->buttons[i], i+1 == value);
}
abs_x = ((data[4] & 0x07) << 5) | ((data[3] & 0x7C) >> 2);
if (data[4] & 0x08) abs_x -= 256;
abs_y = ((data[3] & 0x01) << 7) | ((data[2] & 0x7F) >> 0);
if (data[3] & 0x02) abs_y -= 256;
input_report_abs(dev, ABS_X, -abs_x);
input_report_abs(dev, ABS_Y, +abs_y);
}
return;
}
/*
* twidjoy_interrupt() is called by the low level driver when characters
* are ready for us. We then buffer them for further processing, or call the
* packet processing routine.
*/
static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
{
struct twidjoy *twidjoy = serio->private;
/* All Twiddler packets are 5 bytes. The fact that the first byte
* has a MSB of 0 and all other bytes have a MSB of 1 can be used
* to check and regain sync. */
if ((data & 0x80) == 0)
twidjoy->idx = 0; /* this byte starts a new packet */
else if (twidjoy->idx == 0)
return; /* wrong MSB -- ignore this byte */
if (twidjoy->idx < TWIDJOY_MAX_LENGTH)
twidjoy->data[twidjoy->idx++] = data;
if (twidjoy->idx == TWIDJOY_MAX_LENGTH) {
twidjoy_process_packet(twidjoy);
twidjoy->idx = 0;
}
return;
}
/*
* twidjoy_disconnect() is the opposite of twidjoy_connect()
*/
static void twidjoy_disconnect(struct serio *serio)
{
struct twidjoy *twidjoy = serio->private;
input_unregister_device(&twidjoy->dev);
serio_close(serio);
kfree(twidjoy);
}
/*
* twidjoy_connect() is the routine that is called when someone adds a
* new serio device. It looks for the Twiddler, and if found, registers
* it as an input device.
*/
static void twidjoy_connect(struct serio *serio, struct serio_dev *dev)
{
struct twidjoy_button_spec *bp;
struct twidjoy *twidjoy;
int i;
if (serio->type != (SERIO_RS232 | SERIO_TWIDJOY))
return;
if (!(twidjoy = kmalloc(sizeof(struct twidjoy), GFP_KERNEL)))
return;
memset(twidjoy, 0, sizeof(struct twidjoy));
sprintf(twidjoy->phys, "%s/input0", serio->phys);
twidjoy->dev.name = twidjoy_name;
twidjoy->dev.phys = twidjoy->phys;
twidjoy->dev.idbus = BUS_RS232;
twidjoy->dev.idvendor = SERIO_TWIDJOY;
twidjoy->dev.idproduct = 0x0001;
twidjoy->dev.idversion = 0x0100;
twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (bp = twidjoy_buttons; bp->bitmask; bp++) {
for (i = 0; i < bp->bitmask; i++)
set_bit(bp->buttons[i], twidjoy->dev.keybit);
}
twidjoy->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
for (i = 0; i < 2; i++) {
twidjoy->dev.absmax[ABS_X+i] = 50;
twidjoy->dev.absmin[ABS_X+i] = -50;
/* TODO: arndt 20010708: Are these values appropriate? */
twidjoy->dev.absfuzz[ABS_X+i] = 4;
twidjoy->dev.absflat[ABS_X+i] = 4;
}
twidjoy->dev.private = twidjoy;
serio->private = twidjoy;
if (serio_open(serio, dev)) {
kfree(twidjoy);
return;
}
input_register_device(&twidjoy->dev);
printk(KERN_INFO "input: %s on %s\n", twidjoy_name, serio->phys);
}
/*
* The serio device structure.
*/
static struct serio_dev twidjoy_dev = {
interrupt: twidjoy_interrupt,
connect: twidjoy_connect,
disconnect: twidjoy_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
int __init twidjoy_init(void)
{
serio_register_device(&twidjoy_dev);
return 0;
}
void __exit twidjoy_exit(void)
{
serio_unregister_device(&twidjoy_dev);
}
module_init(twidjoy_init);
module_exit(twidjoy_exit);
/*
* $Id: keybdev.c,v 1.16 2002/01/09 04:21:41 lethal Exp $
* $Id: keybdev.c,v 1.19 2002/03/13 10:09:20 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
......@@ -179,7 +179,7 @@ void panic_blink(void)
static unsigned long last_jiffie;
static char led;
/* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is different. */
if (jiffies - last_jiffie > HZ/2) {
if (time_after(jiffies, last_jiffie + HZ/2)) {
led ^= 0x01 | 0x04;
keybdev_ledfunc(led);
last_jiffie = jiffies;
......
CONFIG_INPUT_KEYBOARD
Say Y here, and a list of supported keyboards will be displayed.
This option doesn't affect the kernel.
If unsure, say Y.
CONFIG_KEYBOARD_ATKBD
Say Y here if you want to use the standard AT keyboard. Usually
you'll need this, unless you have a different type keyboard (USB,
ADB or other).
If unsure, say Y.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called atkbd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_KEYBOARD_SUNKBD
Say Y here if you want to use a Sun Type 4 or Type 5 keyboard,
connected either to the Sun keyboard connector or to an serial
(RS-232) port via a simple adapter.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called sunkbd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_KEYBOARD_PS2SERKBD
Say Y here if you want to use a PS/2 to Serial converter with a
keyboard attached to it.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called ps2serkbd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_KEYBOARD_XTKBD
Say Y here if you want to use the old IBM PC/XT keyboard (or
compatible) on your system. This is only possible with a
parallel port keyboard adapter, you cannot connect it to the
keyboard port on a PC that runs Linux.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called xtkbd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_KEYBOARD_MAPLE
Say Y here if you have a DreamCast console running Linux and have
a keyboard attached to its Maple bus.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called maple_keyb.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_KEYBOARD_AMIGA
Say Y here if you are running Linux on any AMIGA and have a keyboard
attached.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called amikbd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
#
# Input core configuration
#
bool 'Keyboards' CONFIG_INPUT_KEYBOARD
dep_tristate ' AT keyboard support' CONFIG_KEYBOARD_ATKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
dep_tristate ' Sun Type 4 and Type 5 keyboard support' CONFIG_KEYBOARD_SUNKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
dep_tristate ' PS/2 to Serial converter support' CONFIG_KEYBOARD_PS2SERKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
dep_tristate ' XT Keyboard support' CONFIG_KEYBOARD_XTKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
dep_tristate ' Maple bus keyboard support' CONFIG_KEYBOARD_MAPLE $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_MAPLE
fi
if [ "$CONFIG_AMIGA" = "y" ]; then
dep_tristate ' Amiga keyboard' CONFIG_KEYBOARD_AMIGA $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD
fi
#
# Makefile for the input core drivers.
#
# Each configuration option enables a list of files.
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
obj-$(CONFIG_KEYBOARD_PS2SERKBD) += ps2serkbd.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
# The global Rules.make.
include $(TOPDIR)/Rules.make
/*
* $Id: amikbd.c,v 1.13 2002/02/01 16:02:24 vojtech Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik
*
* Based on the work of:
* Hamish Macdonald
*/
/*
* Amiga keyboard driver for Linux/m68k
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <asm/amigaints.h>
#include <asm/amigahw.h>
#include <asm/irq.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Amiga keyboard driver");
MODULE_LICENSE("GPL");
static unsigned char amikbd_keycode[0x78] = {
41, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 43, 0, 82,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0, 79, 80, 81,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 0, 0, 75, 76, 77,
0, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 0, 83, 71, 72, 73,
57, 14, 15, 96, 28, 1,111, 0, 0, 0, 74, 0,103,108,106,105,
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 98, 55, 78, 87,
42, 54, 58, 29, 56,100
}
static char *amikbd_messages[] = {
KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n",
KERN_WARNING "amikbd: keyboard lost sync\n",
KERN_WARNING "amikbd: keyboard buffer overflow\n",
KERN_WARNING "amikbd: keyboard controller failure\n",
KERN_ERR "amikbd: keyboard selftest failure\n",
KERN_INFO "amikbd: initiate power-up key stream\n",
KERN_INFO "amikbd: terminate power-up key stream\n",
KERN_WARNING "amikbd: keyboard interrupt\n"
};
static struct input_dev amikbd_dev;
static char *amikbd_name = "Amiga keyboard";
static char *amikbd_phys = "amikbd/input0";
static void amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
unsigned char scancode, down;
scancode = ~ciaa.sdr; /* get and invert scancode (keyboard is active low) */
ciaa.cra |= 0x40; /* switch SP pin to output for handshake */
udelay(85); /* wait until 85 us have expired */
ciaa.cra &= ~0x40; /* switch CIA serial port to input mode */
down = scancode & 1; /* lowest bit is release bit */
scancode = scancode >> 1;
if (scancode < 0x78) { /* scancodes < 0x78 are keys */
scancode = amikbd_keycode[scancode];
if (scancode == KEY_CAPS) { /* CapsLock is a toggle switch key on Amiga */
input_report_key(&amikbd_dev, scancode, 1);
input_report_key(&amikbd_dev, scancode, 0);
return;
}
input_report_key(&amikbd_dev, scancode, down);
return;
}
printk(amikbd_messages[scancode - 0x78]); /* scancodes >= 0x78 are error codes */
}
static int __init amikbd_init(void)
{
int i;
if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
return -EIO;
if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))
return -EBUSY;
amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
amikbd_dev.keycode = amikbd_keycode;
for (i = 0; i < 0x78; i++)
if (amikbd_keycode[i])
set_bit(amikbd_keycode[i], amikbd_dev.keybit);
ciaa.cra &= ~0x41; /* serial data in, turn off TA */
request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", NULL);
amikbd_dev.name = amikbd_name;
amikbd_dev.phys = amikbd_phys;
amikbd_dev.idbus = BUS_AMIGA;
amikbd_dev.idvendor = 0x0001;
amikbd_dev.idproduct = 0x0001;
amikbd_dev.idversion = 0x0100;
input_register_device(&amikbd_dev);
printk(KERN_INFO "input: %s\n", amikbd_name);
return 0;
}
static void __exit amikbd_exit(void)
{
input_unregister_device(&amikbd_dev);
free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt);
release_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100);
}
module_init(amikbd_init);
module_exit(amikbd_exit);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#
# Makefile for the mouse drivers.
#
# Each configuration option enables a list of files.
obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o
obj-$(CONFIG_MOUSE_ACORN) += rpcmouse.o
obj-$(CONFIG_MOUSE_INPORT) += inport.o
obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o
obj-$(CONFIG_MOUSE_PS2) += psmouse.o
obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
# The global Rules.make.
include $(TOPDIR)/Rules.make
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment