~ubuntu-core-dev/usplash/ubuntu

« back to all changes in this revision

Viewing changes to bogl/boml.c

  • Committer: Scott James Remnant
  • Date: 2006-06-09 15:01:23 UTC
  • Revision ID: scott@netsplit.com-20060609150123-fee9f1bc83d30884
import 0.3-1 into bzr

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* BOGL - Ben's Own Graphics Library.
 
2
   Written by Ben Pfaff <pfaffben@debian.org>.
 
3
 
 
4
   This program is free software; you can redistribute it and/or
 
5
   modify it under the terms of the GNU General Public License as
 
6
   published by the Free Software Foundation; either version 2 of the
 
7
   License, or (at your option) any later version.
 
8
   
 
9
   This program is distributed in the hope that it will be useful, but
 
10
   WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
   General Public License for more details.
 
13
   
 
14
   You should have received a copy of the GNU General Public License
 
15
   along with this program; if not, write to the Free Software
 
16
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 
17
   USA. */
 
18
 
 
19
#define _GNU_SOURCE 1
 
20
#include <assert.h>
 
21
#include <errno.h>
 
22
#include <fcntl.h>
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
#include <sys/ioctl.h>
 
27
#include <sys/time.h>
 
28
#include <sys/types.h>
 
29
#include <termios.h>
 
30
#include <unistd.h>
 
31
#include <time.h>
 
32
#include "bogl.h"
 
33
#include "boml.h"
 
34
 
 
35
#define M_GPM
 
36
#define M_INPUT
 
37
 
 
38
#ifdef M_GPM
 
39
#include <sys/socket.h>
 
40
#include <sys/un.h>
 
41
#endif
 
42
 
 
43
#if defined __alpha__
 
44
#define M_SERIAL
 
45
#define M_PS2
 
46
#elif defined __i386__
 
47
#define M_SERIAL
 
48
#define M_PS2
 
49
#define M_MSBUS
 
50
#elif defined __mc68000__
 
51
#define M_ADB
 
52
#elif defined __powerpc__
 
53
#define M_SERIAL
 
54
#define M_ADB
 
55
#define M_PS2
 
56
#elif defined __sparc__
 
57
#define M_SUN
 
58
#endif
 
59
 
 
60
struct mouse;
 
61
 
 
62
/* Packet drivers and detection routines. */
 
63
#define N_SERIAL 0
 
64
#define N_PS2 0
 
65
#define N_MSBUS 0
 
66
#define N_ADB 0
 
67
#define N_SUN 0
 
68
 
 
69
#ifdef M_GPM
 
70
static int detect_gpm (void);
 
71
# ifndef M_SERIAL
 
72
#  define M_SERIAL_MS
 
73
static void ms_driver (struct mouse *);
 
74
# endif
 
75
#endif
 
76
 
 
77
#ifdef M_INPUT
 
78
# ifndef M_PS2
 
79
#  define M_PS2_DRIVER
 
80
static void ps2_driver (struct mouse *);
 
81
# endif
 
82
static int input_mouse_found = 0;
 
83
static void detect_input (void);
 
84
#endif
 
85
 
 
86
#ifdef M_SERIAL
 
87
#undef N_SERIAL
 
88
#define N_SERIAL 8
 
89
#define M_SERIAL_MS
 
90
static void detect_serial (void);
 
91
static void ms_driver (struct mouse *);
 
92
static void msc_driver (struct mouse *);
 
93
static void mman_driver (struct mouse *);
 
94
#endif
 
95
 
 
96
/* These next three are actually the same protocol, but bind to
 
97
   different files in /dev.  Thus they use bm_driver. */
 
98
#if defined(M_MSBUS) ||  defined(M_ADB) || defined(M_SUN)
 
99
static void bm_driver (struct mouse *);
 
100
#endif
 
101
 
 
102
#ifdef M_MSBUS
 
103
#undef N_MSBUS
 
104
#define N_MSBUS 1
 
105
static void detect_msbus (void);
 
106
#endif
 
107
 
 
108
#ifdef M_ADB
 
109
#undef N_ADB
 
110
#define N_ADB 1
 
111
static void detect_adb (void);
 
112
#endif
 
113
 
 
114
#ifdef M_SUN
 
115
#undef N_SUN
 
116
#define N_SUN 1
 
117
static void detect_sun (void);
 
118
#endif
 
119
 
 
120
#ifdef M_PS2
 
121
#undef N_PS2
 
122
#define N_PS2 1
 
123
#define M_PS2_DRIVER
 
124
static void detect_ps2 (void);
 
125
static void ps2_driver (struct mouse *);
 
126
#endif
 
127
 
 
128
#define N_DETECT (N_SERIAL + N_MSBUS + N_PS2 + N_ADB + N_SUN)
 
129
 
 
130
/* Detection progress. */
 
131
static void inc (void);
 
132
 
 
133
static void (*detect_callback) (int);
 
134
static int detect_count;
 
135
 
 
136
/* Mouse types. */
 
137
enum
 
138
  {
 
139
#ifdef M_SERIAL_MS
 
140
    /* Serial mice using the MS protocol */
 
141
    T_MS_SERIAL,                /* Microsoft. */
 
142
    T_MS3_SERIAL,               /* Microsoft Intellimouse. */
 
143
#endif
 
144
 
 
145
#ifdef M_SERIAL
 
146
    /* Other serial mice. */
 
147
    T_MSC_SERIAL,               /* Mouse Systems. */
 
148
    T_MMAN_SERIAL,              /* Logitech Mouseman. */
 
149
#endif
 
150
 
 
151
#ifdef M_MSBUS
 
152
    /* Bus mice. */
 
153
    T_MS_BUS,                   /* Microsoft/Logitech. */
 
154
#endif
 
155
 
 
156
#ifdef M_ADB
 
157
    T_ADB,                      /* Apple ADB */
 
158
#endif
 
159
 
 
160
#ifdef M_SUN
 
161
    T_SUN,                      /* Sun */
 
162
#endif
 
163
 
 
164
#ifdef M_PS2_DRIVER
 
165
    /* PS/2 mice. */
 
166
    T_PS2,                      /* Generic. */
 
167
#endif
 
168
  };
 
169
 
 
170
/* Mouse attributes description. */
 
171
struct mouse_info
 
172
  {
 
173
    char *name;                         /* Name. */
 
174
    int packet_size;                    /* (Initial) bytes per packet. */
 
175
    unsigned char id[4];                /* Packet identification info. */
 
176
    void (*driver) (struct mouse *);    /* Packet driver. */
 
177
  };
 
178
 
 
179
/* Some of the information below is borrowed from gpm. */
 
180
static struct mouse_info mouse_info[] = 
 
