root/drivers/sbus/char/sunmouse.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. push_event
  2. queue_empty
  3. get_from_queue
  4. push_char
  5. sun_mouse_inbyte
  6. sun_mouse_open
  7. sun_mouse_fasync
  8. sun_mouse_close
  9. sun_mouse_write
  10. sun_mouse_read
  11. sun_mouse_select
  12. sun_mouse_ioctl
  13. sun_mouse_init
  14. sun_mouse_zsinit

   1 /* sunmouse.c: Sun mouse driver for the Sparc
   2  *
   3  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
   4  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
   5  *
   6  * Parts based on the psaux.c driver written by:
   7  * Johan Myreen.
   8  *
   9  * Dec/19/95 Added SunOS mouse ioctls - miguel.
  10  * Jan/5/96  Added VUID support, sigio support - miguel.
  11  * Mar/5/96  Added proper mouse stream support - miguel.
  12  */
  13 
  14 /* The mouse is run off of one of the Zilog serial ports.  On
  15  * that port is the mouse and the keyboard, each gets a zs channel.
  16  * The mouse itself is mouse-systems in nature.  So the protocol is:
  17  *
  18  * Byte 1) Button state which is bit-encoded as
  19  *            0x4 == left-button down, else up
  20  *            0x2 == middle-button down, else up
  21  *            0x1 == right-button down, else up
  22  *
  23  * Byte 2) Delta-x
  24  * Byte 3) Delta-y
  25  * Byte 4) Delta-x again
  26  * Byte 5) Delta-y again
  27  *
  28  * One day this driver will have to support more than one mouse in the system.
  29  *
  30  * This driver has two modes of operation: the default VUID_NATIVE is
  31  * set when the device is opened and allows the application to see the
  32  * mouse character stream as we get it from the serial (for gpm for
  33  * example).  The second method, VUID_FIRM_EVENT will provide cooked
  34  * events in Firm_event records.
  35  * */
  36 
  37 #include <linux/kernel.h>
  38 #include <linux/sched.h>
  39 #include <linux/fcntl.h>
  40 #include <linux/signal.h>
  41 #include <linux/timer.h>
  42 #include <linux/errno.h>
  43 #include <linux/miscdevice.h>
  44 #include <linux/mm.h>
  45 #include <asm/segment.h>
  46 #include <asm/system.h>
  47 #include <asm/vuid_event.h>
  48 #include <linux/random.h>
  49 /* The following keeps track of software state for the Sun
  50  * mouse.
  51  */
  52 #define STREAM_SIZE   2048
  53 #define EV_SIZE       (STREAM_SIZE/sizeof (Firm_event))
  54 #define BUTTON_LEFT   4
  55 #define BUTTON_MIDDLE 2
  56 #define BUTTON_RIGHT  1
  57 
  58 struct sun_mouse {
  59         unsigned char transaction[5];  /* Each protocol transaction */
  60         unsigned char byte;            /* Counter, starts at 0 */
  61         unsigned char button_state;    /* Current button state */
  62         unsigned char prev_state;      /* Previous button state */
  63         int delta_x;                   /* Current delta-x */
  64         int delta_y;                   /* Current delta-y */
  65         int present;
  66         int ready;                     /* set if there if data is available */
  67         int active;                    /* set if device is open */
  68         int vuid_mode;                 /* VUID_NATIVE or VUID_FIRM_EVENT */
  69         struct wait_queue *proc_list;
  70         struct fasync_struct *fasync;
  71         
  72         /* The event/stream queue */
  73         unsigned int head;
  74         unsigned int tail;
  75         union {
  76                 char stream [STREAM_SIZE];
  77                 Firm_event ev [0];
  78         } queue;
  79 };
  80 
  81 static struct sun_mouse sunmouse;
  82 #define gen_events (sunmouse.vuid_mode != VUID_NATIVE)
  83 #define bstate sunmouse.button_state
  84 #define pstate sunmouse.prev_state
  85 
  86 extern void mouse_put_char(char ch);
  87 
  88 /* #define SMOUSE_DEBUG */
  89 
  90 static void
  91 push_event (Firm_event *ev)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93         int next = (sunmouse.head + 1) % EV_SIZE;
  94         
  95         if (next != sunmouse.tail){
  96                 sunmouse.queue.ev [sunmouse.head] = *ev;
  97                 sunmouse.head = next;
  98         }
  99 }
 100 
 101 static int
 102 queue_empty (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104         return sunmouse.head == sunmouse.tail;
 105 }
 106 
 107 static Firm_event *
 108 get_from_queue (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110         Firm_event *result;
 111         
 112         result = &sunmouse.queue.ev [sunmouse.tail];
 113         sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE;
 114         return result;
 115 }
 116 
 117 static void
 118 push_char (char c)
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120         int next = (sunmouse.head + 1) % STREAM_SIZE;
 121 
 122         if (next != sunmouse.tail){
 123                 sunmouse.queue.stream [sunmouse.head] = c;
 124                 sunmouse.head = next;
 125         }
 126         sunmouse.ready = 1;
 127         if (sunmouse.fasync)
 128                 kill_fasync (sunmouse.fasync, SIGIO);
 129         wake_up_interruptible (&sunmouse.proc_list);
 130 }
 131 
 132 /* The following is called from the zs driver when bytes are received on
 133  * the Mouse zs8530 channel.
 134  */
 135 void
 136 sun_mouse_inbyte(unsigned char byte, unsigned char status)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 {
 138         signed char mvalue;
 139         int d;
 140         Firm_event ev;
 141 
 142         add_mouse_randomness (byte);
 143         if(!sunmouse.active)
 144                 return;
 145 
 146         if (!gen_events){
 147                 push_char (byte);
 148                 return;
 149         }
 150         /* Check for framing errors and parity errors */
 151         /* XXX TODO XXX */
 152 
 153         /* If the mouse sends us a byte from 0x80 to 0x87
 154          * we are starting at byte zero in the transaction
 155          * protocol.
 156          */
 157         if(byte >= 0x80 && byte <= 0x87)
 158                 sunmouse.byte = 0;
 159 
 160         mvalue = (signed char) byte;
 161         switch(sunmouse.byte) {
 162         case 0:
 163                 /* Button state */
 164                 sunmouse.button_state = (~byte) & 0x7;
 165 #ifdef SMOUSE_DEBUG
 166                 printk("B<Left %s, Middle %s, Right %s>",
 167                        ((sunmouse.button_state & 0x4) ? "DOWN" : "UP"),
 168                        ((sunmouse.button_state & 0x2) ? "DOWN" : "UP"),
 169                        ((sunmouse.button_state & 0x1) ? "DOWN" : "UP"));
 170 #endif
 171                 sunmouse.byte++;
 172                 return;
 173         case 1:
 174                 /* Delta-x 1 */
 175 #ifdef SMOUSE_DEBUG
 176                 printk("DX1<%d>", mvalue);
 177 #endif
 178                 sunmouse.delta_x = mvalue;
 179                 sunmouse.byte++;
 180                 return;
 181         case 2:
 182                 /* Delta-y 1 */
 183 #ifdef SMOUSE_DEBUG
 184                 printk("DY1<%d>", mvalue);
 185 #endif
 186                 sunmouse.delta_y = mvalue;
 187                 sunmouse.byte++;
 188                 return;
 189         case 3:
 190                 /* Delta-x 2 */
 191 #ifdef SMOUSE_DEBUG
 192                 printk("DX2<%d>", mvalue);
 193 #endif
 194                 sunmouse.delta_x += mvalue;
 195                 sunmouse.byte++;
 196                 return;
 197         case 4:
 198                 /* Last byte, Delta-y 2 */
 199 #ifdef SMOUSE_DEBUG
 200                 printk("DY2<%d>", mvalue);
 201 #endif
 202                 sunmouse.delta_y += mvalue;
 203                 sunmouse.byte = 69;  /* Some ridiculous value */
 204                 break;
 205         case 69:
 206                 /* Until we get the (0x80 -> 0x87) value we aren't
 207                  * in the middle of a real transaction, so just
 208                  * return.
 209                  */
 210                 return;
 211         default:
 212                 printk("sunmouse: bogon transaction state\n");
 213                 sunmouse.byte = 69;  /* What could cause this? */
 214                 return;
 215         };
 216         d = bstate ^ pstate;
 217         pstate = bstate;
 218         if (d){
 219                 if (d & BUTTON_LEFT){
 220                         ev.id = MS_LEFT;
 221                         ev.value = bstate & BUTTON_LEFT;
 222                 }
 223                 if (d & BUTTON_RIGHT){
 224                         ev.id = MS_RIGHT;
 225                         ev.value = bstate & BUTTON_RIGHT;
 226                 }
 227                 if (d & BUTTON_MIDDLE){
 228                         ev.id = MS_MIDDLE;
 229                         ev.value = bstate & BUTTON_MIDDLE;
 230                 }
 231                 ev.time = xtime;
 232                 ev.value = ev.value ? VKEY_DOWN : VKEY_UP;
 233                 push_event (&ev);
 234         }
 235         if (sunmouse.delta_x){
 236                 ev.id = LOC_X_DELTA;
 237                 ev.time = xtime;
 238                 ev.value = sunmouse.delta_x;
 239                 push_event (&ev);
 240                 sunmouse.delta_x = 0;
 241         }
 242         if (sunmouse.delta_y){
 243                 ev.id = LOC_Y_DELTA;
 244                 ev.time = xtime;
 245                 ev.value = sunmouse.delta_y;
 246                 push_event (&ev);
 247         }
 248         
 249         /* We just completed a transaction, wake up whoever is awaiting
 250          * this event.
 251          */
 252         sunmouse.ready = 1;
 253         if (sunmouse.fasync)
 254                 kill_fasync (sunmouse.fasync, SIGIO);
 255         wake_up_interruptible(&sunmouse.proc_list);
 256         return;
 257 }
 258 
 259 static int
 260 sun_mouse_open(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 261 {
 262         if(!sunmouse.present)
 263                 return -EINVAL;
 264         if(sunmouse.active)
 265                 return -EBUSY;
 266         sunmouse.active = 1;
 267         sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
 268         sunmouse.button_state = 0x80;
 269         sunmouse.vuid_mode = VUID_NATIVE;
 270         return 0;
 271 }
 272 
 273 static int
 274 sun_mouse_fasync (struct inode *inode, struct file *filp, int on)
     /* [previous][next][first][last][top][bottom][index][help] */
 275 {
 276         int retval;
 277 
 278         retval = fasync_helper (inode, filp, on, &sunmouse.fasync);
 279         if (retval < 0)
 280                 return retval;
 281         return 0;
 282 }
 283 
 284 static void
 285 sun_mouse_close(struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 286 {
 287         sunmouse.active = sunmouse.ready = 0;
 288         sun_mouse_fasync (inode, file, 0);
 289 }
 290 
 291 static int
 292 sun_mouse_write(struct inode *inode, struct file *file, const char *buffer,
     /* [previous][next][first][last][top][bottom][index][help] */
 293                 int count)
 294 {
 295         return -EINVAL;  /* foo on you */
 296 }
 297 
 298 static int
 299 sun_mouse_read(struct inode *inode, struct file *file, char *buffer,
     /* [previous][next][first][last][top][bottom][index][help] */
 300                int count)
 301 {
 302         struct wait_queue wait = { current, NULL };
 303 
 304         if (queue_empty ()){
 305                 if (file->f_flags & O_NONBLOCK)
 306                         return -EWOULDBLOCK;
 307                 add_wait_queue (&sunmouse.proc_list, &wait);
 308                 while (queue_empty () && !(current->signal & ~current->blocked)){
 309                         current->state = TASK_INTERRUPTIBLE;
 310                         schedule ();
 311                 }
 312                 current->state = TASK_RUNNING;
 313                 remove_wait_queue (&sunmouse.proc_list, &wait);
 314         }
 315         if (gen_events){
 316                 char *p = buffer, *end = buffer+count;
 317                 
 318                 while (p < end && !queue_empty ()){
 319                         *(Firm_event *)p = *get_from_queue ();
 320                         p += sizeof (Firm_event);
 321                 }
 322                 sunmouse.ready = !queue_empty ();
 323                 inode->i_atime = CURRENT_TIME;
 324                 return p-buffer;
 325         } else {
 326                 int c;
 327                 
 328                 for (c = count; !queue_empty () && c; c--){
 329                         *buffer++ = sunmouse.queue.stream [sunmouse.tail];
 330                         sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
 331                 }
 332                 sunmouse.ready = !queue_empty ();
 333                 inode->i_atime = CURRENT_TIME;
 334                 return count-c;
 335         }
 336         /* Only called if nothing was sent */
 337         if (current->signal & ~current->blocked)
 338                 return -ERESTARTSYS;
 339         return 0;
 340 }
 341 
 342 static int
 343 sun_mouse_select(struct inode *inode, struct file *file, int sel_type,
     /* [previous][next][first][last][top][bottom][index][help] */
 344                             select_table *wait)
 345 {
 346         if(sel_type != SEL_IN)
 347                 return 0;
 348         if(sunmouse.ready)
 349                 return 1;
 350         select_wait(&sunmouse.proc_list, wait);
 351         return 0;
 352 }
 353 int
 354 sun_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 355 {
 356         int i;
 357         
 358         switch (cmd){
 359                 /* VUIDGFORMAT - Get input device byte stream format */
 360         case _IOR('v', 2, int):
 361                 i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (int));
 362                 if (i) return i;
 363                 *(int *)arg = sunmouse.vuid_mode;
 364                 break;
 365 
 366                 /* VUIDSFORMAT - Set input device byte stream format*/
 367         case _IOW('v', 1, int):
 368                 i = verify_area (VERIFY_READ, (void *)arg, sizeof (int));
 369                 if (i) return i;
 370                 i = *(int *) arg;
 371                 if (i == VUID_NATIVE || i == VUID_FIRM_EVENT){
 372                         sunmouse.vuid_mode = *(int *)arg;
 373                         sunmouse.head = sunmouse.tail = 0;
 374                 } else
 375                         return -EINVAL;
 376                 break;
 377                 
 378         default:
 379                 printk ("[MOUSE-ioctl: %8.8x]\n", cmd);
 380                 return -1;
 381         }
 382         return 0;
 383 }
 384 
 385 struct file_operations sun_mouse_fops = {
 386         NULL,
 387         sun_mouse_read,
 388         sun_mouse_write,
 389         NULL,
 390         sun_mouse_select,
 391         sun_mouse_ioctl,
 392         NULL,
 393         sun_mouse_open,
 394         sun_mouse_close,
 395         NULL,
 396         sun_mouse_fasync,
 397 };
 398 
 399 static struct miscdevice sun_mouse_mouse = {
 400         SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops
 401 };
 402 
 403 int
 404 sun_mouse_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 405 {
 406         printk("Sun Mouse-Systems mouse driver version 1.00\n");
 407         sunmouse.present = 1;
 408         sunmouse.ready = sunmouse.active = 0;
 409         misc_register (&sun_mouse_mouse);
 410         sunmouse.delta_x = sunmouse.delta_y = 0;
 411         sunmouse.button_state = 0x80;
 412         sunmouse.proc_list = NULL;
 413         return 0;
 414 }
 415 
 416 void
 417 sun_mouse_zsinit(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 418 {
 419         sunmouse.ready = 1;
 420 }

/* [previous][next][first][last][top][bottom][index][help] */