home *** CD-ROM | disk | FTP | other *** search
/ Dream 44 / Amiga_Dream_44.iso / Amiga / workbench / pilotes / Zorro / vbak2091.lha / vbak2091.c < prev    next >
C/C++ Source or Header  |  1997-08-13  |  16KB  |  741 lines

  1. /* vb2091 V1.2 (13.8.97)
  2.  
  3.     (c) in 1994 by Volker Barthelmann
  4.     modified 1996-97 by Andreas R. Kleinert,
  5.                         Andreas_Kleinert@t-online.de
  6.  
  7.    USAGE AT YOUR OWN RISK. NOBODY CAN BE HELD RESPONSIBLE FOR ANY DAMAGES.
  8. */
  9.  
  10. #include "compiler.h"
  11.  
  12.  
  13. #define AUTHORS "vb2091 V1.2 (c) in 1994 by Volker Barthelmann.\n"   \
  14.                 "Changes by Andreas R. Kleinert in 1996-97\n"
  15. #define RISK    "USAGE AT YOUR OWN RISK.\n"                          \
  16.                 "NOBODY CAN BE HELD RESPONSIBLE FOR ANY DAMAGES.\n"
  17.  
  18.  
  19. #ifdef __SASC
  20. #define __USE_SYSBASE
  21. #endif
  22.  
  23. #ifndef __inline
  24. #define __inline inline
  25. #endif
  26.  
  27. #ifndef inline
  28. #define inline
  29. #endif
  30.  
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35.  
  36. #include <exec/execbase.h>
  37. #include <exec/memory.h>
  38. #include <exec/io.h>
  39. #include <exec/semaphores.h>
  40. #include <devices/trackdisk.h>
  41. #include <devices/timer.h>
  42. #include <dos/dosextens.h>
  43. #include <dos/filehandler.h>
  44. #include <dos/dostags.h>
  45.  
  46. #ifdef __SASC
  47. #include <proto/exec.h>
  48. #include <proto/dos.h>
  49. #include <proto/utility.h>
  50. #include <clib/alib_protos.h>
  51. #else
  52. #include <clib/exec_protos.h>
  53. #include <clib/alib_protos.h>
  54. #include <clib/dos_protos.h>
  55. #endif /* __SASC */
  56.  
  57.  
  58.  
  59. #define DEV_BEGINIO (-30)
  60.  
  61. #define min(a,b)    ((a) < (b) ? (a) : (b))
  62.  
  63.  
  64. #define RESERVED (1<<0)
  65. #define BROKEN   (1<<1)
  66. #define SINGLEF  (1<<2)
  67. #define NOCACHE  (1<<3)
  68. #define NOWRITE  (1<<4)
  69. #define NOASYNCH (1<<5)
  70.  
  71.  
  72. #define MAXUNIT 8
  73.  
  74. #ifdef __SASC
  75.  
  76. void __asm (*oldbeginio)(register __a1 struct IOStdReq *req, register __a6 struct Device *dev);
  77.  
  78. __aligned struct IOStdReq *IO  [MAXUNIT] = { 0, 0, 0, 0, 0, 0, 0, 0};
  79. __aligned void            *Unit[MAXUNIT] = { 0, 0, 0, 0, 0, 0, 0, 0};
  80.  
  81. char              __aligned zahl[]        = "0123456789";
  82.  
  83. void __inline __regargs copymem(UBYTE *s, UBYTE *d, ULONG b);
  84. void __inline __regargs copymem(UBYTE *s, UBYTE *d, ULONG b)
  85. {
  86.  while(b--) *d++ = *s++;
  87. }
  88.  
  89. void __inline __regargs copymemquick(ULONG *s, ULONG *d, ULONG b);
  90. void __inline __regargs copymemquick(ULONG *s, ULONG *d, ULONG b)
  91. {
  92.  while(b) { *d++ = *s++; b -= 4; }
  93. }
  94.  
  95. void __inline __regargs FastCopy(APTR s, APTR d, ULONG b);
  96. void __inline __regargs FastCopy(APTR s, APTR d, ULONG b)
  97. {
  98.  /* -----------------------------------------------------
  99.  
  100.     #define one out of:  OS_COPY_PLAIN,  OS_COPY_OPT
  101.                          OWN_COPY_PLAIN, OWN_COPY_OPT
  102.                          OWN_COPY_SPECIAL
  103.  
  104.     ----------------------------------------------------- */
  105. #define OWN_COPY_SPECIAL
  106.  
  107.  
  108.  
  109.  /* >>--------------------------------------------------- */
  110. #ifdef OS_COPY_PLAIN
  111.  
  112.  CopyMem(s, d, b);
  113.  
  114. #endif
  115.  
  116.  /* >>--------------------------------------------------- */
  117. #ifdef OS_COPY_OPT
  118.  
  119.       if((ULONG)b & 3) CopyMem(      s, d, b);
  120.  else if((ULONG)s & 3) CopyMem(      s, d, b);
  121.  else if((ULONG)d & 3) CopyMem(      s, d, b);
  122.  else                  CopyMemQuick( s, d, b);
  123.  
  124. #endif
  125.  
  126.  /* >>--------------------------------------------------- */
  127. #ifdef OWN_COPY_PLAIN
  128.  
  129.  copymem(s, d, b);
  130.  
  131. #endif
  132.  
  133.  /* >>--------------------------------------------------- */
  134. #ifdef OWN_COPY_OPT
  135.  
  136.       if((ULONG)b & 3) copymem(      s, d, b);
  137.  else if((ULONG)s & 3) copymem(      s, d, b);
  138.  else if((ULONG)d & 3) copymem(      s, d, b);
  139.  else                  copymemquick( s, d, b);
  140.  
  141.  #endif
  142.  
  143.  
  144.  /* >>------------ FASTEST in comparison ---------------- */
  145.  /* >>             on 4000/040 with 16 MB FAST            */
  146. #ifdef OWN_COPY_SPECIAL
  147.  
  148.       if((ULONG)b & 3) CopyMem(      s, d, b);
  149.  else if((ULONG)s & 3) CopyMem(      s, d, b);
  150.  else if((ULONG)d & 3) CopyMem(      s, d, b);
  151.  else                  copymemquick( s, d, b);
  152.  
  153. #endif
  154. }
  155.  
  156. #else /* __SASC */
  157.  
  158. #ifdef __VBCC
  159.  
  160. void (*oldbeginio)(__reg("a1") struct IOStdReq *, __reg("a6") struct Device *);
  161.  
  162. #else
  163.  
  164. void            (*oldbeginio)( register __a1 struct IOStdReq *req_a1 GNUCREG(a1), register __a6 struct Device *dev GNUCREG(a6) );
  165.  
  166. #endif /* __VBCC */
  167.  
  168. struct IOStdReq *IO  [MAXUNIT] = { 0, 0, 0, 0, 0, 0, 0, 0};
  169. void            *Unit[MAXUNIT] = { 0, 0, 0, 0, 0, 0, 0, 0};
  170.  
  171. char             zahl[]        = "0123456789";
  172.  
  173. #define FastCopy CopyMem
  174.  
  175. #endif /* __SASC */
  176.  
  177.  
  178. ULONG flags      = 0,           UnitNr   = 0,      unitmask = 0;
  179. ULONG SIZE       = 262144,      DIVSIZE2 = 131072, msize;
  180. ULONG MAXN       = 16,          MIN1BUF  = 131072, MIN2BUF  = 65536;
  181. ULONG MULMIN2BUF = 16 * 131072;
  182.  
  183. struct SignalSemaphore *ss      = NULL;
  184. UBYTE                  *buffer  = NULL;
  185. UBYTE                  *buffer2 = NULL;
  186.  
  187.  
  188. #ifdef __SASC
  189. void __saveds __asm mybeginio(register __a1 struct IOStdReq *req_a1,register __a6 struct Device *dev_a6)
  190. {
  191.  struct IOStdReq *req = req_a1;
  192.  struct Device   *dev = dev_a6;
  193.  ULONG flag;
  194. #else
  195.  
  196. #ifdef __VBCC
  197.  
  198. void mybeginio(__reg("a1") struct IOStdReq *req,__reg("a6") struct Device *dev)
  199. {
  200.  ULONG flag;
  201.  geta4();
  202.  
  203. #else
  204.  
  205. ULONG __saveds ASM mybeginio( register __a1 struct IOStdReq *req_a1 GNUCREG(a1), register __a6 struct Device *dev GNUCREG(a6) )
  206. {
  207.  struct IOStdReq *req = req_a1;
  208.  struct Device   *dev = dev_a6;
  209.  ULONG flag;
  210.  
  211. #endif /* __VBCC */
  212.  
  213. #endif
  214.  
  215.  
  216.  
  217.  ObtainSemaphore(ss);
  218.  
  219.  for(flag = 0; flag < MAXUNIT; flag++)
  220.   {
  221.    if(req->io_Unit == Unit[flag])
  222.     {
  223.      struct IOStdReq *mreq;
  224.      struct MsgPort  *port;
  225.      ULONG  actual,data,offset,length,lactual,un;
  226.  
  227.      mreq = req;
  228.      un   = flag;
  229.  
  230.      if((req->io_Command & 0xFF) == CMD_READ)
  231.       {
  232.        ULONG ldata, msize;
  233.  
  234.  
  235.        if(!(flags & BROKEN))
  236.          if((ULONG) req->io_Data < 16777216) goto old;
  237.  
  238.  
  239.        port = (struct MsgPort *) CreatePort(NULL,0);
  240.        if(!port) goto old;
  241.  
  242.  
  243.        IO[un]->io_Message.mn_ReplyPort = port;
  244.  
  245.        actual = 0;
  246.        length = mreq->io_Length;
  247.  
  248.        if(length < MIN1BUF)
  249.         {
  250.                                  msize = min( length,              DIVSIZE2);
  251.         }else
  252.         {
  253.          if(length > MULMIN2BUF) msize = min((length+MAXN-1)/MAXN, DIVSIZE2);
  254.           else                   msize = min( MIN2BUF,             DIVSIZE2);
  255.         }
  256.  
  257.        if(msize >= 512) msize = msize & 0xfffffe00;
  258.  
  259.        offset  =         mreq->io_Offset;
  260.        data    = (ULONG) mreq->io_Data;
  261.        lactual =         (flag = 0);
  262.        ldata   =         data;
  263.  
  264.        req = IO[un];
  265.        dev = IO[un]->io_Device;
  266.  
  267.        if(flags & NOCACHE) CacheControl(0, CACRF_EnableD);
  268.        if(flags & SINGLEF)
  269.         {
  270.          do
  271.           {
  272.            req->io_Command = CMD_READ;
  273.            req->io_Offset  = offset;
  274.            req->io_Length  = min(SIZE, length);
  275.            req->io_Length  = min(msize, length);
  276.            req->io_Data    = buffer;
  277.  
  278. #ifdef __SASC
  279.             oldbeginio(req, dev);
  280. #else
  281. #ifdef __VBCC
  282.             oldbeginio(req, dev);
  283. #else
  284.             oldbeginio(req, dev);
  285. #endif /* __VBCC */
  286. #endif
  287.  
  288.            WaitIO((struct IORequest *) req);
  289.  
  290.            lactual  = req->io_Actual;
  291.            actual  += lactual;
  292.  
  293.            ldata    = data;
  294.            data    += lactual;
  295.            offset  += lactual;
  296.            length  -= lactual;
  297.  
  298.            flag     = 1-flag; /* toggle 0/1 */
  299.  
  300.            FastCopy(buffer,(APTR) ldata,lactual);
  301.  
  302.           }while( (length) && (req->io_Actual >= req->io_Length) );
  303.         }else
  304.         {
  305.          do
  306.           {
  307.            req->io_Command = CMD_READ;
  308.            req->io_Offset  = offset;
  309.            req->io_Length  = min(msize, length);
  310.  
  311.            if(!flag) req->io_Data = buffer;
  312.             else     req->io_Data = buffer2;
  313.  
  314. #ifdef __SASC
  315.            oldbeginio(req, dev);
  316. #else
  317. #ifdef __VBCC
  318.            oldbeginio(req, dev);
  319. #else
  320.            oldbeginio(req, dev);
  321. #endif /* __VBCC */
  322. #endif
  323.  
  324.            if(flag) FastCopy(buffer,  (APTR) ldata, lactual);
  325.             else    FastCopy(buffer2, (APTR) ldata, lactual);
  326.  
  327.            WaitIO((struct IORequest *) req);
  328.  
  329.            lactual  = req->io_Actual;
  330.            actual  += lactual;
  331.  
  332.            ldata    = data;
  333.            data    += lactual;
  334.            offset  += lactual;
  335.            length  -= lactual;
  336.  
  337.            flag     = 1-flag; /* toggle 0/1 */
  338.  
  339.           }while( (length) && (req->io_Actual >= req->io_Length) );
  340.  
  341.          if(flag) FastCopy(buffer,  (APTR) ldata, lactual);
  342.           else    FastCopy(buffer2, (APTR) ldata, lactual);
  343.  
  344.         }
  345.  
  346.        if(flags & NOCACHE) CacheControl(0xffffffff, CACRF_EnableD);
  347.  
  348.        mreq->io_Actual = actual;
  349.        mreq->io_Error  = req->io_Error;
  350.  
  351.        if(!(mreq->io_Flags & IOF_QUICK)) ReplyMsg(&mreq->io_Message);
  352.  
  353.        DeletePort(port);
  354.  
  355.        ReleaseSemaphore(ss);
  356.  
  357.        return;
  358.       }
  359.  
  360.      if((req->io_Command & 0xFF) == CMD_WRITE)
  361.       {
  362.        if(flags & NOWRITE) goto old;
  363.  
  364.        if(!(flags & BROKEN))
  365.          if((ULONG) req->io_Data<16777216) goto old;
  366.  
  367.  
  368.        port = (struct MsgPort *) CreatePort(NULL,0);
  369.        if(!port) goto old;
  370.  
  371.        IO[un]->io_Message.mn_ReplyPort = port;
  372.  
  373.        actual =         0;
  374.        length =         mreq->io_Length;
  375.        offset =         mreq->io_Offset;
  376.        data   = (ULONG) mreq->io_Data;
  377.  
  378.        req = IO[un];
  379.        dev = IO[un]->io_Device;
  380.  
  381.        if(flags & NOCACHE) CacheControl(0,CACRF_EnableD);
  382.  
  383.        do
  384.         {
  385.          if(SIZE >= length) req->io_Length = length;
  386.           else              req->io_Length = SIZE;
  387.  
  388.          FastCopy((APTR) data, buffer, req->io_Length);
  389.  
  390.          req->io_Offset  = offset;
  391.          req->io_Data    = buffer;
  392.          req->io_Command = CMD_WRITE;
  393.  
  394. #ifdef __SASC
  395.          oldbeginio(req, dev);
  396. #else
  397. #ifdef __VBCC
  398.          oldbeginio(req, dev);
  399. #else
  400.          oldbeginio(req, dev);
  401. #endif /* __VBCC */
  402. #endif
  403.  
  404.          WaitIO((struct IORequest *) req);
  405.  
  406.          actual  += (lactual = req->io_Actual);
  407.          data    +=  lactual;
  408.          offset  +=  lactual;
  409.          length  -=  lactual;
  410.  
  411.         }while( (length) && (req->io_Actual >= req->io_Length) );
  412.  
  413.        if(flags & NOCACHE) CacheControl(0xffffffff, CACRF_EnableD);
  414.  
  415.        mreq->io_Actual = actual;
  416.        mreq->io_Error  = req->io_Error;
  417.  
  418.        if(!(mreq->io_Flags & IOF_QUICK)) ReplyMsg(&mreq->io_Message);
  419.  
  420.        DeletePort(port);
  421.  
  422.        ReleaseSemaphore(ss);
  423.  
  424.        return;
  425.       }
  426.  
  427.      break;
  428.     }
  429.   }
  430.  
  431. old:
  432. #ifdef __SASC
  433.  oldbeginio(req, dev);
  434. #else
  435. #ifdef __VBCC
  436.  oldbeginio(req, dev);
  437. #else
  438.  oldbeginio(req, dev);
  439. #endif /* __VBCC */
  440. #endif
  441.  
  442.  if(flags & NOASYNCH)
  443.   {
  444.    ULONG sig = 1<<req->io_Message.mn_ReplyPort->mp_SigBit;
  445.  
  446.    Wait(sig);
  447.    SetSignal(sig, sig); /* again */
  448.   }
  449.  
  450.  ReleaseSemaphore(ss);
  451. }
  452.  
  453.  
  454. #ifdef __SASC
  455.  
  456. void __regargs __chkabort(void) { } /* don't break us ! */
  457. void __regargs _CXBRK(void)     { }
  458.  
  459. void __inline StdioWrite(BPTR out, char *txt);
  460. void __inline StdioWrite(BPTR out, char *txt)
  461. {
  462.  if(out) Write(out, txt, strlen(txt));
  463. }
  464.  
  465. #else
  466.  
  467. #ifdef __VBCC
  468.  
  469. void StdioWrite(BPTR out, char *txt);
  470. void StdioWrite(BPTR out, char *txt)
  471. {
  472.  if(out) Write(out, txt, strlen(txt));
  473. }
  474.  
  475. #else
  476.  
  477. void inline StdioWrite(BPTR out, char *txt);
  478. void inline StdioWrite(BPTR out, char *txt)
  479. {
  480.  if(out) Write(out, txt, strlen(txt));
  481. }
  482.  
  483. #endif /* __VBCC */
  484.  
  485. #endif
  486.  
  487.  
  488. char version[] = "\0$VER: vb2091 1.2 (13.8.97)";
  489.  
  490. int main(long argc, char *argv[])
  491. {
  492.  ULONG           tmp, op, devopen, i, j, ret = 0;
  493.  ULONG           opened[8], patched[8];
  494.  struct MsgPort *iosink[MAXUNIT] = {0,0,0,0,0,0,0,0};
  495.  char           *Device, *p;
  496.  UBYTE           port_name[256];
  497.  
  498.  
  499.  tmp     = 0;
  500.  devopen = 0;
  501.  Device  = "2nd.scsi.device";
  502.  
  503.  op = Output();
  504.  
  505.  for(i=1; i<argc; i++)
  506.   {
  507.    if(!strcmp("BUFSIZE",argv[i]))
  508.     {
  509.                SIZE = atol(argv[++i])*1024;
  510.      if(!SIZE) SIZE = 262144;
  511.  
  512.      DIVSIZE2 = SIZE >> 1;
  513.  
  514.      continue;
  515.     }
  516.  
  517.    if(!strcmp("MIN1BUF",argv[i]))
  518.     {
  519.                   MIN1BUF = atol(argv[++i])*1024;
  520.      if(!MIN1BUF) MIN1BUF = 131072;
  521.  
  522.      continue;
  523.     }
  524.  
  525.    if(!strcmp("MIN2BUF",argv[i]))
  526.     {
  527.                   MIN2BUF = atol(argv[++i])*1024;
  528.      if(!MIN2BUF) MIN2BUF = 65536;
  529.  
  530.      continue;
  531.     }
  532.  
  533.    if(!strcmp("MAXN",argv[i]))
  534.     {
  535.                MAXN = atol(argv[++i]);
  536.      if(!MAXN) MAXN = 16;
  537.  
  538.      continue;
  539.     }
  540.  
  541.    if(!strcmp("DEVICE",argv[i]))
  542.     {
  543.      Device = argv[++i];
  544.  
  545.      continue;
  546.     }
  547.  
  548.    if(!strcmp("UNIT",argv[i]))
  549.     {
  550.      p = argv[++i];
  551.  
  552.      while(*p!=0)
  553.       {
  554.        if(*p<'0'||*p>'7')
  555.         {
  556.          StdioWrite(op, "You can only use unit 0..7!!\n");
  557.          exit(0);
  558.         }
  559.  
  560.        unitmask|=1<<(*p-'0');
  561.        p++;
  562.       }
  563.  
  564.      continue;
  565.     }
  566.  
  567.    if(!strcmp("BROKEN",argv[i]))
  568.     {
  569.      flags |= BROKEN;
  570.  
  571.      continue;
  572.     }
  573.  
  574.    if(!strcmp("SINGLE",argv[i]))
  575.     {
  576.      flags |= SINGLEF;
  577.  
  578.      continue;
  579.     }
  580.  
  581.    if(!strcmp("NOCACHE",argv[i]))
  582.     {
  583.      flags |= NOCACHE;
  584.  
  585.      continue;
  586.     }
  587.  
  588.    if(!strcmp("NOWRITE",argv[i]))
  589.     {
  590.      flags |= NOWRITE;
  591.  
  592.      continue;
  593.     }
  594.  
  595.    if(!strcmp("NOASYNCH",argv[i]))
  596.     {
  597.      flags |= NOASYNCH;
  598.  
  599.      continue;
  600.     }
  601.  
  602.    StdioWrite(op,"Wrong argument: ");
  603.    StdioWrite(op,argv[i]);
  604.    StdioWrite(op,"\nPLEASE READ THE MANUAL !!\n");
  605.  
  606.    exit(0);
  607.   }
  608.  
  609.  strcpy(port_name, "vb2091_");
  610.  strcat(port_name, Device);
  611.  
  612.  if(FindPort(port_name))
  613.   {
  614.    StdioWrite(op, "vb2091 already running for this device !\n");
  615.    exit(0);
  616.   }
  617.  
  618.  MULMIN2BUF = MIN2BUF * MAXN;
  619.  
  620.  StdioWrite(op, AUTHORS);
  621.  StdioWrite(op, RISK);
  622.  
  623.  for(i=0;i<MAXUNIT;i++)
  624.   {
  625.    opened[i]  = FALSE;
  626.    patched[i] = FALSE;
  627.  
  628.    if(!(unitmask&(1<<i))) continue;
  629.  
  630.    iosink[i] = (struct MsgPort *)CreatePort(NULL, 0);
  631.    if(iosink[i])
  632.     {
  633.      IO[i] = (struct IOStdReq *) CreateExtIO(iosink[i], sizeof(struct IOStdReq));
  634.      if(IO[i]) tmp = OpenDevice(Device, i, (struct IORequest *) IO[i], 0);
  635.     }
  636.  
  637.    if(tmp || (!IO[i]) || (!iosink[i]))
  638.     {
  639.      UBYTE digit[2];
  640.  
  641.      StdioWrite(op,"Unable to open ");
  642.      StdioWrite(op, Device);
  643.      StdioWrite(op," Unit ");
  644.  
  645.      digit[0] = zahl[i];
  646.      digit[1] = (UBYTE) 0;
  647.      StdioWrite(op, digit);
  648.      StdioWrite(op,"\n");
  649.  
  650.      IO[i] = 0;
  651.  
  652.      continue;
  653.     }else
  654.     {
  655.      UBYTE digit[2];
  656.  
  657.      StdioWrite(op, "Opened ");
  658.      StdioWrite(op, Device);
  659.      StdioWrite(op, " Unit ");
  660.  
  661.      digit[0] = zahl[i];
  662.      digit[1] = (UBYTE) 0;
  663.      StdioWrite(op, digit);
  664.      StdioWrite(op,"\n");
  665.  
  666.      devopen    = 1;
  667.      opened[i]  = TRUE;
  668.      patched[i] = TRUE;
  669.  
  670.      SumLibrary((struct Library *) IO[i]->io_Device);
  671. #ifdef __SASC
  672.      if(oldbeginio==NULL) oldbeginio = (void (* __asm )(register __a1 struct IOStdReq *req,
  673.                                                         register __a6 struct Device   *dev)) SetFunction((struct Library *) IO[i]->io_Device, DEV_BEGINIO, (APTR) &mybeginio);
  674. #else
  675.      if(oldbeginio==NULL) oldbeginio = (void (* )()) SetFunction((struct Library *) IO[i]->io_Device, DEV_BEGINIO, (APTR) &mybeginio);
  676. #endif /* __SASC */
  677.      Unit[i]=IO[i]->io_Unit;
  678.     }
  679.   }
  680.  
  681.  ss = (struct SignalSemaphore *)AllocVec(sizeof (struct SignalSemaphore), MEMF_PUBLIC);
  682.  if(ss)
  683.   {
  684.    InitSemaphore(ss);
  685.  
  686.    if(flags & BROKEN) buffer = (char *) AllocVec(SIZE, MEMF_24BITDMA|MEMF_FAST|MEMF_PUBLIC);
  687.     else              buffer = (char *) AllocVec(SIZE, MEMF_24BITDMA|MEMF_PUBLIC);
  688.  
  689.    if(buffer)
  690.     {
  691.      buffer2 = buffer + DIVSIZE2;
  692.  
  693.      if(devopen)
  694.       {
  695.        struct MsgPort *inst;
  696.  
  697.        inst = (struct MsgPort *)CreatePort(port_name, 0);
  698.  
  699.        Wait(SIGBREAKF_CTRL_C);
  700.  
  701.        if(inst) DeletePort(inst);
  702.       }
  703.  
  704.      ObtainSemaphore(ss);
  705.  
  706.      for(i=0; i<MAXUNIT; i++)
  707.       {
  708.        j = MAXUNIT-i-1;
  709.  
  710.        if(IO[j])
  711.         {
  712.          if(patched[j]) SetFunction((struct Library *) IO[j]->io_Device, DEV_BEGINIO, (APTR) oldbeginio);
  713.  
  714.          if(opened[j])  CloseDevice((struct IORequest *) IO[j]);
  715.                         DeleteExtIO((struct IORequest *) IO[j]);
  716.         }
  717.  
  718.        if(iosink[j]) DeletePort(iosink[j]);
  719.       }
  720.  
  721.      ReleaseSemaphore(ss);
  722.  
  723.      FreeVec(buffer);
  724.  
  725.     }else
  726.     {
  727.      StdioWrite(op,"Cannot allocate buffer!!\n");
  728.      ret = 20;
  729.     }
  730.  
  731.    FreeVec(ss);
  732.  
  733.   }else
  734.   {
  735.    StdioWrite(op,"Cannot allocate semaphore!!\n");
  736.    ret = 20;
  737.   }
  738.  
  739.  exit(ret);
  740. }
  741.