📄 sunmouse.c
字号:
/* 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 support - 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 1struct 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_stateextern void mouse_put_char(char ch);/* #define SMOUSE_DEBUG */static voidpush_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 intqueue_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 voidpush_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. */voidsun_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 ridiculous 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 intsun_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 intsun_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 voidsun_mouse_close(struct inode *inode, struct file *file){ sunmouse.active = sunmouse.ready = 0; sun_mouse_fasync (inode, file, 0);}static intsun_mouse_write(struct inode *inode, struct file *file, const char *buffer, int count){ return -EINVAL; /* foo on you */}static intsun_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 intsun_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;}intsun_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};intsun_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;}voidsun_mouse_zsinit(void){ sunmouse.ready = 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -