M pc/clock.c => pc/clock.c +0 -1
@@ 62,7 62,6 @@ clock(Ureg *ur)
m->ticks++;
checkalarms();
- mouseclock();
/*
* process time accounting
M pc/devfloppy.c => pc/devfloppy.c +6 -29
@@ 31,12 31,6 @@ enum
DMAchan= 2, /* floppy dma channel */
- /* sector size encodings */
- S128= 0,
- S256= 1,
- S512= 2,
- S1024= 3,
-
/* status 0 byte */
Drivemask= 3<<0,
Seekend= 1<<5,
@@ 45,7 39,6 @@ enum
/* file types */
Qdir= 0,
Qdata= (1<<2),
- Qstruct= (2<<2),
Qmask= (3<<2),
};
@@ 163,14 156,10 @@ static long floppyxfer(Drive*, int, void*, long, long);
static void floppyintr(Ureg*);
Dirtab floppydir[]={
- "fd0data", {Qdata + 0}, 0, 0600,
- "fd0struct", {Qstruct + 0}, 8, 0600,
- "fd1data", {Qdata + 1}, 0, 0600,
- "fd1struct", {Qstruct + 1}, 8, 0600,
- "fd2data", {Qdata + 2}, 0, 0600,
- "fd2struct", {Qstruct + 2}, 8, 0600,
- "fd3data", {Qdata + 3}, 0, 0600,
- "fd3struct", {Qstruct + 3}, 8, 0600,
+ "fd0disk", {Qdata + 0}, 0, 0600,
+ "fd1disk", {Qdata + 1}, 0, 0600,
+ "fd2disk", {Qdata + 2}, 0, 0600,
+ "fd3disk", {Qdata + 3}, 0, 0600,
};
#define NFDIR 2 /* directory entries/drive */
@@ 337,15 326,6 @@ floppyread(Chan *c, void *a, long n)
memmove(aa+rv, dp->ccache + (sec-1)*dp->t->bytes, len);
}
break;
- case Qstruct:
- if (n < 2*sizeof(ulong))
- error(Ebadarg);
- if (c->offset >= 2*sizeof(ulong))
- return 0;
- rv = 2*sizeof(ulong);
- ul2user((uchar*)a, dp->t->cap);
- ul2user((uchar*)a+sizeof(ulong), dp->t->bytes);
- break;
default:
panic("floppyread: bad qid");
}
@@ 369,9 349,6 @@ floppywrite(Chan *c, void *a, long n)
break;
}
break;
- case Qstruct:
- error(Eperm);
- break;
default:
panic("floppywrite: bad qid");
}
@@ 733,7 710,7 @@ floppyxfer(Drive *dp, int cmd, void *a, long off, long n)
if(floppyseek(dp) < 0)
errors("seeking floppy");
-print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n",
+/*print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n",
dp->tcyl, dp->thead, dp->tsec, addr, n);/**/
/*
@@ 797,7 774,7 @@ print("new offset %d instead of %d\n", offset, off+dp->len);
static void
floppyintr(Ureg *ur)
{
-print("floppy intr\n");
+/*print("floppy intr\n");/**/
floppy.intr = 1;
wakeup(&floppy.r);
}
M pc/devuart.c => pc/devuart.c +32 -10
@@ 1,4 1,4 @@
-
#include "u.h"
+#include "u.h"
#include "lib.h"
#include "mem.h"
#include "dat.h"
@@ 18,6 18,10 @@ enum
*/
Data= 0, /* xmit/rcv buffer */
Iena= 1, /* interrupt enable */
+ Ircv= (1<<0), /* for char rcv'd */
+ Ixmt= (1<<1), /* for xmit buffer empty */
+ Irstat=(1<<2), /* for change in rcv'er status */
+ Imstat=(1<<3), /* for change in modem status */
Istat= 2, /* interrupt flag (read) */
Tctl= 2, /* test control (write) */
Format= 3, /* byte format */
@@ 36,7 40,9 @@ enum
Loop= (1<<4), /* loop bask */
Lstat= 5, /* line status */
Inready=(1<<0), /* receive buffer full */
- Overrun=(1<<1), /* we lost an input char */
+ Oerror=(1<<1), /* receiver overrun */
+ Perror=(1<<2), /* receiver parity error */
+ Ferror=(1<<3), /* rcv framing error */
Outready=(1<<5), /* output buffer full */
Mstat= 6, /* modem status */
Scratch=7, /* scratchpad */
@@ 67,6 73,10 @@ struct Uart
Alarm *a; /* alarm for waking the kernel process */
int kstarted; /* kproc started */
uchar delim[256/8]; /* characters that act as delimiters */
+
+ /* error statistics */
+ ulong frame;
+ ulong overrun;
};
Uart uart[2];
@@ 213,14 223,15 @@ uartintr(Uart *up)
IOQ *cq;
int s, l;
- /*
- * the for loop takes care of multiple events per interrupt
- */
for(;;){
s = uartrdreg(up, Istat);
switch(s){
case 6: /* receiver line status */
l = uartrdreg(up, Lstat);
+ if(l & Ferror)
+ up->frame++;
+ if(l & Oerror)
+ up->overrun++;
break;
case 4: /* received data available */
@@ 233,9 244,6 @@ uartintr(Uart *up)
if(up->delim[ch/8] & (1<<(ch&7)) )
wakeup(&cq->r);
}
- l = uartrdreg(up, Lstat);
- if(l & Overrun)
- screenputc('!');
break;
case 2: /* transmitter empty */
@@ 257,7 265,7 @@ uartintr(Uart *up)
default:
if(s&1)
return;
- print("weird modem interrupt\n");
+/* print("weird modem interrupt\n");/**/
break;
}
}
@@ 290,6 298,11 @@ uartenable(Uart *up)
}
/*
+ * speed up the clock to poll the uart
+ fclockinit();
+ */
+
+ /*
* set up i/o routines
*/
if(up->oq){
@@ 304,7 317,7 @@ uartenable(Uart *up)
/*
* turn on interrupts
*/
- up->sticky[Iena] = 0x7;
+ up->sticky[Iena] = Ircv | Ixmt | Irstat;
uartwrreg(up, Iena, 0);
/*
@@ 514,6 527,7 @@ uartkproc(void *a)
IOQ *cq = up->iq;
Block *bp;
int n;
+ ulong frame, overrun;
if(waserror())
print("uartkproc got an error\n");
@@ 531,6 545,14 @@ uartkproc(void *a)
PUTNEXT(RD(up->wq), bp);
}
qunlock(up);
+ if(up->frame != frame){
+ kprint("uart%d: %d framing\n", up-uart, up->frame);
+ frame = up->frame;
+ }
+ if(up->overrun != overrun){
+ kprint("uart%d: %d overruns\n", up-uart, up->overrun);
+ overrun = up->overrun;
+ }
}
}
M pc/kbd.c => pc/kbd.c +1 -0
@@ 359,6 359,7 @@ mymouseputc(int c)
mouse.dx = msg[1];
mouse.dy = -msg[2];
mouse.track = 1;
+ spllo(); /* mouse tracking kills uart0 */
mouseclock();
}
}
M pc/main.c => pc/main.c +11 -12
@@ 18,6 18,7 @@ main(void)
confinit();
screeninit();
printinit();
+ print("%lud K bytes of physical memory\n", 1024 + conf.npage1*BY2PG/1024);
mmuinit();
trapinit();
kbdinit();
@@ 141,7 142,15 @@ confinit(void)
int mul;
/*
- * size memory
+ * the first 640k is the standard useful memory
+ * the next 128K is the display
+ * the last 256k belongs to the roms
+ */
+ conf.npage0 = 640/4;
+ conf.base0 = 0;
+
+ /*
+ * size the non-standard memory
*/
x = 0x12345678;
for(i=1; i<16; i++){
@@ 165,17 174,7 @@ confinit(void)
break;
x += 0x3141526;
}
-
- /*
- * the first 640k is the standard useful memory
- */
- conf.npage0 = 640/4;
- conf.base0 = 0;
-
- /*
- * the last 128k belongs to the roms
- */
- conf.npage1 = (i-1)*1024/4;
+ conf.npage1 = (i-2)*1024/4;
conf.base1 = 1024*1024;
conf.npage = conf.npage0 + conf.npage1;
M pc/trap.c => pc/trap.c +19 -24
@@ 79,27 79,27 @@ trapinit(void)
* set all interrupts to panics
*/
for(i = 32; i < 256; i++)
- sethvec(i, intrbad, SEGIG, 0);
+ sethvec(i, intrbad, SEGTG, 0);
/*
* set the standard traps
*/
- sethvec(0, intr0, SEGIG, 0);
- sethvec(1, intr1, SEGIG, 0);
- sethvec(2, intr2, SEGIG, 0);
- sethvec(3, intr3, SEGIG, 0);
- sethvec(4, intr4, SEGIG, 0);
- sethvec(5, intr5, SEGIG, 0);
- sethvec(6, intr6, SEGIG, 0);
- sethvec(7, intr7, SEGIG, 0);
- sethvec(8, intr8, SEGIG, 0);
- sethvec(9, intr9, SEGIG, 0);
- sethvec(10, intr10, SEGIG, 0);
- sethvec(11, intr11, SEGIG, 0);
- sethvec(12, intr12, SEGIG, 0);
- sethvec(13, intr13, SEGIG, 0);
- sethvec(14, intr14, SEGIG, 0);
- sethvec(15, intr15, SEGIG, 0);
+ sethvec(0, intr0, SEGTG, 0);
+ sethvec(1, intr1, SEGTG, 0);
+ sethvec(2, intr2, SEGTG, 0);
+ sethvec(3, intr3, SEGTG, 0);
+ sethvec(4, intr4, SEGTG, 0);
+ sethvec(5, intr5, SEGTG, 0);
+ sethvec(6, intr6, SEGTG, 0);
+ sethvec(7, intr7, SEGTG, 0);
+ sethvec(8, intr8, SEGTG, 0);
+ sethvec(9, intr9, SEGTG, 0);
+ sethvec(10, intr10, SEGTG, 0);
+ sethvec(11, intr11, SEGTG, 0);
+ sethvec(12, intr12, SEGTG, 0);
+ sethvec(13, intr13, SEGTG, 0);
+ sethvec(14, intr14, SEGTG, 0);
+ sethvec(15, intr15, SEGTG, 0);
/*
* set the standard devices
@@ 188,15 188,11 @@ trap(Ureg *ur)
if(c == Int1vec)
outb(Int1ctl, EOI);
outb(Int0ctl, EOI);
+ if(v != Uart0vec)
+ uartintr0(ur);
}
/*
- * check for a waiting character, the uart is at too low
- * a priority level to work correctly at 9600 baud.
- */
- uartintr0(ur);
-
- /*
* call the trap routine
*/
(*ivec[v])(ur);
@@ 270,7 266,6 @@ syscall(Ureg *ur)
u->p->pc = ur->pc;
if((ur->cs)&0xffff == KESEL)
panic("recursive system call");
- spllo();
/*
* do something about floating point!!!
M port/devwren.c => port/devwren.c +202 -194
@@ 7,41 7,41 @@
#include "devtab.h"
#include "io.h"
-typedef struct Part Part;
-typedef struct Disk Disk;
+typedef struct Partition Partition;
+typedef struct Drive Drive;
enum {
- Npart= 2, /* maximum partitions per disk */
+ Npart= 8+2, /* 8 sub partitions, disk, and partition */
Ndisk= 64, /* maximum disks */
+ /* file types */
Qdir= 0,
- Qdata= 16,
- Qstruct= 32,
-
- Mask= 0x7,
};
+#define PART(x) ((x)&0xF)
+#define DRIVE(x) (((x)>>4)&0x7)
+#define MKQID(d,p) (((d)<<4) | (p))
-static Dirtab *wrendir;
-#define NWREN (2*(Npart+1))
-
-struct Part
+struct Partition
{
- ulong firstblock;
- ulong maxblock;
+ ulong start;
+ ulong end;
+ char name[NAMELEN+1];
};
-struct Disk
+
+struct Drive
{
- ulong blocksize;
- Part p[Npart];
+ ulong bytes; /* bytes per block */
+ int npart; /* actual number of partitions */
+ int drive;
+ Partition p[Npart];
};
-static Disk wren[Ndisk];
-
-void wrenint(uchar*, ulong);
+static Drive wren[Ndisk];
#define DATASIZE (8*1024) /* BUG */
-#define BGLONG(p) (((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3])
+static void wrenpart(int);
+static long wrenio(Drive *, Partition *, int, char *, ulong, ulong);
/*
* accepts [0-7].[0-7], or abbreviation
@@ 50,21 50,22 @@ static int
wrendev(char *p)
{
int dev = 0;
- if (p==0 || p[0]==0)
+
+ if(p == 0 || p[0] == 0)
goto out;
- if (p[0]<'0' || p[0]>'7')
+ if(p[0] < '0' || p[0] > '7')
goto cant;
- dev = (p[0]-'0')<<3;
- if (p[1]==0)
+ dev = (p[0] - '0') << 3;
+ if(p[1] == 0)
goto out;
- if (p[1]!='.')
+ if(p[1] != '.')
goto cant;
- if (p[2]==0)
+ if(p[2] == 0)
goto out;
- if (p[2]<'0' || p[2]>'7')
+ if(p[2] < '0' || p[2] > '7')
goto cant;
- dev |= p[2]-'0';
- if (p[3]!=0)
+ dev |= p[2] - '0';
+ if(p[3] != 0)
goto cant;
out:
if(dev >= Ndisk)
@@ 75,58 76,43 @@ cant:
}
static int
-wrengen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp)
+wrengen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp)
{
- long l;
- Part *p;
- Disk *d;
-
- if(s >= ntab)
- return -1;
- if(c->dev >= Ndisk)
+ Qid qid;
+ int drive;
+ char name[NAMELEN+4];
+ Drive *dp;
+ Partition *pp;
+ ulong l;
+
+ qid.vers = 0;
+ drive = s/Npart;
+ s = s % Npart;
+ if(drive >= Ndisk)
return -1;
+ dp = &wren[drive];
- tab += s;
- d = &wren[c->dev];
- p = &d->p[tab->qid.path&Mask];
- if((tab->qid.path&~Mask) == Qdata)
- l = d->blocksize * (p->maxblock - p->firstblock);
- else
- l = 8;
- devdir(c, tab->qid, tab->name, l, tab->perm, dp);
+ if(s >= dp->npart)
+ return 0;
+
+ pp = &dp->p[s];
+ sprint(name, "hd%d%s", drive, pp->name);
+ name[NAMELEN] = 0;
+ qid.path = MKQID(drive, s);
+ l = (pp->end - pp->start) * dp->bytes;
+ devdir(c, qid, name, l, 0600, dirp);
return 1;
}
void
wrenreset(void)
{
- Dirtab *p;
- int i;
-
- p = wrendir = ialloc((Npart+1) * 2 * sizeof(Dirtab), 0);
- for(i = 0; i < Npart; i++){
- sprint(p->name, "data%d", i);
- p->qid.path = Qdata + i;
- p->perm = 0600;
- p++->length = 0;
- sprint(p->name, "struct%d", i);
- p->qid.path = Qstruct + i;
- p->perm = 0600;
- p++->length = 0;
- }
- strcpy(p->name, "data");
- p->qid.path = Qdata + Npart;
- p->perm = 0600;
- p++->length = 0;
- strcpy(p->name, "struct");
- p->qid.path = Qstruct + Npart;
- p->perm = 0600;
- p->length = 0;
}
void
wreninit(void)
-{}
+{
+}
/*
* param is #r<target>.<lun>
@@ 134,34 120,17 @@ wreninit(void)
Chan *
wrenattach(char *param)
{
- uchar buf[32];
- int dev;
Chan *c;
- Disk *d;
- ulong plen;
- int i;
+ int drive;
- dev = wrendev(param);
- scsiready(dev);
- scsisense(dev, buf);
- scsicap(dev, buf);
+ drive = wrendev(param);
+ wrenpart(drive);
c = devattach('r', param);
- c->dev = dev;
- d = &wren[dev];
- d->blocksize = BGLONG(&buf[4]);
-
- plen = BGLONG(&buf[0])+1;
- d->p[Npart].firstblock = 0;
- d->p[Npart].maxblock = plen;
- plen = plen/Npart;
- for(i = 0; i < Npart; i++){
- d->p[i].firstblock = i*plen;
- d->p[i].maxblock = (i+1)*plen;
- }
+ c->dev = drive;
return c;
}
-Chan *
+Chan*
wrenclone(Chan *c, Chan *nc)
{
return devclone(c, nc);
@@ 170,21 139,19 @@ wrenclone(Chan *c, Chan *nc)
int
wrenwalk(Chan *c, char *name)
{
- return devwalk(c, name, wrendir, NWREN, wrengen);
+ return devwalk(c, name, 0, 0, wrengen);
}
void
-wrenstat(Chan *c, char *db)
+wrenstat(Chan *c, char *dp)
{
- devstat(c, db, wrendir, NWREN, wrengen);
+ devstat(c, dp, 0, 0, wrengen);
}
-Chan *
+Chan*
wrenopen(Chan *c, int omode)
{
- if (c->qid.path == Qdata && scsiready(c->dev) != 0)
- error(Eio);
- return devopen(c, omode, wrendir, NWREN, wrengen);
+ return devopen(c, omode, 0, 0, wrengen);
}
void
@@ 195,123 162,164 @@ wrencreate(Chan *c, char *name, int omode, ulong perm)
void
wrenclose(Chan *c)
-{}
+{
+}
+
+void
+wrenremove(Chan *c)
+{
+ error(Eperm);
+}
+
+void
+wrenwstat(Chan *c, char *dp)
+{
+ error(Eperm);
+}
long
wrenread(Chan *c, char *a, long n, ulong offset)
{
- Scsi *cmd;
- ulong lbn;
- Part *p;
- Disk *d;
+ Drive *d;
+ Partition *p;
- if (n == 0)
- return 0;
if(c->qid.path == CHDIR)
- return devdirread(c, a, n, wrendir, NWREN, wrengen);
-
- d = &wren[c->dev];
- p = &(d->p[Mask&c->qid.path]);
- switch ((int)(c->qid.path & ~Mask)) {
- case Qdata:
- if (n % d->blocksize || offset % d->blocksize)
- error(Ebadarg);
- lbn = (offset/d->blocksize) + p->firstblock;
- if (lbn >= p->maxblock)
- error(Ebadarg);
- if (n > DATASIZE)
- n = DATASIZE;
- cmd = scsicmd(c->dev, 0x08, n);
- if (waserror()) {
- qunlock(cmd);
- nexterror();
- }
- cmd->cmdblk[1] = lbn>>16;
- cmd->cmdblk[2] = lbn>>8;
- cmd->cmdblk[3] = lbn;
- cmd->cmdblk[4] = n/d->blocksize;
- scsiexec(cmd, 1);
- n = cmd->data.ptr - cmd->data.base;
- memmove(a, cmd->data.base, n);
- qunlock(cmd);
- poperror();
- break;
- case Qstruct:
- if (n < 2*sizeof(ulong))
- error(Ebadarg);
- if (offset >= 2*sizeof(ulong))
- return 0;
- n = 2*sizeof(ulong);
- wrenint((uchar*)a, p->maxblock - p->firstblock);
- wrenint((uchar*)a+sizeof(ulong), d->blocksize);
- break;
- default:
- panic("wrenread");
- }
- return n;
+ return devdirread(c, a, n, 0, 0, wrengen);
+
+ d = &wren[DRIVE(c->qid.path)];
+ p = &d->p[PART(c->qid.path)];
+ return wrenio(d, p, 0, a, n, offset);
}
long
wrenwrite(Chan *c, char *a, long n, ulong offset)
{
+ Drive *d;
+ Partition *p;
+
+ d = &wren[DRIVE(c->qid.path)];
+ p = &d->p[PART(c->qid.path)];
+ return wrenio(d, p, 1, a, n, offset);
+}
+
+static long
+wrenio(Drive *d, Partition *p, int write, char *a, ulong n, ulong offset)
+{
Scsi *cmd;
- ulong lbn;
- Part *p;
- Disk *d;
+ void *b;
+ ulong block;
- if (n == 0)
+ if(n % d->bytes || offset % d->bytes)
+ error(Ebadarg);
+ block = offset / d->bytes + p->start;
+ if(block >= p->end)
return 0;
-
- d = &wren[c->dev];
- p = &(d->p[Mask&c->qid.path]);
- switch ((int)(c->qid.path & ~Mask)) {
- case Qdata:
- if (n % d->blocksize || offset % d->blocksize)
- error(Ebadarg);
- lbn = offset/d->blocksize + p->firstblock;
- if (lbn >= p->maxblock)
- error(Ebadarg);
- if (n > DATASIZE)
- n = DATASIZE;
- cmd = scsicmd(c->dev, 0x0a, n);
- if (waserror()) {
- qunlock(cmd);
- nexterror();
- }
- cmd->cmdblk[1] = lbn>>16;
- cmd->cmdblk[2] = lbn>>8;
- cmd->cmdblk[3] = lbn;
- cmd->cmdblk[4] = n/d->blocksize;
- memmove(cmd->data.base, a, n);
- scsiexec(cmd, 0);
- n = cmd->data.ptr - cmd->data.base;
+ if(n > DATASIZE)
+ n = DATASIZE;
+ n /= d->bytes;
+ if(block + n > p->end)
+ n = p->end - block;
+ if(n == 0)
+ return 0;
+ if(write)
+ cmd = scsicmd(d->drive, 0x0a, n*d->bytes);
+ else
+ cmd = scsicmd(d->drive, 0x08, n*d->bytes);
+ if(waserror()){
qunlock(cmd);
- poperror();
- break;
- default:
- panic("wrenwrite");
+ nexterror();
}
+ cmd->cmdblk[1] = block>>16;
+ cmd->cmdblk[2] = block>>8;
+ cmd->cmdblk[3] = block;
+ cmd->cmdblk[4] = n;
+ if(write)
+ memmove(cmd->data.base, a, n*d->bytes);
+ scsiexec(cmd, !write);
+ n = cmd->data.ptr - cmd->data.base;
+ if(!write)
+ memmove(a, cmd->data.base, n);
+ qunlock(cmd);
+ poperror();
return n;
}
-void
-wrenremove(Chan *c)
-{
- error(Eperm);
-}
-
-void
-wrenwstat(Chan *c, char *dp)
+/*
+ * read partition table. The partition table is just ascii strings.
+ */
+#define MAGIC "plan9 partitions"
+static void
+wrenpart(int dev)
{
- error(Eperm);
-}
+ Scsi *cmd;
+ Drive *dp;
+ Partition *pp;
+ uchar buf[32];
+ char *b;
+ char *line[Npart+1];
+ char *field[3];
+ ulong n;
+ int i;
-void
-wrenint(uchar *a, ulong x)
-{
- a[0] = x >> 24;
- a[1] = x >> 16;
- a[2] = x >> 8;
- a[3] = x;
+ scsiready(dev);
+ scsisense(dev, buf);
+ scsicap(dev, buf);
+ dp = &wren[dev];
+ dp->drive = dev;
+ if(dp->npart)
+ return;
+ /*
+ * we always have a partition for the whole disk
+ * and one for the partition table
+ */
+ dp->bytes = (buf[4]<<24)+(buf[5]<<16)+(buf[6]<<8)+(buf[7]);
+ pp = &dp->p[0];
+ strcpy(pp->name, "disk");
+ pp->start = 0;
+ pp->end = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]) + 1;
+ pp++;
+ strcpy(pp->name, "partition");
+ pp->start = dp->p[0].end - 1;
+ pp->end = dp->p[0].end;
+ dp->npart = 2;
+
+ /*
+ * read partition table from disk, null terminate
+ */
+ cmd = scsicmd(dev, 0x08, dp->bytes);
+ if(waserror()){
+ qunlock(cmd);
+ nexterror();
+ }
+ n = dp->p[0].end-1;
+ cmd->cmdblk[1] = n>>16;
+ cmd->cmdblk[2] = n>>8;
+ cmd->cmdblk[3] = n;
+ cmd->cmdblk[4] = 1;
+ scsiexec(cmd, 1);
+ cmd->data.base[dp->bytes-1] = 0;
+
+ /*
+ * parse partition table.
+ */
+ n = getfields((char *)cmd->data.base, line, Npart+1, '\n');
+ if(strncmp(line[0], MAGIC, sizeof(MAGIC)-1) != 0)
+ goto out;
+ for(i = 1; i < n; i++){
+ pp++;
+ if(getfields(line[i], field, 3, ' ') != 3){
+ break;
+ }
+ strncpy(pp->name, field[0], NAMELEN);
+ pp->start = strtoul(field[1], 0, 0);
+ pp->end = strtoul(field[2], 0, 0);
+ if(pp->start > pp->end || pp->start >= dp->p[0].end){
+ break;
+ }
+ dp->npart++;
+ }
+out:
+ qunlock(cmd);
+ poperror();
}