patch-1.3.93 linux/drivers/char/sunmouse.c
Next file: linux/drivers/isdn/Config.in
Previous file: linux/drivers/char/suncons.c
Back to the patch index
Back to the overall index
- Lines: 421
- Date:
Sun Apr 21 17:32:01 1996
- Orig file:
v1.3.92/linux/drivers/char/sunmouse.c
- Orig date:
Thu Jan 1 02:00:00 1970
diff -u --recursive --new-file v1.3.92/linux/drivers/char/sunmouse.c linux/drivers/char/sunmouse.c
@@ -0,0 +1,420 @@
+/* sunmouse.c: Sun mouse driver for the Sparc
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Parts based on the psaux.c driver written by:
+ * Johan Myreen.
+ *
+ * Dec/19/95 Added SunOS mouse ioctls - miguel.
+ * Jan/5/96 Added VUID support, sigio supprot - miguel.
+ * Mar/5/96 Added proper mouse stream support - miguel.
+ */
+
+/* The mouse is run off of one of the Zilog serial ports. On
+ * that port is the mouse and the keyboard, each gets a zs channel.
+ * The mouse itself is mouse-systems in nature. So the protocol is:
+ *
+ * Byte 1) Button state which is bit-encoded as
+ * 0x4 == left-button down, else up
+ * 0x2 == middle-button down, else up
+ * 0x1 == right-button down, else up
+ *
+ * Byte 2) Delta-x
+ * Byte 3) Delta-y
+ * Byte 4) Delta-x again
+ * Byte 5) Delta-y again
+ *
+ * One day this driver will have to support more than one mouse in the system.
+ *
+ * This driver has two modes of operation: the default VUID_NATIVE is
+ * set when the device is opened and allows the application to see the
+ * mouse character stream as we get it from the serial (for gpm for
+ * example). The second method, VUID_FIRM_EVENT will provide cooked
+ * events in Firm_event records.
+ * */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fcntl.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/vuid_event.h>
+#include <linux/random.h>
+/* The following keeps track of software state for the Sun
+ * mouse.
+ */
+#define STREAM_SIZE 2048
+#define EV_SIZE (STREAM_SIZE/sizeof (Firm_event))
+#define BUTTON_LEFT 4
+#define BUTTON_MIDDLE 2
+#define BUTTON_RIGHT 1
+
+struct sun_mouse {
+ unsigned char transaction[5]; /* Each protocol transaction */
+ unsigned char byte; /* Counter, starts at 0 */
+ unsigned char button_state; /* Current button state */
+ unsigned char prev_state; /* Previous button state */
+ int delta_x; /* Current delta-x */
+ int delta_y; /* Current delta-y */
+ int present;
+ int ready; /* set if there if data is available */
+ int active; /* set if device is open */
+ int vuid_mode; /* VUID_NATIVE or VUID_FIRM_EVENT */
+ struct wait_queue *proc_list;
+ struct fasync_struct *fasync;
+
+ /* The event/stream queue */
+ unsigned int head;
+ unsigned int tail;
+ union {
+ char stream [STREAM_SIZE];
+ Firm_event ev [0];
+ } queue;
+};
+
+static struct sun_mouse sunmouse;
+#define gen_events (sunmouse.vuid_mode != VUID_NATIVE)
+#define bstate sunmouse.button_state
+#define pstate sunmouse.prev_state
+
+extern void mouse_put_char(char ch);
+
+/* #define SMOUSE_DEBUG */
+
+static void
+push_event (Firm_event *ev)
+{
+ int next = (sunmouse.head + 1) % EV_SIZE;
+
+ if (next != sunmouse.tail){
+ sunmouse.queue.ev [sunmouse.head] = *ev;
+ sunmouse.head = next;
+ }
+}
+
+static int
+queue_empty (void)
+{
+ return sunmouse.head == sunmouse.tail;
+}
+
+static Firm_event *
+get_from_queue (void)
+{
+ Firm_event *result;
+
+ result = &sunmouse.queue.ev [sunmouse.tail];
+ sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE;
+ return result;
+}
+
+static void
+push_char (char c)
+{
+ int next = (sunmouse.head + 1) % STREAM_SIZE;
+
+ if (next != sunmouse.tail){
+ sunmouse.queue.stream [sunmouse.head] = c;
+ sunmouse.head = next;
+ }
+ sunmouse.ready = 1;
+ if (sunmouse.fasync)
+ kill_fasync (sunmouse.fasync, SIGIO);
+ wake_up_interruptible (&sunmouse.proc_list);
+}
+
+/* The following is called from the zs driver when bytes are received on
+ * the Mouse zs8530 channel.
+ */
+void
+sun_mouse_inbyte(unsigned char byte, unsigned char status)
+{
+ signed char mvalue;
+ int d;
+ Firm_event ev;
+
+ add_mouse_randomness (byte);
+ if(!sunmouse.active)
+ return;
+
+ if (!gen_events){
+ push_char (byte);
+ return;
+ }
+ /* Check for framing errors and parity errors */
+ /* XXX TODO XXX */
+
+ /* If the mouse sends us a byte from 0x80 to 0x87
+ * we are starting at byte zero in the transaction
+ * protocol.
+ */
+ if(byte >= 0x80 && byte <= 0x87)
+ sunmouse.byte = 0;
+
+ mvalue = (signed char) byte;
+ switch(sunmouse.byte) {
+ case 0:
+ /* Button state */
+ sunmouse.button_state = (~byte) & 0x7;
+#ifdef SMOUSE_DEBUG
+ printk("B<Left %s, Middle %s, Right %s>",
+ ((sunmouse.button_state & 0x4) ? "DOWN" : "UP"),
+ ((sunmouse.button_state & 0x2) ? "DOWN" : "UP"),
+ ((sunmouse.button_state & 0x1) ? "DOWN" : "UP"));
+#endif
+ sunmouse.byte++;
+ return;
+ case 1:
+ /* Delta-x 1 */
+#ifdef SMOUSE_DEBUG
+ printk("DX1<%d>", mvalue);
+#endif
+ sunmouse.delta_x = mvalue;
+ sunmouse.byte++;
+ return;
+ case 2:
+ /* Delta-y 1 */
+#ifdef SMOUSE_DEBUG
+ printk("DY1<%d>", mvalue);
+#endif
+ sunmouse.delta_y = mvalue;
+ sunmouse.byte++;
+ return;
+ case 3:
+ /* Delta-x 2 */
+#ifdef SMOUSE_DEBUG
+ printk("DX2<%d>", mvalue);
+#endif
+ sunmouse.delta_x += mvalue;
+ sunmouse.byte++;
+ return;
+ case 4:
+ /* Last byte, Delta-y 2 */
+#ifdef SMOUSE_DEBUG
+ printk("DY2<%d>", mvalue);
+#endif
+ sunmouse.delta_y += mvalue;
+ sunmouse.byte = 69; /* Some rediculious value */
+ break;
+ case 69:
+ /* Until we get the (0x80 -> 0x87) value we aren't
+ * in the middle of a real transaction, so just
+ * return.
+ */
+ return;
+ default:
+ printk("sunmouse: bogon transaction state\n");
+ sunmouse.byte = 69; /* What could cause this? */
+ return;
+ };
+ d = bstate ^ pstate;
+ pstate = bstate;
+ if (d){
+ if (d & BUTTON_LEFT){
+ ev.id = MS_LEFT;
+ ev.value = bstate & BUTTON_LEFT;
+ }
+ if (d & BUTTON_RIGHT){
+ ev.id = MS_RIGHT;
+ ev.value = bstate & BUTTON_RIGHT;
+ }
+ if (d & BUTTON_MIDDLE){
+ ev.id = MS_MIDDLE;
+ ev.value = bstate & BUTTON_MIDDLE;
+ }
+ ev.time = xtime;
+ ev.value = ev.value ? VKEY_DOWN : VKEY_UP;
+ push_event (&ev);
+ }
+ if (sunmouse.delta_x){
+ ev.id = LOC_X_DELTA;
+ ev.time = xtime;
+ ev.value = sunmouse.delta_x;
+ push_event (&ev);
+ sunmouse.delta_x = 0;
+ }
+ if (sunmouse.delta_y){
+ ev.id = LOC_Y_DELTA;
+ ev.time = xtime;
+ ev.value = sunmouse.delta_y;
+ push_event (&ev);
+ }
+
+ /* We just completed a transaction, wake up whoever is awaiting
+ * this event.
+ */
+ sunmouse.ready = 1;
+ if (sunmouse.fasync)
+ kill_fasync (sunmouse.fasync, SIGIO);
+ wake_up_interruptible(&sunmouse.proc_list);
+ return;
+}
+
+static int
+sun_mouse_open(struct inode * inode, struct file * file)
+{
+ if(!sunmouse.present)
+ return -EINVAL;
+ if(sunmouse.active)
+ return -EBUSY;
+ sunmouse.active = 1;
+ sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
+ sunmouse.button_state = 0x80;
+ sunmouse.vuid_mode = VUID_NATIVE;
+ return 0;
+}
+
+static int
+sun_mouse_fasync (struct inode *inode, struct file *filp, int on)
+{
+ int retval;
+
+ retval = fasync_helper (inode, filp, on, &sunmouse.fasync);
+ if (retval < 0)
+ return retval;
+ return 0;
+}
+
+static void
+sun_mouse_close(struct inode *inode, struct file *file)
+{
+ sunmouse.active = sunmouse.ready = 0;
+ sun_mouse_fasync (inode, file, 0);
+}
+
+static int
+sun_mouse_write(struct inode *inode, struct file *file, const char *buffer,
+ int count)
+{
+ return -EINVAL; /* foo on you */
+}
+
+static int
+sun_mouse_read(struct inode *inode, struct file *file, char *buffer,
+ int count)
+{
+ struct wait_queue wait = { current, NULL };
+
+ if (queue_empty ()){
+ if (file->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+ add_wait_queue (&sunmouse.proc_list, &wait);
+ while (queue_empty () && !(current->signal & ~current->blocked)){
+ current->state = TASK_INTERRUPTIBLE;
+ schedule ();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue (&sunmouse.proc_list, &wait);
+ }
+ if (gen_events){
+ char *p = buffer, *end = buffer+count;
+
+ while (p < end && !queue_empty ()){
+ *(Firm_event *)p = *get_from_queue ();
+ p += sizeof (Firm_event);
+ }
+ sunmouse.ready = !queue_empty ();
+ inode->i_atime = CURRENT_TIME;
+ return p-buffer;
+ } else {
+ int c;
+
+ for (c = count; !queue_empty () && c; c--){
+ *buffer++ = sunmouse.queue.stream [sunmouse.tail];
+ sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
+ }
+ sunmouse.ready = !queue_empty ();
+ inode->i_atime = CURRENT_TIME;
+ return count-c;
+ }
+ /* Only called if nothing was sent */
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ return 0;
+}
+
+static int
+sun_mouse_select(struct inode *inode, struct file *file, int sel_type,
+ select_table *wait)
+{
+ if(sel_type != SEL_IN)
+ return 0;
+ if(sunmouse.ready)
+ return 1;
+ select_wait(&sunmouse.proc_list, wait);
+ return 0;
+}
+int
+sun_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int i;
+
+ switch (cmd){
+ /* VUIDGFORMAT - Get input device byte stream format */
+ case _IOR('v', 2, int):
+ i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (int));
+ if (i) return i;
+ *(int *)arg = sunmouse.vuid_mode;
+ break;
+
+ /* VUIDSFORMAT - Set input device byte stream format*/
+ case _IOW('v', 1, int):
+ i = verify_area (VERIFY_READ, (void *)arg, sizeof (int));
+ if (i) return i;
+ i = *(int *) arg;
+ if (i == VUID_NATIVE || i == VUID_FIRM_EVENT){
+ sunmouse.vuid_mode = *(int *)arg;
+ sunmouse.head = sunmouse.tail = 0;
+ } else
+ return -EINVAL;
+ break;
+
+ default:
+ printk ("[MOUSE-ioctl: %8.8x]\n", cmd);
+ return -1;
+ }
+ return 0;
+}
+
+struct file_operations sun_mouse_fops = {
+ NULL,
+ sun_mouse_read,
+ sun_mouse_write,
+ NULL,
+ sun_mouse_select,
+ sun_mouse_ioctl,
+ NULL,
+ sun_mouse_open,
+ sun_mouse_close,
+ NULL,
+ sun_mouse_fasync,
+};
+
+static struct miscdevice sun_mouse_mouse = {
+ SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops
+};
+
+int
+sun_mouse_init(void)
+{
+ printk("Sun Mouse-Systems mouse driver version 1.00\n");
+ sunmouse.present = 1;
+ sunmouse.ready = sunmouse.active = 0;
+ misc_register (&sun_mouse_mouse);
+ sunmouse.delta_x = sunmouse.delta_y = 0;
+ sunmouse.button_state = 0x80;
+ sunmouse.proc_list = NULL;
+ return 0;
+}
+
+void
+sun_mouse_zsinit(void)
+{
+ sunmouse.ready = 1;
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this