1
/* BOGL - Ben's Own Graphics Library.
2
Written by Ben Pfaff <pfaffben@debian.org>.
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.
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.
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
26
#include <sys/ioctl.h>
28
#include <sys/types.h>
39
#include <sys/socket.h>
46
#elif defined __i386__
50
#elif defined __mc68000__
52
#elif defined __powerpc__
56
#elif defined __sparc__
62
/* Packet drivers and detection routines. */
70
static int detect_gpm (void);
73
static void ms_driver (struct mouse *);
80
static void ps2_driver (struct mouse *);
82
static int input_mouse_found = 0;
83
static void detect_input (void);
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 *);
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 *);
105
static void detect_msbus (void);
111
static void detect_adb (void);
117
static void detect_sun (void);
124
static void detect_ps2 (void);
125
static void ps2_driver (struct mouse *);
128
#define N_DETECT (N_SERIAL + N_MSBUS + N_PS2 + N_ADB + N_SUN)
130
/* Detection progress. */
131
static void inc (void);
133
static void (*detect_callback) (int);
134
static int detect_count;
140
/* Serial mice using the MS protocol */
141
T_MS_SERIAL, /* Microsoft. */
142
T_MS3_SERIAL, /* Microsoft Intellimouse. */
146
/* Other serial mice. */
147
T_MSC_SERIAL, /* Mouse Systems. */
148
T_MMAN_SERIAL, /* Logitech Mouseman. */
153
T_MS_BUS, /* Microsoft/Logitech. */
157
T_ADB, /* Apple ADB */
166
T_PS2, /* Generic. */
170
/* Mouse attributes description. */
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. */
179
/* Some of the information below is borrowed from gpm. */
180
static struct mouse_info mouse_info[] =
183
{"Microsoft serial", 3, {0x40,0x40,0x40,0x00}, ms_driver},
184
{"Microsoft Intellimouse serial", 4, {0xc0,0x40,0xc0,0x00}, ms_driver},
188
{"Mouse Systems serial", 5, {0xf8,0x80,0x00,0x00}, msc_driver},
189
{"Mouseman serial", 3, {0xe0,0x80,0x80,0x00}, mman_driver},
193
{"Microsoft bus", 3, {0xf8,0x80,0x00,0x00}, bm_driver},
197
{"Apple Desktop Bus", 3, {0xf8,0x80,0x00,0x00}, bm_driver},
201
{"Sun", 3, {0xf8,0x80,0x00,0x00}, bm_driver},
205
{"Generic PS/2", 3, {0xc0,0x00,0x00,0x00}, ps2_driver},
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. */
220
/* All detected mice. */
221
static struct mouse *mice;
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? */
232
int type; /* One of BOML_E_*. */
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)
245
static struct event queue[QUEUE_SIZE];
249
static int probe_com (char *port, int pnp);
251
static void state (int dx, int dy, int button);
254
static const struct bogl_pointer *pointer;
255
static int pointer_colors[2];
261
boml_quick_init (void)
263
static int inited = 0;
278
if (input_mouse_found)
288
/* Detects mice and initializes the mouse library. */
290
boml_init (void (*callback) (int))
292
/* Assure idempotence. */
293
static int inited = 0;
298
detect_callback = callback;
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
334
detect_callback (100 * detect_count / N_DETECT);
337
/* Reads mouse activities from the proper port and update the screen
344
/* How many bytes to read at once */
348
for (mouse = mice; mouse; mouse = mouse->next)
350
struct mouse_info *minfo = &mouse_info[mouse->type];
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
357
if (mouse->type == T_ADB)
360
#if defined (M_MSBUS)
361
if (mouse->type == T_MS_BUS)
364
while (read (mouse->fd, &mouse->pbuf[mouse->ppos], howmany) == howmany)
367
/* The MouseMan protocol is extremely fscked up. Packets can
368
have 3 or 4 bytes. Attempt to detect changing from 3 byte to
370
if (mouse->type == T_MMAN_SERIAL
372
&& (mouse->pbuf[0] & minfo->id[0]) != minfo->id[1]
373
&& (mouse->pbuf[0] >> 4) <= 3)
375
int b = mouse->pbuf[0] >> 4;
376
mouse->packet_size = 4;
377
state (0, 0, b & 0x20);
383
if ((mouse->ppos == 0
384
&& (mouse->pbuf[0] & minfo->id[0]) != minfo->id[1])
386
&& (mouse->pbuf[1] & minfo->id[2]) != minfo->id[3]))
388
/* Nope, not a packet */
393
mouse->ppos += howmany;
394
if (mouse->ppos >= mouse->packet_size)
396
minfo->driver (mouse);
402
if ((sx != x || sy != y || !drawn) && show)
405
bogl_pointer (0, sx, sy, pointer, pointer_colors);
406
bogl_pointer (1, x, y, pointer, pointer_colors);
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. */
416
boml_drawn (int is_drawn)
421
/* Draw the mouse cursor if it's not drawn but it should be. */
425
if (show > 0 && !drawn)
427
bogl_pointer (1, x, y, pointer, pointer_colors);
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
443
if (show == 1 && !drawn)
445
bogl_pointer (1, x, y, pointer, pointer_colors);
450
/* Hide the mouse cursor. See comment above boml_show() for more
459
if (show == 0 && drawn)
461
bogl_pointer (0, x, y, pointer, pointer_colors);
466
/* Change the mouse cursor to pointer P. The cursor is drawn in the
467
colors specified by COLORS. */
469
boml_pointer (const struct bogl_pointer *p, int colors[2])
473
pointer_colors[0] = colors[0];
474
pointer_colors[1] = colors[1];
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
482
boml_fds (int test, fd_set *fds)
486
for (mouse = mice; mouse; mouse = mouse->next)
489
if (FD_ISSET (mouse->fd, fds))
493
FD_SET (mouse->fd, fds);
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. */
502
boml_event (int *x, int *y, int *btn)
509
type = queue[qt].type;
515
*btn = queue[qt].btn;
523
/* Add an event of the specified type to the event queue. */
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)
531
queue[q_prev (qh)].x = x;
532
queue[q_prev (qh)].y = y;
536
queue[qh].type = type;
539
queue[qh].btn = button;
546
/* The mouse moved (DX,DY) units, and the button is in state BTN (!=0:
547
pressed). Record that fact. */
549
state (int dx, int dy, int btn)
568
event (BOML_E_PRESS);
570
event (BOML_E_RELEASE);
576
/* Add a mouse of type TYPE to the list of mice. The mouse is open on
577
file descriptor FD. */
579
add_mouse (int type, int fd)
581
struct mouse *mouse = malloc (sizeof (struct mouse));
586
mouse->packet_size = mouse_info[type].packet_size;
591
/* If we have a gpm repeater, assume ms3. */
597
struct sockaddr_un sock;
601
/* Make sure GPM is answering requests... */
602
fd = socket (PF_UNIX, SOCK_STREAM, 0);
607
sock.sun_family = AF_UNIX;
608
strcpy(sock.sun_path, "/dev/gpmctl");
609
if(connect (fd, &sock, SUN_LEN(&sock)) < 0)
614
fd = open ("/dev/gpmdata", O_RDONLY | O_NONBLOCK);
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);
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. */
634
fd = open("/dev/input/mouse0", O_RDONLY | O_NONBLOCK);
636
input_mouse_found = 1;
640
fd = open("/dev/input/mice", O_RDONLY | O_NONBLOCK);
644
add_mouse(T_PS2, fd);
648
/* PS/2 mouse code. */
651
/* Attempt to detect presence of a PS/2 mouse. If successful, sets
652
`type' to indicate mouse type. */
656
static const unsigned char s2[] = { 246, 230, 244, 243, 100, 232, 3, };
659
fd = open ("/dev/psaux", O_RDWR | O_NONBLOCK);
663
write (fd, s2, sizeof s2);
665
tcflush (fd, TCIFLUSH);
667
add_mouse (T_PS2, fd);
673
ps2_driver (struct mouse *m)
679
x = (m->pbuf[0] & 0x10) ? m->pbuf[1] - 256 : m->pbuf[1];
681
y = (m->pbuf[0] & 0x20) ? 256 - m->pbuf[2] : -m->pbuf[2];
683
state (x, y, m->pbuf[0] & 1);
685
#endif /* M_PS2_DRIVER */
687
/* Microsoft/Apple Busmouse and Sun mouse code. */
690
/* Attempt to detect presence of a Microsoft bus mouse. If
691
successful, sets `type' to indicate mouse type. */
695
int fd = open ("/dev/inportbm", O_RDONLY | O_NONBLOCK);
699
add_mouse (T_MS_BUS, fd);
707
int fd = open ("/dev/adbmouse", O_RDONLY | O_NONBLOCK);
711
add_mouse (T_ADB, fd);
716
/* FIXME: Reading the GPM code tells me that this is almost certainly
717
wrong. Some Sparc person will have to fix it. */
721
int fd = open ("/dev/sunmouse", O_RDONLY | O_NONBLOCK);
725
add_mouse (T_SUN, fd);
729
/* The decoder is definitely the same for all three though */
730
#if defined(M_ADB) || defined(M_SUN) || defined(M_MSBUS)
732
bm_driver (struct mouse *m)
734
signed char *p = (signed char *) (m->pbuf);
735
state (p[1], -p[2], !(p[0] & 0x04));
737
#endif /* M_ADB || M_SUN || M_MSBUS */
742
/* Attempt to detect presence of a serial mouse. If successful, sets
743
`type' to indicate mouse type. */
747
static char device[] = "/dev/ttySx";
749
for (device[9] = '0'; device[9] <= '3'; device[9]++)
753
success = probe_com (device, 1);
757
probe_com (device, 0);
761
#endif /* M_SERIAL */
764
/* ms and ms3 protocols are the same except that ms3 has an extra byte
767
ms_driver (struct mouse *m)
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),
777
msc_driver (struct mouse *m)
779
signed char *p = (signed char *) (m->pbuf);
780
state (p[3] + p[1], p[4] - p[2], !(m->pbuf[0] & 0x04));
784
mman_driver (struct mouse *m)
786
if (m->packet_size == 4 && (m->pbuf[3] >> 4) == 0)
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)),
796
logi_driver (struct mouse *m)
798
state (m->pbuf[0] & 0x10 ? m->pbuf[1] : -m->pbuf[1],
799
m->pbuf[0] & 0x08 ? -m->pbuf[2] : m->pbuf[2],
804
#endif /* M_SERIAL_DRIVER */
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
822
* mice.c - mouse definitions for gpm-Linux
824
* Copyright 1993 ajh@gec-mrc.co.uk (Andrew Haylett)
825
* Copyright 1994-1998 rubini@linux.it (Alessandro Rubini)
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.
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.
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.
843
set_speed (int fd, int old, unsigned short flags)
848
tty.c_iflag = IGNBRK | IGNPAR;
854
tty.c_cflag = flags | old;
855
tcsetattr(fd, TCSAFLUSH, &tty);
860
tty.c_cflag = flags | B1200;
861
tcsetattr(fd, TCSAFLUSH, &tty);
867
const int flags = CS7 | CREAD | CLOCAL | HUPCL;
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);
875
/* Flush pending input. */
877
struct timeval timeout = {0, 0};
885
switch (select (fd+1, &set, NULL, NULL, &timeout))
888
if (read(fd,&c,1)==0)
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.
905
The original copyright notice is reproduced in full below. All
906
modifications are subject to the license at the top of this
909
/* probe serial port for PnP/Legacy devices
912
* Michael Fulbright (msf@redhat.com)
914
* Copyright 1997 Red Hat Software
916
* This software may be freely redistributed under the terms of the GNU
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.
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) */
939
/* There are two possible bytes to signify the start of a PnP ID
941
#define BeginPnP1 0x28
942
#define BeginPnP2 0x08
944
/* Likewise, two possible stop bytes. */
948
/* These chars indicate extensions to the base dev id exist. */
949
#define ExtendPnP1 0x5c
950
#define ExtendPnP2 0x3c
952
#define PNP_COM_MAXLEN 256
954
/* Wait until there is data available on fd, for up to TIMEOUT
957
wait_for_input (int fd, long timeout)
964
tv.tv_usec = timeout;
969
n = select (fd + 1, &ready, NULL, &ready, &tv);
974
open_serial_port (char *port)
978
fd = open (port, O_RDWR | O_NONBLOCK);
982
/* Reset file so it is no longer in non-blocking mode. */
983
if (fcntl (fd, F_SETFL, 0) < 0)
992
/* <0 means ioctl error occurred. */
994
get_serial_lines (int fd)
998
ioctl (fd, TIOCMGET, &modem_lines);
1002
/* <0 means ioctl error occurred */
1004
set_serial_lines (int fd, int modem_lines)
1006
return ioctl (fd, TIOCMSET, &modem_lines);
1010
get_serial_attr (int fd, struct termios *attr)
1012
return tcgetattr (fd, attr);
1016
set_serial_attr (int fd, struct termios *attr)
1018
return tcsetattr (fd, TCSANOW, attr);
1021
/* Set serial port to 1200 baud, 'nbits' bits, 1 stop, no parity. */
1023
setup_serial_port (int fd, int nbits)
1025
struct termios attr;
1027
if (get_serial_attr (fd, &attr) < 0)
1030
attr.c_iflag = IGNBRK | IGNPAR;
1032
attr.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | PARENB);
1033
attr.c_cflag |= CREAD | CLOCAL; /*| CRTSCTS ; */
1035
attr.c_cflag |= CS7 | CSTOPB;
1037
attr.c_cflag |= CS8;
1041
attr.c_cc[VMIN] = 1;
1042
attr.c_cc[VTIME] = 5;
1044
cfsetospeed (&attr, B1200);
1045
cfsetispeed (&attr, B1200);
1047
return set_serial_attr (fd, &attr) >= 0;
1050
/* Request for PnP info from serial device. See page 6 of the pnpcom
1051
doc from Microsoft. Returns nonzero only if successful. */
1053
init_pnp_com_seq1 (int fd)
1055
int modem_lines = get_serial_lines (fd);
1057
/* Turn off RTS and wait 200 ms for DSR to come up. */
1058
set_serial_lines (fd, modem_lines & ~(TIOCM_RTS));
1061
/* See if DSR came up. */
1062
modem_lines = get_serial_lines(fd);
1063
if (!(modem_lines & TIOCM_DSR))
1065
set_serial_lines (fd, modem_lines | TIOCM_DTR | TIOCM_RTS);
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))
1074
/* Drop DTR and RTS. */
1075
modem_lines &= ~(TIOCM_RTS | TIOCM_DTR);
1076
set_serial_lines (fd, modem_lines);
1079
/* Bring DTR back up. */
1080
modem_lines |= TIOCM_DTR;
1081
set_serial_lines (fd, modem_lines);
1084
/* Enter next phase. */
1085
modem_lines |= TIOCM_RTS;
1086
set_serial_lines (fd, modem_lines);
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. */
1097
legacy_probe_com (int fd)
1099
/* Now we set port to be 1200 baud, 7 bits, no parity, 1 stop bit. */
1100
if (!setup_serial_port (fd, 7))
1103
/* Drop DTR and RTS, then bring them back up. */
1105
int modem_lines = get_serial_lines (fd);
1107
set_serial_lines (fd, modem_lines & ~(TIOCM_RTS | TIOCM_DTR));
1109
set_serial_lines (fd, modem_lines | TIOCM_DTR | TIOCM_RTS);
1112
/* Start reading - quit after first character. */
1114
int starttime = (int) time (NULL);
1118
if (wait_for_input (fd, 250000) <= 0)
1121
/* Read a character. */
1125
if (read (fd, &resp, 1) > 0)
1127
if (errno != EAGAIN)
1131
/* Shouldn't run more than 2 seconds. */
1132
if (time (NULL) - starttime > 2)
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. */
1142
read_pnp_string (int fd, unsigned char *pnp_string, int *pnp_len)
1150
starttime = time (NULL);
1156
/* Don't wait more than 3 seconds. */
1157
if (time (NULL) - starttime > 4)
1160
/* Wait for a character to arrive. */
1161
if (wait_for_input (fd, 250000) <= 0)
1166
ssize_t nbytes = read (fd, &c, 1);
1168
if (nbytes < 0 && errno != EAGAIN)
1174
/* Store the byte. */
1176
pnp_string[pnp_index++] = c;
1178
/* Check for end of string. */
1184
else if (c == BeginPnP1)
1186
else if (c == BeginPnP2)
1190
pnp_string[pnp_index] = 0;
1191
*pnp_len = pnp_index;
1196
/* Parse the PnP ID string into components. Returns nonzero only if
1199
parse_pnp_string (unsigned char *pnp_id_string, int pnp_len,
1200
struct pnp_com_id *pnp_id)
1202
unsigned char pnp_string[100];
1204
unsigned char *p1, *p2;
1205
unsigned char *start;
1206
unsigned char *curpos;
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);
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
1222
p1 = memchr (pnp_string, BeginPnP1, pnp_len);
1223
p2 = memchr (pnp_string, BeginPnP2, pnp_len);
1226
if (!start || (p2 && p2 < start))
1228
if (!start || start - pnp_string > 17)
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;
1236
/* Translate data in PnP fields if necessary. */
1241
for (cp = start; ; cp++)
1243
/* Skip the revision fields (bytes 1 and 2 after start). */
1244
if (cp != start + 1 && cp != start + 2)
1257
/* Now we get the PnP fields - all were zeroed out above. */
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;
1267
memcpy (pnp_id->manufacturer, curpos, 3);
1270
memcpy (pnp_id->product_id, curpos, 4);
1273
/* Now read extension fields, if any. */
1274
for (stage = 0; *curpos == ExtendPnP1 || *curpos == ExtendPnP2; stage++)
1276
static const char extension_delims[] =
1277
{EndPnP1, ExtendPnP1, ExtendPnP2, 0};
1281
unsigned char *endfield = strpbrk ((unsigned char*)++curpos, extension_delims);
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)
1294
if (len != 8 && len != 0)
1296
memcpy (pnp_id->serial_number, curpos, len);
1302
memcpy (pnp_id->class_name, curpos, len);
1308
memcpy (pnp_id->driver_id, curpos, len);
1314
memcpy (pnp_id->user_name, curpos, len);
1318
/* Ignore additional extension fields. */
1323
if (*endfield == EndPnP1)
1327
/* If we had any extensions, we expect and check a checksum. */
1330
unsigned int checksum;
1331
const unsigned char *cp;
1332
char hex_checksum[3];
1334
checksum = curpos[2];
1335
for (cp = start; cp < curpos; cp++)
1339
checksum -= 0x20 * (curpos - start + 1 - 2);
1341
sprintf (hex_checksum, "%.2X", checksum & 0xff);
1342
if (strncmp (hex_checksum, curpos, 2))
1350
guess_mouse_type (struct pnp_com_id *pnp_id)
1354
/* First, figure out whether it's a mouse or not. */
1355
if (pnp_id->class_name[0] == 0)
1359
model = strstr (pnp_id->driver_id, "PNP");
1363
model = pnp_id->product_id;
1365
if (strncmp (model, "0F", 2))
1368
else if (strcmp (pnp_id->class_name, "MOUSE"))
1371
/* It's a mouse. Default to Microsoft protocol--most common. */
1374
/* Test for some common mouse types. Send me more! */
1376
const char *mfg = pnp_id->manufacturer;
1377
const char *model = pnp_id->product_id;
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;
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. */
1394
probe_com (char *port, int pnp)
1396
struct termios origattr;
1398
/* Open serial port. */
1399
int fd = open_serial_port (port);
1403
/* Save port attributes. */
1404
if (get_serial_attr (fd, &origattr) < 0)
1410
/* Retrieve PnP string or check for legacy mouse. */
1413
struct pnp_com_id pnp_id;
1415
unsigned char pnp_string[100];
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))
1422
int type = guess_mouse_type (&pnp_id);
1425
add_mouse (type, fd);
1430
else if (legacy_probe_com (fd))
1434
/* FIXME: Must detect MS, MSC, LOGI. */
1435
add_mouse (T_MS_SERIAL, fd);
1440
/* Restore port attributes. */
1441
set_serial_attr (fd, &origattr);
1448
#endif /* M_SERIAL */