M bitsy/clock.c => bitsy/clock.c +78 -4
@@ 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;
@@ 125,6 167,38 @@ clockintr(Ureg *ureg, void*)
}
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)
{
ulong start;
M bitsy/dat.h => bitsy/dat.h +13 -6
@@ 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 */
};
+
M bitsy/devether.c => bitsy/devether.c +5 -5
@@ 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]);
M bitsy/devpcmcia.c => bitsy/devpcmcia.c +90 -9
@@ 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;
+}
M bitsy/devpenmouse.c => bitsy/devpenmouse.c +1 -0
@@ 474,6 474,7 @@ penmousetrack(int b, int x, int y)
}
wakeup(&mouse.r);
drawactive(1);
+ resetsuspendtimer();
}
int
M bitsy/devuda1341.c => bitsy/devuda1341.c +2 -2
@@ 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));
}
M bitsy/devµc.c => bitsy/devµc.c +20 -6
@@ 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);
}
M bitsy/etherwavelan.c => bitsy/etherwavelan.c +10 -4
@@ 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);
M bitsy/fns.h => bitsy/fns.h +3 -2
@@ 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);
M bitsy/io.h => bitsy/io.h +11 -0
@@ 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; };
M bitsy/main.c => bitsy/main.c +12 -6
@@ 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;
+}
M bitsy/power.c => bitsy/power.c +71 -1
@@ 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<<IRQgpio0);
intrregs->icip = (1<<IRQgpio0);
}
- clockpower(1);
+ clkd = clockpower(1);
gpclkregs->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();
}
}
+
D bitsy/sd.h => bitsy/sd.h +0 -125
@@ 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*);
M bitsy/sdata.c => bitsy/sdata.c +40 -14
@@ 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 */
};
M bitsy/uartsa1110.c => bitsy/uartsa1110.c +3 -3
@@ 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;
M bitsy/wavelan.c => bitsy/wavelan.c +1150 -1
@@ 1,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; i<WTmOut; i++)
+ if((csr_ins(ctlr, WR_Cmd)&WCmdBusy) == 0)
+ break;
+ if(i==WTmOut){
+ print("#l%d: issuing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_Cmd));
+ return -1;
+ }
+
+ csr_outs(ctlr, WR_Parm0, arg);
+ csr_outs(ctlr, WR_Cmd, cmd);
+
+ for(i=0; i<WTmOut; i++)
+ if(csr_ins(ctlr, WR_EvSts)&WCmdEv)
+ break;
+ if(i==WTmOut){
+ /*
+ * WCmdIni can take a really long time.
+ */
+ enum { IniTmOut = 2000 };
+ for(i=0; i<IniTmOut; i++){
+ if(csr_ins(ctlr, WR_EvSts)&WCmdEv)
+ break;
+ microdelay(100);
+ }
+ if(i < IniTmOut)
+ if(0) print("#l%d: long cmd %.4ux %d\n", ctlr->ctlrno, 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; i<WTmOut; i++){
+ rc = csr_ins(ctlr, off[chan]);
+ if((rc & (WBusyOff|WErrOff)) == 0)
+ return 0;
+ }
+ return -1;
+}
+
+int
+w_inltv(Ctlr* ctlr, Wltv* ltv)
+{
+ int len;
+ ushort code;
+
+ if(w_cmd(ctlr, WCmdAccRd, ltv->type)){
+ 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; i<WTmOut; i++)
+ if(csr_ins(ctlr, WR_EvSts) & WAllocEv){
+ csr_ack(ctlr, WAllocEv);
+ rc=csr_ins(ctlr, WR_Alloc);
+ if(w_seek(ctlr, rc, 0, 0))
+ return -1;
+ len = len/2;
+ for (j=0; j<len; j++)
+ csr_outs(ctlr, WR_Data0, 0);
+ return rc;
+ }
+ return -1;
+}
+
+static int
+w_enable(Ether* ether)
+{
+ Wltv ltv;
+ Ctlr* ctlr = (Ctlr*) ether->ctlr;
+
+ 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,
+};
+
M bitsy/wavelan.h => bitsy/wavelan.h +0 -3
@@ 1,4 1,1 @@
-typedef struct Pcidev Pcidev;
-/* not used, but needed in a struct declaration */
-
#include "../pc/wavelan.h"
M ip/ipifc.c => ip/ipifc.c +1 -1
@@ 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;