181
  {
 
182
#ifdef M_SERIAL_MS
 
183
    {"Microsoft serial",                3, {0x40,0x40,0x40,0x00}, ms_driver},
 
184
    {"Microsoft Intellimouse serial",   4, {0xc0,0x40,0xc0,0x00}, ms_driver},
 
185
#endif
 
186
 
 
187
#ifdef M_SERIAL
 
188
    {"Mouse Systems serial",            5, {0xf8,0x80,0x00,0x00}, msc_driver},
 
189
    {"Mouseman serial",                 3, {0xe0,0x80,0x80,0x00}, mman_driver},
 
190
#endif
 
191
 
 
192
#ifdef M_MSBUS
 
193
    {"Microsoft bus",                   3, {0xf8,0x80,0x00,0x00}, bm_driver},
 
194
#endif
 
195
 
 
196
#ifdef M_ADB
 
197
    {"Apple Desktop Bus",               3, {0xf8,0x80,0x00,0x00}, bm_driver},
 
198
#endif
 
199
 
 
200
#ifdef M_SUN
 
201
    {"Sun",                             3, {0xf8,0x80,0x00,0x00}, bm_driver},
 
202
#endif
 
203
 
 
204
#ifdef M_PS2_DRIVER
 
205
    {"Generic PS/2",                    3, {0xc0,0x00,0x00,0x00}, ps2_driver},
 
206
#endif
 
207
  };
 
208
 
 
209
/* A mouse. */
 
210
struct mouse
 
211
  {
 
212
    struct mouse *next;         /* Linked list. */
 
213
    int type;                   /* Type of mouse, one of T_*. */
 
214
    int fd;                     /* File descriptor. */
 
215
    unsigned char pbuf[8];      /* Protocol buffer. */
 
216
    int ppos;                   /* Number of bytes in buffer. */
 
217
    int packet_size;            /* Bytes per packet. */
 
218
  };
 
219
 
 
220
/* All detected mice. */
 
221
static struct mouse *mice;
 
222
 
 
223
/* Current mouse state. */
 
224
static int x, y;        /* Pointer location. */
 
225
static int show;        /* >0: Show the pointer. */
 
226
static int drawn;       /* !=0: Pointer is currently drawn. */
 
227
static int button;      /* Button down? */
 
228
 
 
229
/* Event queue. */
 
230
struct event
 
231
  {
 
232
    int type;           /* One of BOML_E_*. */
 
233
    int x;
 
234
    int y;
 
235
    int btn;
 
236
  };
 
237
 
 
238
/* Next or previous item in the queue after INDEX. */
 
239
#define q_next(INDEX) \
 
240
        ((INDEX) + 1 < QUEUE_SIZE ? (INDEX) + 1 : 0)
 
241
#define q_prev(INDEX) \
 
242
        ((INDEX) > 0 ? (INDEX) - 1 : QUEUE_SIZE - 1)
 
243
 
 
244
#define QUEUE_SIZE 8
 
245
static struct event queue[QUEUE_SIZE];
 
246
static int qh, qt;      
 
247
 
 
248
#ifdef M_SERIAL
 
249
static int probe_com (char *port, int pnp);
 
250
#endif
 
251
static void state (int dx, int dy, int button);
 
252
 
 
253
/* Mouse pointer. */
 
254
static const struct bogl_pointer *pointer;
 
255
static int pointer_colors[2];
 
256
 
 
257
 
 
258
/* Public code. */
 
259
 
 
260
int
 
261
boml_quick_init (void)
 
262
{
 
263
  static int inited = 0;
 
264
  if (inited)
 
265
    return inited - 1;
 
266
  inited = 1;
 
267
  
 
268
#ifdef M_GPM
 
269
  if(detect_gpm ())
 
270
    {
 
271
      inited++;
 
272
      return (inited - 1);
 
273
    }
 
274
#endif
 
275
 
 
276
#ifdef M_INPUT
 
277
  detect_input ();
 
278
  if (input_mouse_found)
 
279
    {
 
280
      inited++;
 
281
      return (inited - 1);
 
282
    }
 
283
#endif
 
284
 
 
285
  return (inited - 1);
 
286
}
 
287
 
 
288
/* Detects mice and initializes the mouse library. */
 
289
void
 
290
boml_init (void (*callback) (int))
 
291
{
 
292
  /* Assure idempotence. */
 
293
  static int inited = 0;
 
294
  if (inited)
 
295
    return;
 
296
  inited = 1;
 
297
 
 
298
  detect_callback = callback;
 
299
  detect_count = 0;
 
300
 
 
301
#ifdef M_PS2
 
302
  detect_ps2 ();
 
303
  inc ();
 
304
#endif
 
305
 
 
306
#ifdef M_MSBUS
 
307
  detect_msbus ();
 
308
  inc ();
 
309
#endif
 
310
 
 
311
#ifdef M_ADB
 
312
  detect_adb ();
 
313
  inc ();
 
314
#endif
 
315
 
 
316
#ifdef M_SUN
 
317
  detect_sun ();
 
318
  inc ();
 
319
#endif
 
320
 
 
321
#ifdef M_SERIAL
 
322
  detect_serial ();
 
323
#endif
 
324
}
 
325
 
 
326
/* Calls the callback, if any, with a report of the progress of mouse
 
327
   detection in percent, incremented to the next mark (out of N_DETECT
 
328
   marks total). */
 
329
static void
 
330
inc (void)
 
331
{
 
332
  detect_count++;
 
333
  if (detect_callback)
 
334
    detect_callback (100 * detect_count / N_DETECT);
 
335
}
 
336
 
 
337
/* Reads mouse activities from the proper port and update the screen
 
338
   pointer position. */
 
339
void
 
340
boml_refresh (void)
 
