Path: utzoo!utgpu!water!watmath!clyde!att!pacbell!ames!pasteur!ucbvax!unisoft!paul From: paul@unisoft.UUCP (n) Newsgroups: comp.sys.mac.programmer Subject: Re: Serial drivers and interrupt trapping Summary: sample serial driver find code Keywords: Macintosh, Serial, Interrupt, Programming Message-ID: <1307@unisoft.UUCP> Date: 30 Sep 88 05:47:29 GMT References: <10407@tekecs.TEK.COM> <1299@unisoft.UUCP> Lines: 434 Lots of people have asked for copies of the code to find 3rd party serial boards so I'm posting it here (we don't get comp.sources.mac here). Please remember that this is only a temporary solution, Apple have announced that they are producing a much more elegant solution to this problem - this is probably the best we can use in the mean time Paul Campbell PS: sorry to those who got the version I posted earlier today, someone reported a silly bug just after I posted it (Murphy strikes again). This is the correct one. Cut between the dotted lines -------------------------------------------------------------------------------- /* * * Copyright Paul Campbell, September 1988, All Rights Reserved. * Taniwha Systems Design * * The material contained in this document is copyright, as described * above. Permission is granted for you to use it provided you follow * the following restrictions: * * - this document may not be reproduced without this copyright message * included * * - you may not sell this source file * * - you may use object code derived from this document in a commercial * product provided you do not charge any additional fee because of * its inclusion * * Paul Campbell * Taniwha Systems Design * 4368 Montgomery St * Oakland * CA 94611 * (415) 420-8179 * * Free plug ..... * * This code was developed for use with SuperMac's CommCard an intelligent * 4 port asynchronous serial (or 1 port LocalTalk) card which runs with * the Mac Operating System or A/UX. Specifications are: * * Serial: * - baud rates 50-38400 baud * - 6k output/200 byte input buffers * - onboard software/hardware flow controll * * MacOS - built-in serial port like programming interface * - built-in protocol support for X/Y/Z-modem, Kermit, * Quick-B and CompuServe DL protocols * * A/UX - streams/tty programming interface * - built-in protocol support for UUCP 'G' protocol * * LocalTalk: * - onboard LAP support (offloads most network overhead * to the card * - 25 packets onboard buffering * * MacOS - single card support under Apple's LAP manager * * A/UX - full kernel support for DDP/NBP/ATP/PAP/ZIP/RTMP * protocols * - TransScript backend for PostScript conversion and * printing to LaserWriters from A/UX * - multiple cards can be used to implement bridges * running in the background * - AppleShare Server included * - TOPS Server and mailbridge available from StarNine * Technologies, Berkeley * * For more info contact Scott Meltzer at SuperMac (415)962-2491 */ #include #include #include #include #define UTableBase (*(DCtlHandle **)0x11C) /* unit I/O table [pointer] */ #define UnitNtryCnt (*(short *)0x1D2) /* count of entries in unit table [word] */ #define RamFlag 0x0040 /* driver is Ram Based */ struct driver { short drvrFlags; short drvrDelay; short drvrEMask; short drvrMenu; short drvrOpen; short drvrPrime; short drvrCtl; short drvrStatus; short drvrClose; char drvrName[64]; }; /* * This file contains code designed to search the Mac Unit Table for * devices that are PROBABLY serial lines. This is intended as a * temporary solution of how to find extra serial lines in a Macintosh * until Apple comes up with its promised Communications Manager which * will be a much better (and elegant) solution to this problem. * * The code is written in MPW C. * * The basic technique used here is search for two drivers with names that * * - start with '.' * * - One has the form of In ('In' can ne in any case) * * - The other has the form Out * * - the strings and name */ short in_refnum; /* input refnum */ char in_name[64]; /* input driver name to pass to PBOpen() */ short out_refnum; /* output refnum */ char out_name[64]; /* output driver name to pass to PBOpen() */ }; pascal short find_serial(s, sp) short s; struct serial_entry *sp; { DCtlHandle *dpp, dp; /* pointers into unit table */ short count, len; struct driver *dvp, **dvpp; /* pointers to drivers */ char prefix[64], suffix[64]; /* prefix/suffix values */ short plen, slen; /* their lengths */ int i, j, out; count = UnitNtryCnt; /* unit table length */ dpp = UTableBase; /* unit table address */ for (; s < count; s++) { /* loop thru the unit table */ if ((dp = dpp[s]) == 0) /* ignore empty entries */ continue; if ((*dp)->dCtlFlags&RamFlag) { /* must do indirection for ram drivers */ dvpp = (struct driver **)(*dp)->dCtlDriver; len = (*dvpp)->drvrName[0]; /* get driver name length */ if (len <= 4 || (*dvpp)->drvrName[1] != '.') /* sanity check */ continue; out = -1; for (i = 2; i <= (len-1); i++) { /* look for 'In' in the name */ if (((*dvpp)->drvrName[i] == 'I' || (*dvpp)->drvrName[i] == 'i') && ((*dvpp)->drvrName[i+1] == 'n' || (*dvpp)->drvrName[i+1] == 'N')) { plen = i - 2; /* isolate the prefix/suffix */ for (j = 0; j < plen; j++) prefix[j] = (*dvpp)->drvrName[j+2]; slen = len - i - 1; for (j = 0; j < slen; j++) suffix[j] = (*dvpp)->drvrName[i+j+2]; /* search for a matching 'Out' */ if ((out = find_serial_out(sp, len, plen, prefix, slen, suffix)) >= 0) { for (i = 0; i <= len; i++) sp->in_name[i] = (*dvpp)->drvrName[i]; } break; } } } else { dvp = (struct driver *)(*dp)->dCtlDriver; /* same as above but with no */ len = dvp->drvrName[0]; /* indirection */ if (len < 4 || dvp->drvrName[1] != '.') continue; out = -1; for (i = 2; i <= (len-1); i++) { if ((dvp->drvrName[i] == 'I' || dvp->drvrName[i] == 'i') && (dvp->drvrName[i+1] == 'n' || dvp->drvrName[i+1] == 'N')) { plen = i - 2; for (j = 0; j < plen; j++) prefix[j] = dvp->drvrName[j+2]; slen = len - i - 1; for (j = 0; j < slen; j++) suffix[j] = dvp->drvrName[j+i+2]; if ((out = find_serial_out(sp, len, plen, prefix, slen, suffix)) >= 0) { for (i = 0; i <= len; i++) sp->in_name[i] = dvp->drvrName[i]; } break; } } } if (out < 0) continue; sp->real_name[0] = len = plen + slen; /* build a real_name */ for (i = 1; i <= plen; i++) sp->real_name[i] = prefix[i-1]; if (slen > 0 && plen > 0) { /* add '-' to complex names */ len++; sp->real_name[0]++; sp->real_name[i++] = '-'; for (; i <= len; i++) sp->real_name[i] = suffix[i-plen-2]; } else { for (; i <= len; i++) sp->real_name[i] = suffix[i-plen-1]; } if (len == 1) { /* treat the built-in ports specially */ if (sp->real_name[1] == 'A') { sp->real_name[0] = 5; sp->real_name[1] = 'M'; sp->real_name[2] = 'o'; sp->real_name[3] = 'd'; sp->real_name[4] = 'e'; sp->real_name[5] = 'm'; } else if (sp->real_name[1] == 'B') { sp->real_name[0] = 7; sp->real_name[1] = 'P'; sp->real_name[2] = 'r'; sp->real_name[3] = 'i'; sp->real_name[4] = 'n'; sp->real_name[5] = 't'; sp->real_name[6] = 'e'; sp->real_name[7] = 'r'; } else { sp->real_name[0] = 8; /* do something for those who */ sp->real_name[8] = sp->real_name[1]; /* follow a different tune */ sp->real_name[1] = 'S'; sp->real_name[2] = 'e'; sp->real_name[3] = 'r'; sp->real_name[4] = 'i'; sp->real_name[5] = 'a'; sp->real_name[6] = 'l'; sp->real_name[7] = '-'; } } sp->in_refnum = -(s+1); return(s+1); } return(-1); } /* * This routine searches the unit table for a matching 'Out' * entry. */ static int find_serial_out(sp, length, plen, prefix, slen, suffix) struct serial_entry *sp; short plen, slen; char *prefix, *suffix; { DCtlHandle *dpp, dp; short count, len; struct driver *dvp, **dvpp; int i, j, out, s; count = UnitNtryCnt; dpp = UTableBase; for (s = 0; s < count; s++) { /* search the table */ if ((dp = dpp[s]) == 0) continue; if ((*dp)->dCtlFlags&RamFlag) { /* do indirections */ dvpp = (struct driver **)(*dp)->dCtlDriver; len = (*dvpp)->drvrName[0]; if (len != (length+1) || (*dvpp)->drvrName[1] != '.') /* simple screening */ continue; if (((*dvpp)->drvrName[plen+2] != 'O' && /* look for 'Out' in the right place */ (*dvpp)->drvrName[plen+2] != 'o') || ((*dvpp)->drvrName[plen+3] != 'u' && (*dvpp)->drvrName[plen+3] != 'U') || ((*dvpp)->drvrName[plen+4] != 't' && (*dvpp)->drvrName[plen+4] != 'T')) continue; for (i = 0; i < plen; i++) /* compare prefixes */ if (prefix[i] != (*dvpp)->drvrName[i+2]) break; if (i < plen) continue; for (i = 0; i < slen; i++) /* compare suffixes */ if (suffix[i] != (*dvpp)->drvrName[i+plen+2+3]) break; if (i < slen) continue; for (i = 0; i <= len; i++) /* copy out the name to the result */ sp->out_name[i] = (*dvpp)->drvrName[i]; } else { dvp = (struct driver *)(*dp)->dCtlDriver; /* do the same for ROM drivers */ len = dvp->drvrName[0]; if (len != (length+1) || dvp->drvrName[1] != '.') continue; if ((dvp->drvrName[plen+2] != 'O' && dvp->drvrName[plen+2] != 'o') || (dvp->drvrName[plen+3] != 'u' && dvp->drvrName[plen+3] != 'U') || (dvp->drvrName[plen+4] != 't' && dvp->drvrName[plen+4] != 'T')) continue; for (i = 0; i < plen; i++) if (prefix[i] != dvp->drvrName[i+2]) break; if (i < plen) continue; for (i = 0; i < slen; i++) if (suffix[i] != dvp->drvrName[i+plen+2+3]) break; if (i < slen) continue; for (i = 0; i <= len; i++) sp->out_name[i] = dvp->drvrName[i]; } sp->out_refnum = -(s+1); /* return the refnum and success */ return(s); } return(-1); } #ifdef TEST list_serial() { register short i, j, k; register short count = 0; struct serial_entry s[50]; struct serial_entry *sp[50], *x, **spp; char cc[200]; /* * build a list of devices */ j = 0; for (i = 0; ;i++) { j = find_serial(j, &s[i]); if (j < 0) break; sp[i] = &s[i]; count++; } /* * sort the list */ for (i = 0; i < (count-1); i++) { spp = &sp[i]; for (j = i+1; j < count; j++) { for (k = 0; ;k++) { if (sp[j]->real_name[0] == k) { if ((*spp)->real_name[0] != k) spp = &sp[j]; break; } if ((*spp)->real_name[0] == k) break; if (sp[j]->real_name[k+1] < (*spp)->real_name[k+1]) spp = &sp[j]; if (sp[j]->real_name[k+1] != (*spp)->real_name[k+1]) break; } } if (spp != &sp[i]) { x = sp[i]; sp[i] = *spp; *spp = x; } } /* * print the list */ for (i = 0; i < count; i++) { sprintf(cc, "%d: '", i); logit(cc); sp[i]->real_name[1+sp[i]->real_name[0]] = '\0'; logit(&sp[i]->real_name[1]); sprintf(cc, "' [%d]='", sp[i]->in_refnum); logit(cc); sp[i]->in_name[1+sp[i]->in_name[0]] = '\0'; logit(&sp[i]->in_name[1]); sprintf(cc, "' [%d]='", sp[i]->out_refnum); logit(cc); sp[i]->out_name[1+sp[i]->out_name[0]] = '\0'; logit(&sp[i]->out_name[1]); logit("\n"); } sprintf(cc, "%d entries found\n", count); logit(cc); } #endif /* TEST */ -------------------------------------------------------------------------------- -- Paul Campbell, UniSoft Corp. 6121 Hollis, Emeryville, Ca E-mail: ..!{ucbvax,hoptoad}!unisoft!paul Nothing here represents the opinions of UniSoft or its employees (except me) "Nuclear war doesn't prove who's Right, just who's Left" (ABC news 10/13/87)