From afec3802f7a9437fb2169cf0edff22699c17e708 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 4 Apr 1997 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1997-04-04 --- carrera/devrtc.c | 185 +++++++++++++++-------------------------------- ip/il.c | 2 +- pc/archgeneric.c | 3 +- pc/audio.h | 2 +- pc/devether.c | 11 +++ pc/devfloppy.c | 8 +- pc/dma.c | 39 ++++++---- pc/etherelnk3.c | 7 +- pc/fns.h | 2 +- pc/main.c | 1 - port/netif.c | 92 +++++++++++++++++++---- port/netif.h | 14 ++-- port/qio.c | 5 ++ 13 files changed, 206 insertions(+), 165 deletions(-) diff --git a/carrera/devrtc.c b/carrera/devrtc.c index af6fe6424fe1e4eb6c859aa00a0f4810f3b586be..246dcb437c21fac49d629e9737b865b088542eb4 100644 --- a/carrera/devrtc.c +++ b/carrera/devrtc.c @@ -20,8 +20,6 @@ struct Rtc int mon; int year; }; -static QLock rtclock; /* mutex on clock operations */ - enum { @@ -39,11 +37,16 @@ enum StatusC= 0x0C, StatusD= 0x0D, + Update= 0x80, + Nvsize = 4096, Nclock= 6, }; +#define GETBCD(v) (((v) & 0x0F) + 10*((v)>>4)) +#define PUTBCD(v) ((v) % 10)|((((v)/10) % 10)<<4) + Dirtab rtcdir[]={ "nvram", {Qnvram, 0}, Nvsize, 0664, "rtc", {Qrtc, 0}, 0, 0664, @@ -52,10 +55,11 @@ Dirtab rtcdir[]={ static ulong rtc2sec(Rtc*); static void sec2rtc(ulong, Rtc*); -static uchar statusB; +static int isbinary; +static Lock rtclock; static void -getstatusB(void) +rtcreset(void) { int i, x; uchar r; @@ -68,7 +72,7 @@ getstatusB(void) continue; *(uchar*)Rtcindex = x|StatusB; - statusB = *(uchar*)Rtcdata; + isbinary = *(uchar*)Rtcdata & 0x04; break; } } @@ -76,7 +80,6 @@ getstatusB(void) static Chan* rtcattach(char *spec) { - getstatusB(); return devattach('r', spec); } @@ -114,106 +117,51 @@ rtcclose(Chan *c) USED(c); } -static uchar -bcd2binary(int reg) -{ - uchar x; - - x = (*(uchar*)Rtcindex)&~0x7f; - *(uchar*)Rtcindex = x|reg; - x = *(uchar*)Rtcdata; - return (x&0xf) + 10*(x>>4); -} - -#define GETBCD(o) ((clock[o]&0xf) + 10*(clock[o]>>4)) - -static void -dumprtcstatus(void) -{ - int i, x; - uchar status[4], r; - - for(i = 0; i < 10000; i++){ - x = (*(uchar*)Rtcindex)&~0x7f; - *(uchar*)Rtcindex = x|Status; - r = *(uchar*)Rtcdata; - if(r & 0x80) - continue; - - status[0] = r; - *(uchar*)Rtcindex = x|StatusB; - status[1] = *(uchar*)Rtcdata; - *(uchar*)Rtcindex = x|StatusC; - status[2] = *(uchar*)Rtcdata; - *(uchar*)Rtcindex = x|StatusD; - status[3] = *(uchar*)Rtcdata; - - *(uchar*)Rtcindex = x|Status; - r = *(uchar*)Rtcdata; - if((r & 0x80) == 0) - break; - } - - print("RTC: %uX %uX %uX %uX\n", status[0], status[1], status[2], status[3]); -} - static long _rtctime(void) { Rtc rtc; int i, x; - uchar clock[Nclock], r; - int busy; + uchar r; /* don't do the read until the clock is no longer busy */ - busy = 0; for(i = 0; i < 10000; i++){ x = (*(uchar*)Rtcindex)&~0x7f; *(uchar*)Rtcindex = x|Status; r = *(uchar*)Rtcdata; - if(r & 0x80){ - busy++; + if(r & Update) continue; - } /* read clock values */ *(uchar*)Rtcindex = x|Seconds; - clock[0] = *(uchar*)Rtcdata; + rtc.sec = *(uchar*)Rtcdata; *(uchar*)Rtcindex = x|Minutes; - clock[1] = *(uchar*)Rtcdata; + rtc.min = *(uchar*)Rtcdata; *(uchar*)Rtcindex = x|Hours; - clock[2] = *(uchar*)Rtcdata; + rtc.hour = *(uchar*)Rtcdata; *(uchar*)Rtcindex = x|Mday; - clock[3] = *(uchar*)Rtcdata; + rtc.mday = *(uchar*)Rtcdata; *(uchar*)Rtcindex = x|Month; - clock[4] = *(uchar*)Rtcdata; + rtc.mon = *(uchar*)Rtcdata; *(uchar*)Rtcindex = x|Year; - clock[5] = *(uchar*)Rtcdata; + rtc.year = *(uchar*)Rtcdata; *(uchar*)Rtcindex = x|Status; r = *(uchar*)Rtcdata; - if((r & 0x80) == 0) + if((r & Update) == 0) break; } - if(statusB & 0x04){ - rtc.sec = clock[0]; - rtc.min = clock[1]; - rtc.hour = clock[2]; - rtc.mday = clock[3]; - rtc.mon = clock[4]; - rtc.year = clock[5]; - } - else{ + if(!isbinary){ /* * convert from BCD */ - rtc.sec = GETBCD(0); - rtc.min = GETBCD(1); - rtc.hour = GETBCD(2); - rtc.mday = GETBCD(3); - rtc.mon = GETBCD(4); - rtc.year = GETBCD(5); + rtc.sec = GETBCD(rtc.sec); + rtc.min = GETBCD(rtc.min); + rtc.hour = GETBCD(rtc.hour); + rtc.mday = GETBCD(rtc.mday); + rtc.mon = GETBCD(rtc.mon); + rtc.year = GETBCD(rtc.year); } /* @@ -224,17 +172,13 @@ _rtctime(void) return rtc2sec(&rtc); } -static Lock rtlock; - long rtctime(void) { -#define notdef -#ifdef notdef int i; long t, ot; - ilock(&rtlock); + ilock(&rtclock); /* loop till we get two reads in a row the same */ t = _rtctime(); @@ -244,22 +188,14 @@ rtctime(void) if(ot == t) break; } - iunlock(&rtlock); - - if(i == 100) print("we are boofheads\n"); + iunlock(&rtclock); return t; -#else - extern ulong boottime; - - return boottime+TK2SEC(MACHP(0)->ticks); -#endif /* notdef */ } static long rtcread(Chan *c, void *buf, long n, ulong offset) { - ulong t; uchar *f, *to, *e; if(c->qid.path & CHDIR) @@ -267,12 +203,7 @@ rtcread(Chan *c, void *buf, long n, ulong offset) switch(c->qid.path){ case Qrtc: - qlock(&rtclock); - t = rtctime(); -dumprtcstatus(); - qunlock(&rtclock); - n = readnum(offset, buf, n, t, 12); - return n; + return readnum(offset, buf, n, rtctime(), 12); case Qnvram: if(offset > Nvsize) return -1; @@ -289,20 +220,6 @@ dumprtcstatus(); return 0; } -static void -binary2bcd(int reg, uchar val) -{ - uchar x; - - x = (*(uchar*)Rtcindex)&~0x7f; - *(uchar*)Rtcindex = x|reg; - if(statusB & 0x04) - *(uchar*)Rtcdata = val; - else - *(uchar*)Rtcdata = (val % 10) | (((val / 10) % 10)<<4); -} - - static long rtcwrite(Chan *c, void *buf, long n, ulong offset) { @@ -310,7 +227,7 @@ rtcwrite(Chan *c, void *buf, long n, ulong offset) ulong secs; char *cp, *ep; uchar *f, *t, *e; - int s; + uchar x; USED(c); switch(c->qid.path){ @@ -327,18 +244,36 @@ rtcwrite(Chan *c, void *buf, long n, ulong offset) } secs = strtoul(cp, 0, 0); sec2rtc(secs, &rtc); - - /* - * convert to bcd - */ - s = splhi(); - binary2bcd(Seconds, rtc.sec); - binary2bcd(Minutes, rtc.min); - binary2bcd(Hours, rtc.hour); - binary2bcd(Mday, rtc.mday); - binary2bcd(Month, rtc.mon); - binary2bcd(Year, rtc.year-1970); - splx(s); + rtc.year -= 1970; + + if(!isbinary){ + /* + * convert to bcd + */ + rtc.sec = PUTBCD(rtc.sec); + rtc.min = PUTBCD(rtc.min); + rtc.hour = PUTBCD(rtc.hour); + rtc.mday = PUTBCD(rtc.mday); + rtc.mon = PUTBCD(rtc.mon); + rtc.year = PUTBCD(rtc.year); + } + + ilock(&rtclock); + /* set clock values */ + x = (*(uchar*)Rtcindex)&~0x7f; + *(uchar*)Rtcindex = x|Seconds; + *(uchar*)Rtcdata = rtc.sec; + *(uchar*)Rtcindex = x|Minutes; + *(uchar*)Rtcdata = rtc.min; + *(uchar*)Rtcindex = x|Hours; + *(uchar*)Rtcdata = rtc.hour; + *(uchar*)Rtcindex = x|Mday; + *(uchar*)Rtcdata = rtc.mday; + *(uchar*)Rtcindex = x|Month; + *(uchar*)Rtcdata = rtc.mon; + *(uchar*)Rtcindex = x|Year; + *(uchar*)Rtcdata = rtc.year; + iunlock(&rtclock); return n; case Qnvram: @@ -358,7 +293,7 @@ rtcwrite(Chan *c, void *buf, long n, ulong offset) } Dev rtcdevtab = { - devreset, + rtcreset, devinit, rtcattach, devclone, diff --git a/ip/il.c b/ip/il.c index 0d6da926eb590629b030455fe7583d6be2479a61..171632466f7b5a51f7c3158638b141b84a32a1b8 100644 --- a/ip/il.c +++ b/ip/il.c @@ -184,7 +184,7 @@ ilannounce(Conv *c, char **argv, int argc) char *e; e = Fsstdannounce(c, argv, argc); - if(e != nil); + if(e != nil) return e; e = ilstart(c, IL_LISTEN, 20); if(e != nil) diff --git a/pc/archgeneric.c b/pc/archgeneric.c index 031a14154ace608c63312ad86dc66452928967ad..0d316c0846b7e22400415f4e392738fd2e8193d0 100644 --- a/pc/archgeneric.c +++ b/pc/archgeneric.c @@ -56,9 +56,10 @@ static X86type x86type[] = { 5, 1, 23, "P5", }, { 5, 2, 23, "P54C", }, { 5, 3, 23, "P24T", }, /* PODP5V83 */ - { 5, 4, 23, "PODP54", }, + { 5, 4, 23, "P54C MMX", }, { 5, 5, 23, "PODDX4", }, { 5, 6, 23, "PODP5", }, + { 5, 7, 23, "P54C VRT", }, { 6, 4, 23, "P55CT", }, { 6, 1, 16, "PentiumPro", },/* determined by trial and error */ diff --git a/pc/audio.h b/pc/audio.h index 553979ad8cc545e15555e622e4cdaefb0560fdc8..bf4c12312e595bfb84aad62bf03fc55a0229b318 100644 --- a/pc/audio.h +++ b/pc/audio.h @@ -6,7 +6,7 @@ enum SBswab = 0, }; -#define seteisadma(a, b) ; +#define seteisadma(a, b) dmainit(a); #define CACHELINESZ 8 #define UNCACHED(type, v) (type*)((ulong)(v)) diff --git a/pc/devether.c b/pc/devether.c index ffcd25fa897440769e1a6731c058795a84de9ed9..e8b51b2f195b7c58763df0f84abf4a14b6c9613f 100644 --- a/pc/devether.c +++ b/pc/devether.c @@ -145,6 +145,17 @@ etheriq(Ether* ether, Block* bp, int freebp) fx = 0; ep = ðer->f[Ntypes]; + /* check for valid multcast addresses */ + if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){ + if(!activemulti(ether, pkt->d, sizeof(pkt->d))){ + if(freebp){ + freeb(bp); + bp = 0; + } + return bp; + } + } + /* * Multiplex the packet to all the connections which want it. * If the packet is not to be used subsequently (freebp != 0), diff --git a/pc/devfloppy.c b/pc/devfloppy.c index 73d04dca7b85a93f80e79aa7cc3565347ee4ca22..b1b30b6690119b75e1b8051c596ce0263f74f054 100644 --- a/pc/devfloppy.c +++ b/pc/devfloppy.c @@ -19,6 +19,7 @@ * floppyeject() * floppysetup0() * floppysetup1() + * dmainit() * dmasetup() * dmaend() * @@ -143,6 +144,8 @@ floppyreset(void) FDrive *dp; FType *t; ulong maxtsize; + + dmainit(DMAchan); floppysetup0(&fl); @@ -793,6 +796,8 @@ floppyxfer(FDrive *dp, int cmd, void *a, long off, long n) nexterror(); } dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread); + if(dp->len < 0) + error(Eio); /* * start operation @@ -930,7 +935,8 @@ floppyformat(FDrive *dp, char *params) dmaend(DMAchan); nexterror(); } - dmasetup(DMAchan, buf, bp-buf, 0); + if(dmasetup(DMAchan, buf, bp-buf, 0) < 0) + error(Eio); /* * start operation diff --git a/pc/dma.c b/pc/dma.c index a62b2872385622deedd3fdbe9af6a2c3d588e077..ff566d8caf4df713c9c06b640bc7055a5f757eb5 100644 --- a/pc/dma.c +++ b/pc/dma.c @@ -79,26 +79,33 @@ DMA dma[2] = { }; /* - * DMA must be in the first 16 meg. This gets called early by main() to - * ensure that. + * DMA must be in the first 16MB. This gets called early by the + * initialisation routines of any devices which require DMA to ensure + * the allocated bounce buffers are below the 16MB limit. */ void -dmainit(void) +dmainit(int chan) { - int i, chan; DMA *dp; DMAxfer *xp; + ulong v; - for(i = 0; i < 2; i++){ - dp = &dma[i]; - for(chan = 0; chan < 4; chan++){ - xp = &dp->x[chan]; - xp->bva = xspanalloc(BY2PG, BY2PG, 0); - xp->bpa = PADDR(xp->bva); - xp->len = 0; - xp->isread = 0; - } + dp = &dma[(chan>>2)&1]; + chan = chan & 3; + xp = &dp->x[chan]; + if(xp->bva != nil) + return; + + v = (ulong)xalloc(BY2PG+BY2PG); + if(v == 0 || PADDR(v) >= 16*MB){ + print("dmainit: chan %d: 0x%luX out of range\n", chan, v); + xfree((void*)v); + v = 0; } + xp->bva = (void*)ROUND(v, BY2PG); + xp->bpa = PADDR(xp->bva); + xp->len = 0; + xp->isread = 0; } /* @@ -131,6 +138,8 @@ dmasetup(int chan, void *va, long len, int isread) if((((ulong)va)&0xF0000000) != KZERO || (pa&0xFFFF0000) != ((pa+len)&0xFFFF0000) || pa > 16*MB) { + if(xp->bva == nil) + return -1; if(len > BY2PG) len = BY2PG; if(!isread) @@ -205,7 +214,8 @@ dmaend(int chan) memmove(xp->va, xp->bva, xp->len); xp->len = 0; } - + +/* int dmacount(int chan) { @@ -218,3 +228,4 @@ dmacount(int chan) retval |= inb(dp->count[chan]) << 8; return((retval<shift)+1); } + */ diff --git a/pc/etherelnk3.c b/pc/etherelnk3.c index 3270d1ddff789b4b8c65725a54fd5565a2fb4baa..7459de517746e7710efc882dec5e78442b48725a 100644 --- a/pc/etherelnk3.c +++ b/pc/etherelnk3.c @@ -457,14 +457,17 @@ promiscuous(void* arg, int on) } static void -multicast(void* arg, char *addr, int on) +multicast(void* arg, uchar *addr, int on) { int filter, port; Ether *ether; + USED(addr, on); + ether = (Ether*)arg; port = ether->port; +print("mutlicast nmaddr == %d\n", ether->nmaddr); filter = receiveBroadcast|receiveIndividual; if(ether->nmaddr) filter |= receiveMulticast; @@ -1314,6 +1317,7 @@ etherelnk3reset(Ether* ether) rxstatus9 = 1; break; } + USED(did); /* * Check if the adapter's station address is to be overridden. @@ -1436,6 +1440,7 @@ etherelnk3reset(Ether* ether) ether->ifstat = ifstat; ether->promiscuous = promiscuous; + ether->multicast = multicast; ether->arg = ether; return 0; diff --git a/pc/fns.h b/pc/fns.h index 90e2d5cba880ce5f1062f579e825b09f2813dc9a..8f7101caa41b42ff8fc83088ebded20735e88ae3 100644 --- a/pc/fns.h +++ b/pc/fns.h @@ -18,7 +18,7 @@ void delay(int); int dmacount(int); int dmadone(int); void dmaend(int); -void dmainit(void); +void dmainit(int); long dmasetup(int, void*, long, int); #define evenaddr(x) /* x86 doesn't care */ void fpenv(FPsave*); diff --git a/pc/main.c b/pc/main.c index ee96e45996585bf0a77188c9ead73946cfa72bb5..e87231867867d84b3fc462d35f500ae480a14651 100644 --- a/pc/main.c +++ b/pc/main.c @@ -138,7 +138,6 @@ main(void) confinit(); archinit(); xinit(); - dmainit(); trapinit(); printinit(); if(isoldbcom) diff --git a/port/netif.c b/port/netif.c index bdb7138fc99c59b445a6182f92bbbf6af7305b93..69f0d251ef773b9ac91a558d2b65edb500084e65 100644 --- a/port/netif.c +++ b/port/netif.c @@ -9,7 +9,8 @@ static int netown(Netfile*, char*, int); static int openfile(Netif*, int); static char* matchtoken(char*, char*); -static void netmulti(Netif*, Netfile*, char*, int); +static char* netmulti(Netif*, Netfile*, uchar*, int); +static int parseaddr(uchar*, char*, int); /* * set up a new network interface @@ -215,6 +216,7 @@ netifwrite(Netif *nif, Chan *c, void *a, long n) Netfile *f; char *p; char buf[256]; + uchar binaddr[Nmaxaddr]; if(NETTYPE(c->qid.path) != Nctlqid) error(Eperm); @@ -224,6 +226,11 @@ netifwrite(Netif *nif, Chan *c, void *a, long n) memmove(buf, a, n); buf[n] = 0; + if(waserror()){ + qunlock(nif); + nexterror(); + } + qlock(nif); f = nif->f[NETID(c->qid.path)]; if((p = matchtoken(buf, "connect")) != 0){ @@ -236,11 +243,20 @@ netifwrite(Netif *nif, Chan *c, void *a, long n) if(nif->prom == 1 && nif->promiscuous != nil) nif->promiscuous(nif->arg, 1); } else if((p = matchtoken(buf, "addmulti")) != 0){ - netmulti(nif, f, p, 1); + if(parseaddr(binaddr, p, nif->alen) < 0) + error("bad address"); + p = netmulti(nif, f, binaddr, 1); + if(p) + error(p); } else if((p = matchtoken(buf, "remmulti")) != 0){ - netmulti(nif, f, p, 0); + if(parseaddr(binaddr, p, nif->alen) < 0) + error("bad address"); + p = netmulti(nif, f, binaddr, 0); + if(p) + error(p); } qunlock(nif); + poperror(); return n; } @@ -461,26 +477,71 @@ nhgets(void *p) return (a[0]<<8)|(a[1]<<0); } +static ulong +hash(uchar *a, int len) +{ + ulong sum = 0; + + while(len-- > 0) + sum = (sum << 1) + *a++; + return sum%Nmhash; +} + +int +activemulti(Netif *nif, uchar *addr, int alen) +{ + Netaddr *hp; + + for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext) + if(memcmp(addr, hp->addr, alen) == 0){ + if(hp->ref) + return 1; + else + break; + } + return 0; +} + +static int +parseaddr(uchar *to, char *from, int alen) +{ + char nip[4]; + char *p; + int i; + + p = from; + for(i = 0; i < alen; i++){ + if(*p == 0) + return -1; + nip[0] = *p++; + if(*p == 0) + return -1; + nip[1] = *p++; + nip[2] = 0; + to[i] = strtoul(nip, 0, 16); + if(*p == ':') + p++; + } + return 0; +} + /* * keep track of multicast addresses */ -static void -netmulti(Netif *nif, Netfile *f, char *addr, int add) +static char* +netmulti(Netif *nif, Netfile *f, uchar *addr, int add) { Netaddr **l, *ap; int i; - uchar hexaddr[Nmaxaddr]; + ulong h; if(nif->multicast == nil) - return; - - if(strlen(addr) != 2*nif->alen) - return; + return "interface does not support multicast"; l = &nif->maddr; i = 0; for(ap = *l; ap; ap = *l){ - if(strcmp(addr, ap->addr) == 0) + if(memcmp(addr, ap->addr, nif->alen) == 0) break; i++; l = &ap->next; @@ -489,10 +550,12 @@ netmulti(Netif *nif, Netfile *f, char *addr, int add) if(add){ if(ap == 0){ *l = ap = smalloc(sizeof(*ap)); - ap->addr = smalloc(strlen(addr)+1); - strcpy(ap->addr, addr); + memmove(ap->addr, addr, nif->alen); ap->next = 0; ap->ref = 1; + h = hash(addr, nif->alen); + ap->hnext = nif->mhash[h]; + nif->mhash[h] = ap; } else { ap->ref++; } @@ -507,7 +570,7 @@ netmulti(Netif *nif, Netfile *f, char *addr, int add) } } else { if(ap == 0 || ap->ref == 0) - return; + return 0; ap->ref--; if(ap->ref == 0){ nif->nmaddr--; @@ -519,4 +582,5 @@ netmulti(Netif *nif, Netfile *f, char *addr, int add) f->maddr[i/8] &= ~(1<<(i%8)); } } + return 0; } diff --git a/port/netif.h b/port/netif.h index f276bd8c23f0ecd41af72ac16a8ac232e35654a5..567d49be594f8b700b0ba8cb17b63358970104b7 100644 --- a/port/netif.h +++ b/port/netif.h @@ -6,6 +6,7 @@ typedef struct Netif Netif; enum { Nmaxaddr= 64, + Nmhash= 31, Ncloneqid= 1, N2ndqid, @@ -48,8 +49,9 @@ struct Netfile */ struct Netaddr { - Netaddr *next; - char *addr; + Netaddr *next; /* allocation chain */ + Netaddr *hnext; + uchar addr[Nmaxaddr]; int ref; }; @@ -70,8 +72,9 @@ struct Netif int alen; /* address length */ uchar addr[Nmaxaddr]; uchar bcast[Nmaxaddr]; - Netaddr *maddr; /* multicast addresses */ - int nmaddr; /* number of multicast addresses */ + Netaddr *maddr; /* known multicast addresses */ + int nmaddr; /* number of known multicast addresses */ + Netaddr *mhash[Nmhash]; /* hash table of multicast addresses */ int prom; /* number of promiscuous opens */ int all; /* number of -1 multiplexors */ @@ -89,7 +92,7 @@ struct Netif /* routines for touching the hardware */ void *arg; void (*promiscuous)(void*, int); - void (*multicast)(void*, char*, int); + void (*multicast)(void*, uchar*, int); }; void netifinit(Netif*, char*, int, ulong); @@ -101,6 +104,7 @@ Block* netifbread(Netif*, Chan*, long, ulong); long netifwrite(Netif*, Chan*, void*, long); void netifwstat(Netif*, Chan*, char*); void netifstat(Netif*, Chan*, char*); +int activemulti(Netif*, uchar*, int); /* * Ethernet specific diff --git a/port/qio.c b/port/qio.c index a54992f3918bc3a2cc4eecccf9f23375f849c066..dab1669e8c0928fe6e63b771b5dc1f0f594db906 100644 --- a/port/qio.c +++ b/port/qio.c @@ -586,6 +586,11 @@ qpass(Queue *q, Block *b) /* sync with qread */ dowakeup = 0; ilock(q); + if(q->len >= q->limit){ + freeb(b); + iunlock(q); + return -1; + } /* add buffer to queue */ if(q->bfirst)