portable keyboard for pc kernels Reference: /n/atom/patch/applied/pckbpc Date: Tue May 6 19:43:24 CES 2014 Signed-off-by: quanstro@quanstro.net --- /sys/src/9/pc/devi82365.c Tue May 6 19:43:24 2014 +++ /sys/src/9/pc/devi82365.c Tue May 6 19:43:24 2014 @@ -242,7 +242,7 @@ * get a map for pc card region, return corrected len */ PCMmap* -pcmmap(int slotno, ulong offset, int len, int attr) +pcmmap(int slotno, u32int offset, int len, int attr) { PCMslot *pp; uchar we, bit; --- /sys/src/9/pc/fns.h Tue May 6 19:43:24 2014 +++ /sys/src/9/pc/fns.h Tue May 6 19:43:24 2014 @@ -18,6 +18,7 @@ int cpuidentify(void); void cpuidprint(void); void (*cycles)(uvlong*); +int cas(int*, int, int); void delay(int); void* dmabva(int); int dmacount(int); @@ -42,8 +43,10 @@ void halt(void); int i8042auxcmd(int); int i8042auxcmds(uchar*, int); -void i8042auxenable(void (*)(int, int)); +void i8042auxenable(void (*)(int)); void i8042reset(void); +void i8042kbdenable(void); +void i8042init(void); void i8250console(void); void* i8250alloc(int, int, int); void i8250mouse(char*, int (*)(Queue*, int), int); @@ -80,8 +83,6 @@ int iprint(char*, ...); int isaconfig(char*, int, ISAConf*); void* kaddr(uintmem); -void kbdenable(void); -void kbdinit(void); #define kmapinval() void lgdt(ushort[3]); void lidt(ushort[3]); @@ -101,7 +102,7 @@ void nvramwrite(int, uchar); void outb(int, int); void outsb(int, void*, int); -void outs(int, ushort); +void outs(int, u16int); void outss(int, void*, int); void outl(int, u32int); void outsl(int, void*, int); @@ -131,7 +132,7 @@ int pcisetpms(Pcidev*, int); void pcmcisread(PCMslot*); int pcmcistuple(int, int, int, void*, int); -PCMmap* pcmmap(int, ulong, int, int); +PCMmap* pcmmap(int, u32int, int, int); int pcmspecial(char*, ISAConf*); int (*_pcmspecial)(char *, ISAConf *); void pcmspecialclose(int); --- /sys/src/9/pc/i8042.c Thu Jan 1 00:00:00 1970 +++ /sys/src/9/pc/i8042.c Tue May 6 19:43:24 2014 @@ -0,0 +1,337 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +enum { + Data= 0x60, /* data port */ + + Status= 0x64, /* status port */ + Inready= 0x01, /* input character ready */ + Outbusy= 0x02, /* output busy */ + Sysflag= 0x04, /* system flag */ + Cmddata= 0x08, /* cmd==0, data==1 */ + Inhibit= 0x10, /* keyboard/mouse inhibited */ + Minready= 0x20, /* mouse character ready */ + Rtimeout= 0x40, /* general timeout */ + Parity= 0x80, + + Cmd= 0x64, /* command port (write only) */ + + /* controller command byte */ + Cscs1= 1<<6, /* scan code set 1 */ + Cauxdis= 1<<5, /* mouse disable */ + Ckbddis= 1<<4, /* kbd disable */ + Csf= 1<<2, /* system flag */ + Cauxint= 1<<1, /* mouse interrupt enable */ + Ckbdint= 1<<0, /* kbd interrupt enable */ +}; + +extern int mouseshifted; + +static void (*auxputc)(int); +static Lock i8042lock; +static uchar ccc; +static Kbscan *scan; + +/* + * wait for output no longer busy + */ +static int +outready(void) +{ + int tries; + + for(tries = 0; (inb(Status) & Outbusy); tries++){ + if(tries > 500) + return -1; + delay(2); + } + return 0; +} + +/* + * wait for input + */ +static int +inready(void) +{ + int tries; + + for(tries = 0; !(inb(Status) & Inready); tries++){ + if(tries > 500) + return -1; + delay(2); + } + return 0; +} + +/* + * ask 8042 to reset the machine + */ +void +i8042reset(void) +{ + ushort *s; + int i, x; + + if(conf.nokbd) + return; + + s = KADDR(0x472); + *s = 0x1234; /* BIOS warm-boot flag */ + + /* + * newer reset the machine command + */ + outready(); + outb(Cmd, 0xFE); + outready(); + + /* + * Pulse it by hand (old somewhat reliable) + */ + x = 0xDF; + for(i = 0; i < 5; i++){ + x ^= 1; + outready(); + outb(Cmd, 0xD1); + outready(); + outb(Data, x); /* toggle reset */ + delay(100); + } +} + +/* + * keyboard interrupt + */ +static void +i8042intr(Ureg*, void*) +{ + int s, c; + + /* + * get status + */ + ilock(&i8042lock); + s = inb(Status); + if(!(s&Inready)){ + iunlock(&i8042lock); + return; + } + + /* + * get the character + */ + c = inb(Data); + iunlock(&i8042lock); + + /* + * if it's the aux port... + */ + if(s & Minready){ + if(auxputc != nil) + auxputc(c); + return; + } + kbdputsc(c, scan); +} + +void +i8042auxenable(void (*putc)(int)) +{ + char *err = "i8042: aux init failed\n"; + + /* enable kbd/aux xfers and interrupts */ + ccc &= ~Cauxdis; + ccc |= Cauxint; + + ilock(&i8042lock); + if(outready() < 0) + iprint(err); + outb(Cmd, 0x60); /* write control register */ + if(outready() < 0) + iprint(err); + outb(Data, ccc); + if(outready() < 0) + iprint(err); + outb(Cmd, 0xA8); /* auxiliary device enable */ + if(outready() < 0){ + iunlock(&i8042lock); + return; + } + auxputc = putc; + intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux"); + iunlock(&i8042lock); +} + +static char *initfailed = "i8042: kbdinit failed\n"; + +static int +outbyte(int port, int c) +{ + outb(port, c); + if(outready() < 0) { + print(initfailed); + return -1; + } + return 0; +} + +int +i8042auxcmd(int cmd) +{ + uint c; + int tries; + + c = 0; + tries = 0; + + ilock(&i8042lock); + do{ + if(tries++ > 2) + break; + if(outready() < 0) + break; + outb(Cmd, 0xD4); + if(outready() < 0) + break; + outb(Data, cmd); + if(outready() < 0) + break; + if(inready() < 0) + break; + c = inb(Data); + } while(c == 0xFE || c == 0); + iunlock(&i8042lock); + + if(c != 0xFA){ + print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd); + return -1; + } + return 0; +} + +/* + * set keyboard's leds for lock states (scroll, numeric, caps). + * pc keyboards set numeric-lock behaviour to match the led state + */ +static void +setleds(int leds) +{ + if(conf.nokbd) + return; + ilock(&i8042lock); + outready(); + outb(Data, 0xed); /* talk directly to kbd, not ctlr */ + microdelay(1); + outready(); + if(inready() == 0) + inb(Data); + outb(Data, leds); + if(inready() == 0) + inb(Data); + + outready(); + iunlock(&i8042lock); +} + +static int +ledmsg(char *msg) +{ + int leds, c; + + leds = 0; + while(c = *msg++){ + switch(c){ + case 's': + leds |= 1<<0; + break; + case 'n': + leds |= 1<<1; + break; + case 'c': + leds |= 1<<2; + break; + } + } + return leds; +} + +static void +i8042msg(char *msg) +{ + switch(*msg){ + case 'L': + setleds(ledmsg(msg+1)); + break; + } +} + +void +failkbd(void) +{ + conf.nokbd = 1; + iofree(Data); + iofree(Cmd); + print(initfailed); +} + +void +i8042init(void) +{ + int c, try; + + if(conf.nokbd) + return; + + ioalloc(Data, 1, 0, "kbd data"); + ioalloc(Cmd, 1, 0, "kbd cmd"); + + /* wait for a quiescent controller */ + try = 1000; + while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) { + if(c & Inready) + inb(Data); + delay(1); + } + if (try <= 0) { + failkbd(); + return; + } + + /* get current controller command byte */ + outb(Cmd, 0x20); + if(inready() < 0){ + print("i8042: kbdinit can't read ccc\n"); + ccc = 0; + } else + ccc = inb(Data); + + /* enable kbd xfers and interrupts */ + ccc &= ~Ckbddis; + ccc |= Csf | Ckbdint | Cscs1; + if(outready() < 0) { + failkbd(); + return; + } + + /* disable mouse */ + if (outbyte(Cmd, 0x60) < 0 || outbyte(Data, ccc) < 0) + print("i8042: kbdinit mouse disable failed\n"); + + /* set typematic rate/delay (0 -> delay=250ms & rate=30cps) */ + if(outbyte(Cmd, 0xf3) < 0 || outbyte(Data, 0) < 0) + print("i8042: kbdinit set typematic rate failed\n"); +} + +void +i8042kbdenable(void) +{ + if(!conf.nokbd){ + intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "i8042"); + scan = kbdnewscan(i8042msg); + } +} --- /sys/src/9/pc/lsi.h Thu Jan 1 00:00:00 1970 +++ /sys/src/9/pc/lsi.h Tue May 6 19:43:24 2014 @@ -0,0 +1,52 @@ +enum{ + /* registers */ + Doorbell = 0x00/4, + Wseq = 0x04/4, /* write sequence */ + Hdiag = 0x08/4, /* host diagnostic */ + Testba = 0x0c/4, /* test base address */ + Diagd = 0x10/4, /* diagnostic data */ + Diaga = 0x14/4, /* diagnostic address */ + Int = 0x30/4, /* interrupt status */ + Intmask = 0x34/4, /* interrupt mask */ + Tqueue = 0x40/4, /* requerst queue */ + Rqueue = 0x44/4, /* reply queue */ + Hqueue = 0x48/4, /* high priority queue */ + + /* Doorbell read */ + Dbusy = 1<<27, /* doorbell busy */ + Dfmask = 0xffff, /* fault mask */ + + /* Doorbell write; values only in header not in docs */ + Mur = 0x40, /* message unit reset */ + Iur = 0x41, /* io unit reset */ + Gladhand = 0x42, /* handshake */ + Rfr = 0x43, /* reply frame removal */ + Hpac = 0x44, /* host page access ctl */ + + /* handshake subtypes p 2-11 */ + Hconf = 0x04, /* configuration */ + Hevent = 0x07, /* event notification */ + Hfwd = 0x09, /* firmware download */ + Hfwu = 0x12, /* firmware upload */ + Hiocfacts = 0x03, /* get controller configuration */ + Hiocinit = 0x02, /* controller init */ + Hportenable = 0x06, /* port enable */ + Hportfacts = 0x05, /* get port configuration */ + + /* Hdiag */ + Cfbs = 1<<10, /* clear flash bad sig */ + Drwe = 1<<9, /* write enabled */ + Flashbad = 1<<6, /* flash bad signature */ + Reseth = 1<<5, /* reset by any function */ + Diagenable = 1<<4, /* enable diag registers */ + Reset = 1<<2, /* reset adapter */ + Disable = 1<<1, /* hold in reset state */ + Dmeme = 1<<0, /* enable diag bar[1] */ + + /* Int */ + Ids = 1<<31, /* ioc rx doorbell “host” */ + Ireply = 1<<3, /* reply in reply fifo */ + Idr = 1<<0, /* ioc set doorbell */ +}; + +static uchar wseqmagic[] = { 0xff, 0x4, 0xb, 0x2, 0x7, 0xd, }; --- /sys/src/9/pc/main.c Tue May 6 19:43:24 2014 +++ /sys/src/9/pc/main.c Tue May 6 19:43:24 2014 @@ -94,7 +94,7 @@ trapinit0(); mmuinit0(); - kbdinit(); + i8042init(); i8253init(); cpuidentify(); meminit(); @@ -111,7 +111,7 @@ arch->intrinit(); timersinit(); mathinit(); - kbdenable(); + i8042kbdenable(); if(arch->clockenable) arch->clockenable(); procinit0(); --- /sys/src/9/pc/mdbg.c Thu Jan 1 00:00:00 1970 +++ /sys/src/9/pc/mdbg.c Tue May 6 19:43:24 2014 @@ -0,0 +1,103 @@ +/* + * the counters in MCP memory are pointed to by mcp_gen_header.counters_addr + * the structure has the following layout: + * ulong ncnt; // each MCP can have a different subset counters + * ulong cnt[n]; // the counters value + * ushort id[n]; // identification of each counter in the array, + * // using counter id values from the list below + */ + +enum{ + Zint, + Zhex, +}; + +typedef struct Zcnt Zcnt; +struct Zcnt { + char *name; + int id; + int type; +}; + +Zcnt ztab[] = { + "p0_rx_bad_crc8", 1, Zint, + "p0_rx_good_crc8", 2, Zint, + "pcie_pad_overflow", 3, Zint, + "pcie_bad_tlp", 4, Zint, + "pcie_send_timeout", 5, Zint, + "pcie_send_nacked", 6, Zint, + "pcie_link_error", 7, Zint, + "eeprom_id", 8, Zhex, + "msix_irq_masked", 9, Zint, + "pcie_tx_stopped", 10, Zint, + "ext_pio_read", 11, Zint, + "partial_ext_write", 12, Zint, + "ltssm_lane_resync", 13, Zint, + "ltssm_misc", 14, Zhex, + "ltssm_rxdetect", 15, Zhex, + "pcie_fc_no_dllp", 16, Zhex, + "pcie_sw_naks", 17, Zint, + "pcie_sw_naks_dpend", 18, Zint, + "pcie_sw_naks_gotdata", 19, Zint, + "pcie_pretimeout0", 20, Zint, + "pcie_pretimeout1", 21, Zint, + "p0_unaligned", 22, Zint, + "pcie_not_in_l0", 23, Zint, + "pcie_lane_invalid", 24, Zint, + "pcie_tlp_dup", 25, Zint, + "pcie_tlp_dup_pad", 26, Zint, + "mean_gate_delay", 27, Zint, + "mean_gate_delay_low", 28, Zint, + "mean_gate_delay_high", 29, Zint, + "pcie_invalid_be", 30, Zint, +}; + +static void +readcntr(Ctlr *c) +{ + char *name; + int i, n, l, cntid, type; + uchar *p, *id; + ulong off; + Fwhdr h; + + off = gbit32(c->ram + Hdroff); + print("header %p\n", off); + if(off == 0 || off&3 || off + sizeof h >= c->ramsz){ + print("bad header off %p\n", off); + return; + } + memmove(&h, c->ram + off, sizeof h); + l = gbit32(h.len); + print("hlen %d\n", l); + if(l < 152 || l > 256) { + print("bad hlen %d\n", l); + return; + } + + off = gbit32(h.cntaddr); + print("cntaddr %p\n", off); + if(off == 0 || off&3 || off + sizeof h >= c->ramsz){ + print("bad cntaddr off %p\n", off); + return; + } + n = gbit32(p = c->ram + gbit32(h.cntaddr)); + print("ncnt %d\n", n); + p += 4; + if(n > 100) + print("bad n %d\n", n); + id = p + 4*n; + for(i = 0; i < n; i++) { + cntid = gbit16(id + 2*i) - 1; + name = "unknown"; + type = Zint; + if(cntid < nelem(ztab)){ + name = ztab[cntid].name; + type = ztab[cntid].type; + } + if(type == Zhex) + print("%s\t%ux\n", name, gbit32(p + 4*i)); + else + print("%s\t%ud\n", name, gbit32(p + 4*i)); + } +} --- /sys/src/9/pc/mkfile Tue May 6 19:43:24 2014 +++ /sys/src/9/pc/mkfile Tue May 6 19:43:24 2014 @@ -1,7 +1,7 @@ CONF=pccpu CONFLIST=pc pccpu # unloved: pcauth pccpuf -CRAPLIST=pccd pcflop pcdist pcdisk pcusb pcf pccpuf pccpud +CRAPLIST=pccd pcflop pcdist pcdisk pcf pccpuf pccpud objtype=386