341
{
 
342
  int sx = x;
 
343
  int sy = y;
 
344
  /* How many bytes to read at once */
 
345
  int howmany = 1;
 
346
  struct mouse *mouse;
 
347
 
 
348
  for (mouse = mice; mouse; mouse = mouse->next)
 
349
    {
 
350
      struct mouse_info *minfo = &mouse_info[mouse->type];
 
351
 
 
352
      fcntl (mouse->fd, F_SETFL, O_NONBLOCK);
 
353
      /* On bus mice (which means also all m68k mice) we have to read
 
354
         three bytes instead of one... This might be true of other
 
355
         mice as well. */
 
356
#if defined(M_ADB)
 
357
      if (mouse->type == T_ADB)
 
358
        howmany = 3;
 
359
#endif /* M_ADB */
 
360
#if defined (M_MSBUS)
 
361
      if (mouse->type == T_MS_BUS)
 
362
        howmany = 3;
 
363
#endif /* M_MSBUS */
 
364
      while (read (mouse->fd, &mouse->pbuf[mouse->ppos], howmany) == howmany)
 
365
        {
 
366
#ifdef M_SERIAL
 
367
          /* The MouseMan protocol is extremely fscked up.  Packets can
 
368
             have 3 or 4 bytes.  Attempt to detect changing from 3 byte to
 
369
             4 byte packets. */
 
370
          if (mouse->type == T_MMAN_SERIAL
 
371
              && mouse->ppos == 0
 
372
              && (mouse->pbuf[0] & minfo->id[0]) != minfo->id[1]
 
373
              && (mouse->pbuf[0] >> 4) <= 3)
 
374
            {
 
375
              int b = mouse->pbuf[0] >> 4;
 
376
              mouse->packet_size = 4;
 
377
              state (0, 0, b & 0x20);
 
378
              mouse->ppos = 0;
 
379
              continue;
 
380
            }
 
381
#endif
 
382
 
 
383
          if ((mouse->ppos == 0
 
384
               && (mouse->pbuf[0] & minfo->id[0]) != minfo->id[1])
 
385
              || (mouse->ppos == 1
 
386
                  && (mouse->pbuf[1] & minfo->id[2]) != minfo->id[3]))
 
387
            {
 
388
              /* Nope, not a packet */
 
389
              mouse->ppos = 0;
 
390
              continue;
 
391
            }
 
392
 
 
393
          mouse->ppos += howmany;
 
394
          if (mouse->ppos >= mouse->packet_size)
 
395
            {
 
396
              minfo->driver (mouse);
 
397
              mouse->ppos = 0;
 
398
            }
 
399
        }
 
400
    }
 
401
  
 
402
  if ((sx != x || sy != y || !drawn) && show)
 
403
    {
 
404
      if (drawn)
 
405
        bogl_pointer (0, sx, sy, pointer, pointer_colors);
 
406
      bogl_pointer (1, x, y, pointer, pointer_colors);
 
407
      drawn = 1;
 
408
    }
 
409
}
 
410
 
 
411
/* Tells the library whether the mouse cursor is drawn.  This is
 
412
   different from whether it is *supposed* to be drawn.  For instance,
 
413
   if the screen got cleared by a VT switch, the mouse cursor may have
 
414
   been erased inadvertently. */
 
415
void
 
416
boml_drawn (int is_drawn)
 
417
{
 
418
  drawn = is_drawn;
 
419
}
 
420
 
 
421
/* Draw the mouse cursor if it's not drawn but it should be. */
 
422
void
 
423
boml_redraw (void)
 
424
{
 
425
  if (show > 0 && !drawn)
 
426
    {
 
427
      bogl_pointer (1, x, y, pointer, pointer_colors);
 
428
      drawn = 1;
 
429
    }
 
430
}
 
431
 
 
432
/* Show the mouse cursor.  The mouse cursor being `shown' is a
 
433
   recursive property: if you call boml_show() N times to show the
 
434
   cursor, then you must call boml_hide() N times in order to hide
 
435
   it. */
 
436
void
 
437
boml_show (void)
 
438
{
 
439
  if (!mice)
 
440
    return;
 
441
 
 
442
  show++;
 
443
  if (show == 1 && !drawn)
 
444
    {
 
445
      bogl_pointer (1, x, y, pointer, pointer_colors);
 
446
      drawn = 1;
 
447
    }
 
448
}
 
449
 
 
450
/* Hide the mouse cursor.  See comment above boml_show() for more
 
451
   details. */
 
452
void
 
453
boml_hide (void)
 
454
{
 
455
  if (!mice)
 
456
    return;
 
457
 
 
458
  show--;
 
459
  if (show == 0 && drawn)
 
460
    {
 
461
      bogl_pointer (0, x, y, pointer, pointer_colors);
 
462
      drawn = 0;
 
463
    }
 
464
}
 
465
 
 
466
/* Change the mouse cursor to pointer P.  The cursor is drawn in the
 
467
   colors specified by COLORS. */
 
468
void
 
469
boml_pointer (const struct bogl_pointer *p, int colors[2])
 
470
{
 
471
  boml_hide ();
 
472
  pointer = p;
 
473
  pointer_colors[0] = colors[0];
 
474
  pointer_colors[1] = colors[1];
 
475
  boml_show ();
 
476
}
 
477
 
 
478
/* If TEST == 0, sets all the mice' file descriptors into FDS.  If
 
479
   TEST != 0, returns if at least one file descriptor is set in
 
480
   FDS. */
 
481
int
 
482
boml_fds (int test, fd_set *fds)
 
483
{
 
484
  struct mouse *mouse;
 
485
 
 
486
  for (mouse = mice; mouse; mouse = mouse->next)
 
487
    if (test)
 
488
      {
 
489
        if (FD_ISSET (mouse->fd, fds))
 
490
          return 1;
 
491
      }
 
492
    else
 
493
      FD_SET (mouse->fd, fds);
 
494
 
 
495
  return 0;
 
496
}
 
497
 
 
498
/* Check for mouse activity.  Returns the mouse event type.  Stores
 
499
   the mouse location into (X,Y) and the button status into BTN, where
 
500
   nonzero indicates the button is pressed. */
 
501
int
 
502
boml_event (int *x, int *y, int *btn)
 
503
{
 
504
  int type;
 
505
  
 
506
  if (qt == qh)
 
507
    return BOML_E_NONE;
 
508
 
 
509
  type = queue[qt].type;
 
510
  if (x)
 
511
    *x = queue[qt].x;
 
512
  if (y)
 
513
    *y = queue[qt].y;
 
514
  if (btn)
 
515
    *btn = queue[qt].btn;
 
516
 
 
517
  qt = q_next (qt);
 
518
  return type;
 
519
}
 
520
 
 
521
/* Bookkeeping. */
 
522
 
 
523
/* Add an event of the specified type to the event queue. */
 
524
static void
 
525
event (int type)
 
526
{
 
527
  /* Merge multiple movement events into a single events. */
 
528
  if (type == BOML_E_MOVE && qh != qt
 
529
      && queue[q_prev (qh)].type == BOML_E_MOVE)
 
530
    {
 
531
      queue[q_prev (qh)].x = x;
 
532
      queue[q_prev (qh)].y = y;
 
533
      return;
 
534
    }
 
535
 
 
536
  queue[qh].type = type;
 
537
  queue[qh].x = x;
 
538
  queue[qh].y = y;
 
539
  queue[qh].btn = button;
 
540
  
 
541
  qh = q_next (qh);
 
542
  if (qt == qh)
 
543
    qt = q_next (qt);
 
544
}
 
545
      
 
546
/* The mouse moved (DX,DY) units, and the button is in state BTN (!=0:
 
547
   pressed).  Record that fact. */
 
548
static void
 
549
state (int dx, int dy, int btn)
 
550
{
 
551
  if (dx || dy)
 
552
    {
 
553
      x += dx;
 
554
      y += dy;
 
555
      if (x < 0)
 
556
        x = 0;
 
557
      if (x >= bogl_xres)
 
558
        x = bogl_xres - 1;
 
559
      if (y < 0)
 
560
        y = 0;
 
561
      if (y >= bogl_yres)
 
562
        y = bogl_yres - 1;
 
563
    }
 
564
  if (btn != button)
 
565
    {
 
566
      button = btn;
 
567
      if (button)
 
568
        event (BOML_E_PRESS);
 
569
      else
 
570
        event (BOML_E_RELEASE);
 
571
    }
 
572
  else if (button)
 
573
    event (BOML_E_MOVE);
 
574
}
 
