home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 396.lha / MSH_v1.30s / src / device.c < prev    next >
C/C++ Source or Header  |  1990-07-10  |  19KB  |  803 lines

  1. /*-
  2.  * $Id: device.c,v 1.30 90/06/04 23:18:39 Rhialto Rel $
  3.  * $Log:    device.c,v $
  4.  * Revision 1.30  90/06/04  23:18:39  Rhialto
  5.  * Release 1 Patch 3
  6.  * 
  7.  * DEVICE.C
  8.  *
  9.  * The messydisk.device code that makes it a real Exec .device.
  10.  * Mostly based on the 1.1 RKM example and Matt Dillon's library code.
  11.  *
  12.  * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
  13.  * not be used or copied without a licence.
  14. -*/
  15.  
  16. #include "dev.h"
  17. #include "device.h"
  18.  
  19. /*#undef DEBUG            /**/
  20. #ifdef DEBUG
  21. #   define    debug(x)  dbprintf x
  22. #else
  23. #   define    debug(x)
  24. #endif
  25.  
  26. /*
  27.  * The first executable location. This should return an error in case
  28.  * someone tried to run you as a program (instead of loading you as a
  29.  * device)
  30.  */
  31. /* INDENT OFF */
  32. #asm
  33.     moveq.l #20,d0
  34.     rts
  35. #endasm
  36. /* INDENT ON */
  37.  
  38. /*
  39.  * A romtag structure. Both "exec" and "ramlib" look for this structure to
  40.  * discover magic constants about you (such as where to start running you
  41.  * from...).
  42.  */
  43. /* INDENT OFF */
  44. #asm
  45.     public    __H0_end
  46. _EndCode equ    __H0_end
  47.     public    _RomTag
  48. _RomTag:
  49.     dc.w    $4AFC        ; RTC_MATCHWORD
  50.     dc.l    _RomTag     ; rt_MatchTag
  51.     dc.l    __H0_end    ; rt_EndSkip
  52.     dc.b    0        ; rt_Flags (no RTF_AUTOINIT)
  53.     dc.b    VERSION     ; rt_Version
  54.     dc.b    3        ; rt_Type  NT_DEVICE
  55.     dc.b    RTPRI        ; rt_Pri
  56.     dc.l    _DevName    ; rt_Name
  57.     dc.l    _idString    ; rt_IdString
  58.     dc.l    _Init        ; rt_Init
  59. #endasm
  60. /* INDENT ON */
  61.  
  62. char        DevName[] = "messydisk.device";
  63. char        idString[] = "messydisk.device $Revision: 1.30 $ $Date: 90/06/04 23:18:39 $\r\n";
  64.  
  65. /*
  66.  * -30-6*X  Library vectors:
  67.  */
  68.  
  69. void        (*LibVectors[]) () =
  70. {
  71.     _DevOpen, _DevClose, _DevExpunge, _LibNull,
  72.  
  73.     _DevBeginIO,
  74.     _DevAbortIO,
  75.     (void (*) ()) -1
  76. };
  77.  
  78. /*
  79.  * Device commands:
  80.  */
  81.  
  82. void        (*funcTable[]) () = {
  83.     CMD_Invalid, CMD_Reset, CMD_Read, CMD_Write, CMD_Update, CMD_Clear,
  84.     CMD_Stop, CMD_Start, CMD_Flush, TD_Motor, TD_Seek, TD_Format,
  85.     TD_Remove, TD_Changenum, TD_Changestate, TD_Protstatus, TD_Rawread,
  86.     TD_Rawwrite, TD_Getdrivetype, TD_Getnumtracks, TD_Addchangeint,
  87.     TD_Remchangeint,
  88. };
  89.  
  90. /*
  91.  * Here begin the system interface commands. When the user calls
  92.  * OpenDevice/CloseDevice/RemDevice, this eventually gets trahslated into
  93.  * a call to the following routines (Open/Close/Expunge).  Exec has
  94.  * already put our device pointer in A6 for us.  Exec has turned off task
  95.  * switching while in these routines (via Forbid/Permit), so we should not
  96.  * take too long in them.
  97.  */
  98. /* INDENT OFF */
  99. #asm
  100.     public    _Init
  101. _Init:                ;a0=segment list
  102.     movem.l D2-D3/A0/A6,-(sp)
  103.     jsr    _CInit
  104.     movem.l (sp)+,D2-D3/A0/A6
  105.     rts
  106.  
  107.     public    __DevOpen
  108. __DevOpen:            ;d0=unitnum,d1=flags,a1=ioreq,a6=device
  109.     movem.l D0-D3/A1/A6,-(sp)
  110.     jsr    _DevOpen
  111.     movem.l (sp)+,D0-D3/A1/A6
  112.     rts
  113.  
  114.     public    __DevClose
  115. __DevClose:            ;a1=ioreq,a6=device
  116.     movem.l D2-D3/A1/A6,-(sp)
  117.     jsr    _DevClose
  118.     movem.l (sp)+,D2-D3/A1/A6
  119.     rts
  120.  
  121.     public    __DevExpunge
  122. __DevExpunge:            ;a6=device
  123.     movem.l D2-D3/A6,-(sp)
  124.     jsr    _DevExpunge
  125.     movem.l (sp)+,D2-D3/A6
  126.     rts
  127.  
  128.     public    __LibNull
  129. __LibNull:
  130.     clr.l    d0
  131.     rts
  132.  
  133.     public    __DevBeginIO
  134. __DevBeginIO:            ;a1=ioreq,a6=device
  135.     movem.l D2-D3/A1/A6,-(sp)
  136.     jsr    _DevBeginIO
  137.     movem.l (sp)+,D2-D3/A1/A6
  138.     rts
  139.  
  140.     public    __DevAbortIO
  141. __DevAbortIO:            ;a1=ioreq,a6=device
  142.     movem.l D2-D3/A1/A6,-(sp)
  143.     jsr    _DevAbortIO
  144.     movem.l (sp)+,D2-D3/A1/A6
  145.     rts
  146. #endasm
  147.  
  148. #ifdef HANDLE_IO_QUICK
  149. #asm
  150. ;;;;
  151. ;
  152. ;   C interface to the atomic set bit and test old value instruction.
  153. ;
  154. ;   Called as    BSET_ACTIVE(byte *address).
  155. ;
  156. ;   Old value of the bit returned all over d0.w
  157.  
  158. _BSET_ACTIVE:
  159.     move.l    4(sp),a0
  160.     bset    #0,(a0)         ; UNITB_ACTIVE
  161.     sne    d0
  162.     rts
  163.  
  164. #endasm
  165. #endif
  166. /* INDENT ON */
  167.  
  168. long        SysBase;    /* Argh! A global variable! */
  169.  
  170. /*
  171.  * The Initialization routine is given only a seglist pointer.    Since we
  172.  * are NOT AUTOINIT we must construct and add the device ourselves and
  173.  * return either NULL or the device pointer.  Exec has Forbid() for us
  174.  * during the call.
  175.  *
  176.  * If you have an extended device structure you must specify the size of the
  177.  * extended structure in MakeLibrary().
  178.  */
  179.  
  180. DEV           *
  181. CInit(D2, D3, segment)
  182. ulong        D2,
  183.         D3;
  184. long        segment;
  185. {
  186.     DEV        *dev;
  187.  
  188.     SysBase = *(long *) 4;
  189. #ifdef DEBUG
  190.     dbinit();
  191. #endif
  192.     dev = MakeLibrary(LibVectors, NULL, NULL, (long) sizeof (DEV), NULL);
  193.     if (DevInit(dev)) {
  194.     dev->dev_Node.ln_Type = NT_DEVICE;
  195.     dev->dev_Node.ln_Name = DevName;
  196.     dev->dev_Flags = LIBF_CHANGED | LIBF_SUMUSED;
  197.     dev->dev_Version = VERSION;
  198.     dev->dev_Revision = REVISION;
  199.     dev->dev_IdString = (APTR) idString;
  200.     dev->md_Seglist = segment;
  201.     AddDevice(dev);
  202.     return (dev);
  203.     }
  204.     FreeMem((char *) dev - dev->dev_NegSize, dev->dev_NegSize + dev->dev_PosSize);
  205.     return NULL;
  206. }
  207.  
  208. /*
  209.  * Open is given the device pointer, unitno and flags.    Either return the
  210.  * device pointer or NULL.  Remove the DELAYED-EXPUNGE flag. Exec has
  211.  * Forbid() for us during the call.
  212.  */
  213.  
  214. void
  215. DevOpen(unitno, flags, D2, D3, ioreq, dev)
  216. ulong        unitno;
  217. ulong        flags;
  218. ulong        D2,
  219.         D3;
  220. struct IOStdReq *ioreq;
  221. DEV           *dev;
  222. {
  223.     UNIT       *unit;
  224.  
  225.     debug(("OpenDevice unit %ld, flags %lx\n", unitno, flags));
  226.     if (unitno >= MD_NUMUNITS)
  227.     goto error;
  228.  
  229.     if ((unit = dev->md_Unit[unitno]) == NULL) {
  230.     if ((unit = UnitInit(dev, unitno)) == NULL)
  231.         goto error;
  232.     dev->md_Unit[unitno] = unit;
  233.     }
  234.     ioreq->io_Unit = (struct Unit *) unit;
  235.  
  236.     ++unit->mu_OpenCnt;
  237.     ++dev->dev_OpenCnt;
  238.     dev->dev_Flags &= ~LIBF_DELEXP;
  239.  
  240.     return;
  241.  
  242. error:
  243.     ioreq->io_Error = IOERR_OPENFAIL;
  244. }
  245.  
  246. /*
  247.  * Close is given the device pointer and the io request.  Be sure not to
  248.  * decrement the open count if already zero.    If the open count is or
  249.  * becomes zero AND there is a LIBF_DELEXP, we expunge the device and
  250.  * return the seglist.    Otherwise we return NULL.
  251.  *
  252.  * Note that this routine never sets LIBF_DELEXP on its own.
  253.  *
  254.  * Exec has Forbid() for us during the call.
  255.  */
  256.  
  257. long
  258. DevClose(D2, D3, ioreq, dev)
  259. ulong        D2,
  260.         D3;
  261. struct IOStdReq *ioreq;
  262. DEV           *dev;
  263. {
  264.     UNIT       *unit;
  265.  
  266.     unit = (UNIT *) ioreq->io_Unit;
  267.     debug(("CloseDevice io %08lx unit %08lx\n", ioreq, unit));
  268.  
  269.     /*
  270.      * See if the unit is still in use. If not, close it down. This may
  271.      * need to do an update, which requires the ioreq.
  272.      */
  273.  
  274.     if (unit->mu_OpenCnt && --unit->mu_OpenCnt == 0) {
  275.     dev->md_Unit[unit->mu_UnitNr] = NULL;
  276.     UnitCloseDown(ioreq, dev, unit);
  277.     }
  278.     /*
  279.      * Make sure the ioreq is not used again.
  280.      */
  281.     ioreq->io_Unit = (void *) -1;
  282.     ioreq->io_Device = (void *) -1;
  283.  
  284.     if (dev->dev_OpenCnt && --dev->dev_OpenCnt)
  285.     return (NULL);
  286.     if (dev->dev_Flags & LIBF_DELEXP)
  287.     return (DevExpunge(D2, D3, dev));
  288.     return (NULL);
  289. }
  290.  
  291. /*
  292.  * We expunge the device and return the Seglist ONLY if the open count is
  293.  * zero. If the open count is not zero we set the DELAYED-EXPUNGE
  294.  * flag and return NULL.
  295.  *
  296.  * Exec has Forbid() for us during the call.  NOTE ALSO that Expunge might be
  297.  * called from the memory allocator and thus we CANNOT DO A Wait() or
  298.  * otherwise take a long time to complete (straight from RKM).
  299.  *
  300.  * Apparently RemLibrary(lib) calls our expunge routine and would therefore
  301.  * freeze if we called it ourselves.  As far as I can tell from RKM,
  302.  * DevExpunge(lib) must remove the device itself as shown below.
  303.  */
  304.  
  305. long
  306. DevExpunge(D2, D3, dev)
  307. ulong        D2,
  308.         D3;
  309. DEV           *dev;
  310. {
  311.     long        Seglist;
  312.  
  313.     if (dev->dev_OpenCnt) {
  314.     dev->dev_Flags |= LIBF_DELEXP;
  315.     return (NULL);
  316.     }
  317.     Remove(dev);
  318.     DevCloseDown(dev);          /* Should be quick! */
  319. #ifdef DEBUG
  320.     dbuninit();
  321. #endif
  322.     Seglist = dev->md_Seglist;
  323.     FreeMem((char *) dev - dev->dev_NegSize,
  324.         (long) dev->dev_NegSize + dev->dev_PosSize);
  325.     return (Seglist);
  326. }
  327.  
  328. /*
  329.  * BeginIO entry point. We don't handle any QUICK requests, we just send
  330.  * the request to the proper unit to handle.
  331.  */
  332.  
  333. void
  334. DevBeginIO(D2, D3, ioreq, dev)
  335. ulong        D2,
  336.         D3;
  337. register struct IOStdReq *ioreq;
  338. DEV           *dev;
  339. {
  340.     UNIT       *unit;
  341.  
  342.     /*
  343.      * Bookkeeping.
  344.      */
  345.     unit = (UNIT *) ioreq->io_Unit;
  346.     debug(("BeginIO: io %08lx dev %08lx u %08lx\n", ioreq, dev, unit));
  347.  
  348.     /*
  349.      * See if the io command is within range.
  350.      */
  351.     if (STRIP(ioreq->io_Command) > TD_LASTCOMM)
  352.     goto NoCmd;
  353.  
  354. #ifdef HANDLE_IO_QUICK
  355.     Forbid();                   /* Disable(); is a bit too strong for us. */
  356. #endif
  357.  
  358.     /*
  359.      * Process all immediate commands no matter what. Don't even require
  360.      * an exclusive lock on the unit.
  361.      */
  362.     if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
  363.     goto Immediate;
  364.  
  365.     /*
  366.      * We don't handle any QUICK I/O since that only gives trouble with
  367.      * message ports and so. Other devices normally would include the code
  368.      * below.
  369.      */
  370. #ifdef HANDLE_IO_QUICK
  371.     /*
  372.      * See if the user does not request QUICK IO. If not, it is likely to
  373.      * be async and therefore we don't do it sync.
  374.      */
  375.     if (!(ioreq->io_Flags & IOF_QUICK))
  376.     goto NoQuickRequested;
  377.  
  378.     /*
  379.      * See if the unit is STOPPED. If so, queue the msg.
  380.      */
  381.     if (unit->mu_Flags & UNITF_STOPPED)
  382.     goto QueueMsg;
  383.  
  384.     /*
  385.      * This is not an immediate command. See if the device is busy. If
  386.      * not, process the action in this (the caller's) context.
  387.      */
  388.     if (!BSET_ACTIVE(&unit->mu_Flags))
  389.     goto Immediate;
  390. #endif
  391.  
  392.     /*
  393.      * We need to queue the device. Clear the QUICK flag.
  394.      */
  395. QueueMsg:
  396.     ioreq->io_Flags &= ~IOF_QUICK;
  397. NoQuickRequested:
  398. #ifdef HANDLE_IO_QUICK
  399.     Permit();                   /* Enable(); is a bit too strong for us. */
  400. #endif
  401.     PutMsg(&unit->mu_Port, ioreq);
  402.  
  403.     return;
  404.  
  405. Immediate:
  406. #ifdef HANDLE_IO_QUICK
  407.     Permit();                   /* Enable(); is a bit too strong for us. */
  408. #endif
  409.     debug(("BeginIO: Immediate\n"));
  410.     ioreq->io_Error = TDERR_NoError;
  411.     PerformIO(ioreq, unit);
  412.     return;
  413.  
  414. NoCmd:
  415.     ioreq->io_Error = IOERR_NOCMD;
  416.     TermIO(ioreq);
  417.     return;
  418.  
  419. }
  420.  
  421. /*
  422.  * Terminate an io request. Called (normally) for every BeginIO. 'Funny'
  423.  * commands that don't call TermIO, or call it multiple times, may not be
  424.  * properly handled unless you are careful. TD_ADDCHANGEINT and
  425.  * TD_REMCHANGEINT are obvious examples.
  426.  */
  427.  
  428. void
  429. TermIO(ioreq)
  430. register struct IOStdReq *ioreq;
  431. {
  432.     register UNIT  *unit;
  433.  
  434.     unit = (UNIT *) ioreq->io_Unit;
  435.     debug(("TermIO: io %08lx u %08lx %ld %d\n", ioreq, unit,
  436.        ioreq->io_Actual, ioreq->io_Error));
  437.  
  438. #ifdef HANDLE_IO_QUICK
  439.     /*
  440.      * Since immediate commands don't even require an exclusive lock on
  441.      * the unit, don't unlock it.
  442.      */
  443.     if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
  444.     goto Immediate;
  445.  
  446.     /*
  447.      * We may need to turn the active (lock) bit off, but not if we are
  448.      * within the task.
  449.      */
  450.     if (unit->mu_Flags & UNITF_INTASK)
  451.     goto Immediate;
  452.  
  453.     unit->mu_Flags &= ~UNITF_ACTIVE;
  454.  
  455.     /*
  456.      * The task may have work to do that came in while we were processing
  457.      * in the caller's context.
  458.      */
  459.     if (unit->mu_Flags & UNITF_WAKETASK) {
  460.     unit->mu_Flags &= ~UNITF_WAKETASK;
  461.     WakePort(&unit->mu_Port);
  462.     }
  463. #endif
  464.  
  465. Immediate:
  466.     /*
  467.      * If the quick bit is still set then wen don't need to reply the msg
  468.      * -- just return to the user.
  469.      */
  470.  
  471.     if (!(ioreq->io_Flags & IOF_QUICK))
  472.     ReplyMsg(&ioreq->io_Message);
  473.  
  474.     return;
  475. }
  476.  
  477. /*
  478.  * AbortIO entry point. We don't abort IO here.
  479.  */
  480.  
  481. long
  482. DevAbortIO(D2, D3, ioreq, dev)
  483. ulong        D2,
  484.         D3;
  485. DEV           *dev;
  486. struct IOStdReq *ioreq;
  487. {
  488.     return 1;
  489. }
  490.  
  491. void
  492. WakePort(port)
  493. register struct MsgPort *port;
  494. {
  495.     Signal(port->mp_SigTask, 1L << port->mp_SigBit);
  496. }
  497.  
  498. /*
  499.  * This is the main loop of the Unit tasks. It must be very careful with
  500.  * global data.
  501.  */
  502.  
  503. void
  504. UnitTask()
  505. {
  506.     /* DEV *dev; */
  507.     UNIT       *unit;
  508.     long        waitmask;
  509.     struct IOExtTD *ioreq;
  510.  
  511.     {
  512.     struct Task    *task,
  513.                *FindTask();
  514.  
  515.     task = FindTask(NULL);
  516.     unit = (UNIT *) task->tc_UserData;
  517.     /* dev = unit->mu_Dev; */
  518.     task->tc_UserData = NULL;
  519.     }
  520.  
  521.     /*
  522.      * Now finish initializing the message ports and other signal things
  523.      */
  524.  
  525.     {
  526.     byte        sigbit;
  527.  
  528.     unit->mu_DiskReplyPort.mp_SigBit = AllocSignal(-1L);
  529.     unit->mu_DiskReplyPort.mp_Flags = PA_SIGNAL;
  530.  
  531.     sigbit = AllocSignal(-1L);
  532.     unit->mu_Port.mp_SigBit = sigbit;
  533.     unit->mu_Port.mp_Flags = PA_SIGNAL;
  534.     waitmask = 1L << sigbit;
  535.  
  536.     unit->mu_DmaSignal = AllocSignal(-1L);
  537.     }
  538.  
  539.     for (;;) {
  540.     debug(("Task: Waiting... "));
  541.     Wait(waitmask);
  542.  
  543.     /*
  544.      * See if we are stopped.
  545.      */
  546.     if (unit->mu_Flags & UNITF_STOPPED)
  547.         continue;
  548.  
  549. #ifdef HANDLE_IO_QUICK
  550.     /*
  551.      * Lock the device. If it fails, we have set a flag such that the
  552.      * TermIO wakes us again.
  553.      */
  554.     unit->mu_Flags |= UNITF_WAKETASK;
  555.     if (BSET_ACTIVE(&unit->mu_Flags))
  556.         continue;
  557.  
  558.     unit->mu_Flags |= UNITF_INTASK;
  559. #endif
  560.  
  561.     while (ioreq = (struct IOExtTD *) GetMsg(&unit->mu_Port)) {
  562.         debug(("Task: io %08lx %x\n", ioreq, ioreq->iotd_Req.io_Command));
  563.         ioreq->iotd_Req.io_Error = 0;
  564.         PerformIO((&ioreq->iotd_Req), unit);
  565.     }
  566.  
  567. #ifdef HANDLE_IO_QUICK
  568.     unit->mu_Flags &= ~(UNITF_ACTIVE | UNITF_INTASK | UNITF_WAKETASK);
  569. #endif
  570.     }
  571. }
  572.  
  573. void
  574. CMD_Invalid(ioreq, unit)
  575. struct IOStdReq *ioreq;
  576. UNIT           *unit;
  577. {
  578.     ioreq->io_Error = IOERR_NOCMD;
  579.     TermIO(ioreq);
  580. }
  581.  
  582. void
  583. CMD_Stop(ioreq, unit)
  584. struct IOExtTD *ioreq;
  585. UNIT           *unit;
  586. {
  587.     unit->mu_Flags |= UNITF_STOPPED;
  588.     TermIO(ioreq);
  589. }
  590.  
  591. void
  592. CMD_Start(ioreq, unit)
  593. struct IOExtTD *ioreq;
  594. UNIT           *unit;
  595. {
  596.     unit->mu_Flags &= ~UNITF_STOPPED;
  597.     WakePort(&unit->mu_Port);
  598.     TermIO(ioreq);
  599. }
  600.  
  601. void
  602. CMD_Flush(ioreq, unit)
  603. struct IOExtTD *ioreq;
  604. UNIT           *unit;
  605. {
  606.     register struct IOStdReq *req;
  607.  
  608.     /* Flush our own command queue */
  609.     Forbid();
  610.     while (req = (struct IOStdReq *) GetMsg(unit->mu_Port)) {
  611.     req->io_Error = IOERR_ABORTED;
  612.     ReplyMsg(&req->io_Message);
  613.     }
  614.     Permit();
  615.  
  616.     WakePort(&unit->mu_Port);
  617.     TermIO(ioreq);
  618. }
  619.  
  620. void
  621. TrackdiskGateway(ioreq, unit)
  622. register struct IOExtTD *ioreq;
  623. UNIT           *unit;
  624. {
  625.     register struct IOExtTD *tdioreq;
  626.  
  627.     debug(("Trackdisk: %x ", ioreq->iotd_Req.io_Command));
  628.     tdioreq = unit->mu_DiskIOReq;
  629.  
  630.     /*
  631.      * Clone almost the entire io request to relay to the
  632.      * trackdisk.device.
  633.      */
  634.  
  635.     tdioreq->iotd_Req.io_Command = ioreq->iotd_Req.io_Command;
  636.     tdioreq->iotd_Req.io_Flags = ioreq->iotd_Req.io_Flags | IOF_QUICK;
  637.     tdioreq->iotd_Req.io_Length = ioreq->iotd_Req.io_Length;
  638.     tdioreq->iotd_Req.io_Data = ioreq->iotd_Req.io_Data;
  639.     tdioreq->iotd_Req.io_Offset = ioreq->iotd_Req.io_Offset;
  640.     if (ioreq->iotd_Req.io_Command & TDF_EXTCOM) {
  641.     tdioreq->iotd_Count = ioreq->iotd_Count;
  642.     tdioreq->iotd_SecLabel = ioreq->iotd_SecLabel;
  643.     }
  644.     BeginIO(tdioreq);
  645.     WaitIO(tdioreq);
  646.  
  647.     ioreq->iotd_Req.io_Error = tdioreq->iotd_Req.io_Error;
  648.     ioreq->iotd_Req.io_Actual = tdioreq->iotd_Req.io_Actual;
  649.  
  650.     TermIO(ioreq);
  651. }
  652.  
  653. #ifdef DEBUG
  654. /* DEBUGGING                */
  655. struct MsgPort *Dbport;     /* owned by the debug process        */
  656. struct MsgPort *Dback;        /* owned by the DOS device driver  */
  657. short        DBEnable;
  658. struct SignalSemaphore PortUse;
  659.  
  660. #define CTOB(x) (void *)(((long)(x))>>2)        /* BCPL conversion */
  661.  
  662. /*
  663.  * DEBUGGING CODE.    You cannot make DOS library calls that access
  664.  * other devices from within a device driver because the caller may not be
  665.  * a process.  If you need to make such calls you must create a port and
  666.  * construct the DOS messages yourself.  I do not do this.  To get
  667.  * debugging info out another PROCESS is created to which debugging
  668.  * messages can be sent. The replyport gets a new SigTask for every
  669.  * dbprintf call, therefore the semaphore.
  670.  */
  671.  
  672. extern void    debugproc();
  673. struct Library *DOSBase,
  674.            *OpenLibrary();
  675.  
  676. dbinit()
  677. {
  678.     struct Task    *task = FindTask(NULL);
  679.  
  680.     DOSBase = OpenLibrary("dos.library", 0L);
  681.     Dback = CreatePort("Dback", -1L);
  682.     FreeSignal((long) Dback->mp_SigBit);
  683.     Dback->mp_SigBit = 2;
  684.     InitSemaphore(&PortUse);
  685.     CreateProc("messydisk_DB", (long) TASKPRI + 1, CTOB(debugproc), 2000L);
  686.     WaitPort(Dback);            /* handshake startup    */
  687.     GetMsg(Dback);              /* remove dummy msg     */
  688.     DBEnable = 1;
  689.     dbprintf("Debugger running V1.11\n");
  690. }
  691.  
  692. dbuninit()
  693. {
  694.     struct Message  killmsg;
  695.  
  696.     if (Dbport) {
  697.     killmsg.mn_Length = 0;    /* 0 means die        */
  698.     ObtainSemaphore(&PortUse);
  699.     Dback->mp_SigTask = FindTask(NULL);
  700.     PutMsg(Dbport, &killmsg);
  701.     WaitPort(Dback);        /* He's dead jim!      */
  702.     GetMsg(Dback);
  703.     ReleaseSemaphore(&PortUse);
  704.     Dback->mp_SigBit = -1;
  705.     DeletePort(Dback);
  706.  
  707.     /*
  708.      * Since the debug process is running at a greater priority, I am
  709.      * pretty sure that it is guarenteed to be completely removed
  710.      * before this task gets control again.
  711.      */
  712.     }
  713.     CloseLibrary(DOSBase);
  714. }
  715.  
  716. dbprintf(a, b, c, d, e, f, g, h, i, j)
  717. long        a, b, c, d, e, f, g, h, i, j;
  718. {
  719.     struct {
  720.     struct Message    msg;
  721.     char        buf[256];
  722.     }            msgbuf;
  723.     register struct Message *msg = &msgbuf.msg;
  724.     register long   len;
  725.  
  726.     if (Dbport && DBEnable) {
  727.     ObtainSemaphore(&PortUse);      /* sprintf is not re-entrant */
  728.     sprintf(msgbuf.buf, a, b, c, d, e, f, g, h, i, j);
  729.     len = strlen(msgbuf.buf) + 1;
  730.     msg->mn_Length = len;    /* Length NEVER 0     */
  731.     Dback->mp_SigTask = FindTask(NULL);
  732.     PutMsg(Dbport, msg);
  733.     WaitPort(Dback);
  734.     GetMsg(Dback);
  735.     ReleaseSemaphore(&PortUse);
  736.     }
  737. }
  738.  
  739. /*
  740.  * BTW, the DOS library used by debugmain() was actually opened by the
  741.  * opener of the device driver.
  742.  */
  743.  
  744. debugmain()
  745. {
  746.     register struct Message *msg;
  747.     register long   len;
  748.     register void  *fh,
  749.            *Open();
  750.     void       *fh2;
  751.     struct Message  DummyMsg;
  752.  
  753.     Dbport = CreatePort("Dbport", -1L);
  754.     fh = Open("CON:0/20/640/101/Device debug", MODE_NEWFILE);
  755.     fh2 = Open("PAR:", MODE_OLDFILE);
  756.     PutMsg(Dback, &DummyMsg);
  757.     for (;;) {
  758.     WaitPort(Dbport);
  759.     msg = GetMsg(Dbport);
  760.     len = msg->mn_Length;
  761.     if (len == 0)
  762.         break;
  763.     --len;            /* Fix length up     */
  764.     if (DBEnable & 1)
  765.         Write(fh, msg + 1, len);
  766.     if (DBEnable & 2)
  767.         Write(fh2, msg + 1, len);
  768.     PutMsg(Dback, msg);
  769.     }
  770.     Close(fh);
  771.     Close(fh2);
  772.     DeletePort(Dbport);
  773.     PutMsg(Dback, msg);         /* Kill handshake  */
  774. }
  775.  
  776. /*
  777.  * The assembly tag for the DOS process:  CNOP causes alignment problems
  778.  * with the Aztec assembler for some reason.  I assume then, that the
  779.  * alignment is unknown.  Since the BCPL conversion basically zero's the
  780.  * lower two bits of the address the actual code may start anywhere within
  781.  * 8 bytes of address (remember the first longword is a segment pointer
  782.  * and skipped).  Sigh....  (see CreateProc() above).
  783.  */
  784. /* INDENT OFF */
  785. #asm
  786.     public    _debugproc
  787.     public    _debugmain
  788.  
  789.     cseg
  790. _debugproc:
  791.     nop
  792.     nop
  793.     nop
  794.     nop
  795.     nop
  796.     movem.l D2-D7/A2-A6,-(sp)
  797.     jsr    _debugmain
  798.     movem.l (sp)+,D2-D7/A2-A6
  799.     rts
  800. #endasm
  801.  
  802. #endif                /* DEBUG */
  803.