summaryrefslogtreecommitdiffstats
path: root/arch/m68k/atari/joystick.c
blob: df41b38d8b1317960112b055672a7cb00a4bc8c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
 * Atari Joystick Driver for Linux
 * by Robert de Vries (robert@and.nl) 19Jul93
 *
 * 16 Nov 1994 Andreas Schwab
 * Support for three button mouse (shamelessly stolen from MiNT)
 * third button wired to one of the joystick directions on joystick 1
 */

#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/major.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/smp_lock.h>

#include <asm/atarikb.h>
#include <asm/atari_joystick.h>
#include <asm/uaccess.h>

#define MAJOR_NR    JOYSTICK_MAJOR

#define	ANALOG_JOY(n)	(!(n & 0x80))
#define	DIGITAL_JOY(n)	(n & 0x80)
#define	DEVICE_NR(n)	(MINOR(n) & 0x7f)


static struct joystick_status joystick[2];
int atari_mouse_buttons; /* for three-button mouse */

void atari_joystick_interrupt(char *buf)
{
    int j;
/*    ikbd_joystick_disable(); */

    j = buf[0] & 0x1;
    joystick[j].dir   = buf[1] & 0xF;
    joystick[j].fire  = (buf[1] & 0x80) >> 7;
    joystick[j].ready = 1;
    wake_up_interruptible(&joystick[j].wait);

    /* For three-button mouse emulation fake a mouse packet */
    if (atari_mouse_interrupt_hook &&
	j == 1 && (buf[1] & 1) != ((atari_mouse_buttons & 2) >> 1))
      {
	char faked_packet[3];

	atari_mouse_buttons = (atari_mouse_buttons & 5) | ((buf[1] & 1) << 1);
	faked_packet[0] = (atari_mouse_buttons & 1) | 
			  (atari_mouse_buttons & 4 ? 2 : 0);
	faked_packet[1] = 0;
	faked_packet[2] = 0;
	atari_mouse_interrupt_hook (faked_packet);
      }

/*    ikbd_joystick_event_on(); */
}

static int release_joystick(struct inode *inode, struct file *file)
{
    int minor = DEVICE_NR(inode->i_rdev);

    lock_kernel();
    joystick[minor].active = 0;
    joystick[minor].ready = 0;

    if ((joystick[0].active == 0) && (joystick[1].active == 0))
	ikbd_joystick_disable();
    unlock_kernel();
    return 0;
}

static int open_joystick(struct inode *inode, struct file *file)
{
    int minor = DEVICE_NR(inode->i_rdev);

    if (!DIGITAL_JOY(inode->i_rdev) || minor > 1)
	return -ENODEV;
    if (joystick[minor].active)
	return -EBUSY;
    joystick[minor].active = 1;
    joystick[minor].ready = 0;
    ikbd_joystick_event_on();
    return 0;
}

static ssize_t write_joystick(struct file *file, const char *buffer,
			      size_t count, loff_t *ppos)
{
    return -EINVAL;
}

static ssize_t read_joystick(struct file *file, char *buffer, size_t count,
			     loff_t *ppos)
{
    struct inode *inode = file->f_dentry->d_inode;
    int minor = DEVICE_NR(inode->i_rdev);

    if (count < 2)
	return -EINVAL;
    if (!joystick[minor].ready)
	return -EAGAIN;
    joystick[minor].ready = 0;
    if (put_user(joystick[minor].fire, buffer++) ||
	put_user(joystick[minor].dir, buffer++))
	return -EFAULT;
    if (count > 2)
	if (clear_user(buffer, count - 2))
	    return -EFAULT;
    return count;
}

static unsigned int joystick_poll(struct file *file, poll_table *wait)
{
    int minor = DEVICE_NR(file->f_dentry->d_inode->i_rdev);

    poll_wait(file, &joystick[minor].wait, wait);
    if (joystick[minor].ready)
	return POLLIN | POLLRDNORM;
    return 0;
}

struct file_operations atari_joystick_fops = {
	read:		read_joystick,
	write:		write_joystick,
	poll:		joystick_poll,
	open:		open_joystick,
	release:	release_joystick,
};

int __init atari_joystick_init(void)
{
    joystick[0].active = joystick[1].active = 0;
    joystick[0].ready = joystick[1].ready = 0;
    init_waitqueue_head(&joystick[0].wait);
    init_waitqueue_head(&joystick[1].wait);

    if (devfs_register_chrdev(MAJOR_NR, "Joystick", &atari_joystick_fops))
	printk("unable to get major %d for joystick devices\n", MAJOR_NR);
    devfs_register_series (NULL, "joysticks/digital%u", 2, DEVFS_FL_DEFAULT,
			   MAJOR_NR, 128, S_IFCHR | S_IRUSR | S_IWUSR,
			   &atari_joystick_fops, NULL);

    return 0;
}