575
 
 
576
/* Add a mouse of type TYPE to the list of mice.  The mouse is open on
 
577
   file descriptor FD. */
 
578
static void
 
579
add_mouse (int type, int fd)
 
580
{
 
581
  struct mouse *mouse = malloc (sizeof (struct mouse));
 
582
  mouse->next = mice;
 
583
  mouse->type = type;
 
584
  mouse->fd = fd;
 
585
  mouse->ppos = 0;
 
586
  mouse->packet_size = mouse_info[type].packet_size;
 
587
  mice = mouse;
 
588
}
 
589
 
 
590
#ifdef M_GPM
 
591
/* If we have a gpm repeater, assume ms3. */
 
592
static int
 
593
detect_gpm (void)
 
594
{
 
595
  int ret;
 
596
  int fd;
 
597
  struct sockaddr_un sock;
 
598
  
 
599
  ret = 1;
 
600
 
 
601
  /* Make sure GPM is answering requests... */
 
602
  fd = socket (PF_UNIX, SOCK_STREAM, 0);  
 
603
  if(fd < 0)
 
604
    ret = 0;
 
605
  else
 
606
    {
 
607
      sock.sun_family = AF_UNIX;
 
608
      strcpy(sock.sun_path, "/dev/gpmctl");
 
609
      if(connect (fd, &sock, SUN_LEN(&sock)) < 0)
 
610
        ret = 0;
 
611
      close (fd);
 
612
    }
 
613
 
 
614
  fd = open ("/dev/gpmdata", O_RDONLY | O_NONBLOCK);
 
615
  if (fd < 0)
 
616
    return 0;
 
617
  
 
618
  /* Poll the mouse whether or not we could find gpm, in
 
619
     case it starts up later; but keep searching in that case. */
 
620
  add_mouse (T_MS3_SERIAL, fd);
 
621
  return ret;
 
622
}
 
623
#endif
 
624
 
 
625
#ifdef M_INPUT
 
626
/* Check for /dev/input/mice, by opening mouse0 instead -
 
627
   i.e. check that there's really a mouse there right now. 
 
628
   Keep it open anyway, but set the mouse found flag accordingly. */
 
629
static void
 
630
detect_input (void)
 
631
{
 
632
  int fd;
 
633
 
 
634
  fd = open("/dev/input/mouse0", O_RDONLY | O_NONBLOCK);
 
635
  if (fd >= 0) {
 
636
    input_mouse_found = 1;
 
637
    close(fd);
 
638
  }
 
639
 
 
640
  fd = open("/dev/input/mice", O_RDONLY | O_NONBLOCK);
 
641
  if(fd < 0)
 
642
    return;
 
643
 
 
644
  add_mouse(T_PS2, fd);
 
645
}
 
646
#endif
 
647
 
 
648
/* PS/2 mouse code. */
 
649
 
 
650
#ifdef M_PS2
 
651
/* Attempt to detect presence of a PS/2 mouse.  If successful, sets
 
652
   `type' to indicate mouse type. */
 
653
static void
 
654
detect_ps2 (void)
 
655
{
 
656
  static const unsigned char s2[] = { 246, 230, 244, 243, 100, 232, 3, };
 
657
  int fd;
 
658
 
 
659
  fd = open ("/dev/psaux", O_RDWR | O_NONBLOCK);
 
660
  if (fd < 0)
 
661
    return;
 
662
 
 
663
  write (fd, s2, sizeof s2);
 
664
  usleep (30000);
 
665
  tcflush (fd, TCIFLUSH);
 
666
 
 
667
  add_mouse (T_PS2, fd);
 
668
}
 
669
#endif /* M_PS2 */
 
670
 
 
671
#ifdef M_PS2_DRIVER
 
672
static void
 
673
ps2_driver (struct mouse *m)
 
674
{
 
675
  int x, y;
 
676
 
 
677
  x = y = 0;
 
678
  if (m->pbuf[1])
 
679
    x = (m->pbuf[0] & 0x10) ? m->pbuf[1] - 256 : m->pbuf[1];
 
680
  if (m->pbuf[2])
 
681
    y = (m->pbuf[0] & 0x20) ? 256 - m->pbuf[2] : -m->pbuf[2];
 
682
 
 
683
  state (x, y, m->pbuf[0] & 1);
 
684
}
 
685
#endif /* M_PS2_DRIVER */
 
686
 
 
687
/* Microsoft/Apple Busmouse and Sun mouse code. */
 
688
 
 
689
#ifdef M_MSBUS
 
690
/* Attempt to detect presence of a Microsoft bus mouse.  If
 
691
   successful, sets `type' to indicate mouse type. */
 
692
static void
 
693
detect_msbus (void)
 
694
{
 
695
  int fd = open ("/dev/inportbm", O_RDONLY | O_NONBLOCK);
 
696
  if (fd < 0)
 
697
    return;
 
698
 
 
699
  add_mouse (T_MS_BUS, fd);
 
700
}
 
701
#endif /* M_MSBUS */
 
702
 
 
703
#ifdef M_ADB
 
704
static void
 
705
detect_adb (void)
 
706
{
 
707
  int fd = open ("/dev/adbmouse", O_RDONLY | O_NONBLOCK);
 
708
  if (fd < 0)
 
709
    return;
 
710
 
 
711
  add_mouse (T_ADB, fd);
 
712
}
 
713
#endif /* M_ADB */
 
714
 
 
715
#ifdef M_SUN
 
716
/* FIXME: Reading the GPM code tells me that this is almost certainly
 
717
   wrong.  Some Sparc person will have to fix it. */
 
718
static void
 
719
detect_sun (void)
 
720
{
 
721
  int fd = open ("/dev/sunmouse", O_RDONLY | O_NONBLOCK);
 
722
  if (fd < 0)
 
723
    return;
 
724
 
 
725
  add_mouse (T_SUN, fd);
 
726
}
 
727
#endif /* M_SUN */
 
728
 
 
729
/* The decoder is definitely the same for all three though */
 
730
#if defined(M_ADB) || defined(M_SUN) || defined(M_MSBUS)
 
731
static void
 
732
bm_driver (struct mouse *m)
 
733
{
 
734
  signed char *p = (signed char *) (m->pbuf);
 
735
  state (p[1], -p[2], !(p[0] & 0x04));
 
736
}
 
737
#endif /* M_ADB || M_SUN || M_MSBUS */
 
738
 
 
739
/* Serial mice. */
 
740
 
 
741
#ifdef M_SERIAL
 
742
/* Attempt to detect presence of a serial mouse.  If successful, sets
 
743
   `type' to indicate mouse type. */
 
744
static void
 
745
detect_serial (void)
 
