|
|
1.1 root 1: /* autoconf.c 6.3 83/08/11 */
2:
3: /*
4: * Setup the system to run on the current machine.
5: *
6: * Configure() is called at boot time and initializes the uba and mba
7: * device tables and the memory controller monitoring. Available
8: * devices are determined (from possibilities mentioned in ioconf.c),
9: * and the drivers are initialized.
10: *
11: * N.B.: A lot of the conditionals based on processor type say
12: * #if VAX780
13: * and
14: * #if VAX750
15: * which may be incorrect after more processors are introduced if they
16: * are like either of these machines.
17: *
18: * TODO:
19: * use pcpu info about whether a ubasr exists
20: */
21:
22: #include "mba.h"
23: #include "uba.h"
24:
25: #include "../machine/pte.h"
26:
27: #include "../h/param.h"
28: #include "../h/systm.h"
29: #include "../h/map.h"
30: #include "../h/buf.h"
31: #include "../h/dk.h"
32: #include "../h/vm.h"
33: #include "../h/conf.h"
34: #include "../h/dmap.h"
35:
36: #include "../vax/cpu.h"
37: #include "../vax/mem.h"
38: #include "../vax/mtpr.h"
39: #include "../vax/nexus.h"
40: #include "../vax/scb.h"
41: #include "../vaxmba/mbareg.h"
42: #include "../vaxmba/mbavar.h"
43: #include "../vaxuba/ubareg.h"
44: #include "../vaxuba/ubavar.h"
45:
46: /*
47: * The following several variables are related to
48: * the configuration process, and are used in initializing
49: * the machine.
50: */
51: int cold; /* if 1, still working on cold-start */
52: int nexnum; /* current nexus number */
53: int dkn; /* number of iostat dk numbers assigned so far */
54:
55: /*
56: * Addresses of the (locore) routines which bootstrap us from
57: * hardware traps to C code. Filled into the system control block
58: * as necessary.
59: */
60: #if NMBA > 0
61: int (*mbaintv[4])() = { Xmba0int, Xmba1int, Xmba2int, Xmba3int };
62: #endif
63: #if VAX780
64: int (*ubaintv[4])() = { Xua0int, Xua1int, Xua2int, Xua3int };
65: #endif
66:
67: /*
68: * This allocates the space for the per-uba information,
69: * such as buffered data path usage.
70: */
71: struct uba_hd uba_hd[MAXNUBA];
72:
73: /*
74: * Determine mass storage and memory configuration for a machine.
75: * Get cpu type, and then switch out to machine specific procedures
76: * which will probe adaptors to see what is out there.
77: */
78: configure()
79: {
80: union cpusid cpusid;
81: register struct percpu *ocp;
82: register int *ip;
83: extern char Sysbase[];
84:
85: cpusid.cpusid = mfpr(SID);
86: for (ocp = percpu; ocp->pc_cputype; ocp++)
87: if (ocp->pc_cputype == cpusid.cpuany.cp_type) {
88: probenexus(ocp);
89: /*
90: * Write protect the scb and UNIBUS interrupt vectors.
91: * It is strange that this code is here, but this is
92: * as soon as we are done mucking with it, and the
93: * write-enable was done in assembly language
94: * to which we will never return.
95: */
96: ip = (int *)Sysmap + 1; *ip &= ~PG_PROT; *ip |= PG_KR;
97: ip++; *ip &= ~PG_PROT; *ip |= PG_KR;
98: #if NUBA > 1
99: ip++; *ip &= ~PG_PROT; *ip |= PG_KR;
100: #endif
101: mtpr(TBIS, Sysbase);
102: #if GENERIC
103: setconf();
104: #endif
105: /*
106: * Configure swap area and related system
107: * parameter based on device(s) used.
108: */
109: swapconf();
110: cold = 0;
111: memenable();
112: return;
113: }
114: printf("cpu type %d not configured\n", cpusid.cpuany.cp_type);
115: asm("halt");
116: }
117:
118: /*
119: * Probe nexus space, finding the interconnects
120: * and setting up and probing mba's and uba's for devices.
121: */
122: /*ARGSUSED*/
123: probenexus(pcpu)
124: register struct percpu *pcpu;
125: {
126: register struct nexus *nxv;
127: struct nexus *nxp = pcpu->pc_nexbase;
128: union nexcsr nexcsr;
129: int i;
130:
131: nexnum = 0, nxv = nexus;
132: for (; nexnum < pcpu->pc_nnexus; nexnum++, nxp++, nxv++) {
133: nxaccess(nxp, Nexmap[nexnum]);
134: if (badaddr((caddr_t)nxv, 4))
135: continue;
136: if (pcpu->pc_nextype && pcpu->pc_nextype[nexnum] != NEX_ANY)
137: nexcsr.nex_csr = pcpu->pc_nextype[nexnum];
138: else
139: nexcsr = nxv->nexcsr;
140: if (nexcsr.nex_csr&NEX_APD)
141: continue;
142: switch (nexcsr.nex_type) {
143:
144: case NEX_MBA:
145: printf("mba%d at tr%d\n", nummba, nexnum);
146: if (nummba >= NMBA) {
147: printf("%d mba's", nummba);
148: goto unconfig;
149: }
150: #if NMBA > 0
151: mbafind(nxv, nxp);
152: nummba++;
153: #endif
154: break;
155:
156: case NEX_UBA0:
157: case NEX_UBA1:
158: case NEX_UBA2:
159: case NEX_UBA3:
160: printf("uba%d at tr%d\n", numuba, nexnum);
161: if (numuba >= 4) {
162: printf("5 uba's");
163: goto unsupp;
164: }
165: #if VAX780
166: if (cpu == VAX_780)
167: setscbnex(ubaintv[numuba]);
168: #endif
169: i = nexcsr.nex_type - NEX_UBA0;
170: unifind((struct uba_regs *)nxv, (struct uba_regs *)nxp,
171: umem[i], pcpu->pc_umaddr[i], UMEMmap[i]);
172: #if VAX780
173: if (cpu == VAX_780)
174: ((struct uba_regs *)nxv)->uba_cr =
175: UBACR_IFS|UBACR_BRIE|
176: UBACR_USEFIE|UBACR_SUEFIE|
177: (((struct uba_regs *)nxv)->uba_cr&0x7c000000);
178: #endif
179: numuba++;
180: break;
181:
182: case NEX_DR32:
183: /* there can be more than one... are there other codes??? */
184: printf("dr32");
185: goto unsupp;
186:
187: case NEX_MEM4:
188: case NEX_MEM4I:
189: case NEX_MEM16:
190: case NEX_MEM16I:
191: case NEX_MEM64L:
192: case NEX_MEM64LI:
193: case NEX_MEM64U:
194: case NEX_MEM64UI:
195: case NEX_MEM64I:
196: printf("mcr%d at tr%d\n", nmcr, nexnum);
197: if (nmcr >= 4) {
198: printf("5 mcr's");
199: goto unsupp;
200: }
201: mcraddr[nmcr++] = (struct mcr *)nxv;
202: break;
203:
204: case NEX_MPM0:
205: case NEX_MPM1:
206: case NEX_MPM2:
207: case NEX_MPM3:
208: printf("mpm");
209: goto unsupp;
210:
211: case NEX_CI:
212: printf("ci");
213: goto unsupp;
214:
215: default:
216: printf("nexus type %x", nexcsr.nex_type);
217: unsupp:
218: printf(" unsupported (at tr %d)\n", nexnum);
219: continue;
220: unconfig:
221: printf(" not configured\n");
222: continue;
223: }
224: }
225: }
226:
227: #if NMBA > 0
228: struct mba_device *mbaconfig();
229: /*
230: * Find devices attached to a particular mba
231: * and look for each device found in the massbus
232: * initialization tables.
233: */
234: mbafind(nxv, nxp)
235: struct nexus *nxv, *nxp;
236: {
237: register struct mba_regs *mdp;
238: register struct mba_drv *mbd;
239: register struct mba_device *mi;
240: register struct mba_slave *ms;
241: int dn, dt, sn;
242: struct mba_device fnd;
243:
244: mdp = (struct mba_regs *)nxv;
245: mba_hd[nummba].mh_mba = mdp;
246: mba_hd[nummba].mh_physmba = (struct mba_regs *)nxp;
247: setscbnex(mbaintv[nummba]);
248: fnd.mi_mba = mdp;
249: fnd.mi_mbanum = nummba;
250: for (mbd = mdp->mba_drv, dn = 0; mbd < &mdp->mba_drv[8]; mbd++, dn++) {
251: if ((mbd->mbd_ds&MBDS_DPR) == 0)
252: continue;
253: mdp->mba_sr |= MBSR_NED; /* si kludge */
254: dt = mbd->mbd_dt & 0xffff;
255: if (dt == 0)
256: continue;
257: if (mdp->mba_sr&MBSR_NED)
258: continue; /* si kludge */
259: if (dt == MBDT_MOH)
260: continue;
261: fnd.mi_drive = dn;
262: #define qeq(a, b) ( a == b || a == '?' )
263: if ((mi = mbaconfig(&fnd, dt)) && (dt & MBDT_TAP))
264: for (sn = 0; sn < 8; sn++) {
265: mbd->mbd_tc = sn;
266: for (ms = mbsinit; ms->ms_driver; ms++)
267: if (ms->ms_driver == mi->mi_driver &&
268: ms->ms_alive == 0 &&
269: qeq(ms->ms_ctlr, mi->mi_unit) &&
270: qeq(ms->ms_slave, sn) &&
271: (*ms->ms_driver->md_slave)(mi, ms, sn)) {
272: printf("%s%d at %s%d slave %d\n"
273: , ms->ms_driver->md_sname
274: , ms->ms_unit
275: , mi->mi_driver->md_dname
276: , mi->mi_unit
277: , sn
278: );
279: ms->ms_alive = 1;
280: ms->ms_ctlr = mi->mi_unit;
281: ms->ms_slave = sn;
282: }
283: }
284: }
285: mdp->mba_cr = MBCR_INIT;
286: mdp->mba_cr = MBCR_IE;
287: }
288:
289: /*
290: * Have found a massbus device;
291: * see if it is in the configuration table.
292: * If so, fill in its data.
293: */
294: struct mba_device *
295: mbaconfig(ni, type)
296: register struct mba_device *ni;
297: register int type;
298: {
299: register struct mba_device *mi;
300: register short *tp;
301: register struct mba_hd *mh;
302:
303: for (mi = mbdinit; mi->mi_driver; mi++) {
304: if (mi->mi_alive)
305: continue;
306: tp = mi->mi_driver->md_type;
307: for (mi->mi_type = 0; *tp; tp++, mi->mi_type++)
308: if (*tp == (type&MBDT_TYPE))
309: goto found;
310: continue;
311: found:
312: #define match(fld) (ni->fld == mi->fld || mi->fld == '?')
313: if (!match(mi_drive) || !match(mi_mbanum))
314: continue;
315: printf("%s%d at mba%d drive %d\n",
316: mi->mi_driver->md_dname, mi->mi_unit,
317: ni->mi_mbanum, ni->mi_drive);
318: mi->mi_alive = 1;
319: mh = &mba_hd[ni->mi_mbanum];
320: mi->mi_hd = mh;
321: mh->mh_mbip[ni->mi_drive] = mi;
322: mh->mh_ndrive++;
323: mi->mi_mba = ni->mi_mba;
324: mi->mi_drv = &mi->mi_mba->mba_drv[ni->mi_drive];
325: mi->mi_mbanum = ni->mi_mbanum;
326: mi->mi_drive = ni->mi_drive;
327: /*
328: * If drive has never been seen before,
329: * give it a dkn for statistics.
330: */
331: if (mi->mi_driver->md_info[mi->mi_unit] == 0) {
332: mi->mi_driver->md_info[mi->mi_unit] = mi;
333: if (mi->mi_dk && dkn < DK_NDRIVE)
334: mi->mi_dk = dkn++;
335: else
336: mi->mi_dk = -1;
337: }
338: (*mi->mi_driver->md_attach)(mi);
339: return (mi);
340: }
341: return (0);
342: }
343: #endif
344:
345: /*
346: * Fixctlrmask fixes the masks of the driver ctlr routines
347: * which otherwise save r10 and r11 where the interrupt and br
348: * level are passed through.
349: */
350: fixctlrmask()
351: {
352: register struct uba_ctlr *um;
353: register struct uba_device *ui;
354: register struct uba_driver *ud;
355: #define phys(a,b) ((b)(((int)(a))&0x7fffffff))
356:
357: for (um = ubminit; ud = phys(um->um_driver, struct uba_driver *); um++)
358: *phys(ud->ud_probe, short *) &= ~0xc00;
359: for (ui = ubdinit; ud = phys(ui->ui_driver, struct uba_driver *); ui++)
360: *phys(ud->ud_probe, short *) &= ~0xc00;
361: }
362:
363: /*
364: * Find devices on a UNIBUS.
365: * Uses per-driver routine to set <br,cvec> into <r11,r10>,
366: * and then fills in the tables, with help from a per-driver
367: * slave initialization routine.
368: */
369: unifind(vubp, pubp, vumem, pumem, memmap)
370: struct uba_regs *vubp, *pubp;
371: caddr_t vumem, pumem;
372: struct pte *memmap;
373: {
374: #ifndef lint
375: register int br, cvec; /* MUST BE r11, r10 */
376: #else
377: /*
378: * Lint doesn't realize that these
379: * can be initialized asynchronously
380: * when devices interrupt.
381: */
382: register int br = 0, cvec = 0;
383: #endif
384: register struct uba_device *ui;
385: register struct uba_ctlr *um;
386: u_short *reg, *ap, addr;
387: struct uba_hd *uhp;
388: struct uba_driver *udp;
389: int i, (**ivec)(), haveubasr;
390: caddr_t ualloc, zmemall();
391: extern int catcher[256];
392:
393: /*
394: * Initialize the UNIBUS, by freeing the map
395: * registers and the buffered data path registers
396: */
397: uhp = &uba_hd[numuba];
398: uhp->uh_map = (struct map *)calloc(UAMSIZ * sizeof (struct map));
399: ubainitmaps(uhp);
400: haveubasr = cpu == VAX_780;
401:
402: /*
403: * Save virtual and physical addresses
404: * of adaptor, and allocate and initialize
405: * the UNIBUS interrupt vector.
406: */
407: uhp->uh_uba = vubp;
408: uhp->uh_physuba = pubp;
409: if (numuba == 0)
410: uhp->uh_vec = UNIvec;
411: #if NUBA > 1
412: else if (numuba == 1)
413: uhp->uh_vec = UNI1vec;
414: else {
415: #if defined(VAX_750)
416: if (cpu == VAX_750)
417: printf("More than 2 UBA's not supported\n");
418: else
419: #endif
420: uhp->uh_vec = (int(**)())calloc(512);
421: }
422: #endif
423: for (i = 0; i < 128; i++)
424: uhp->uh_vec[i] =
425: scbentry(&catcher[i*2], SCB_ISTACK);
426: /*
427: * Set last free interrupt vector for devices with
428: * programmable interrupt vectors. Use is to decrement
429: * this number and use result as interrupt vector.
430: */
431: uhp->uh_lastiv = 0x200;
432:
433: ubaaccess(pumem, memmap);
434: #if VAX780
435: if (haveubasr) {
436: vubp->uba_sr = vubp->uba_sr;
437: vubp->uba_cr = UBACR_IFS|UBACR_BRIE;
438: }
439: #endif
440: /*
441: * Grab some memory to record the umem address space we allocate,
442: * so we can be sure not to place two devices at the same address.
443: *
444: * We could use just 1/8 of this (we only want a 1 bit flag) but
445: * we are going to give it back anyway, and that would make the
446: * code here bigger (which we can't give back), so ...
447: *
448: * One day, someone will make a unibus with something other than
449: * an 8K i/o address space, & screw this totally.
450: */
451: ualloc = zmemall(memall, 8*1024);
452: if (ualloc == (caddr_t)0)
453: panic("no mem for unifind");
454:
455: /*
456: * Map the first page of UNIBUS i/o
457: * space to the first page of memory
458: * for devices which will need to dma
459: * output to produce an interrupt.
460: */
461: *(int *)(&vubp->uba_map[0]) = UBAMR_MRV;
462:
463: #define ubaoff(off) ((off)&0x1fff)
464: #define ubaddr(off) (u_short *)((int)vumem + (ubaoff(off)|0x3e000))
465: /*
466: * Check each unibus mass storage controller.
467: * For each one which is potentially on this uba,
468: * see if it is really there, and if it is record it and
469: * then go looking for slaves.
470: */
471: for (um = ubminit; udp = um->um_driver; um++) {
472: if (um->um_ubanum != numuba && um->um_ubanum != '?')
473: continue;
474: addr = (u_short)um->um_addr;
475: /*
476: * use the particular address specified first,
477: * or if it is given as "0", of there is no device
478: * at that address, try all the standard addresses
479: * in the driver til we find it
480: */
481: for (ap = udp->ud_addr; addr || (addr = *ap++); addr = 0) {
482:
483: if (ualloc[ubaoff(addr)])
484: continue;
485: reg = ubaddr(addr);
486: if (badaddr((caddr_t)reg, 2))
487: continue;
488: #if VAX780
489: if (haveubasr && vubp->uba_sr) {
490: vubp->uba_sr = vubp->uba_sr;
491: continue;
492: }
493: #endif
494: cvec = 0x200;
495: i = (*udp->ud_probe)(reg, um->um_ctlr);
496: #if VAX780
497: if (haveubasr && vubp->uba_sr) {
498: vubp->uba_sr = vubp->uba_sr;
499: continue;
500: }
501: #endif
502: if (i == 0)
503: continue;
504: printf("%s%d at uba%d csr %o ",
505: udp->ud_mname, um->um_ctlr, numuba, addr);
506: if (cvec == 0) {
507: printf("zero vector\n");
508: continue;
509: }
510: if (cvec == 0x200) {
511: printf("didn't interrupt\n");
512: continue;
513: }
514: printf("vec %o, ipl %x\n", cvec, br);
515: um->um_alive = 1;
516: um->um_ubanum = numuba;
517: um->um_hd = &uba_hd[numuba];
518: um->um_addr = (caddr_t)reg;
519: udp->ud_minfo[um->um_ctlr] = um;
520: for (ivec = um->um_intr; *ivec; ivec++) {
521: um->um_hd->uh_vec[cvec/4] =
522: scbentry(*ivec, SCB_ISTACK);
523: cvec += 4;
524: }
525: for (ui = ubdinit; ui->ui_driver; ui++) {
526: if (ui->ui_driver != udp || ui->ui_alive ||
527: ui->ui_ctlr != um->um_ctlr && ui->ui_ctlr != '?' ||
528: ui->ui_ubanum != numuba && ui->ui_ubanum != '?')
529: continue;
530: if ((*udp->ud_slave)(ui, reg)) {
531: ui->ui_alive = 1;
532: ui->ui_ctlr = um->um_ctlr;
533: ui->ui_ubanum = numuba;
534: ui->ui_hd = &uba_hd[numuba];
535: ui->ui_addr = (caddr_t)reg;
536: ui->ui_physaddr = pumem + ubdevreg(addr);
537: if (ui->ui_dk && dkn < DK_NDRIVE)
538: ui->ui_dk = dkn++;
539: else
540: ui->ui_dk = -1;
541: ui->ui_mi = um;
542: /* ui_type comes from driver */
543: udp->ud_dinfo[ui->ui_unit] = ui;
544: printf("%s%d at %s%d slave %d\n",
545: udp->ud_dname, ui->ui_unit,
546: udp->ud_mname, um->um_ctlr, ui->ui_slave);
547: (*udp->ud_attach)(ui);
548: }
549: }
550: break;
551: }
552: }
553: /*
554: * Now look for non-mass storage peripherals.
555: */
556: for (ui = ubdinit; udp = ui->ui_driver; ui++) {
557: if (ui->ui_ubanum != numuba && ui->ui_ubanum != '?' ||
558: ui->ui_alive || ui->ui_slave != -1)
559: continue;
560: addr = (u_short)ui->ui_addr;
561:
562: for (ap = udp->ud_addr; addr || (addr = *ap++); addr = 0) {
563:
564: if (ualloc[ubaoff(addr)])
565: continue;
566: reg = ubaddr(addr);
567: if (badaddr((caddr_t)reg, 2))
568: continue;
569: #if VAX780
570: if (haveubasr && vubp->uba_sr) {
571: vubp->uba_sr = vubp->uba_sr;
572: continue;
573: }
574: #endif
575: cvec = 0x200;
576: i = (*udp->ud_probe)(reg);
577: #if VAX780
578: if (haveubasr && vubp->uba_sr) {
579: vubp->uba_sr = vubp->uba_sr;
580: continue;
581: }
582: #endif
583: if (i == 0)
584: continue;
585: printf("%s%d at uba%d csr %o ",
586: ui->ui_driver->ud_dname, ui->ui_unit, numuba, addr);
587: if (cvec == 0) {
588: printf("zero vector\n");
589: continue;
590: }
591: if (cvec == 0x200) {
592: printf("didn't interrupt\n");
593: continue;
594: }
595: printf("vec %o, ipl %x\n", cvec, br);
596: while (--i >= 0)
597: ualloc[ubaoff(addr+i)] = 1;
598: ui->ui_hd = &uba_hd[numuba];
599: for (ivec = ui->ui_intr; *ivec; ivec++) {
600: ui->ui_hd->uh_vec[cvec/4] =
601: scbentry(*ivec, SCB_ISTACK);
602: cvec += 4;
603: }
604: ui->ui_alive = 1;
605: ui->ui_ubanum = numuba;
606: ui->ui_addr = (caddr_t)reg;
607: ui->ui_physaddr = pumem + ubdevreg(addr);
608: ui->ui_dk = -1;
609: /* ui_type comes from driver */
610: udp->ud_dinfo[ui->ui_unit] = ui;
611: (*udp->ud_attach)(ui);
612: break;
613: }
614: }
615:
616: #ifdef AUTO_DEBUG
617: printf("Unibus allocation map");
618: for (i = 0; i < 8*1024; ) {
619: register n, m;
620:
621: if ((i % 128) == 0) {
622: printf("\n%6o:", i);
623: for (n = 0; n < 128; n++)
624: if (ualloc[i+n])
625: break;
626: if (n == 128) {
627: i += 128;
628: continue;
629: }
630: }
631:
632: for (n = m = 0; n < 16; n++) {
633: m <<= 1;
634: m |= ualloc[i++];
635: }
636:
637: printf(" %4x", m);
638: }
639: printf("\n");
640: #endif
641:
642: wmemfree(ualloc, 8*1024);
643: }
644:
645: setscbnex(fn)
646: int (*fn)();
647: {
648: register struct scb *scbp = &scb;
649:
650: scbp->scb_ipl14[nexnum] = scbp->scb_ipl15[nexnum] =
651: scbp->scb_ipl16[nexnum] = scbp->scb_ipl17[nexnum] =
652: scbentry(fn, SCB_ISTACK);
653: }
654:
655: /*
656: * Make a nexus accessible at physical address phys
657: * by mapping kernel ptes starting at pte.
658: *
659: * WE LEAVE ALL NEXI MAPPED; THIS IS PERHAPS UNWISE
660: * SINCE MISSING NEXI DONT RESPOND. BUT THEN AGAIN
661: * PRESENT NEXI DONT RESPOND TO ALL OF THEIR ADDRESS SPACE.
662: */
663: nxaccess(physa, pte)
664: struct nexus *physa;
665: register struct pte *pte;
666: {
667: register int i = btop(sizeof (struct nexus));
668: register unsigned v = btop(physa);
669:
670: do
671: *(int *)pte++ = PG_V|PG_KW|v++;
672: while (--i > 0);
673: mtpr(TBIA, 0);
674: }
675:
676: ubaaccess(pumem, pte)
677: caddr_t pumem;
678: register struct pte *pte;
679: {
680: register int i = 512;
681: register unsigned v = btop(pumem);
682:
683: do
684: *(int *)pte++ = PG_V|PG_KW|v++;
685: while (--i > 0);
686: mtpr(TBIA, 0);
687: }
688:
689: #define DMMIN 32
690: #define DMMAX 1024
691: #define DMTEXT 1024
692: #define MAXDUMP (10*2048)
693: /*
694: * Configure swap space and related parameters.
695: */
696: swapconf()
697: {
698: register struct swdevt *swp;
699: register int nblks;
700:
701: for (swp = swdevt; swp->sw_dev; swp++) {
702: if (bdevsw[major(swp->sw_dev)].d_psize)
703: nblks =
704: (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev);
705: if (swp->sw_nblks == 0 || swp->sw_nblks > nblks)
706: swp->sw_nblks = nblks;
707: }
708: if (!cold) /* in case called for mba device */
709: return;
710: if (dumplo == 0)
711: dumplo = swdevt[0].sw_nblks - MAXDUMP;
712: if (dumplo < 0)
713: dumplo = 0;
714: if (dmmin == 0)
715: dmmin = DMMIN;
716: if (dmmax == 0)
717: dmmax = DMMAX;
718: if (dmtext == 0)
719: dmtext = DMTEXT;
720: if (dmtext > dmmax)
721: dmtext = dmmax;
722: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.