jeffsi@tekecs.TEK.COM (Jeff Siegel) (09/28/88)
Help!! I am trying desperately to write a serial driver which will allow me to: (1) trap the interrupt (2) load the data pending (3) do some special processing whenever a specific sized packet has been completely grabbed I've done this type of thing before on other machines (breaking the rules though). I'd like to do it on the Mac in a standard way, but Inside Macintosh V1/2 just doesn't give enough information... Is there anyone out there with some example code or can you offer any advice? I'd be eternally grateful... Jeffrey Siegel (301) 948-7151
paul@unisoft.UUCP (n) (09/28/88)
In article <10407@tekecs.TEK.COM> jeffsi@tekecs.TEK.COM (Jeff Siegel) writes:
] Help!! I am trying desperately to write a serial driver which will
] allow me to: (1) trap the interrupt
] (2) load the data pending
] (3) do some special processing whenever a specific sized
] packet has been completely grabbed
]
] I've done this type of thing before on other machines (breaking the
] rules though). I'd like to do it on the Mac in a standard way, but
] Inside Macintosh V1/2 just doesn't give enough information...
]
Be warned! Doing something like this will NOT work with a 3rd party
serial card (yes they do exist), (who knows maybe it wont work on future Macs,
they may change the hardware, that's why there is a driver interface), if you
want to write portable code make sure you use the interface in IM2/4.
The only problem with connecting to 3rd party cards is the original
'appliance' idea (its a closed box, it only has two serial ports ..... etc
etc). At the moment the only 'known' ports have names '.AIn'/'.Aout',
'.Bin'/'.Bout', if you want to connect to 3rd party boards you have to
know their 'real' names. Apple have publicly said that this will all be fixed
in the medium term (ie probably sometime next year), in the short term
I have code which I have put in the public domain (mail me if you want a copy)
that searches the driver name space (the unit table) for driver pairs that
have names of the form <PREFIX>In<SUFFIX> and <PREFIX>Out<SUFFIX> ('In'/'Out'
are case insensitive) and returns a list to the caller, this seems to
identify all the drivers of all the boards I know of.
Paul Campbell
--
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)
han@Apple.COM (Byron Han, Architect) (09/30/88)
Direct manipulation of the unit table or traversal thereof is strictly forbidden. Use the of code Paul posted is **strictly at your own risk** You will probably break in the future. The Macintosh Communications Toolbox will contain a Communications Resource Manager which will provide a directory services for the registration and lookup of communications resources. ------------------------------------------------------------------------------ Byron Han, Communications Architect "Just say NO to MS-DOS." Apple Computer, Inc. ------------------------------------- 20525 Mariani Ave, MS27Y domain: han@apple.COM Cupertino, CA 95014 UUCP:{sun,voder,nsc,decwrl}!apple!han -------------------------------------- GENIE: BYRONHAN ATTnet: 408-973-6450 Applelink: HAN1 CompuServe: 72167,1664 ------------------------------------------------------------------------------
imp@crayview.msi.umn.edu (Chuck Lukaszewski) (09/30/88)
In article <10407@tekecs.TEK.COM>, jeffsi@tekecs.TEK.COM (Jeff Siegel) writes: > Help!! I am trying desperately to write a serial driver which will > allow me to: (1) trap the interrupt > (2) load the data pending > (3) do some special processing whenever a specific sized > packet has been completely grabbed I'm not certain whether you want to replace the SERD driver or just do some special processing above and beyond it, but here are some things to consider: The Zilog 8530 is configured entirely from software, and its two ports may be manipulated basically independently. I don't think that Apple would be too upset if you were to trap the level-2 interrupts for a given port, as there is no real provision anywhere in IM for what you want to do, and the address of the level-2 interrupt vector is constant in the 680x0 arch.. HOWEVER, I would STRONGLY caution you to be multifinder friendly as a test of your interface to the rest of the operating system. That implies that I ought to be able to run Red Ryder out the other port while using your program. To this end, I believe that you could simply vector the level-2 interrupt to you and then check the IFR register in the 8530 to see if it is for you. If not, you must jump to the routine that was there before. In this situation, it is CRITICAL that you leave the stack alone (i.e. don't do the initial processing that the level-2 routine does now) and jump to the TOP of the level-2 routine and not to some offset inside of it. I say this for three reasons: (1) To minize the rule-bending/breaking affect as little as possible, and it seems to me that changing the level-2 interrupt address is plenty; (2) You can't make assumptions about which machine you are running on so you can't assume the header code in the interrupt handler will be the same and (3) that code may be totally different anyway as someone else may have already trapped it. You can do all of those things that you want by paying attention to appropriate registers and enables in the 8530. As far as machine compatibility goes, be SURE to use the global SCCBase rather than hardcoding addresses. (I know, I know - globals are off-limits but there is no OS routine to give that value). This is especially true if you are running on the Lisa. BTW, if you want to run on the Lisa, note that the 8530 interrupts are level 6 (!!) rather than level 2. The 8530 is mapped into mem- ory just as on the Macintosh Plus/SE/II, however, so SCCBase will work properly. There is also a baud rate compensation you must do because of a 2% difference in speeds between the machines. Write to me if you need more information. ---===---===---===---===--/* Chuck Lukaszewski */--===---===---===---===--- ARPAnet/NSFnet/MRnet: AppleLink: SnailMail: Ma Bell: imp@crayview.msi.umn.edu UG0138 Minneapolis MN 55418 612/789-0931
tim@hoptoad.uucp (Tim Maroney) (09/30/88)
In article <17974@apple.Apple.COM> han@apple.com.UUCP (Byron Han, Architect) writes: >Direct manipulation of the unit table or traversal thereof is strictly >forbidden. Use the of code Paul posted is **strictly at your own risk** >You will probably break in the future. Oh? I am not completely up to date on technical notes (the last one I have is #162) but Tech Note #71, "Finding Drivers in the Unit Table", gives sample code that iterates over the unit table. I don't recall seeing anything about this in the Compatibility Guidelines, either. It's really irritating to be told over and over that everything will be fine if we just follow the rules, only to have Apple repeatedly change the rules, and get hostile if we point out ways the rules can't be followed (e.g., socket listeners accessing globals under Multifinder). -- Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim "I wrapped a newspaper round my head, so I'd look like I was deep. I said some mumbo-jumbos then: I told him he was going to sleep. I robbed his ring, his pocket watch, and everything else I found. I had that sucker hypnotized; he didn't even make a sound!" - Frank Zappa, "Kozmik Debris"
paul@unisoft.UUCP (n) (09/30/88)
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 <Resources.h> #include <Memory.h> #include <Devices.h> #include <Files.h> #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 <PREFIX>In<SUFFIX> ('In' can ne in any case) * * - The other has the form <PREFIX>Out<SUFFIX> * * - the strings <PREFIX> and <SUFFIX) for the two devices must resp. * match. Either (but not both) can be of zero lengh. * * Of course we can't make absolutely certain that these are serial drivers * but for the moment it should suffice. * * The results are returned in the data structure declared below, it should be * callable from Pascal without change (in C dont forget to declare it * 'pascal ... extern'). * * The last routine in this file is used for my testing and is also an example * of how to call find_serial(). One can obtain a list of all the serial devices * in a system by code like: * * for (ind = 0; ;) { * ind = find_serial(ind, &result); * if (ind < 0) * break; * * .... do something with result .... * * } * * A name is returned in 'real_name' which is recommend for use when providing * menus to users. */ /* * returned structure - all strings are 'pascal' counted strings */ struct serial_entry { char real_name[64]; /* The <PREFIX><SUFFIX> 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)