746
{
 
747
  static char device[] = "/dev/ttySx";
 
748
 
 
749
  for (device[9] = '0'; device[9] <= '3'; device[9]++)
 
750
    {
 
751
      int success;
 
752
 
 
753
      success = probe_com (device, 1);
 
754
      inc ();
 
755
      
 
756
      if (!success)     
 
757
        probe_com (device, 0);
 
758
      inc ();
 
759
    }
 
760
}
 
761
#endif /* M_SERIAL */
 
762
 
 
763
#ifdef M_SERIAL_MS
 
764
/* ms and ms3 protocols are the same except that ms3 has an extra byte
 
765
   in each packet. */
 
766
static void
 
767
ms_driver (struct mouse *m)
 
768
{
 
769
  state ((signed char) ((m->pbuf[0] & 0x03) << 6) | (m->pbuf[1] & 0x3f),
 
770
         (signed char) ((m->pbuf[0] & 0x0c) << 4) | (m->pbuf[2] & 0x3f),
 
771
         m->pbuf[0] & 0x20);
 
772
}
 
773
#endif
 
774
 
 
775
#ifdef M_SERIAL
 
776
static void
 
777
msc_driver (struct mouse *m)
 
778
{
 
779
  signed char *p = (signed char *) (m->pbuf);
 
780
  state (p[3] + p[1], p[4] - p[2], !(m->pbuf[0] & 0x04));
 
781
}
 
782
 
 
783
static void
 
784
mman_driver (struct mouse *m)
 
785
{
 
786
  if (m->packet_size == 4 && (m->pbuf[3] >> 4) == 0)
 
787
    m->packet_size = 3;
 
788
  
 
789
  state ((signed char) (((m->pbuf[0] & 0x03) << 6) | (m->pbuf[1] & 0x3f)),
 
790
         (signed char) (((m->pbuf[0] & 0x0c) << 4) | (m->pbuf[2] & 0xef)),
 
791
         m->pbuf[0] & 0x20);
 
792
}
 
793
 
 
794
#if 0
 
795
static void
 
796
logi_driver (struct mouse *m)
 
797
{
 
798
  state (m->pbuf[0] & 0x10 ? m->pbuf[1] : -m->pbuf[1],
 
799
         m->pbuf[0] & 0x08 ? -m->pbuf[2] : m->pbuf[2],
 
800
         m->pbuf[0] & 0x04);
 
801
}
 
802
#endif /* 0*/
 
803
 
 
804
#endif /* M_SERIAL_DRIVER */
 
805
 
 
806
#if 0
 
807
/* Test routine. */
 
808
int
 
809
main (void)
 
810
{
 
811
  boml_init ();
 
812
  return 0;
 
813
}
 
814
#endif
 
815
 
 
816
#ifdef M_SERIAL
 
817
/* The following code comes from mice.c in gpm-1.13, although it is
 
818
   heavily modified.  The original copyright notice is reproduced in
 
819
   full below. */
 
820
 
 
821
/*
 
822
 * mice.c - mouse definitions for gpm-Linux
 
823
 *
 
824
 * Copyright 1993        ajh@gec-mrc.co.uk (Andrew Haylett)
 
825
 * Copyright 1994-1998   rubini@linux.it (Alessandro Rubini)
 
826
 *
 
827
 *   This program is free software; you can redistribute it and/or modify
 
828
 *   it under the terms of the GNU General Public License as published by
 
829
 *   the Free Software Foundation; either version 2 of the License, or
 
830
 *   (at your option) any later version.
 
831
 *
 
832
 *   This program is distributed in the hope that it will be useful,
 
833
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
834
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
835
 *   GNU General Public License for more details.
 
836
 *
 
837
 *   You should have received a copy of the GNU General Public License
 
838
 *   along with this program; if not, write to the Free Software
 
839
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
840
 ********/
 
841
 
 
842
static void
 
843
set_speed (int fd, int old, unsigned short flags)
 
844
{
 
845
  struct termios tty;
 
846
  tcgetattr(fd, &tty);
 
847
    
 
848
  tty.c_iflag = IGNBRK | IGNPAR;
 
849
  tty.c_oflag = 0;
 
850
  tty.c_lflag = 0;
 
851
  tty.c_line = 0;
 
852
  tty.c_cc[VTIME] = 0;
 
853
  tty.c_cc[VMIN] = 1;
 
854
  tty.c_cflag = flags | old;
 
855
  tcsetattr(fd, TCSAFLUSH, &tty);
 
856
 
 
857
  write(fd, "*n", 2);
 
858
  usleep(100000);
 
859
 
 
860
  tty.c_cflag = flags | B1200;
 
861
  tcsetattr(fd, TCSAFLUSH, &tty);
 
862
}
 
863
 
 
864
static void
 
865
init_serial (int fd)
 
866
{
 
867
  const int flags = CS7 | CREAD | CLOCAL | HUPCL;
 
868
 
 
869
  /* Change to 1200 baud from any baud rate. */
 
870
  set_speed (fd, B9600, flags);
 
871
  set_speed (fd, B4800, flags);
 
872
  set_speed (fd, B2400, flags);
 
873
  set_speed (fd, B1200, flags);
 
874
 
 
875
  /* Flush pending input. */
 
876
  {
 
877
    struct timeval timeout = {0, 0};
 
878
    unsigned char c;
 
879
    fd_set set;
 
880
    
 
881
    FD_ZERO (&set);
 
882
    for (;;)
 
883
      {
 
884
        FD_SET (fd, &set);
 
885
        switch (select (fd+1, &set, NULL, NULL, &timeout))
 
886
          {
 
887
          case 1:
 
888
            if (read(fd,&c,1)==0)
 
889
              break;
 
890
 
 
891
          case -1:
 
892
            continue;
 
893
          }
 
894
        break;
 
895
      }
 
896
  }
 
897
}
 
898
 
 
899
/* The code below is taken from the following files in the Red Hat 5.2
 
900
   mouseconfig-3.1.3 distribution.  It's been essentially rewritten.
 
901
 
 
902
   pnp_probe_com.c
 
903
   pnp_probe_com.h
 
904
 
 
905
   The original copyright notice is reproduced in full below.  All
 
906
   modifications are subject to the license at the top of this
 
907
   file. */
 
908
 
 
909
/* probe serial port for PnP/Legacy devices
 
910
 *
 
911
 *
 
912
 * Michael Fulbright (msf@redhat.com)
 
913
 *
 
914
 * Copyright 1997 Red Hat Software
 
915
 *
 
916
 * This software may be freely redistributed under the terms of the GNU
 
917
 * public license.
 
918
 *
 
919
 * You should have received a copy of the GNU General Public License
 
920
 * along with this program; if not, write to the Free Software
 
921
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
922
 *
 
923
 */
 
924
 
 
925
struct pnp_com_id
 
