#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
+#include <linux/mutex.h>
#include <asm/system.h>
#include <asm/amigahw.h>
__obsolete_setup("amijoy=");
-static int amijoy_used[2] = { 0, 0 };
-static struct input_dev amijoy_dev[2];
+static int amijoy_used;
+static DEFINE_MUTEX(amijoy_mutex);
+static struct input_dev *amijoy_dev[2];
static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
-static char *amijoy_name = "Amiga joystick";
-
static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
int i, data = 0, button = 0;
if (amijoy[i]) {
switch (i) {
- case 0: data = ~custom.joy0dat; button = (~ciaa.pra >> 6) & 1; break;
- case 1: data = ~custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break;
+ case 0: data = ~amiga_custom.joy0dat; button = (~ciaa.pra >> 6) & 1; break;
+ case 1: data = ~amiga_custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break;
}
- input_regs(amijoy_dev + i, fp);
+ input_regs(amijoy_dev[i], fp);
- input_report_key(amijoy_dev + i, BTN_TRIGGER, button);
+ input_report_key(amijoy_dev[i], BTN_TRIGGER, button);
- input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1));
+ input_report_abs(amijoy_dev[i], ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1));
data = ~(data ^ (data << 1));
- input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1));
+ input_report_abs(amijoy_dev[i], ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1));
- input_sync(amijoy_dev + i);
+ input_sync(amijoy_dev[i]);
}
return IRQ_HANDLED;
}
static int amijoy_open(struct input_dev *dev)
{
- int *used = dev->private;
+ int err;
- if ((*used)++)
- return 0;
+ err = mutex_lock_interruptible(&amijoy_mutex);
+ if (err)
+ return err;
- if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
- (*used)--;
+ if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
- return -EBUSY;
+ err = -EBUSY;
+ goto out;
}
- return 0;
+ amijoy_used++;
+out:
+ mutex_unlock(&amijoy_mutex);
+ return err;
}
static void amijoy_close(struct input_dev *dev)
{
- int *used = dev->private;
-
- if (!--(*used))
+ mutex_lock(&amijoy_mutex);
+ if (!--amijoy_used)
free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
+ mutex_unlock(&amijoy_mutex);
}
static int __init amijoy_init(void)
{
int i, j;
+ int err;
- for (i = 0; i < 2; i++)
- if (amijoy[i]) {
- if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2,
- "amijoy [Denise]")) {
- if (i == 1 && amijoy[0]) {
- input_unregister_device(amijoy_dev);
- release_mem_region(CUSTOM_PHYSADDR+10, 2);
- }
- return -EBUSY;
- }
-
- amijoy_dev[i].open = amijoy_open;
- amijoy_dev[i].close = amijoy_close;
- amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
- amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- for (j = 0; j < 2; j++) {
- amijoy_dev[i].absmin[ABS_X + j] = -1;
- amijoy_dev[i].absmax[ABS_X + j] = 1;
- }
+ for (i = 0; i < 2; i++) {
+ if (!amijoy[i])
+ continue;
- amijoy_dev[i].name = amijoy_name;
- amijoy_dev[i].phys = amijoy_phys[i];
- amijoy_dev[i].id.bustype = BUS_AMIGA;
- amijoy_dev[i].id.vendor = 0x0001;
- amijoy_dev[i].id.product = 0x0003;
- amijoy_dev[i].id.version = 0x0100;
+ amijoy_dev[i] = input_allocate_device();
+ if (!amijoy_dev[i]) {
+ err = -ENOMEM;
+ goto fail;
+ }
- amijoy_dev[i].private = amijoy_used + i;
+ if (!request_mem_region(CUSTOM_PHYSADDR + 10 + i * 2, 2, "amijoy [Denise]")) {
+ input_free_device(amijoy_dev[i]);
+ err = -EBUSY;
+ goto fail;
+ }
- input_register_device(amijoy_dev + i);
- printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
+ amijoy_dev[i]->name = "Amiga joystick";
+ amijoy_dev[i]->phys = amijoy_phys[i];
+ amijoy_dev[i]->id.bustype = BUS_AMIGA;
+ amijoy_dev[i]->id.vendor = 0x0001;
+ amijoy_dev[i]->id.product = 0x0003;
+ amijoy_dev[i]->id.version = 0x0100;
+
+ amijoy_dev[i]->open = amijoy_open;
+ amijoy_dev[i]->close = amijoy_close;
+
+ amijoy_dev[i]->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ amijoy_dev[i]->absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+ amijoy_dev[i]->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ for (j = 0; j < 2; j++) {
+ amijoy_dev[i]->absmin[ABS_X + j] = -1;
+ amijoy_dev[i]->absmax[ABS_X + j] = 1;
}
+
+ input_register_device(amijoy_dev[i]);
+ }
return 0;
+
+ fail: while (--i >= 0)
+ if (amijoy[i]) {
+ input_unregister_device(amijoy_dev[i]);
+ release_mem_region(CUSTOM_PHYSADDR + 10 + i * 2, 2);
+ }
+ return err;
}
static void __exit amijoy_exit(void)
for (i = 0; i < 2; i++)
if (amijoy[i]) {
- input_unregister_device(amijoy_dev + i);
- release_mem_region(CUSTOM_PHYSADDR+10+i*2, 2);
+ input_unregister_device(amijoy_dev[i]);
+ release_mem_region(CUSTOM_PHYSADDR + 10 + i * 2, 2);
}
}