M pc/mouse.c => pc/mouse.c +90 -33
@@ 101,6 101,80 @@ ps2mouse(void)
mousetype = MousePS2;
}
+static int intellimouse;
+static int resolution;
+static int accelerated;
+
+static void
+setaccelerated(int x)
+{
+ accelerated = x;
+ switch(mousetype){
+ case MousePS2:
+ i8042auxcmd(0xE7);
+ break;
+ default:
+ mouseaccelerate(x);
+ break;
+ }
+}
+
+static void
+setlinear(void)
+{
+ accelerated = 0;
+ switch(mousetype){
+ case MousePS2:
+ i8042auxcmd(0xE6);
+ break;
+ default:
+ mouseaccelerate(0);
+ break;
+ }
+}
+
+static void
+setres(int n)
+{
+ resolution = n;
+ switch(mousetype){
+ case MousePS2:
+ i8042auxcmd(0xE8);
+ i8042auxcmd(n);
+ break;
+ }
+}
+
+static void
+setintellimouse(void)
+{
+ intellimouse = 1;
+ switch(mousetype){
+ case MousePS2:
+ i8042auxcmd(0xF3); /* set sample */
+ i8042auxcmd(0xC8);
+ i8042auxcmd(0xF3); /* set sample */
+ i8042auxcmd(0x64);
+ i8042auxcmd(0xF3); /* set sample */
+ i8042auxcmd(0x50);
+ break;
+ }
+}
+
+static void
+resetmouse(void)
+{
+ switch(mousetype){
+ case MousePS2:
+ i8042auxcmd(0xF6);
+ i8042auxcmd(0xEA); /* streaming */
+ i8042auxcmd(0xE8); /* set resolution */
+ i8042auxcmd(3);
+ i8042auxcmd(0xF4); /* enabled */
+ break;
+ }
+}
+
void
mousectl(char* field[], int n)
{
@@ 119,44 193,27 @@ mousectl(char* field[], int n)
}
} else if(strcmp(field[0], "ps2") == 0){
ps2mouse();
+ } else if(strcmp(field[0], "ps2intellimouse") == 0){
+ ps2mouse();
+ setintellimouse();
} else if(strcmp(field[0], "accelerated") == 0){
- switch(mousetype){
- case MousePS2:
- i8042auxcmd(0xE7);
- break;
- default:
- if(n == 1)
- mouseaccelerate("1");
- else
- mouseaccelerate(field[1]);
- break;
- }
+ setaccelerated(n == 1 ? 1 : atoi(field[1]));
} else if(strcmp(field[0], "linear") == 0){
- switch(mousetype){
- case MousePS2:
- i8042auxcmd(0xE6);
- break;
- default:
- mouseaccelerate("0");
- break;
- }
+ setlinear();
} else if(strcmp(field[0], "res") == 0){
- if(n < 2)
- n = 1;
- else
+ if(n >= 2)
n = atoi(field[1]);
- switch(mousetype){
- case MousePS2:
- i8042auxcmd(0xE8);
- i8042auxcmd(n);
- break;
- }
+ setres(n);
} else if(strcmp(field[0], "reset") == 0){
- i8042auxcmd(0xF6);
- i8042auxcmd(0xEA); /* streaming */
- i8042auxcmd(0xE8); /* set resolution */
- i8042auxcmd(3);
- i8042auxcmd(0xF4); /* enabled */
+ resetmouse();
+ if(accelerated)
+ setaccelerated(accelerated);
+ if(resolution)
+ setres(resolution);
+ if(intellimouse)
+ setintellimouse();
+ } else if(strcmp(field[0], "intellimouse") == 0){
+ setintellimouse();
}
else
error(Ebadctl);
M pc/screen.h => pc/screen.h +1 -1
@@ 9,7 9,7 @@ struct Cursorinfo {
extern void mousetrack(int, int, int);
extern Point mousexy(void);
-extern void mouseaccelerate(char*);
+extern void mouseaccelerate(int);
extern int m3mouseputc(void*, int);
extern int mouseputc(void*, int);
M port/devmouse.c => port/devmouse.c +2 -4
@@ 535,11 535,9 @@ mousexy(void)
}
void
-mouseaccelerate(char *x)
+mouseaccelerate(int x)
{
- if(x == 0)
- x = "1";
- mouse.acceleration = atoi(x);
+ mouse.acceleration = x;
if(mouse.acceleration < 3)
mouse.maxacc = 2;
else
M port/tod.c => port/tod.c +106 -11
@@ 5,22 5,99 @@
#include "fns.h"
#include "../port/error.h"
+// compute nanosecond epoch time from the fastest ticking clock
+// on the system. converting the time to nanoseconds requires
+// the following formula
+//
+// t = (((1000000000<<s1)/f)*(ticks>>s2))>>(s1-s2)
+//
+// where
+//
+// 'f' is the clock frequency
+// 'ticks' are clock ticks
+// 's1' and 's2' are shift ammounts to avoid 64 bit
+// overflows in the calculations
+//
+// to avoid too much calculation in gettod(), we calculate
+//
+// mult = (1000000000<<s1)/f
+//
+// each time f is set. f is normally set by a user level
+// program writing to /dev/fastclock.
+//
+// To calculate s1 and s2, we have to avoid overflowing our
+// signed 64 bit calculations. Also we wish to accomodate
+// 15 minutes of ticks. This gives us the following
+// constraints:
+//
+// 1) log2(1000000000<<s1) <= 63
+// or s1 <= 33
+// 2) accomodate 15 minutes of ticks without overflow
+// or log2(((1000000000<<s1)/f)*((15*60*f)>>s2)) <= 63
+// or log2(mult) + 12 + log2(f) - s2 <= 63
+// or log2(mult) + log2(f) - 51 <= s2
+//
+// by definition
+//
+// 3) log2(mult) = log2(1000000000) + s1 - log2(f)
+// or log2(mult) = 30 + s1 - log2(f)
+//
+// To balance the accuracy of the multiplier and the sampled
+// ticks we set
+//
+// 4) log2(mult) = log2(f>>s2)
+// or log2(mult) = log2(f) - s2
+//
+// Combining 2) and 4) we get
+//
+// 5) log2(f) - s2 + log2(f) - 51 <= s2
+// or 2*log2(f) - 51 <= 2*s2
+// or log2(f) - 25 <= s2
+//
+// Combining 3) and 4)
+//
+// 6) 30 + s1 - log2(f) = log2(f) - s2
+// or s1 = 2*log2(f) - s2 - 30
+//
+// Since shifting ticks left doesn't increase accuracy, and
+// shifting 1000000000 right loses accuracy
+//
+// 7) s2 >= 0
+// 8) s1 >= 0
+//
+// As an example, that gives us the following
+//
+// for f = 100, log2(f) = 7
+//
+// s2 = 0
+// s1 = 0
+//
+// for f = 267000000, log2(f) = 28
+//
+// s2 = 3
+// s1 = 23
+//
+// for f = 2000000000, log2(f) = 31
+//
+// s2 = 6
+// s1 = 26
+//
+// for f = 8000000000, log2(f) = 33
+//
+// s2 = 8
+// s1 = 28
// frequency of the tod clock
#define TODFREQ 1000000000LL
-enum
-{
- Log2mult= 22, // multiplier should have 22 bits
- Log2todfreq= 30, // number of significant bits of TODFREQ
-};
-
static vlong logtab[40];
struct {
Lock;
- int shift; // time = (ticks*multiplier)>>shift
+ int s1; // time = ((ticks>>s2)*multiplier)>>(s1-s2)
vlong multiplier; // ...
+ int s2; // ...
+ vlong maxdiff; // max diff between ticks and last to avoid overflow
vlong hz; // frequency of fast clock
vlong last; // last reading of fast clock
vlong off; // offset from epoch to last
@@ 65,12 142,24 @@ todinit(void)
void
todsetfreq(vlong f)
{
+ int lf;
+
// this ensures that the multiplier has 22 bits
ilock(&tod);
tod.hz = f;
- tod.shift = Log2mult - Log2todfreq + log2(f);
- tod.multiplier = (TODFREQ<<tod.shift)/f;
+ lf = log2(f);
+ tod.s2 = lf - 25;
+ if(tod.s2 < 0)
+ tod.s2 = 0;
+ tod.s1 = 2*lf - tod.s2 - 30;
+ if(tod.s1 < 0)
+ tod.s1 = 0;
+ if(tod.s1 > 33)
+ tod.s1 = 33;
+ tod.multiplier = (TODFREQ<<tod.s1)/f;
+ tod.maxdiff = 1LL<<(10 + lf);
iunlock(&tod);
+//print("hz %lld mult %lld s1 %d s2 %d maxdiff %lld\n", tod.hz, tod.multiplier, tod.s1, tod.s2, tod.maxdiff);
}
//
@@ 109,11 198,11 @@ todget(void)
diff = ticks - tod.last;
// convert to epoch
- x = (diff*tod.multiplier)>>tod.shift;
+ x = ((diff>>tod.s2)*tod.multiplier)>>(tod.s1-tod.s2);
x += tod.off;
// protect against overflows
- if(diff > (1LL<<(63-Log2mult))){
+ if(diff > tod.maxdiff){
tod.last = ticks;
tod.off = x;
}
@@ 135,10 224,16 @@ todfix(void)
{
if((MACHP(0)->ticks % HZ) != 0)
return;
+
+ // once a second apply correction
ilock(&tod);
if(tod.n > tod.i++)
tod.off += tod.delta;
iunlock(&tod);
+
+ // once a minute, make sure we don't overflow
+ if((MACHP(0)->ticks % (60*HZ)) == 0)
+ todget();
}
long