926
  {
 
927
    unsigned char other_id[17];         /* For pre-PNP compatibility. */
 
928
    unsigned char other_len;            /* Length of the other_id. */
 
929
    unsigned char pnp_rev_major;        /* PnP major revision number. */
 
930
    unsigned char pnp_rev_minor;        /* PnP minor revision number. */
 
931
    unsigned char manufacturer[4];      /* EISA manufacturer (string). */
 
932
    unsigned char product_id[5];        /* Mfr determined product ID (string) */
 
933
    unsigned char serial_number[9];     /* Optional dev serial number (string) */
 
934
    unsigned char class_name[33];       /* Optional PnP Class name (string) */
 
935
    unsigned char driver_id[42];        /* Optional compat device IDs (string) */
 
936
    unsigned char user_name[42];        /* Optional verbose product descr (string) */
 
937
  };
 
938
 
 
939
/* There are two possible bytes to signify the start of a PnP ID
 
940
   string. */
 
941
#define BeginPnP1 0x28
 
942
#define BeginPnP2 0x08
 
943
 
 
944
/* Likewise, two possible stop bytes. */
 
945
#define EndPnP1   0x29
 
946
#define EndPnP2   0x09
 
947
 
 
948
/* These chars indicate extensions to the base dev id exist. */
 
949
#define ExtendPnP1 0x5c
 
950
#define ExtendPnP2 0x3c
 
951
 
 
952
#define PNP_COM_MAXLEN 256
 
953
 
 
954
/* Wait until there is data available on fd, for up to TIMEOUT
 
955
   microseconds. */
 
956
static int
 
957
wait_for_input (int fd, long timeout)
 
958
{
 
959
  struct timeval tv;
 
960
  fd_set ready;
 
961
  int n;
 
962
 
 
963
  tv.tv_sec = 0;
 
964
  tv.tv_usec = timeout;
 
965
 
 
966
  FD_ZERO (&ready);
 
967
  FD_SET (fd, &ready);
 
968
 
 
969
  n = select (fd + 1, &ready, NULL, &ready, &tv);
 
970
  return n;
 
971
}
 
972
 
 
973
static int
 
974
open_serial_port (char *port)
 
975
{
 
976
  int fd;
 
977
 
 
978
  fd = open (port, O_RDWR | O_NONBLOCK);
 
979
  if (fd < 0)
 
980
    return fd;
 
981
 
 
982
  /* Reset file so it is no longer in non-blocking mode. */
 
983
  if (fcntl (fd, F_SETFL, 0) < 0)
 
984
    {
 
985
      close (fd);
 
986
      return -1;
 
987
    }
 
988
 
 
989
  return fd;
 
990
}
 
991
 
 
992
/* <0 means ioctl error occurred. */
 
993
static int
 
994
get_serial_lines (int fd)
 
995
{
 
996
  int modem_lines;
 
997
 
 
998
  ioctl (fd, TIOCMGET, &modem_lines);
 
999
  return modem_lines;
 
1000
}
 
1001
 
 
1002
/* <0 means ioctl error occurred */
 
1003
static int
 
1004
set_serial_lines (int fd, int modem_lines)
 
1005
{
 
1006
  return ioctl (fd, TIOCMSET, &modem_lines);
 
1007
}
 
1008
 
 
1009
static int
 
1010
get_serial_attr (int fd, struct termios *attr)
 
1011
{
 
1012
  return tcgetattr (fd, attr);
 
1013
}
 
1014
 
 
1015
static int
 
1016
set_serial_attr (int fd, struct termios *attr)
 
1017
{
 
1018
  return tcsetattr (fd, TCSANOW, attr);
 
1019
}
 
1020
 
 
1021
/* Set serial port to 1200 baud, 'nbits' bits, 1 stop, no parity. */
 
1022
static int
 
1023
setup_serial_port (int fd, int nbits)
 
1024
{
 
1025
  struct termios attr;
 
1026
 
 
1027
  if (get_serial_attr (fd, &attr) < 0)
 
1028
    return 0;
 
1029
  
 
1030
  attr.c_iflag = IGNBRK | IGNPAR;
 
1031
  attr.c_cflag = 0;
 
1032
  attr.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | PARENB);
 
1033
  attr.c_cflag |= CREAD | CLOCAL;       /*| CRTSCTS ; */
 
1034
  if (nbits == 7)
 
1035
    attr.c_cflag |= CS7 | CSTOPB;
 
1036
  else
 
1037
    attr.c_cflag |= CS8;
 
1038
  attr.c_oflag = 0;
 
1039
  attr.c_lflag = 0;
 
1040
 
 
1041
  attr.c_cc[VMIN] = 1;
 
1042
  attr.c_cc[VTIME] = 5;
 
1043
 
 
1044
  cfsetospeed (&attr, B1200);
 
1045
  cfsetispeed (&attr, B1200);
 
1046
 
 
1047
  return set_serial_attr (fd, &attr) >= 0;
 
1048
}
 
1049
 
 
1050
/* Request for PnP info from serial device.  See page 6 of the pnpcom
 
1051
   doc from Microsoft.  Returns nonzero only if successful. */
 
1052
static int
 
1053
init_pnp_com_seq1 (int fd)
 
1054
{
 
1055
  int modem_lines = get_serial_lines (fd);
 
1056
 
 
1057
  /* Turn off RTS and wait 200 ms for DSR to come up. */
 
1058
  set_serial_lines (fd, modem_lines & ~(TIOCM_RTS));
 
1059
  usleep (200000);
 
1060
 
 
1061
  /* See if DSR came up. */
 
1062
  modem_lines = get_serial_lines(fd);
 
1063
  if (!(modem_lines & TIOCM_DSR))
 
1064
    {
 
1065
      set_serial_lines (fd, modem_lines | TIOCM_DTR | TIOCM_RTS);
 
1066
      return 0;
 
1067
    }
 
1068
 
 
1069
  /* Com port setup, 1st phase.  Now we set port to be 1200 baud, 7
 
1070
     bits, no parity, 1 stop bit. */
 
1071
  if (!setup_serial_port (fd, 7))
 
1072
    return 0;
 
1073
  
 
1074
  /* Drop DTR and RTS. */
 
1075
  modem_lines &= ~(TIOCM_RTS | TIOCM_DTR);
 
1076
  set_serial_lines (fd, modem_lines);
 
1077
  usleep (200000);
 
1078
 
 
1079
  /* Bring DTR back up. */
 
1080
  modem_lines |= TIOCM_DTR;
 
1081
  set_serial_lines (fd, modem_lines);
 
1082
  usleep (200000);
 
1083
 
 
1084
  /* Enter next phase. */
 
1085
  modem_lines |= TIOCM_RTS;
 
1086
  set_serial_lines (fd, modem_lines);
 
1087
  usleep (200000);
 
1088
 
 
1089
  return 1;
 
1090
}
 
1091
 
 
1092
/* See if this is a legacy mouse device.  Only called if the PnP probe
 
1093
   above failed.  We turn off the mouse via RS232 lines, then turn it
 
1094
   on.  If it spits out an 'M' character (at 1200 baud, 7N1) it could
 
1095
   be a mouse.  Returns nonzero only if successful. */
 
