2016-11-25 17:18:40 +01:00
|
|
|
/*
|
|
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
|
|
* in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <u.h>
|
2017-04-19 23:33:14 +02:00
|
|
|
#include <lib9.h>
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Sleep500 = 500,
|
|
|
|
Sleep1000 = 1000,
|
|
|
|
Sleep2000 = 2000,
|
|
|
|
|
|
|
|
TIMEOUT = 5000, /* timeout for writes */
|
|
|
|
};
|
|
|
|
|
|
|
|
char *speeds[] =
|
|
|
|
{
|
|
|
|
"b1200",
|
|
|
|
"b2400",
|
|
|
|
"b4800",
|
|
|
|
"b9600",
|
|
|
|
0,
|
|
|
|
};
|
|
|
|
|
|
|
|
int button2;
|
|
|
|
|
|
|
|
#define DEBUG if(debug)
|
|
|
|
|
|
|
|
int can9600; /* true if type W mouse can be set to 9600 */
|
|
|
|
int debug;
|
|
|
|
int dontset; /* true if we shouldn't try to set the mouse type */
|
|
|
|
|
|
|
|
static void
|
|
|
|
usage(void)
|
|
|
|
{
|
|
|
|
fprint(2, "%s: usage: %s [device]\n", argv0, argv0);
|
|
|
|
exits("usage");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
catch(void *a, char *msg)
|
|
|
|
{
|
|
|
|
USED(a); USED(msg);
|
|
|
|
if(strstr(msg, "alarm"))
|
|
|
|
noted(NCONT);
|
|
|
|
noted(NDFLT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dumpbuf(char *buf, int nbytes, char *s)
|
|
|
|
{
|
|
|
|
print(s);
|
|
|
|
while(nbytes-- > 0)
|
|
|
|
print("#%ux ", *buf++ & 0xFF);
|
|
|
|
print("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32_t
|
|
|
|
timedwrite(int fd, void *p, int n)
|
|
|
|
{
|
|
|
|
int32_t rv;
|
|
|
|
|
|
|
|
alarm(TIMEOUT);
|
|
|
|
rv = write(fd, p, n);
|
|
|
|
alarm(0);
|
|
|
|
if(rv < 0){
|
|
|
|
fprint(2, "%s: timed out\n", argv0);
|
|
|
|
exits("timeout");
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
readbyte(int fd)
|
|
|
|
{
|
|
|
|
uint8_t c;
|
|
|
|
char buf[ERRMAX];
|
|
|
|
|
|
|
|
alarm(200);
|
|
|
|
if(read(fd, &c, sizeof(c)) == -1){
|
|
|
|
alarm(0);
|
|
|
|
errstr(buf, sizeof buf);
|
|
|
|
if(strcmp(buf, "interrupted") == 0)
|
|
|
|
return -1;
|
|
|
|
fprint(2, "%s: readbyte failed - %s\n", argv0, buf);
|
|
|
|
exits("read");
|
|
|
|
}
|
|
|
|
alarm(0);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
slowread(int fd, char *buf, int nbytes, char *msg)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
for(p = buf; nbytes > 1 && (c = readbyte(fd)) != -1; *p++ = c, nbytes--)
|
|
|
|
;
|
|
|
|
*p = 0;
|
|
|
|
DEBUG dumpbuf(buf, p-buf, msg);
|
|
|
|
return p-buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
toggleRTS(int fd)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* reset the mouse (toggle RTS)
|
|
|
|
* must be >100mS
|
|
|
|
*/
|
|
|
|
timedwrite(fd, "d1", 2);
|
|
|
|
timedwrite(fd, "r1", 2);
|
|
|
|
sleep(Sleep500);
|
|
|
|
timedwrite(fd, "d0", 2);
|
|
|
|
timedwrite(fd, "r0", 2);
|
|
|
|
sleep(Sleep500);
|
|
|
|
timedwrite(fd, "d1", 2);
|
|
|
|
timedwrite(fd, "r1", 2);
|
|
|
|
sleep(Sleep500);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setupeia(int fd, char *baud, char *bits)
|
|
|
|
{
|
|
|
|
alarm(TIMEOUT);
|
|
|
|
/*
|
|
|
|
* set the speed to 1200/2400/4800/9600 baud,
|
|
|
|
* 7/8-bit data, one stop bit and no parity
|
|
|
|
*/
|
|
|
|
DEBUG print("setupeia(%s,%s)\n", baud, bits);
|
|
|
|
timedwrite(fd, baud, strlen(baud));
|
|
|
|
timedwrite(fd, bits, strlen(bits));
|
|
|
|
timedwrite(fd, "s1", 2);
|
|
|
|
timedwrite(fd, "pn", 2);
|
|
|
|
timedwrite(fd, "i1", 2);
|
|
|
|
alarm(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check for a types M, M3, & W
|
|
|
|
*
|
|
|
|
* we talk to all these mice using 1200 baud
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
MorW(int ctl, int data)
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
int c;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set up for type M, V or W
|
|
|
|
* flush any pending data
|
|
|
|
*/
|
|
|
|
setupeia(ctl, "b1200", "l7");
|
|
|
|
toggleRTS(ctl);
|
|
|
|
while(slowread(data, buf, sizeof(buf), "flush: ") > 0)
|
|
|
|
;
|
|
|
|
toggleRTS(ctl);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* see if there's any data from the mouse
|
|
|
|
* (type M, V and W mice)
|
|
|
|
*/
|
|
|
|
c = slowread(data, buf, sizeof(buf), "check M: ");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* type M, V and W mice return "M" or "M3" after reset.
|
|
|
|
* check for type W by sending a 'Send Standard Configuration'
|
|
|
|
* command, "*?".
|
|
|
|
*
|
|
|
|
* the second check is a kludge for some type W mice on next's
|
|
|
|
* that send a garbage character back before the "M3".
|
|
|
|
*/
|
|
|
|
if((c > 0 && buf[0] == 'M') || (c > 1 && buf[1] == 'M')){
|
|
|
|
timedwrite(data, "*?", 2);
|
|
|
|
c = slowread(data, buf, sizeof(buf), "check W: ");
|
|
|
|
/*
|
|
|
|
* 4 bytes back
|
|
|
|
* indicates a type W mouse
|
|
|
|
*/
|
|
|
|
if(c == 4){
|
|
|
|
if(buf[1] & (1<<4))
|
|
|
|
can9600 = 1;
|
|
|
|
setupeia(ctl, "b1200", "l8");
|
|
|
|
timedwrite(data, "*U", 2);
|
|
|
|
slowread(data, buf, sizeof(buf), "check W: ");
|
|
|
|
return 'W';
|
|
|
|
}
|
|
|
|
return 'M';
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check for type C by seeing if it responds to the status
|
|
|
|
* command "s". the mouse is at an unknown speed so we
|
|
|
|
* have to check all possible speeds.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
C(int ctl, int data)
|
|
|
|
{
|
|
|
|
char **s;
|
|
|
|
int c;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
sleep(100);
|
|
|
|
for(s = speeds; *s; s++){
|
|
|
|
DEBUG print("%s\n", *s);
|
|
|
|
setupeia(ctl, *s, "l8");
|
|
|
|
timedwrite(data, "s", 1);
|
|
|
|
c = slowread(data, buf, sizeof(buf), "check C: ");
|
|
|
|
if(c >= 1 && (*buf & 0xBF) == 0x0F){
|
|
|
|
sleep(100);
|
|
|
|
timedwrite(data, "*n", 2);
|
|
|
|
sleep(100);
|
|
|
|
setupeia(ctl, "b1200", "l8");
|
|
|
|
timedwrite(data, "s", 1);
|
|
|
|
c = slowread(data, buf, sizeof(buf), "recheck C: ");
|
|
|
|
if(c >= 1 && (*buf & 0xBF) == 0x0F){
|
|
|
|
timedwrite(data, "U", 1);
|
|
|
|
return 'C';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sleep(100);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *bauderr = "mouse: can't set baud rate, mouse at 1200\n";
|
|
|
|
|
|
|
|
void
|
|
|
|
Cbaud(int ctl, int data, int baud)
|
|
|
|
{
|
|
|
|
char buf[32];
|
|
|
|
|
|
|
|
switch(baud){
|
|
|
|
case 0:
|
|
|
|
case 1200:
|
|
|
|
return;
|
|
|
|
case 2400:
|
|
|
|
buf[1] = 'o';
|
|
|
|
break;
|
|
|
|
case 4800:
|
|
|
|
buf[1] = 'p';
|
|
|
|
break;
|
|
|
|
case 9600:
|
|
|
|
buf[1] = 'q';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprint(2, bauderr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[0] = '*';
|
|
|
|
buf[2] = 0;
|
|
|
|
sleep(100);
|
|
|
|
timedwrite(data, buf, 2);
|
|
|
|
sleep(100);
|
|
|
|
timedwrite(data, buf, 2);
|
|
|
|
sprint(buf, "b%d", baud);
|
|
|
|
setupeia(ctl, buf, "l8");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Wbaud(int ctl, int data, int baud)
|
|
|
|
{
|
|
|
|
char buf[32];
|
|
|
|
|
|
|
|
switch(baud){
|
|
|
|
case 0:
|
|
|
|
case 1200:
|
|
|
|
return;
|
|
|
|
case 9600:
|
|
|
|
if(can9600)
|
|
|
|
break;
|
|
|
|
/* fall through */
|
|
|
|
default:
|
|
|
|
fprint(2, bauderr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
timedwrite(data, "*q", 2);
|
|
|
|
setupeia(ctl, "b9600", "l8");
|
|
|
|
slowread(data, buf, sizeof(buf), "setbaud: ");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
int baud;
|
|
|
|
int tries, conf, ctl, data, def, type;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
def = 0;
|
|
|
|
baud = 0;
|
|
|
|
ARGBEGIN{
|
|
|
|
case 'b':
|
|
|
|
baud = atoi(ARGF());
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
p = ARGF();
|
|
|
|
def = *p;
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
dontset = 1;
|
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
debug = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
}ARGEND
|
|
|
|
|
|
|
|
p = "0";
|
|
|
|
if(argc)
|
|
|
|
p = *argv;
|
|
|
|
|
|
|
|
if((conf = open("/dev/mousectl", OWRITE)) == -1){
|
|
|
|
fprint(2, "%s: can't open /dev/mousectl - %r\n", argv0);
|
|
|
|
if(dontset == 0)
|
|
|
|
exits("open /dev/mousectl");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(strncmp(p, "ps2", 3) == 0){
|
|
|
|
if(write(conf, p, strlen(p)) < 0){
|
|
|
|
fprint(2, "%s: error setting mouse type - %r\n", argv0);
|
|
|
|
exits("write conf");
|
|
|
|
}
|
|
|
|
exits(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
type = 0;
|
|
|
|
for(tries = 0; type == 0 && tries < 6; tries++){
|
|
|
|
if(tries)
|
|
|
|
fprint(2, "%s: Unknown mouse type, retrying...\n", argv0);
|
|
|
|
sprint(buf, "#t/eia%sctl", p);
|
|
|
|
if((ctl = open(buf, ORDWR)) == -1){
|
|
|
|
fprint(2, "%s: can't open %s - %r\n", argv0, buf);
|
|
|
|
exits("open ctl");
|
|
|
|
}
|
|
|
|
sprint(buf, "#t/eia%s", p);
|
|
|
|
if((data = open(buf, ORDWR)) == -1){
|
|
|
|
fprint(2, "%s: can't open %s - %r\n", argv0, buf);
|
|
|
|
exits("open data");
|
|
|
|
}
|
|
|
|
|
|
|
|
notify(catch);
|
|
|
|
|
|
|
|
type = MorW(ctl, data);
|
|
|
|
if(type == 0)
|
|
|
|
type = C(ctl, data);
|
|
|
|
if(type == 0){
|
|
|
|
/* with the default we can't assume anything */
|
|
|
|
baud = 0;
|
|
|
|
|
|
|
|
/* try the default */
|
|
|
|
switch(def){
|
|
|
|
case 'C':
|
|
|
|
setupeia(ctl, "b1200", "l8");
|
|
|
|
break;
|
|
|
|
case 'M':
|
|
|
|
setupeia(ctl, "b1200", "l7");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = def;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprint(buf, "serial %s", p);
|
|
|
|
switch(type){
|
|
|
|
case 0:
|
|
|
|
close(data);
|
|
|
|
close(ctl);
|
|
|
|
continue;
|
|
|
|
case 'C':
|
|
|
|
DEBUG print("Logitech 5 byte mouse\n");
|
|
|
|
Cbaud(ctl, data, baud);
|
|
|
|
break;
|
|
|
|
case 'W':
|
|
|
|
DEBUG print("Type W mouse\n");
|
|
|
|
Wbaud(ctl, data, baud);
|
|
|
|
break;
|
|
|
|
case 'M':
|
|
|
|
DEBUG print("Microsoft compatible mouse\n");
|
|
|
|
strcat(buf, " M");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(type == 0){
|
|
|
|
fprint(2, "%s: Unknown mouse type, giving up\n", argv0);
|
|
|
|
exits("no mouse");
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG fprint(2, "mouse configured as '%s'\n", buf);
|
|
|
|
if(dontset == 0 && write(conf, buf, strlen(buf)) < 0){
|
|
|
|
fprint(2, "%s: error setting mouse type - %r\n", argv0);
|
|
|
|
exits("write conf");
|
|
|
|
}
|
|
|
|
|
|
|
|
exits(0);
|
|
|
|
}
|