2 * ATI XL Bus Mouse Driver for Linux
3 * by Bob Harris (rth@sparta.com)
5 * Uses VFS interface for linux 0.98 (01OCT92)
7 * Modified by Chris Colohan (colohan@eecg.toronto.edu)
8 * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
13 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/sched.h>
17 #include <linux/signal.h>
18 #include <linux/errno.h>
19 #include <linux/miscdevice.h>
20 #include <linux/random.h>
21 #include <linux/poll.h>
22 #include <linux/init.h>
25 #include <asm/uaccess.h>
26 #include <asm/system.h>
29 #define ATIXL_MOUSE_IRQ 5 /* H/W interrupt # set up on ATIXL board */
30 #define ATIXL_BUSMOUSE 3 /* Minor device # (mknod c 10 3 /dev/bm) */
32 /* ATI XL Inport Busmouse Definitions */
34 #define ATIXL_MSE_DATA_PORT 0x23d
35 #define ATIXL_MSE_SIGNATURE_PORT 0x23e
36 #define ATIXL_MSE_CONTROL_PORT 0x23c
38 #define ATIXL_MSE_READ_BUTTONS 0x00
39 #define ATIXL_MSE_READ_X 0x01
40 #define ATIXL_MSE_READ_Y 0x02
42 /* Some nice ATI XL macros */
44 /* Select IR7, HOLD UPDATES (INT ENABLED), save X,Y */
45 #define ATIXL_MSE_DISABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
46 outb( (0x20 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
48 /* Select IR7, Enable updates (INT ENABLED) */
49 #define ATIXL_MSE_ENABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
50 outb( (0xdf & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
52 /* Select IR7 - Mode Register, NO INTERRUPTS */
53 #define ATIXL_MSE_INT_OFF() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
54 outb( (0xe7 & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
56 /* Select IR7 - Mode Register, DATA INTERRUPTS ENABLED */
57 #define ATIXL_MSE_INT_ON() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
58 outb( (0x08 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
60 /* Same general mouse structure */
62 static struct mouse_status
{
70 struct wait_queue
*wait
;
71 struct fasync_struct
*fasync
;
74 void mouse_interrupt(int irq
, void *dev_id
, struct pt_regs
* regs
)
78 ATIXL_MSE_DISABLE_UPDATE(); /* Note that interrupts are still enabled */
79 outb(ATIXL_MSE_READ_X
, ATIXL_MSE_CONTROL_PORT
); /* Select IR1 - X movement */
80 dx
= inb( ATIXL_MSE_DATA_PORT
);
81 outb(ATIXL_MSE_READ_Y
, ATIXL_MSE_CONTROL_PORT
); /* Select IR2 - Y movement */
82 dy
= inb( ATIXL_MSE_DATA_PORT
);
83 outb(ATIXL_MSE_READ_BUTTONS
, ATIXL_MSE_CONTROL_PORT
); /* Select IR0 - Button Status */
84 buttons
= inb( ATIXL_MSE_DATA_PORT
);
85 if (dx
!= 0 || dy
!= 0 || buttons
!= mouse
.latch_buttons
) {
86 add_mouse_randomness((buttons
<< 16) + (dy
<< 8) + dx
);
87 mouse
.latch_buttons
|= buttons
;
91 wake_up_interruptible(&mouse
.wait
);
93 kill_fasync(mouse
.fasync
, SIGIO
);
95 ATIXL_MSE_ENABLE_UPDATE();
98 static int fasync_mouse(int fd
, struct file
*filp
, int on
)
101 retval
= fasync_helper(fd
, filp
, on
, &mouse
.fasync
);
107 static int release_mouse(struct inode
* inode
, struct file
* file
)
109 fasync_mouse(-1, file
, 0);
112 ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
114 free_irq(ATIXL_MOUSE_IRQ
, NULL
);
119 static int open_mouse(struct inode
* inode
, struct file
* file
)
125 if (request_irq(ATIXL_MOUSE_IRQ
, mouse_interrupt
, 0, "ATIXL mouse", NULL
)) {
132 mouse
.buttons
= mouse
.latch_buttons
= 0;
133 ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */
139 static ssize_t
write_mouse(struct file
* file
, const char * buffer
,
140 size_t count
, loff_t
*ppos
)
145 static ssize_t
read_mouse(struct file
* file
, char * buffer
,
146 size_t count
, loff_t
*ppos
)
154 ATIXL_MSE_DISABLE_UPDATE();
155 /* Allowed interrupts to occur during data gathering - shouldn't hurt */
156 put_user((char)(~mouse
.latch_buttons
&7) | 0x80 , buffer
);
161 put_user((char)mouse
.dx
, buffer
+ 1);
166 put_user((char)-mouse
.dy
, buffer
+ 2);
167 for(i
= 3; i
< count
; i
++)
168 put_user(0x00, buffer
+ i
);
171 mouse
.latch_buttons
= mouse
.buttons
;
173 ATIXL_MSE_ENABLE_UPDATE();
174 return i
; /* i data bytes returned */
177 static unsigned int mouse_poll(struct file
*file
, poll_table
* wait
)
179 poll_wait(file
, &mouse
.wait
, wait
);
181 return POLLIN
| POLLRDNORM
;
185 struct file_operations atixl_busmouse_fops
= {
186 NULL
, /* mouse_seek */
189 NULL
, /* mouse_readdir */
190 mouse_poll
, /* mouse_poll */
191 NULL
, /* mouse_ioctl */
192 NULL
, /* mouse_mmap */
200 static struct miscdevice atixl_mouse
= {
201 ATIXL_BUSMOUSE
, "atixl", &atixl_busmouse_fops
205 __initfunc(int atixl_busmouse_init(void))
209 a
= inb( ATIXL_MSE_SIGNATURE_PORT
); /* Get signature */
210 b
= inb( ATIXL_MSE_SIGNATURE_PORT
);
211 c
= inb( ATIXL_MSE_SIGNATURE_PORT
);
212 if (( a
!= b
) && ( a
== c
))
213 printk(KERN_INFO
"\nATI Inport ");
218 outb(0x80, ATIXL_MSE_CONTROL_PORT
); /* Reset the Inport device */
219 outb(0x07, ATIXL_MSE_CONTROL_PORT
); /* Select Internal Register 7 */
220 outb(0x0a, ATIXL_MSE_DATA_PORT
); /* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */
224 mouse
.buttons
= mouse
.latch_buttons
= 0;
225 mouse
.dx
= mouse
.dy
= 0;
227 printk("Bus mouse detected and installed.\n");
228 misc_register(&atixl_mouse
);
234 int init_module(void)
236 return atixl_busmouse_init();
239 void cleanup_module(void)
241 misc_deregister(&atixl_mouse
);