1096
static int
 
1097
legacy_probe_com (int fd)
 
1098
{
 
1099
  /* Now we set port to be 1200 baud, 7 bits, no parity, 1 stop bit. */
 
1100
  if (!setup_serial_port (fd, 7))
 
1101
    return 0;
 
1102
 
 
1103
  /* Drop DTR and RTS, then bring them back up. */
 
1104
  {
 
1105
    int modem_lines = get_serial_lines (fd);
 
1106
 
 
1107
    set_serial_lines (fd, modem_lines & ~(TIOCM_RTS | TIOCM_DTR));
 
1108
    usleep (200000);
 
1109
    set_serial_lines (fd, modem_lines | TIOCM_DTR | TIOCM_RTS);
 
1110
  }
 
1111
 
 
1112
  /* Start reading - quit after first character. */
 
1113
  {
 
1114
    int starttime = (int) time (NULL);
 
1115
    
 
1116
    for (;;)
 
1117
      {
 
1118
        if (wait_for_input (fd, 250000) <= 0)
 
1119
          return 0;
 
1120
 
 
1121
        /* Read a character. */
 
1122
        {
 
1123
          unsigned char resp;
 
1124
        
 
1125
          if (read (fd, &resp, 1) > 0)
 
1126
            return resp == 'M';
 
1127
          if (errno != EAGAIN)
 
1128
            return 0;
 
1129
        }
 
1130
 
 
1131
        /* Shouldn't run more than 2 seconds. */
 
1132
        if (time (NULL) - starttime > 2)
 
1133
          return 0;
 
1134
      }
 
1135
  }
 
1136
}
 
1137
 
 
1138
/* Retrieve the PnP ID string.  Timeout after 3 seconds.  Should
 
1139
   probably set a 200 msec timeout per char, as spec says.  If no char
 
1140
   received, we're done.  Returns number of characters retrieved. */
 
1141
static int
 
1142
read_pnp_string (int fd, unsigned char *pnp_string, int *pnp_len)
 
1143
{
 
1144
  int pnp_index;
 
1145
  time_t starttime;
 
1146
  int end_char;
 
1147
 
 
1148
  pnp_index = 0;
 
1149
  end_char = -1;
 
1150
  starttime = time (NULL);
 
1151
 
 
1152
  for (;;)
 
1153
    {
 
1154
      unsigned char c;
 
1155
      
 
1156
      /* Don't wait more than 3 seconds. */
 
1157
      if (time (NULL) - starttime > 4)
 
1158
        break;
 
1159
 
 
1160
      /* Wait for a character to arrive. */
 
1161
      if (wait_for_input (fd, 250000) <= 0)
 
1162
        break;
 
1163
 
 
1164
      /* Read a byte. */
 
1165
      {
 
1166
        ssize_t nbytes = read (fd, &c, 1);
 
1167
        
 
1168
        if (nbytes < 0 && errno != EAGAIN)
 
1169
          break;
 
1170
        if (nbytes == 0)
 
1171
          continue;
 
1172
      }
 
1173
 
 
1174
      /* Store the byte. */
 
1175
      if (pnp_index < 99)
 
1176
        pnp_string[pnp_index++] = c;
 
1177
 
 
1178
      /* Check for end of string. */
 
1179
      if (end_char != -1)
 
1180
        {
 
1181
          if (c == end_char)
 
1182
            break;
 
1183
        }
 
1184
      else if (c == BeginPnP1)
 
1185
        end_char = EndPnP1;
 
1186
      else if (c == BeginPnP2)
 
1187
        end_char = EndPnP2;
 
1188
    }
 
1189
 
 
1190
  pnp_string[pnp_index] = 0;
 
1191
  *pnp_len = pnp_index;
 
1192
 
 
1193
  return pnp_index;
 
1194
}
 
1195
 
 
1196
/* Parse the PnP ID string into components.  Returns nonzero only if
 
1197
   successful. */
 
1198
static int
 
1199
parse_pnp_string (unsigned char *pnp_id_string, int pnp_len,
 
1200
                  struct pnp_com_id *pnp_id)
 
