From bba78dfc3957ae3c01fa0a34f4f14ac03e80b861 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 12 Nov 2002 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2002-11-12 --- bitsy/clock.c | 82 ++- bitsy/dat.h | 19 +- bitsy/devether.c | 10 +- bitsy/devpcmcia.c | 99 +++- bitsy/devpenmouse.c | 1 + bitsy/devuda1341.c | 4 +- "bitsy/dev\302\265c.c" | 26 +- bitsy/etherwavelan.c | 14 +- bitsy/fns.h | 5 +- bitsy/io.h | 11 + bitsy/main.c | 18 +- bitsy/power.c | 72 ++- bitsy/sd.h | 125 ----- bitsy/sdata.c | 54 +- bitsy/uartsa1110.c | 6 +- bitsy/wavelan.c | 1151 +++++++++++++++++++++++++++++++++++++++- bitsy/wavelan.h | 3 - ip/ipifc.c | 2 +- 18 files changed, 1510 insertions(+), 192 deletions(-) delete mode 100644 bitsy/sd.h diff --git a/bitsy/clock.c b/bitsy/clock.c index 54ef093e2e5423b14d13ced6e9edeef9391ee52d..760a2f594d41f555b2134572563bc89cb3cbfcf7 100644 --- a/bitsy/clock.c +++ b/bitsy/clock.c @@ -7,6 +7,17 @@ #include "ureg.h" #include "../port/error.h" + +enum { + RTCREGS = 0x90010000, /* real time clock registers */ + RTSR_al = 0x01, /* alarm detected */ + RTSR_hz = 0x02, /* 1Hz tick */ + RTSR_ale= 0x04, /* alarm interrupt enable */ + RTSR_hze= 0x08, /* 1Hz tick enable */ + + Never = 0xffffffff, +}; + typedef struct OSTimer { ulong osmr[4]; /* match registers */ @@ -16,10 +27,21 @@ typedef struct OSTimer ulong oier; /* timer interrupt enable register */ } OSTimer; +typedef struct RTCregs +{ + ulong rtar; /* alarm */ + ulong rcnr; /* count */ + ulong rttr; /* trim */ + ulong dummy; /* hole */ + ulong rtsr; /* status */ +} RTCregs; + OSTimer *timerregs = (OSTimer*)OSTIMERREGS; +RTCregs *rtcregs = (RTCregs*)RTCREGS; static int clockinited; -static void clockintr(Ureg*, void*); +static void clockintr(Ureg*, void*); +static void rtcintr(Ureg*, void*); static uvlong when; /* scheduled time of next interrupt */ long timeradjust; @@ -30,16 +52,28 @@ enum Maxfreq = ClockFreq/10000, /* At most one interrupt every 100 µs */ }; -void +ulong clockpower(int on) { + static ulong savedtime; if (on){ timerregs->ossr |= 1<<0; timerregs->oier = 1<<0; timerregs->osmr[0] = timerregs->oscr + Minfreq; - } + if (rtcregs->rttr == 0){ + rtcregs->rttr = 0x8000; // nominal frequency. + rtcregs->rcnr = 0; + rtcregs->rtar = 0xffffffff; + rtcregs->rtsr |= RTSR_ale; + rtcregs->rtsr |= RTSR_hze; + } + if (rtcregs->rcnr > savedtime) + return rtcregs->rcnr - savedtime; + } else + savedtime = rtcregs->rcnr; clockinited = on; + return 0L; } void @@ -49,7 +83,8 @@ clockinit(void) ulong id; /* map the clock registers */ - timerregs = mapspecial(OSTIMERREGS, 32); + timerregs = mapspecial(OSTIMERREGS, sizeof(OSTimer)); + rtcregs = mapspecial(RTCREGS, sizeof(RTCregs)); /* enable interrupts on match register 0, turn off all others */ timerregs->ossr |= 1<<0; @@ -71,6 +106,13 @@ clockinit(void) when = timerregs->oscr + Minfreq; timerregs->osmr[0] = when; + /* enable RTC interrupts and alarms */ + intrenable(IRQ, IRQrtc, rtcintr, nil, "rtc"); + rtcregs->rttr = 0x8000; // make rcnr 1Hz + rtcregs->rcnr = 0; // reset counter + rtcregs->rtsr |= RTSR_al; + rtcregs->rtsr |= RTSR_ale; + timersinit(); clockinited = 1; @@ -124,6 +166,38 @@ clockintr(Ureg *ureg, void*) timerintr(ureg, when); } +void +rtcalarm(ulong secs) +{ + vlong t; + + if (t == 0){ + iprint("RTC alarm cancelled\n"); + rtcregs->rtsr &= ~RTSR_ale; + rtcregs->rtar = 0xffffffff; + } else { + t = todget(nil); + t = t / 1000000000ULL; // nsec to secs + if (secs < t) + return; + secs -= t; + iprint("RTC alarm set to %uld seconds from now\n", secs); + rtcregs->rtar = rtcregs->rcnr + secs; + rtcregs->rtsr|= RTSR_ale; + } +} + +static void +rtcintr(Ureg*, void*) +{ + /* reset interrupt */ + rtcregs->rtsr&= ~RTSR_ale; + rtcregs->rtsr&= ~RTSR_al; + + rtcregs->rtar = 0; + iprint("RTC alarm: %lud\n", rtcregs->rcnr); +} + void delay(int ms) { diff --git a/bitsy/dat.h b/bitsy/dat.h index ba77b0659f843d7278345b236049c172595f1c2f..631b9c851fb0bc84aba3cef40c797d629b4e56bb 100644 --- a/bitsy/dat.h +++ b/bitsy/dat.h @@ -236,6 +236,7 @@ struct PCMslot /* status */ uchar occupied; /* card in the slot */ uchar configed; /* card configured */ + uchar inserted; /* card just inserted */ Dev *dev; /* set in ctlwrite `configure' */ @@ -256,13 +257,19 @@ struct PCMslot /* * hardware info about a device */ +typedef struct { + ulong port; + int size; +} port_t; + struct DevConf { RWlock; /* write: configure/unconfigure/suspend; read: normal access */ - ulong mem; /* mapped memory address */ - ulong port; /* mapped i/o regs */ - int size; /* access size */ - int itype; /* type of interrupt */ - ulong irq; /* interrupt number */ - char *type; /* card type, mallocated */ + ulong mem; /* mapped memory address */ + port_t *ports; /* ports[0]: mapped i/o regs, access size */ + int nports; /* always 1 for the bitsy */ + int itype; /* type of interrupt */ + ulong intnum; /* interrupt number */ + char *type; /* card type, mallocated */ }; + diff --git a/bitsy/devether.c b/bitsy/devether.c index e33a1a3ba2d2587341c3010507559fdd5fca5c8c..1e43c16125770885641ab5c43e1afc11bf737d60 100644 --- a/bitsy/devether.c +++ b/bitsy/devether.c @@ -82,7 +82,7 @@ etherconfig(int on, char *spec, DevConf *cf) ether = malloc(sizeof(Ether)); if(ether == nil) panic("etherconfig"); - *(DevConf*)ether = *cf; + ether->DevConf = *cf; for(n = 0; cards[n].type; n++){ if(strcmp(cards[n].type, ether->type) != 0) @@ -110,16 +110,16 @@ etherconfig(int on, char *spec, DevConf *cf) ether->maxmtu = ETHERMAXTU; if(ether->interrupt != nil) - intrenable(cf->itype, cf->irq, ether->interrupt, ether, name); + intrenable(cf->itype, cf->intnum, ether->interrupt, ether, name); p = buf; e = buf+sizeof(buf); p = seprint(p, e, "#l%d: %s: %dMbps port 0x%luX", - ctlrno, ether->type, ether->mbps, ether->port); + ctlrno, ether->type, ether->mbps, ether->ports[0].port); if(ether->mem) p = seprint(p, e, " addr 0x%luX", PADDR(ether->mem)); - if(ether->size) - p = seprint(p, e, " size 0x%X", ether->size); + if(ether->ports[0].size) + p = seprint(p, e, " size 0x%X", ether->ports[0].size); p = seprint(p, e, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX", ether->ea[0], ether->ea[1], ether->ea[2], ether->ea[3], ether->ea[4], ether->ea[5]); diff --git a/bitsy/devpcmcia.c b/bitsy/devpcmcia.c index 7d7dd5140767b58d4a772e1fe7c82b1c2032e059..fd31ff2e9fd7d8d65232b076565ed5b10c7c04da 100644 --- a/bitsy/devpcmcia.c +++ b/bitsy/devpcmcia.c @@ -6,11 +6,20 @@ #include "../port/error.h" #include "io.h" +/* + * BUG: insertion events are detected by polling. + * Should look into the compaq docs to see if + * there's an interrupt for card insertion + * there's probably one. + */ + static PCMslot slot[2]; int nslot = 2; struct { Ref; + Rendez event; // where to wait for card events + int evreader; // there's a reader for events } pcmcia; enum @@ -19,6 +28,7 @@ enum Qmem, Qattr, Qctl, + Qevs, Nents = 3, }; @@ -66,8 +76,14 @@ pcmgen(Chan *c, char *, Dirtab * , int, int i, Dir *dp) return 1; } - if(i >= Nents*nslot) + if(i >= Nents*nslot + 1) return -1; + if(i == Nents*nslot){ + len = 0; + qid.path = PATH(0, Qevs); + snprint(up->genbuf, sizeof up->genbuf, "pcmevs"); + goto found; + } slotno = i/Nents; sp = slot + slotno; @@ -88,6 +104,7 @@ pcmgen(Chan *c, char *, Dirtab * , int, int i, Dir *dp) snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno); break; } +found: qid.vers = 0; qid.type = QTFILE; devdir(c, qid, up->genbuf, len, eve, 0660, dp); @@ -242,6 +259,48 @@ pcmctlread(void *a, long n, ulong off, PCMslot *sp) return n; } +static int +inserted(void *) +{ + if (slot[0].inserted) + return 1; + if (slot[1].inserted) + return 2; + return 0; +} + +static long +pcmevsread(void *a, long n, ulong off) +{ + int i; + char *buf = nil; + char *e; + + if (pcmcia.evreader) + error("At most one reader"); + off = 0; + pcmcia.evreader++; + if (waserror()){ + free(buf); + pcmcia.evreader--; + nexterror(); + } + while((i = inserted(nil)) == 0){ + slotinfo(nil, nil); + tsleep(&pcmcia.event, inserted, nil, 500); + } + pcmcia.evreader--; + slot[i-1].inserted = 0; + buf = malloc(READSTR); + e = buf + READSTR; + buf[0] = 0; + seprint(buf, e, "#y/pcm%dctl\n", i-1); + n = readstr(off, a, n, buf); + free(buf); + poperror(); + return n; +} + static long pcmciaread(Chan *c, void *a, long n, vlong off) { @@ -261,6 +320,8 @@ pcmciaread(Chan *c, void *a, long n, vlong off) if(!sp->occupied) error(Eio); return pcmread(a, n, offset, sp, sp->attr, OneMeg); + case Qevs: + return pcmevsread(a, n, offset); case Qctl: return pcmctlread(a, n, offset, sp); } @@ -294,6 +355,7 @@ pcmctlwrite(char *p, long n, ulong, PCMslot *sp) int index, i, dtx; Rune r; DevConf cf; + port_t port; cmd = parsecmd(p, n); if(strcmp(cmd->f[0], "configure") == 0){ @@ -336,9 +398,12 @@ pcmctlwrite(char *p, long n, ulong, PCMslot *sp) memset(&cf, 0, sizeof cf); kstrdup(&cf.type, cmd->f[2]); cf.mem = (ulong)sp->mem; - cf.port = (ulong)sp->regs; + cf.ports = &port; + cf.ports[0].port = (ulong)sp->regs; + cf.ports[0].size = 0; + cf.nports = 1; cf.itype = GPIOfalling; - cf.irq = bitno(sp == slot ? GPIO_CARD_IRQ0_i : GPIO_CARD_IRQ1_i); + cf.intnum = bitno(sp == slot ? GPIO_CARD_IRQ0_i : GPIO_CARD_IRQ1_i); if(devtab[dtx]->config(1, p, &cf) < 0) error("couldn't configure device"); sp->dev = devtab[dtx]; @@ -388,6 +453,8 @@ pcmciawrite(Chan *c, void *a, long n, vlong off) if(!sp->occupied) error(Eio); return pcmwrite(a, n, offset, sp, sp->attr, OneMeg); + case Qevs: + break; case Qctl: if(!sp->occupied) error(Eio); @@ -477,25 +544,31 @@ slotinfo(Ureg*, void*) if(x & GPIO_OPT_IND_i){ /* no expansion pack */ - slot[0].occupied = 0; - slot[1].occupied = 0; + slot[0].occupied = slot[0].inserted = 0; + slot[1].occupied = slot[1].inserted = 0; } else { if(x & GPIO_CARD_IND0_i){ - slot[0].occupied = 0; + slot[0].occupied = slot[0].inserted = 0; slot[0].cisread = 0; } else { - if(slot[0].occupied == 0) + if(slot[0].occupied == 0){ + slot[0].inserted = 1; slot[0].cisread = 0; + } slot[0].occupied = 1; } if(x & GPIO_CARD_IND1_i){ - slot[1].occupied = 0; + slot[1].occupied = slot[1].inserted = 0; slot[1].cisread = 0; } else { - if(slot[1].occupied == 0) + if(slot[1].occupied == 0){ + slot[1].inserted = 1; slot[1].cisread = 0; + } slot[1].occupied = 1; } + if (inserted(nil)) + wakeup(&pcmcia.event); } } @@ -629,3 +702,11 @@ slottiming(int slotno, int tio, int tattr, int tmem, int fast) } memconfregs->mecr = x; } + +/* For compat with ../pc devices. Don't use it for the bitsy + */ +int +pcmspecial(char*, ISAConf*) +{ + return -1; +} diff --git a/bitsy/devpenmouse.c b/bitsy/devpenmouse.c index 54f903203b8aaaf3158b9ce1e295d92fad730bb3..051892d85d5b544180b9c8cd0807bbf2361aeff6 100644 --- a/bitsy/devpenmouse.c +++ b/bitsy/devpenmouse.c @@ -474,6 +474,7 @@ penmousetrack(int b, int x, int y) } wakeup(&mouse.r); drawactive(1); + resetsuspendtimer(); } int diff --git a/bitsy/devuda1341.c b/bitsy/devuda1341.c index 3b071eea05141cb4b84cbc97a7622667cc7b2636..31bfb7190aea3ac044742bbf8ebce5de7333f619 100644 --- a/bitsy/devuda1341.c +++ b/bitsy/devuda1341.c @@ -482,10 +482,10 @@ static void audioinit(void) { /* Turn MCP operations off */ - mcpregs = mapspecial(MCPREGS, 0x34); + mcpregs = mapspecial(MCPREGS, sizeof(MCPregs)); mcpregs->status &= ~(1<<16); - sspregs = mapspecial(SSPREGS, 32); + sspregs = mapspecial(SSPREGS, sizeof(SSPregs)); } diff --git "a/bitsy/dev\302\265c.c" "b/bitsy/dev\302\265c.c" index d6fa239b0597c9daefe6bd07338a065edb4cbb13..889ddd7275accc7b702119dc7846203504ea404d 100644 --- "a/bitsy/dev\302\265c.c" +++ "b/bitsy/dev\302\265c.c" @@ -51,12 +51,12 @@ enum { Dirtab µcdir[]={ ".", { Qdir, 0, QTDIR }, 0, DMDIR|0755, - "backlight", { Qbacklight, 0 }, 0, 0664, + "backlight", { Qbacklight, 0 }, 0, 0664, "battery", { Qbattery, 0 }, 0, 0664, "buttons", { Qbuttons, 0 }, 0, 0664, "cruft", { Qcruft, 0 }, 0, 0664, "kbdin", { Qkbdin, 0 }, 0, 0664, - "led", { Qled, 0 }, 0, 0664, + "led", { Qled, 0 }, 0, 0664, "version", { Qversion, 0 }, 0, 0664, "power", { Qpower, 0 }, 0, 0600, }; @@ -345,6 +345,8 @@ static long #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4) +static uchar lightdata[16]; + static long µcwrite(Chan* c, void* a, long n, vlong) { @@ -352,6 +354,7 @@ static long uchar data[16]; char str[64]; int i, j; + ulong l; Rune r; extern ulong resumeaddr[]; extern void power_resume(void); @@ -374,7 +377,14 @@ static long *resumeaddr = (ulong)power_resume; else if(strncmp(a, "halt", 4) == 0) *resumeaddr = 0; - else + else if(strncmp(a, "wakeup", 6) == 0){ + cmd = parsecmd(a, n); + if (cmd->nf != 2) + error(Ebadarg); + l = strtoul(cmd->f[1], 0, 0); + rtcalarm(l); + return n; + } else error(Ebadarg); deepsleep(); return n; @@ -391,6 +401,7 @@ static long sendmsgwithack(BLled, data, cmd->nf); break; case Qbacklight: + memmove(lightdata, data, 16); sendmsgwithack(BLbacklight, data, cmd->nf); break; case Qcruft: @@ -409,9 +420,12 @@ void if (on == 0) return; /* maybe dangerous, not holding the lock */ - data[0]= 2; - data[1]= 1; - data[2]= 0x80; + if (lightdata[0] == 0){ + data[0]= 2; + data[1]= 1; + data[2]= 0; + } else + memmove(data, lightdata, 16); _sendmsg(0xd, data, 3); wakeup(&ctlr.r); } diff --git a/bitsy/etherwavelan.c b/bitsy/etherwavelan.c index 872e766623a9480206744bda2fd2253d4a38476d..47cae4557594407a1b3c2a5a29d6c27349243aea 100644 --- a/bitsy/etherwavelan.c +++ b/bitsy/etherwavelan.c @@ -9,7 +9,7 @@ #include "../port/error.h" #include "../port/netif.h" #include "etherif.h" -#include "wavelan.h" +#include "../pc/wavelan.h" static int wavelanpcmciareset(Ether *ether) @@ -22,9 +22,15 @@ wavelanpcmciareset(Ether *ether) ilock(ctlr); ctlr->ctlrno = ether->ctlrno; - if (ether->port==0) - ether->port=WDfltIOB; - ctlr->iob = ether->port; + if (ether->ports == nil){ + ether->ports = malloc(sizeof(port_t)); + ether->ports[0].port = 0; + ether->ports[0].size = 0; + ether->nports= 1; + } + if (ether->ports[0].port==0) + ether->ports[0].port=WDfltIOB; + ctlr->iob = ether->ports[0].port; if(wavelanreset(ether, ctlr) < 0){ iunlock(ctlr); diff --git a/bitsy/fns.h b/bitsy/fns.h index c4220994d4e6316ed58ea0e60e8f3a03c646b997..666d2bdec7b43b98da0bf0d4727611321520948f 100644 --- a/bitsy/fns.h +++ b/bitsy/fns.h @@ -1,6 +1,5 @@ #include "../port/portfns.h" -void addclock0link(void (*)(void)); void audiopower(int); void audioamppower(int); void audioicpower(int); @@ -14,7 +13,7 @@ void dcacheinvalidate(void); int cistrcmp(char*, char*); int cistrncmp(char*, char*, int); void clockinit(void); -void clockpower(int); +ulong clockpower(int); #define coherence() #define dcflush(a, b) void delay(int); @@ -93,7 +92,9 @@ void putdac(ulong); void putttb(ulong); void putpid(ulong); void qpanic(char *, ...); +void resetsuspendtimer(void); void rs232power(int); +void rtcalarm(ulong); void uartspecial(Uart*, int, Queue**, Queue**, int (*)(Queue*, int)); void sa1110_uartsetup(int); void screeninit(void); diff --git a/bitsy/io.h b/bitsy/io.h index aa91760d8246dcf3650c3319395e8da0d7eb0193..f327492b4b54acbe98b89f8ffa3d20c400446ae8 100644 --- a/bitsy/io.h +++ b/bitsy/io.h @@ -323,3 +323,14 @@ struct Gpclkregs ulong r3; }; extern Gpclkregs *gpclkregs; + +/* + * Dont use this on bitsy drivers. + * This is for compat with code compiled + * from the ../pc directory + */ + +typedef struct Pcidev Pcidev; +typedef struct ISAConf ISAConf; +struct Pcidev { int dummy; }; +struct ISAConf{ int port; int irq; }; diff --git a/bitsy/main.c b/bitsy/main.c index b3b2faaa5b767b105fafe4acb7b95adce36fe977..6dce965a7685648b0f966d0af31ccca97b16ad75 100644 --- a/bitsy/main.c +++ b/bitsy/main.c @@ -381,7 +381,7 @@ void machinit(void) { /* set direction of SA1110 io pins and select alternate functions for some */ - gpioregs = mapspecial(GPIOREGS, 32); + gpioregs = mapspecial(GPIOREGS, sizeof(GPIOregs)); gpioregs->direction = GPIO_LDD8_o|GPIO_LDD9_o|GPIO_LDD10_o|GPIO_LDD11_o |GPIO_LDD12_o|GPIO_LDD13_o|GPIO_LDD14_o|GPIO_LDD15_o @@ -396,19 +396,19 @@ machinit(void) |GPIO_SSP_CLK_i; /* map in special H3650 io pins */ - egpioreg = mapspecial(EGPIOREGS, 4); + egpioreg = mapspecial(EGPIOREGS, sizeof(ulong)); /* map in peripheral pin controller (ssp will need it) */ - ppcregs = mapspecial(PPCREGS, 32); + ppcregs = mapspecial(PPCREGS, sizeof(PPCregs)); /* SA1110 power management */ - powerregs = mapspecial(POWERREGS, 32); + powerregs = mapspecial(POWERREGS, sizeof(PowerRegs)); /* memory configuraton */ - memconfregs = mapspecial(MEMCONFREGS, 32); + memconfregs = mapspecial(MEMCONFREGS, sizeof(MemConfRegs)); /* reset controller */ - resetregs = mapspecial(RESETREGS, 32); + resetregs = mapspecial(RESETREGS, sizeof(ResetRegs)); } @@ -523,3 +523,9 @@ inl(ulong a) { return *(ulong*)a; } + +char* +getconf(char*) +{ + return nil; +} diff --git a/bitsy/power.c b/bitsy/power.c index faac6c10fd69b5d207fbc4ea9006f798375c0723..b70b43e4bec9af4ed92d50d0fa7080b5af30e904 100644 --- a/bitsy/power.c +++ b/bitsy/power.c @@ -9,6 +9,26 @@ /* Power management for the bitsy */ + +/* + * Very ugly. This is just to get/set the offset field without + * touching port/tod.c. + */ +#define TODFREQ 1000000000LL +extern struct { + ulong cnt; + Lock; + vlong multiplier; // t = off + (multiplier*ticks)>>31 + vlong hz; // frequency of fast clock + vlong last; // last reading of fast clock + vlong off; // offset from epoch to last + vlong lasttime; // last return value from todget + vlong delta; // add 'delta' each slow clock tick from sstart to send + ulong sstart; // ... + ulong send; // ... +} tod; + + /* saved state during power down. * it's only used up to 164/4. * it's only used by routines in l.s @@ -30,6 +50,18 @@ Intrregs savedintrregs; uchar *savedtext; +static vlong +todgetoff(void) +{ + return tod.off; +} + +static void +todsetoff(vlong off) +{ + tod.off = off; +} + static void checkflash(void) { @@ -166,6 +198,8 @@ deepsleep(void) { static int power_pl; ulong xsp, xlink; // ulong mecr; + ulong clkd; + vlong savedtod; extern void power_resume(void); power_pl = splhi(); @@ -199,8 +233,10 @@ deepsleep(void) { gpioregs->edgestatus = (1<icip = (1<r0 = 1<<0; + todsetoff( savedtod + clkd * TODFREQ); + resetsuspendtimer(); rs232power(1); uartpower(1); delay(100); @@ -218,6 +254,7 @@ deepsleep(void) { } cacheflush(); delay(100); + savedtod = todgetoff(); power_down(); /* no return */ } @@ -273,6 +310,37 @@ blanktimer(void) drawactive(0); } +static ulong suspendtime = 120 * HZ; +static int lastsuspend; + +void +resetsuspendtimer(void) +{ + suspendtime = 60 * HZ; +} + +static void +suspendtimer(void) +{ + uvlong now; + + return; // does not work well. + + if (suspendtime > 0) + suspendtime--; + if (suspendtime == 0){ + now = seconds(); + if (now < lastsuspend + 10){ + resetsuspendtimer(); + return; + } + lastsuspend = seconds(); + deepsleep(); + lastsuspend = seconds(); + return; + } +} + void powerinit(void) { @@ -292,6 +360,7 @@ powerinit(void) *resumeaddr = (ulong) power_resume; addclock0link(blanktimer, 1000/HZ); + addclock0link(suspendtimer, 1000/HZ); intrenable(GPIOrising, bitno(GPIO_PWR_ON_i), onoffintr, nil, "on/off"); } @@ -311,3 +380,4 @@ idlehands(void) spllo(); } } + diff --git a/bitsy/sd.h b/bitsy/sd.h deleted file mode 100644 index 61b57a44a1821a188a126f35eea5be587405a622..0000000000000000000000000000000000000000 --- a/bitsy/sd.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Storage Device. - */ -typedef struct SDev SDev; -typedef struct SDifc SDifc; -typedef struct SDpart SDpart; -typedef struct SDperm SDperm; -typedef struct SDreq SDreq; -typedef struct SDunit SDunit; - -typedef struct SDperm { - char name[KNAMELEN]; - char user[KNAMELEN]; - ulong perm; -} SDperm; - -typedef struct SDpart { - ulong start; - ulong end; - SDperm; - int valid; - ulong vers; -} SDpart; - -typedef struct SDunit { - SDev* dev; - int subno; - uchar inquiry[256]; /* format follows SCSI spec */ - SDperm; - Rendez rendez; - - QLock ctl; - ulong sectors; - ulong secsize; - SDpart* part; /* nil or array of size npart */ - int npart; - ulong vers; - SDperm ctlperm; - - QLock raw; /* raw read or write in progress */ - Lock rawinuse; /* really just a test-and-set */ - int state; - SDreq* req; - SDperm rawperm; - - Log log; -} SDunit; - -typedef struct SDev { - SDifc* ifc; /* pnp/legacy */ - void *ctlr; - int idno; - char name[KNAMELEN]; - int index; /* into unit space */ - int nunit; - SDev* next; - - QLock; /* enable/disable */ - int enabled; -} SDev; - -struct SDifc { - char* name; - - SDev* (*pnp)(void); - SDev* (*legacy)(int, int); - SDev* (*id)(SDev*); - int (*enable)(SDev*); - int (*disable)(SDev*); - - int (*verify)(SDunit*); - int (*online)(SDunit*); - int (*rio)(SDreq*); - int (*rctl)(SDunit*, char*, int); - int (*wctl)(SDunit*, Cmdbuf*); - - long (*bio)(SDunit*, int, int, void*, long, long); - SDev* (*config)(int on, char *spec, DevConf *cf); -}; - -typedef struct SDreq { - SDunit* unit; - int lun; - int write; - uchar cmd[16]; - int clen; - void* data; - int dlen; - - int flags; - - int status; - long rlen; - uchar sense[256]; -} SDreq; - -enum { - SDnosense = 0x00000001, - SDvalidsense = 0x00010000, -}; - -enum { - SDretry = -5, /* internal to controllers */ - SDmalloc = -4, - SDeio = -3, - SDtimeout = -2, - SDnostatus = -1, - - SDok = 0, - - SDcheck = 0x02, /* check condition */ - SDbusy = 0x08, /* busy */ - - SDmaxio = 2048*1024, - SDnpart = 16, -}; - -#define sdmalloc(n) malloc(n) -#define sdfree(p) free(p) - -/* sdscsi.c */ -extern int scsiverify(SDunit*); -extern int scsionline(SDunit*); -extern long scsibio(SDunit*, int, int, void*, long, long); -extern SDev* scsiid(SDev*, SDifc*); diff --git a/bitsy/sdata.c b/bitsy/sdata.c index 694a7e7ccfded2a11439445015939faf4311ff26..1977b98eca8367857418e609f4990faf146b4932 100644 --- a/bitsy/sdata.c +++ b/bitsy/sdata.c @@ -7,7 +7,7 @@ #include "ureg.h" #include "../port/error.h" -#include "sd.h" +#include "../port/sd.h" extern SDifc sdataifc; @@ -253,11 +253,6 @@ typedef struct Drive { } Drive; -char* -getconf(char*) -{ - return nil; -} static void atadumpstate(Drive* drive, uchar* cmd, int lba, int count) @@ -2036,7 +2031,7 @@ struct Try { }; static SDev* -ataconfig(int on, char *, DevConf *cf) +ataprobew(DevConf *cf) { int cmdport; int ctlport; @@ -2044,15 +2039,13 @@ ataconfig(int on, char *, DevConf *cf) SDev* rc; struct Try *try; - if(on == 0) - return nil; rc = nil; for (try = &tries[0]; try->p != 0 || try->c != 0; try++){ ataitype = cf->itype; - atairq = cf->irq; - cmdport = cf->port + try->p; + atairq = cf->intnum; + cmdport = cf->ports[0].port + try->p; ctlport = cmdport + try->c; - irq = cf->irq; + irq = cf->intnum; rc = ataprobe(cmdport, ctlport, irq); if (rc) break; @@ -2060,6 +2053,37 @@ ataconfig(int on, char *, DevConf *cf) return rc; } +static void +ataclear(SDev *sdev) +{ + Ctlr* ctlr; + + ctlr = sdev->ctlr; + + if (ctlr->drive[0]) + free(ctlr->drive[0]); + if (ctlr->drive[1]) + free(ctlr->drive[1]); + if (sdev->name) + free(sdev->name); + if (sdev->unitflg) + free(sdev->unitflg); + if (sdev->unit) + free(sdev->unit); + free(ctlr); + free(sdev); +} + +static char * +atastat(SDev *sdev, char *p, char *e) +{ + Ctlr *ctlr = sdev->ctlr; + + return seprint(p, e, "%s ata port %X ctl %X irq %d\n", + sdev->name, ctlr->cmdport, ctlr->ctlport, ctlr->irq); +} + + SDifc sdataifc = { "ata", /* name */ @@ -2075,7 +2099,9 @@ SDifc sdataifc = { atarctl, /* rctl */ atawctl, /* wctl */ - atabio, /* bio */ - ataconfig, /* config */ + atabio, /* bio */ + ataprobew, /* probew */ + ataclear, /* clear */ + atastat, /* stat */ }; diff --git a/bitsy/uartsa1110.c b/bitsy/uartsa1110.c index 1309f6066fd92b530419738fccc564cee98799d2..939307a1b5f0e654409a2f24bf56be234a422036 100644 --- a/bitsy/uartsa1110.c +++ b/bitsy/uartsa1110.c @@ -465,7 +465,7 @@ sa1110_uartsetup(int console) /* external serial port (eia0) */ p = &sa1110uart[0]; - p->regs = mapspecial(UART3REGS, 64); + p->regs = mapspecial(UART3REGS, sizeof(Uartregs)); p->saveregs = xalloc(sizeof(Uartregs)); /* set eia0 up as a console */ if(console){ @@ -477,11 +477,11 @@ sa1110_uartsetup(int console) intrenable(IRQ, IRQuart3, sa1110_uartintr, p, p->name); /* port for talking to microcontroller (eia1) */ - gpclkregs = mapspecial(GPCLKREGS, 64); + gpclkregs = mapspecial(GPCLKREGS, sizeof(Gpclkregs)); gpclkregs->r0 = Gpclk_sus; /* set uart mode */ p = &sa1110uart[1]; - p->regs = mapspecial(UART1REGS, 64); + p->regs = mapspecial(UART1REGS, sizeof(Uartregs)); p->saveregs = xalloc(sizeof(Uartregs)); uartctl(p, "b115200 l8 pn s1"); µcuart = p; diff --git a/bitsy/wavelan.c b/bitsy/wavelan.c index fcf743151b7eef5a2521eddaa43c443904b38a42..1b3e9f4e3cd1629d84bbcd03a077b2cc3e41771b 100644 --- a/bitsy/wavelan.c +++ b/bitsy/wavelan.c @@ -1 +1,1150 @@ -#include "../pc/wavelan.c" +/* + Lucent Wavelan IEEE 802.11 pcmcia. + There is almost no documentation for the card. + the driver is done using both the FreeBSD, Linux and + original Plan 9 drivers as `documentation'. + + Has been used with the card plugged in during all up time. + no cards removals/insertions yet. + + For known BUGS see the comments below. Besides, + the driver keeps interrupts disabled for just too + long. When it gets robust, locks should be revisited. + + BUGS: check endian, alignment and mem/io issues; + multicast; + receive watchdog interrupts. + TODO: automatic power management; + improve locking. + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" +#include "../port/netif.h" +#include "etherif.h" +#include "wavelan.h" + +/* + * When we're using a PCI device and memory-mapped I/O, + * the registers are spaced out as though each takes 32 bits, + * even though they are only 16-bit registers. Thus, + * ctlr->mmb[reg] is the right way to access register reg, + * even though a priori you'd expect to use ctlr->mmb[reg/2]. + */ +void +csr_outs(Ctlr *ctlr, int reg, ushort arg) +{ + if(ctlr->mmb) + ctlr->mmb[reg] = arg; + else + outs(ctlr->iob+reg, arg); +} + +ushort +csr_ins(Ctlr *ctlr, int reg) +{ + if(ctlr->mmb) + return ctlr->mmb[reg]; + else + return ins(ctlr->iob+reg); +} + +static void +csr_ack(Ctlr *ctlr, int ev) +{ + csr_outs(ctlr, WR_EvAck, ev); +} + +static void +csr_inss(Ctlr *ctlr, int reg, void *dat, int ndat) +{ + ushort *rp, *wp; + + if(ctlr->mmb){ + rp = &ctlr->mmb[reg]; + wp = dat; + while(ndat-- > 0) + *wp++ = *rp; + }else + inss(ctlr->iob+reg, dat, ndat); +} + +static void +csr_outss(Ctlr *ctlr, int reg, void *dat, int ndat) +{ + ushort *rp, *wp; + + if(ctlr->mmb){ + rp = dat; + wp = &ctlr->mmb[reg]; + while(ndat-- > 0) + *wp = *rp++; + }else + outss(ctlr->iob+reg, dat, ndat); +} + +// w_... routines do not ilock the Ctlr and should +// be called locked. + +void +w_intdis(Ctlr* ctlr) +{ + csr_outs(ctlr, WR_IntEna, 0); + csr_ack(ctlr, 0xffff); +} + +static void +w_intena(Ctlr* ctlr) +{ + csr_outs(ctlr, WR_IntEna, WEvs); +} + +int +w_cmd(Ctlr *ctlr, ushort cmd, ushort arg) +{ + int i, rc; + + for(i=0; ictlrno, cmd, csr_ins(ctlr, WR_Cmd)); + return -1; + } + + csr_outs(ctlr, WR_Parm0, arg); + csr_outs(ctlr, WR_Cmd, cmd); + + for(i=0; ictlrno, cmd, i); + if(i == IniTmOut){ + print("#l%d: execing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_EvSts)); + return -1; + } + } + rc = csr_ins(ctlr, WR_Sts); + csr_ack(ctlr, WCmdEv); + + if((rc&WCmdMsk) != (cmd&WCmdMsk)){ + print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc); + return -1; + } + if(rc&WResSts){ + /* + * Don't print; this happens on every WCmdAccWr for some reason. + */ + if(0) print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc); + return -1; + } + return 0; +} + +static int +w_seek(Ctlr* ctlr, ushort id, ushort offset, int chan) +{ + int i, rc; + static ushort sel[] = { WR_Sel0, WR_Sel1 }; + static ushort off[] = { WR_Off0, WR_Off1 }; + + if(chan != 0 && chan != 1) + panic("wavelan: bad chan\n"); + csr_outs(ctlr, sel[chan], id); + csr_outs(ctlr, off[chan], offset); + for (i=0; itype)){ + DEBUG("wavelan: access read failed\n"); + return -1; + } + if(w_seek(ctlr,ltv->type,0,1)){ + DEBUG("wavelan: seek failed\n"); + return -1; + } + len = csr_ins(ctlr, WR_Data1); + if(len > ltv->len) + return -1; + ltv->len = len; + if((code=csr_ins(ctlr, WR_Data1)) != ltv->type){ + USED(code); + DEBUG("wavelan: type %x != code %x\n",ltv->type,code); + return -1; + } + if(ltv->len > 0) + csr_inss(ctlr, WR_Data1, <v->val, ltv->len-1); + + return 0; +} + +static void +w_outltv(Ctlr* ctlr, Wltv* ltv) +{ + if(w_seek(ctlr,ltv->type, 0, 1)) + return; + csr_outss(ctlr, WR_Data1, ltv, ltv->len+1); + w_cmd(ctlr, WCmdAccWr, ltv->type); +} + +void +ltv_outs(Ctlr* ctlr, int type, ushort val) +{ + Wltv ltv; + + ltv.len = 2; + ltv.type = type; + ltv.val = val; + w_outltv(ctlr, <v); +} + +int +ltv_ins(Ctlr* ctlr, int type) +{ + Wltv ltv; + + ltv.len = 2; + ltv.type = type; + ltv.val = 0; + if(w_inltv(ctlr, <v)) + return -1; + return ltv.val; +} + +static void +ltv_outstr(Ctlr* ctlr, int type, char* val) +{ + Wltv ltv; + int len; + + len = strlen(val); + if(len > sizeof(ltv.s)) + len = sizeof(ltv.s); + memset(<v, 0, sizeof(ltv)); + ltv.len = (sizeof(ltv.type)+sizeof(ltv.slen)+sizeof(ltv.s))/2; + ltv.type = type; + +// This should be ltv.slen = len; according to Axel Belinfante + ltv.slen = len; + + strncpy(ltv.s, val, len); + w_outltv(ctlr, <v); +} + +static char Unkname[] = "who knows"; +static char Nilname[] = "card does not tell"; + +static char* +ltv_inname(Ctlr* ctlr, int type) +{ + static Wltv ltv; + int len; + + memset(<v,0,sizeof(ltv)); + ltv.len = WNameLen/2+2; + ltv.type = type; + if(w_inltv(ctlr, <v)) + return Unkname; + len = ltv.slen; + if(len == 0 || ltv.s[0] == 0) + return Nilname; + if(len >= sizeof ltv.s) + len = sizeof ltv.s - 1; + ltv.s[len] = '\0'; + return ltv.s; +} + +static int +w_read(Ctlr* ctlr, int type, int off, void* buf, ulong len) +{ + if(w_seek(ctlr, type, off, 1)){ + DEBUG("wavelan: w_read: seek failed"); + return 0; + } + csr_inss(ctlr, WR_Data1, buf, len/2); + + return len; +} + +static int +w_write(Ctlr* ctlr, int type, int off, void* buf, ulong len) +{ + int tries; + + for (tries=0; tries < WTmOut; tries++){ + if(w_seek(ctlr, type, off, 0)){ + DEBUG("wavelan: w_write: seek failed\n"); + return 0; + } + + csr_outss(ctlr, WR_Data0, buf, len/2); + + csr_outs(ctlr, WR_Data0, 0xdead); + csr_outs(ctlr, WR_Data0, 0xbeef); + if(w_seek(ctlr, type, off + len, 0)){ + DEBUG("wavelan: write seek failed\n"); + return 0; + } + if(csr_ins(ctlr, WR_Data0) == 0xdead) + if(csr_ins(ctlr, WR_Data0) == 0xbeef) + return len; + DEBUG("wavelan: Hermes bug byte.\n"); + return 0; + } + DEBUG("wavelan: tx timeout\n"); + return 0; +} + +static int +w_alloc(Ctlr* ctlr, int len) +{ + int rc; + int i,j; + + if(w_cmd(ctlr, WCmdMalloc, len)==0) + for (i = 0; ictlr; + + if(!ctlr) + return -1; + + w_intdis(ctlr); + w_cmd(ctlr, WCmdDis, 0); + w_intdis(ctlr); + if(w_cmd(ctlr, WCmdIni, 0)) + return -1; + w_intdis(ctlr); + + ltv_outs(ctlr, WTyp_Tick, 8); + ltv_outs(ctlr, WTyp_MaxLen, ctlr->maxlen); + ltv_outs(ctlr, WTyp_Ptype, ctlr->ptype); + ltv_outs(ctlr, WTyp_CreateIBSS, ctlr->createibss); + ltv_outs(ctlr, WTyp_RtsThres, ctlr->rtsthres); + ltv_outs(ctlr, WTyp_TxRate, ctlr->txrate); + ltv_outs(ctlr, WTyp_ApDens, ctlr->apdensity); + ltv_outs(ctlr, WTyp_PMWait, ctlr->pmwait); + ltv_outs(ctlr, WTyp_PM, ctlr->pmena); + if(*ctlr->netname) + ltv_outstr(ctlr, WTyp_NetName, ctlr->netname); + if(*ctlr->wantname) + ltv_outstr(ctlr, WTyp_WantName, ctlr->wantname); + ltv_outs(ctlr, WTyp_Chan, ctlr->chan); + if(*ctlr->nodename) + ltv_outstr(ctlr, WTyp_NodeName, ctlr->nodename); + ltv.len = 4; + ltv.type = WTyp_Mac; + memmove(ltv.addr, ether->ea, Eaddrlen); + w_outltv(ctlr, <v); + + ltv_outs(ctlr, WTyp_Prom, (ether->prom?1:0)); + + if(ctlr->hascrypt){ + ltv_outs(ctlr, WTyp_Crypt, ctlr->crypt); + ltv_outs(ctlr, WTyp_TxKey, ctlr->txkey); + w_outltv(ctlr, &ctlr->keys); + ltv_outs(ctlr, WTyp_XClear, ctlr->xclear); + } + + // BUG: set multicast addresses + + if(w_cmd(ctlr, WCmdEna, 0)){ + DEBUG("wavelan: Enable failed"); + return -1; + } + ctlr->txdid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8); + ctlr->txmid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8); + if(ctlr->txdid == -1 || ctlr->txmid == -1) + DEBUG("wavelan: alloc failed"); + ctlr->txbusy = 0; + w_intena(ctlr); + return 0; +} + +static void +w_rxdone(Ether* ether) +{ + Ctlr* ctlr = (Ctlr*) ether->ctlr; + int len, sp; + WFrame f; + Block* bp=0; + Etherpkt* ep; + + sp = csr_ins(ctlr, WR_RXId); + len = w_read(ctlr, sp, 0, &f, sizeof(f)); + if(len == 0){ + DEBUG("wavelan: read frame error\n"); + goto rxerror; + } + if(f.sts&WF_Err){ + goto rxerror; + } + switch(f.sts){ + case WF_1042: + case WF_Tunnel: + case WF_WMP: + len = f.dlen + WSnapHdrLen; + bp = iallocb(ETHERHDRSIZE + len + 2); + if(!bp) + goto rxerror; + ep = (Etherpkt*) bp->wp; + memmove(ep->d, f.addr1, Eaddrlen); + memmove(ep->s, f.addr2, Eaddrlen); + memmove(ep->type,&f.type,2); + bp->wp += ETHERHDRSIZE; + if(w_read(ctlr, sp, WF_802_11_Off, bp->wp, len+2) == 0){ + DEBUG("wavelan: read 802.11 error\n"); + goto rxerror; + } + bp->wp = bp->rp+(ETHERHDRSIZE+f.dlen); + break; + default: + len = ETHERHDRSIZE + f.dlen + 2; + bp = iallocb(len); + if(!bp) + goto rxerror; + if(w_read(ctlr, sp, WF_802_3_Off, bp->wp, len) == 0){ + DEBUG("wavelan: read 800.3 error\n"); + goto rxerror; + } + bp->wp += len; + } + + ctlr->nrx++; + etheriq(ether,bp,1); + ctlr->signal = ((ctlr->signal*15)+((f.qinfo>>8) & 0xFF))/16; + ctlr->noise = ((ctlr->noise*15)+(f.qinfo & 0xFF))/16; + return; + +rxerror: + freeb(bp); + ctlr->nrxerr++; +} + +static void +w_txstart(Ether* ether) +{ + Etherpkt *pkt; + Ctlr *ctlr; + Block *bp; + int len, off; + + if((ctlr = ether->ctlr) == nil || (ctlr->state & (Attached|Power)) != (Attached|Power) || ctlr->txbusy) + return; + + if((bp = qget(ether->oq)) == nil) + return; + pkt = (Etherpkt*)bp->rp; + + // + // If the packet header type field is > 1500 it is an IP or + // ARP datagram, otherwise it is an 802.3 packet. See RFC1042. + // + memset(&ctlr->txf, 0, sizeof(ctlr->txf)); + if(((pkt->type[0]<<8)|pkt->type[1]) > 1500){ + ctlr->txf.framectl = WF_Data; + memmove(ctlr->txf.addr1, pkt->d, Eaddrlen); + memmove(ctlr->txf.addr2, pkt->s, Eaddrlen); + memmove(ctlr->txf.dstaddr, pkt->d, Eaddrlen); + memmove(ctlr->txf.srcaddr, pkt->s, Eaddrlen); + memmove(&ctlr->txf.type, pkt->type, 2); + bp->rp += ETHERHDRSIZE; + len = BLEN(bp); + off = WF_802_11_Off; + ctlr->txf.dlen = len+ETHERHDRSIZE-WSnapHdrLen; + hnputs((uchar*)&ctlr->txf.dat[0], WSnap0); + hnputs((uchar*)&ctlr->txf.dat[1], WSnap1); + hnputs((uchar*)&ctlr->txf.len, len+ETHERHDRSIZE-WSnapHdrLen); + } + else{ + len = BLEN(bp); + off = WF_802_3_Off; + ctlr->txf.dlen = len; + } + w_write(ctlr, ctlr->txdid, 0, &ctlr->txf, sizeof(ctlr->txf)); + w_write(ctlr, ctlr->txdid, off, bp->rp, len+2); + + if(w_cmd(ctlr, WCmdReclaim|WCmdTx, ctlr->txdid)){ + DEBUG("wavelan: transmit failed\n"); + ctlr->ntxerr++; + } + else{ + ctlr->txbusy = 1; + ctlr->txtmout = 2; + } + freeb(bp); +} + +static void +w_txdone(Ctlr* ctlr, int sts) +{ + ctlr->txbusy = 0; + ctlr->txtmout = 0; + if(sts & WTxErrEv) + ctlr->ntxerr++; + else + ctlr->ntx++; +} + +static int +w_stats(Ctlr* ctlr) +{ + int i, rc, sp; + Wltv ltv; + ulong* p = (ulong*)&ctlr->WStats; + ulong* pend = (ulong*)&ctlr->end; + + sp = csr_ins(ctlr, WR_InfoId); + ltv.len = ltv.type = 0; + w_read(ctlr, sp, 0, <v, 4); + if(ltv.type == WTyp_Stats){ + ltv.len--; + for (i = 0; i < ltv.len && p < pend; i++){ + rc = csr_ins(ctlr, WR_Data1); + if(rc > 0xf000) + rc = ~rc & 0xffff; + p[i] += rc; + } + return 0; + } + return -1; +} + +static void +w_intr(Ether *ether) +{ + int rc, txid; + Ctlr* ctlr = (Ctlr*) ether->ctlr; + + if((ctlr->state & Power) == 0) + return; + + if((ctlr->state & Attached) == 0){ + csr_ack(ctlr, 0xffff); + csr_outs(ctlr, WR_IntEna, 0); + return; + } + + rc = csr_ins(ctlr, WR_EvSts); + csr_ack(ctlr, ~WEvs); // Not interested in them + if(rc & WRXEv){ + w_rxdone(ether); + csr_ack(ctlr, WRXEv); + } + if(rc & WTXEv){ + w_txdone(ctlr, rc); + csr_ack(ctlr, WTXEv); + } + if(rc & WAllocEv){ + ctlr->nalloc++; + txid = csr_ins(ctlr, WR_Alloc); + csr_ack(ctlr, WAllocEv); + if(txid == ctlr->txdid){ + if((rc & WTXEv) == 0) + w_txdone(ctlr, rc); + } + } + if(rc & WInfoEv){ + ctlr->ninfo++; + w_stats(ctlr); + csr_ack(ctlr, WInfoEv); + } + if(rc & WTxErrEv){ + w_txdone(ctlr, rc); + csr_ack(ctlr, WTxErrEv); + } + if(rc & WIDropEv){ + ctlr->nidrop++; + csr_ack(ctlr, WIDropEv); + } + w_txstart(ether); +} + +// Watcher to ensure that the card still works properly and +// to request WStats updates once a minute. +// BUG: it runs much more often, see the comment below. + +static void +w_timer(void* arg) +{ + Ether* ether = (Ether*) arg; + Ctlr* ctlr = (Ctlr*)ether->ctlr; + + ctlr->timerproc = up; + for(;;){ + tsleep(&ctlr->timer, return0, 0, 50); + ctlr = (Ctlr*)ether->ctlr; + if(ctlr == 0) + break; + if((ctlr->state & (Attached|Power)) != (Attached|Power)) + continue; + ctlr->ticks++; + + ilock(ctlr); + + // Seems that the card gets frames BUT does + // not send the interrupt; this is a problem because + // I suspect it runs out of receive buffers and + // stops receiving until a transmit watchdog + // reenables the card. + // The problem is serious because it leads to + // poor rtts. + // This can be seen clearly by commenting out + // the next if and doing a ping: it will stop + // receiving (although the icmp replies are being + // issued from the remote) after a few seconds. + // Of course this `bug' could be because I'm reading + // the card frames in the wrong way; due to the + // lack of documentation I cannot know. + + if(csr_ins(ctlr, WR_EvSts)&WEvs){ + ctlr->tickintr++; + w_intr(ether); + } + + if((ctlr->ticks % 10) == 0) { + if(ctlr->txtmout && --ctlr->txtmout == 0){ + ctlr->nwatchdogs++; + w_txdone(ctlr, WTxErrEv); + if(w_enable(ether)){ + DEBUG("wavelan: wdog enable failed\n"); + } + w_txstart(ether); + } + if((ctlr->ticks % 120) == 0) + if(ctlr->txbusy == 0) + w_cmd(ctlr, WCmdAskStats, WTyp_Stats); + } + iunlock(ctlr); + } + pexit("terminated", 0); +} + +void +w_multicast(void*, uchar*, int) +{ + // BUG: to be added. +} + +void +w_attach(Ether* ether) +{ + Ctlr* ctlr; + char name[64]; + int rc; + + if(ether->ctlr == 0) + return; + + snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno); + ctlr = (Ctlr*) ether->ctlr; + if((ctlr->state & Attached) == 0){ + ilock(ctlr); + rc = w_enable(ether); + iunlock(ctlr); + if(rc == 0){ + ctlr->state |= Attached; + kproc(name, w_timer, ether); + } else + print("#l%d: enable failed\n",ether->ctlrno); + } +} + +void +w_detach(Ether* ether) +{ + Ctlr* ctlr; + char name[64]; + + if(ether->ctlr == nil) + return; + + snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno); + ctlr = (Ctlr*) ether->ctlr; + if(ctlr->state & Attached){ + ilock(ctlr); + w_intdis(ctlr); + if(ctlr->timerproc){ + if(!postnote(ctlr->timerproc, 1, "kill", NExit)) + print("timerproc note not posted\n"); + print("w_detach, killing 0x%p\n", ctlr->timerproc); + } + ctlr->state &= ~Attached; + iunlock(ctlr); + } + ether->ctlr = nil; +} + +void +w_power(Ether* ether, int on) +{ + Ctlr *ctlr; + + ctlr = (Ctlr*) ether->ctlr; + ilock(ctlr); +iprint("w_power %d\n", on); + if(on){ + if((ctlr->state & Power) == 0){ + if (wavelanreset(ether, ctlr) < 0){ + iprint("w_power: reset failed\n"); + iunlock(ctlr); + w_detach(ether); + free(ctlr); + return; + } + if(ctlr->state & Attached) + w_enable(ether); + ctlr->state |= Power; + } + }else{ + if(ctlr->state & Power){ + if(ctlr->state & Attached) + w_intdis(ctlr); + ctlr->state &= ~Power; + } + } + iunlock(ctlr); +} + +#define PRINTSTAT(fmt,val) l += snprint(p+l, READSTR-l, (fmt), (val)) +#define PRINTSTR(fmt) l += snprint(p+l, READSTR-l, (fmt)) + +long +w_ifstat(Ether* ether, void* a, long n, ulong offset) +{ + Ctlr *ctlr = (Ctlr*) ether->ctlr; + char *k, *p; + int i, l, txid; + + ether->oerrs = ctlr->ntxerr; + ether->crcs = ctlr->nrxfcserr; + ether->frames = 0; + ether->buffs = ctlr->nrxdropnobuf; + ether->overflows = 0; + + // + // Offset must be zero or there's a possibility the + // new data won't match the previous read. + // + if(n == 0 || offset != 0) + return 0; + + p = malloc(READSTR); + l = 0; + + PRINTSTAT("Signal: %d\n", ctlr->signal-149); + PRINTSTAT("Noise: %d\n", ctlr->noise-149); + PRINTSTAT("SNR: %ud\n", ctlr->signal-ctlr->noise); + PRINTSTAT("Interrupts: %lud\n", ctlr->nints); + PRINTSTAT("Double Interrupts: %lud\n", ctlr->ndoubleint); + PRINTSTAT("TxPackets: %lud\n", ctlr->ntx); + PRINTSTAT("RxPackets: %lud\n", ctlr->nrx); + PRINTSTAT("TxErrors: %lud\n", ctlr->ntxerr); + PRINTSTAT("RxErrors: %lud\n", ctlr->nrxerr); + PRINTSTAT("TxRequests: %lud\n", ctlr->ntxrq); + PRINTSTAT("AllocEvs: %lud\n", ctlr->nalloc); + PRINTSTAT("InfoEvs: %lud\n", ctlr->ninfo); + PRINTSTAT("InfoDrop: %lud\n", ctlr->nidrop); + PRINTSTAT("WatchDogs: %lud\n", ctlr->nwatchdogs); + PRINTSTAT("Ticks: %ud\n", ctlr->ticks); + PRINTSTAT("TickIntr: %ud\n", ctlr->tickintr); + k = ((ctlr->state & Attached) ? "attached" : "not attached"); + PRINTSTAT("Card %s", k); + k = ((ctlr->state & Power) ? "on" : "off"); + PRINTSTAT("PCardower %s", k); + k = ((ctlr->txbusy)? ", txbusy" : ""); + PRINTSTAT("%s\n", k); + + if(ctlr->hascrypt){ + PRINTSTR("Keys: "); + for (i = 0; i < WNKeys; i++){ + if(ctlr->keys.keys[i].len == 0) + PRINTSTR("none "); + else if(SEEKEYS == 0) + PRINTSTR("set "); + else + PRINTSTAT("%s ", ctlr->keys.keys[i].dat); + } + PRINTSTR("\n"); + } + + // real card stats + ilock(ctlr); + PRINTSTR("\nCard stats: \n"); + PRINTSTAT("Status: %ux\n", csr_ins(ctlr, WR_Sts)); + PRINTSTAT("Event status: %ux\n", csr_ins(ctlr, WR_EvSts)); + i = ltv_ins(ctlr, WTyp_Ptype); + PRINTSTAT("Port type: %d\n", i); + PRINTSTAT("Transmit rate: %d\n", ltv_ins(ctlr, WTyp_TxRate)); + PRINTSTAT("Current Transmit rate: %d\n", + ltv_ins(ctlr, WTyp_CurTxRate)); + PRINTSTAT("Channel: %d\n", ltv_ins(ctlr, WTyp_Chan)); + PRINTSTAT("AP density: %d\n", ltv_ins(ctlr, WTyp_ApDens)); + PRINTSTAT("Promiscuous mode: %d\n", ltv_ins(ctlr, WTyp_Prom)); + if(i == 3) + PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName)); + else { + Wltv ltv; + PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName)); + ltv.type = WTyp_BaseID; + ltv.len = 4; + if(w_inltv(ctlr, <v)) + print("#l%d: unable to read base station mac addr\n", ether->ctlrno); + l += snprint(p+l, READSTR-l, "Base station: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + ltv.addr[0], ltv.addr[1], ltv.addr[2], ltv.addr[3], ltv.addr[4], ltv.addr[5]); + } + PRINTSTAT("Net name: %s\n", ltv_inname(ctlr, WTyp_WantName)); + PRINTSTAT("Node name: %s\n", ltv_inname(ctlr, WTyp_NodeName)); + if(ltv_ins(ctlr, WTyp_HasCrypt) == 0) + PRINTSTR("WEP: not supported\n"); + else { + if(ltv_ins(ctlr, WTyp_Crypt) == 0) + PRINTSTR("WEP: disabled\n"); + else{ + PRINTSTR("WEP: enabled\n"); + k = ((ctlr->xclear)? "excluded": "included"); + PRINTSTAT("Clear packets: %s\n", k); + txid = ltv_ins(ctlr, WTyp_TxKey); + PRINTSTAT("Transmit key id: %d\n", txid); + } + } + iunlock(ctlr); + + PRINTSTAT("ntxuframes: %lud\n", ctlr->ntxuframes); + PRINTSTAT("ntxmframes: %lud\n", ctlr->ntxmframes); + PRINTSTAT("ntxfrags: %lud\n", ctlr->ntxfrags); + PRINTSTAT("ntxubytes: %lud\n", ctlr->ntxubytes); + PRINTSTAT("ntxmbytes: %lud\n", ctlr->ntxmbytes); + PRINTSTAT("ntxdeferred: %lud\n", ctlr->ntxdeferred); + PRINTSTAT("ntxsretries: %lud\n", ctlr->ntxsretries); + PRINTSTAT("ntxmultiretries: %lud\n", ctlr->ntxmultiretries); + PRINTSTAT("ntxretrylimit: %lud\n", ctlr->ntxretrylimit); + PRINTSTAT("ntxdiscards: %lud\n", ctlr->ntxdiscards); + PRINTSTAT("nrxuframes: %lud\n", ctlr->nrxuframes); + PRINTSTAT("nrxmframes: %lud\n", ctlr->nrxmframes); + PRINTSTAT("nrxfrags: %lud\n", ctlr->nrxfrags); + PRINTSTAT("nrxubytes: %lud\n", ctlr->nrxubytes); + PRINTSTAT("nrxmbytes: %lud\n", ctlr->nrxmbytes); + PRINTSTAT("nrxfcserr: %lud\n", ctlr->nrxfcserr); + PRINTSTAT("nrxdropnobuf: %lud\n", ctlr->nrxdropnobuf); + PRINTSTAT("nrxdropnosa: %lud\n", ctlr->nrxdropnosa); + PRINTSTAT("nrxcantdecrypt: %lud\n", ctlr->nrxcantdecrypt); + PRINTSTAT("nrxmsgfrag: %lud\n", ctlr->nrxmsgfrag); + PRINTSTAT("nrxmsgbadfrag: %lud\n", ctlr->nrxmsgbadfrag); + USED(l); + n = readstr(offset, a, n, p); + free(p); + return n; +} +#undef PRINTSTR +#undef PRINTSTAT + +int +w_option(Ctlr* ctlr, char* buf, long n) +{ + char *p; + int i, r; + WKey *key; + Cmdbuf *cb; + + r = 0; + print("here\n"); + cb = parsecmd(buf, n); + for (i = 0; i < cb->nf; i++) + iprint("cb %s\n", cb->f[i]); + + if(cb->nf < 2) + r = -1; + else if(cistrcmp(cb->f[0], "essid") == 0){ + if(cistrcmp(cb->f[1],"default") == 0) + p = ""; + else + p = cb->f[1]; + if(ctlr->ptype == 3){ + memset(ctlr->netname, 0, sizeof(ctlr->netname)); + strncpy(ctlr->netname, p, WNameLen); + } + else{ + memset(ctlr->wantname, 0, sizeof(ctlr->wantname)); + strncpy(ctlr->wantname, p, WNameLen); + } + } + else if(cistrcmp(cb->f[0], "station") == 0){ + memset(ctlr->nodename, 0, sizeof(ctlr->nodename)); + strncpy(ctlr->nodename, cb->f[1], WNameLen); + } + else if(cistrcmp(cb->f[0], "channel") == 0){ + if((i = atoi(cb->f[1])) >= 1 && i <= 16) + ctlr->chan = i; + else + r = -1; + } + else if(cistrcmp(cb->f[0], "mode") == 0){ + if(cistrcmp(cb->f[1], "managed") == 0) + ctlr->ptype = WPTypeManaged; + else if(cistrcmp(cb->f[1], "wds") == 0) + ctlr->ptype = WPTypeWDS; + else if(cistrcmp(cb->f[1], "adhoc") == 0) + ctlr->ptype = WPTypeAdHoc; + else if((i = atoi(cb->f[1])) >= 1 && i <= 3) + ctlr->ptype = i; + else + r = -1; + } + else if(cistrcmp(cb->f[0], "ibss") == 0){ + if(cistrcmp(cb->f[1], "on") == 0) + ctlr->createibss = 1; + else + ctlr->createibss = 0; + } + else if(cistrcmp(cb->f[0], "crypt") == 0){ + if(cistrcmp(cb->f[1], "off") == 0) + ctlr->crypt = 0; + else if(cistrcmp(cb->f[1], "on") == 0 && ctlr->hascrypt) + ctlr->crypt = 1; + else + r = -1; + } + else if(cistrcmp(cb->f[0], "clear") == 0){ + if(cistrcmp(cb->f[1], "on") == 0) + ctlr->xclear = 0; + else if(cistrcmp(cb->f[1], "off") == 0 && ctlr->hascrypt) + ctlr->xclear = 1; + else + r = -1; + } + else if(cistrncmp(cb->f[0], "key", 3) == 0){ + if((i = atoi(cb->f[0]+3)) >= 1 && i <= WNKeys){ + ctlr->txkey = i-1; + key = &ctlr->keys.keys[ctlr->txkey]; + key->len = strlen(cb->f[1]); + if(key->len > WKeyLen) + key->len = WKeyLen; + memset(key->dat, 0, sizeof(key->dat)); + memmove(key->dat, cb->f[1], key->len); + } + else + r = -1; + } + else if(cistrcmp(cb->f[0], "txkey") == 0){ + if((i = atoi(cb->f[1])) >= 1 && i <= WNKeys) + ctlr->txkey = i-1; + else + r = -1; + } + else if(cistrcmp(cb->f[0], "pm") == 0){ + if(cistrcmp(cb->f[1], "off") == 0) + ctlr->pmena = 0; + else if(cistrcmp(cb->f[1], "on") == 0){ + ctlr->pmena = 1; + if(cb->nf == 3){ + i = atoi(cb->f[2]); + // check range here? what are the units? + ctlr->pmwait = i; + } + } + else + r = -1; + } + else + r = -2; + free(cb); + + return r; +} + +long +w_ctl(Ether* ether, void* buf, long n) +{ + Ctlr *ctlr; + + if((ctlr = ether->ctlr) == nil) + error(Enonexist); + if((ctlr->state & Attached) == 0) + error(Eshutdown); + + ilock(ctlr); + if(w_option(ctlr, buf, n)){ + iunlock(ctlr); + error(Ebadctl); + } + if(ctlr->txbusy) + w_txdone(ctlr, WTxErrEv); + w_enable(ether); + w_txstart(ether); + iunlock(ctlr); + + return n; +} + +void +w_transmit(Ether* ether) +{ + Ctlr* ctlr = ether->ctlr; + + if(ctlr == 0) + return; + + ilock(ctlr); + ctlr->ntxrq++; + w_txstart(ether); + iunlock(ctlr); +} + +void +w_promiscuous(void* arg, int on) +{ + Ether* ether = (Ether*)arg; + Ctlr* ctlr = ether->ctlr; + + if(ctlr == nil) + error("card not found"); + if((ctlr->state & Attached) == 0) + error("card not attached"); + ilock(ctlr); + ltv_outs(ctlr, WTyp_Prom, (on?1:0)); + iunlock(ctlr); +} + +void +w_interrupt(Ureg* ,void* arg) +{ + Ether* ether = (Ether*) arg; + Ctlr* ctlr = (Ctlr*) ether->ctlr; + + if(ctlr == 0) + return; + ilock(ctlr); + ctlr->nints++; + w_intr(ether); + iunlock(ctlr); +} + +int +wavelanreset(Ether* ether, Ctlr *ctlr) +{ + Wltv ltv; + + iprint("wavelanreset, iob 0x%ux\n", ctlr->iob); + w_intdis(ctlr); + if(w_cmd(ctlr,WCmdIni,0)){ + iprint("#l%d: init failed\n", ether->ctlrno); + return -1; + } + w_intdis(ctlr); + ltv_outs(ctlr, WTyp_Tick, 8); + + ctlr->chan = 0; + ctlr->ptype = WDfltPType; + ctlr->txkey = 0; + ctlr->createibss = 0; + ctlr->keys.len = sizeof(WKey)*WNKeys/2 + 1; + ctlr->keys.type = WTyp_Keys; + if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt)) + ctlr->crypt = 1; + *ctlr->netname = *ctlr->wantname = 0; + strcpy(ctlr->nodename, "Plan 9 STA"); + + ctlr->netname[WNameLen-1] = 0; + ctlr->wantname[WNameLen-1] = 0; + ctlr->nodename[WNameLen-1] =0; + + ltv.type = WTyp_Mac; + ltv.len = 4; + if(w_inltv(ctlr, <v)){ + iprint("#l%d: unable to read mac addr\n", + ether->ctlrno); + return -1; + } + memmove(ether->ea, ltv.addr, Eaddrlen); + + if(ctlr->chan == 0) + ctlr->chan = ltv_ins(ctlr, WTyp_Chan); + ctlr->apdensity = WDfltApDens; + ctlr->rtsthres = WDfltRtsThres; + ctlr->txrate = WDfltTxRate; + ctlr->maxlen = WMaxLen; + ctlr->pmena = 0; + ctlr->pmwait = 100; + ctlr->signal = 1; + ctlr->noise = 1; + ctlr->state |= Power; + + // free old Ctlr struct if resetting after suspend + if(ether->ctlr && ether->ctlr != ctlr) + free(ether->ctlr); + + // link to ether + ether->ctlr = ctlr; + ether->mbps = 10; + ether->attach = w_attach; + ether->detach = w_detach; + ether->interrupt = w_interrupt; + ether->transmit = w_transmit; + ether->ifstat = w_ifstat; + ether->ctl = w_ctl; + ether->power = w_power; + ether->promiscuous = w_promiscuous; + ether->multicast = w_multicast; + ether->arg = ether; + + iprint("#l%d: irq %ld port %lx type %s", + ether->ctlrno, ether->intnum, ether->ports[0].port, ether->type); + iprint(" %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n", + ether->ea[0], ether->ea[1], ether->ea[2], + ether->ea[3], ether->ea[4], ether->ea[5]); + + return 0; +} + +char* wavenames[] = { + "WaveLAN/IEEE", + "TrueMobile 1150", + "Instant Wireless ; Network PC CARD", + "Avaya Wireless PC Card", + "AirLancer MC-11", + nil, +}; + diff --git a/bitsy/wavelan.h b/bitsy/wavelan.h index ceda19381b44a7f7605911f4b7c0bd2c6bcdc964..c3db893c144ec48fa5f34c7ee7122b0e6c91ec08 100644 --- a/bitsy/wavelan.h +++ b/bitsy/wavelan.h @@ -1,4 +1 @@ -typedef struct Pcidev Pcidev; -/* not used, but needed in a struct declaration */ - #include "../pc/wavelan.h" diff --git a/ip/ipifc.c b/ip/ipifc.c index 586b2aa771bb5320b91b325d1a1585987255d22b..e2068ef9585de50893c8cf49e8a8a194d2da116d 100644 --- a/ip/ipifc.c +++ b/ip/ipifc.c @@ -579,7 +579,7 @@ ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock) /* * find address on this interface and remove from chain. - * for pt to pt we actually specify the remote address at the + * for pt to pt we actually specify the remote address as the * addresss to remove. */ l = &ifc->lifc;