1201
{
 
1202
  unsigned char pnp_string[100];
 
1203
 
 
1204
  unsigned char *p1, *p2;
 
1205
  unsigned char *start;
 
1206
  unsigned char *curpos;
 
1207
 
 
1208
  int xlate_6bit;
 
1209
 
 
1210
  int stage;
 
1211
 
 
1212
  /* Clear out pnp_id and make a local copy of pnp_id_string. */
 
1213
  memset (pnp_id, 0, sizeof (*pnp_id));
 
1214
  memcpy (pnp_string, pnp_id_string, pnp_len + 1);
 
1215
 
 
1216
  /* First find the start of the PnP part of string.  Use the marker
 
1217
     which points nearest to start of the string and is actually
 
1218
     defined.  The length of the initial part cannot be more than 17
 
1219
     bytes. */
 
1220
  {
 
1221
    
 
1222
    p1 = memchr (pnp_string, BeginPnP1, pnp_len);
 
1223
    p2 = memchr (pnp_string, BeginPnP2, pnp_len);
 
1224
 
 
1225
    start = p1;
 
1226
    if (!start || (p2 && p2 < start))
 
1227
      start = p2;
 
1228
    if (!start || start - pnp_string > 17)
 
1229
      return 0;
 
1230
  }
 
1231
  
 
1232
  /* Copy everything before the start of the PnP block. */
 
1233
  memcpy (pnp_id->other_id, pnp_string, start - pnp_string);
 
1234
  pnp_id->other_len = start - pnp_string;
 
1235
 
 
1236
  /* Translate data in PnP fields if necessary. */
 
1237
  if (start == p2)
 
1238
    {
 
1239
      unsigned char *cp;
 
1240
 
 
1241
      for (cp = start; ; cp++)
 
1242
        {
 
1243
          /* Skip the revision fields (bytes 1 and 2 after start). */
 
1244
          if (cp != start + 1 && cp != start + 2)
 
1245
            *cp += 0x20;
 
1246
          putchar (*cp);
 
1247
          
 
1248
          if (*cp == EndPnP1)
 
1249
            break;
 
1250
        }
 
1251
 
 
1252
      xlate_6bit = 1;
 
1253
    }
 
1254
  else
 
1255
    xlate_6bit = 0;
 
1256
 
 
1257
  /* Now we get the PnP fields - all were zeroed out above. */
 
1258
  curpos = start + 1;
 
1259
 
 
1260
  {
 
1261
    int rev_tmp = ((curpos[0] & 0x3f) << 6) + (curpos[1] & 0x3f);
 
1262
    pnp_id->pnp_rev_major = rev_tmp / 100;
 
1263
    pnp_id->pnp_rev_minor = rev_tmp % 100;
 
1264
  }
 
1265
  curpos += 2;
 
1266
 
 
1267
  memcpy (pnp_id->manufacturer, curpos, 3);
 
1268
  curpos += 3;
 
1269
 
 
1270
  memcpy (pnp_id->product_id, curpos, 4);
 
1271
  curpos += 4;
 
1272
 
 
1273
  /* Now read extension fields, if any. */
 
1274
  for (stage = 0; *curpos == ExtendPnP1 || *curpos == ExtendPnP2; stage++)
 
1275
    {
 
1276
      static const char extension_delims[] =
 
1277
        {EndPnP1, ExtendPnP1, ExtendPnP2, 0};
 
1278
 
 
1279
      int len;
 
1280
 
 
1281
      unsigned char *endfield = strpbrk ((unsigned char*)++curpos, extension_delims);
 
1282
      if (!endfield)
 
1283
        return 0;
 
1284
 
 
1285
      /* If we reached the end of all PnP data, back off since
 
1286
         there is a checksum at the end of extension data. */
 
1287
      len = endfield - curpos;
 
1288
      if (*endfield == EndPnP1)
 
1289
        len -= 2;
 
1290
      
 
1291
      switch (stage)
 
1292
        {
 
1293
        case 0:
 
1294
          if (len != 8 && len != 0)
 
1295
            return 0;
 
1296
          memcpy (pnp_id->serial_number, curpos, len);
 
1297
          break;
 
1298
 
 
1299
        case 1:
 
1300
          if (len > 33)
 
1301
            return 0;
 
1302
          memcpy (pnp_id->class_name, curpos, len);
 
1303
          break;
 
1304
 
 
1305
        case 2:
 
1306
          if (len > 41)
 
1307
            return 0;
 
1308
          memcpy (pnp_id->driver_id, curpos, len);
 
1309
          break;
 
1310
 
 
1311
        case 3:
 
1312
          if (len > 41)
 
1313
            return 0;
 
1314
          memcpy (pnp_id->user_name, curpos, len);
 
1315
          break;
 
1316
 
 
1317
        default:
 
1318
          /* Ignore additional extension fields. */
 
1319
          break;
 
1320
        }
 
1321
 
 
1322
      curpos += len;
 
1323
      if (*endfield == EndPnP1)
 
1324
        break;
 
1325
    }
 
1326
 
 
1327
  /* If we had any extensions, we expect and check a checksum. */
 
1328
  if (stage)
 
1329
    {
 
1330
      unsigned int checksum;
 
1331
      const unsigned char *cp;
 
1332
      char hex_checksum[3];
 
1333
 
 
1334
      checksum = curpos[2];
 
1335
      for (cp = start; cp < curpos; cp++)
 
1336
        checksum += *cp;
 
1337
      
 
1338
      if (xlate_6bit)
 
1339
        checksum -= 0x20 * (curpos - start + 1 - 2);
 
1340
      
 
1341
      sprintf (hex_checksum, "%.2X", checksum & 0xff);
 
1342
      if (strncmp (hex_checksum, curpos, 2))
 
1343
        return 0;
 
1344
    }
 
1345
 
 
1346
  return 1;
 
1347
}
 
1348
 
 
1349
static int
 
1350
guess_mouse_type (struct pnp_com_id *pnp_id)
 
1351
{
 
1352
  int type;
 
1353
  
 
1354
  /* First, figure out whether it's a mouse or not. */
 
1355
  if (pnp_id->class_name[0] == 0)
 
1356
    {
 
1357
      char *model;
 
1358
 
 
1359
      model = strstr (pnp_id->driver_id, "PNP");
 
1360
      if (model)
 
1361
        model += 3;
 
1362
      else
 
1363
        model = pnp_id->product_id;
 
1364
 
 
1365
      if (strncmp (model, "0F", 2))
 
1366
        return -1;
 
1367
    }
 
1368
  else if (strcmp (pnp_id->class_name, "MOUSE"))
 
1369
    return -1;
 
1370
  
 
1371
  /* It's a mouse.  Default to Microsoft protocol--most common. */
 
1372
  type = T_MS_SERIAL;
 
1373
 
 
1374
  /* Test for some common mouse types.  Send me more! */
 
1375
  {
 
1376
    const char *mfg = pnp_id->manufacturer;
 
1377
    const char *model = pnp_id->product_id;
 
1378
    
 
1379
    if (!strcmp (mfg, "MSH") && !strcmp (model, "0001"))
 
1380
      type = T_MS3_SERIAL;
 
1381
    else if (!strcmp (mfg, "LGI") && !strncmp (model, "80", 2))
 
1382
      type = T_MMAN_SERIAL;
 
1383
    else if (!strcmp (mfg, "KYE") && !strcmp (model, "0003"))
 
1384
      type = T_MS3_SERIAL;
 
1385
  }
 
1386
 
 
1387
  return type;
 
1388
}
 
1389
 
 
1390
/* If PNP != 0, checks for a plug-n-play mouse on device PORT; if PNP
 
1391
   == 0, checks for a legacy mouse on that device.  Returns nonzero if
 
1392
   a device is found. */
 
1393
static int
 
1394
probe_com (char *port, int pnp)
 
1395
{
 
1396
  struct termios origattr;
 
1397
 
 
1398
  /* Open serial port. */
 
1399
  int fd = open_serial_port (port);
 
1400
  if (fd < 0)
 
1401
    return 0;
 
1402
 
 
1403
  /* Save port attributes. */
 
1404
  if (get_serial_attr (fd, &origattr) < 0)
 
1405
    {
 
1406
      close (fd);
 
1407
      return 0;
 
1408
    }
 
1409
 
 
1410
  /* Retrieve PnP string or check for legacy mouse. */
 
1411
  if (pnp)
 
1412
    {
 
1413
      struct pnp_com_id pnp_id;
 
1414
 
 
1415
      unsigned char pnp_string[100];
 
1416
      int pnp_strlen;
 
1417
 
 
1418
      if (init_pnp_com_seq1 (fd)
 
1419
          && read_pnp_string (fd, pnp_string, &pnp_strlen)
 
1420
          && parse_pnp_string (pnp_string, pnp_strlen, &pnp_id))
 
1421
        {
 
1422
          int type = guess_mouse_type (&pnp_id);
 
1423
          if (type != -1)
 
1424
            {
 
1425
              add_mouse (type, fd);
 
1426
              return 1;
 
1427
            }
 
1428
        }
 
1429
    }
 
1430
  else if (legacy_probe_com (fd))
 
1431
    {
 
1432
      init_serial (fd);
 
1433
 
 
1434
      /* FIXME: Must detect MS, MSC, LOGI. */
 
1435
      add_mouse (T_MS_SERIAL, fd);
 
1436
      return 1;
 
1437
    }
 
1438
  else
 
1439
    {
 
1440
      /* Restore port attributes. */
 
1441
      set_serial_attr (fd, &origattr);
 
1442
      close (fd);
 
1443
    }
 
1444
 
 
1445
  return 0;
 
1446
}
 
1447
 
 
1448
#endif /* M_SERIAL */