home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ddkx86v5.zip / DDKX86 / SRC / DEV / DASD / CDROM / ATAPI / ATAPIGEN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-14  |  19.7 KB  |  675 lines

  1. /*DDK*************************************************************************/
  2. /*                                                                           */
  3. /* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
  4. /*                                                                           */
  5. /*    The following IBM OS/2 WARP source code is provided to you solely for  */
  6. /*    the purpose of assisting you in your development of OS/2 WARP device   */
  7. /*    drivers. You may use this code in accordance with the IBM License      */
  8. /*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
  9. /*    Copyright statement may not be removed.                                */
  10. /*                                                                           */
  11. /*****************************************************************************/
  12. /**************************************************************************
  13.  *
  14.  * SOURCE FILE NAME = ATAPIGEN.C
  15.  *
  16.  * DESCRIPTION : General functions for ATAPI driver
  17.  *
  18.  *
  19.  *
  20.  * VERSION = 1.0
  21.  *
  22.  * DATE
  23.  *
  24.  * DESCRIPTION :
  25.  *
  26.  * Purpose:
  27.  *
  28.  *
  29. */
  30.  
  31. #define INCL_NOBASEAPI
  32. #define INCL_NOPMAPI
  33. #include "os2.h"
  34. #include "dos.h"
  35. #include "devcmd.h"
  36. #include "dskinit.h"
  37.  
  38. #include "iorb.h"
  39. #include "addcalls.h"
  40. #include "dhcalls.h"
  41.  
  42. #define INCL_INITRP_ONLY
  43. #include "reqpkt.h"
  44.  
  45. #include "scsi.h"
  46. #include "cdbscsi.h"
  47.  
  48. #include "atapicon.h"
  49. #include "atapireg.h"
  50. #include "atapityp.h"
  51. #include "atapiext.h"
  52. #include "atapipro.h"
  53.  
  54.  
  55. /*
  56. ╔══════════════════════════════════╗
  57. ║                                  ║
  58. ║  IODelay                         ║
  59. ║                                  ║
  60. ║  Wait for 1 µsec                 ║
  61. ║                                  ║
  62. ╚══════════════════════════════════╝
  63. */
  64. VOID FAR IODelay()
  65. {
  66.    ULONG IODelayCtr = IODelayCount;
  67.  
  68.    while( IODelayCtr--)
  69.       ;
  70. }
  71.  
  72. /*
  73. ╔════════════════════════════════════╗
  74. ║                                    ║
  75. ║  setmem                            ║
  76. ║                                    ║
  77. ║  Sets memory starting at location  ║
  78. ║  p, to the value c, for len bytes  ║
  79. ║                                    ║
  80. ╚════════════════════════════════════╝
  81. */
  82. VOID NEAR setmem( PBYTE d, USHORT c, USHORT len )
  83. {
  84.    USHORT   i;
  85.  
  86.    for ( i = 0; i < len ; i++ )
  87.       d[i] = (UCHAR) c;
  88.  
  89.    return;
  90. }
  91.  
  92. /*
  93. ╔══════════════════════════════════╗
  94. ║                                  ║
  95. ║  memcopy                         ║
  96. ║                                  ║
  97. ║  Copies the contents of memory   ║
  98. ║  at the source (s) to the        ║
  99. ║  destination (d), for len bytes  ║
  100. ║                                  ║
  101. ╚══════════════════════════════════╝
  102. */
  103. VOID NEAR memcopy( PBYTE d, PBYTE s, USHORT len )
  104. {
  105.    USHORT   i;
  106.    USHORT   j;
  107.  
  108.    j = len >> 1;
  109.  
  110.    for ( i = 0; i < j ; i++ )
  111.       ((PUSHORT) d)[i] = ((PUSHORT) s)[i];
  112.  
  113.    if ( j & 1 ) d[len-1] = s[len-1];
  114.  
  115.  
  116.    return;
  117. }
  118.  
  119. /*
  120. ╔══════════════════════════════════╗
  121. ║                                  ║
  122. ║  strncpy                         ║
  123. ║                                  ║
  124. ║  Copies the contents of string   ║
  125. ║  (s) to that of string (d) for   ║
  126. ║  (n) characters.  (d) is then    ║
  127. ║  null terminated.                ║
  128. ║                                  ║
  129. ╚══════════════════════════════════╝
  130. */
  131. VOID NEAR strncpy( PSZ d, PSZ s, USHORT n )
  132. {
  133.    while( *s && n-- ) *d++ = *s++;
  134.    *d = 0;
  135.  
  136.    return;
  137. }
  138.  
  139. /*
  140. ╔═══════════════════════════════════╗
  141. ║                                   ║
  142. ║  strncmp                          ║
  143. ║                                   ║
  144. ║  Compares the contents of string  ║
  145. ║  (s) to that of string (d) for    ║
  146. ║  (n) characters.                  ║
  147. ║                                   ║
  148. ╚═══════════════════════════════════╝
  149. */
  150. BOOL NEAR strncmp( PSZ d, PSZ s, USHORT n )
  151. {
  152.    BOOL  rc = TRUE;
  153.  
  154.    while( n-- )
  155.      if ( *d++ != *s++)
  156.      {
  157.         rc = FALSE;
  158.         break;
  159.      }
  160.  
  161.    return( rc );
  162. }
  163.  
  164. /*
  165. ╔══════════════════════════════════╗
  166. ║                                  ║
  167. ║  BSYWAIT                         ║
  168. ║                                  ║
  169. ║  Poll for BSY until success or   ║
  170. ║  until exceed max poll time      ║
  171. ║                                  ║
  172. ║  Returns True if BSY clear       ║
  173. ║  False if exceeded max poll time ║
  174. ║                                  ║
  175. ╚══════════════════════════════════╝
  176. */
  177. USHORT NEAR BSYWAIT ( NPACB npACB )
  178. {
  179.  
  180.    ULONG cMS = WaitBSYCount;                                         /*V@93531*/
  181.    USHORT Status;
  182.  
  183.    /*
  184.    ┌──────────────────────────────────────┐
  185.    │ Poll for BSY up to WaitBSYCount times│
  186.    └──────────────────────────────────────┘
  187.    */
  188.  
  189.    do
  190.    {
  191.       Status = GetRegister ( npACB, FI_PSTATUS );
  192.       IODelay();
  193.    } while (((Status & FX_BUSY) || Calibrate) && --cMS);
  194.  
  195.    return (cMS);
  196. }
  197.  
  198. /*
  199. ╔══════════════════════════════════╗
  200. ║                                  ║
  201. ║  DRQ_SET_WAIT                    ║
  202. ║                                  ║
  203. ║  Poll for DRQ until asserted or  ║
  204. ║  until exceed max poll time      ║
  205. ║                                  ║
  206. ║  Returns True if DRQ set         ║
  207. ║  False if exceeded max poll time ║
  208. ║                                  ║
  209. ╚══════════════════════════════════╝
  210. */                                                                   /*V@93531*/
  211. USHORT FAR BSY_CLR_DRQ_SET_WAIT( NPACB npACB )                       /*V@93531*/
  212. {                                                                    /*V@93531*/
  213.                                                                      /*V@93531*/
  214.    ULONG cMS = WaitDRQCount;                                         /*V@93531*/
  215.    USHORT Status;                                                    /*V@93531*/
  216.                                                                      /*V@93531*/
  217.    /*                                                                  V@93531*/
  218.    /*┌──────────────────────────────────────┐                          V@93531*/
  219.    /*│ Poll for DRQ up to WaitDRQCount times│                          V@93531*/
  220.    /*└──────────────────────────────────────┘                          V@93531*/
  221.                                                                      /*V@93531*/
  222.    do                                                                /*V@93531*/
  223.    {                                                                 /*V@93531*/
  224.       Status = GetRegister ( npACB, FI_PSTATUS );                    /*V@93531*/
  225.       IODelay();                                                     /*V@93531*/
  226.    } while ((  !(Status & FX_DRQ) ||
  227.                  Status & FX_BUSY ||
  228.                  Calibrate) &&
  229.             --cMS);                                                  /*V@93531*/
  230.                                                                      /*V@93531*/
  231.    return (cMS);                                                     /*V@93531*/
  232. }                                                                    /*V@93531*/
  233.                                                                      /*V@93531*/
  234. /*
  235. ╔══════════════════════════════════╗
  236. ║                                  ║
  237. ║  DRQ_AND_BSY_CLEAR_WAIT          ║
  238. ║                                  ║
  239. ║  Poll for DRQ and BSY until both ║
  240. ║  are clear or until exceed max   ║
  241. ║  poll time                       ║
  242. ║                                  ║
  243. ║  Returns True if DRQ AND BSY are ║
  244. ║  both clear,                     ║
  245. ║  False if exceeded max poll time ║
  246. ║                                  ║
  247. ╚══════════════════════════════════╝
  248. */                                                                   /*V@93531*/
  249. USHORT NEAR DRQ_AND_BSY_CLEAR_WAIT ( NPACB npACB )                   /*V@93531*/
  250. {                                                                    /*V@93531*/
  251.                                                                      /*V@93531*/
  252.    USHORT cMS = WaitDRQCount;                                        /*V@93531*/
  253.    USHORT Status;                                                    /*V@93531*/
  254.                                                                      /*V@93531*/
  255.    /*  ┌──────────────────────────────────────────────┐                V@93531*/
  256.    /*  │ Poll for DRQ and BSY up to WaitDRQCount times│                V@93531*/
  257.    /*  └──────────────────────────────────────────────┘                V@93531*/
  258.                                                                      /*V@93531*/
  259.    do                                                                /*V@93531*/
  260.    {                                                                 /*V@93531*/
  261.       Status = GetRegister ( npACB, FI_PSTATUS );                    /*V@93531*/
  262.       IODelay();                                                     /*V@93531*/
  263.    } while ((   (Status & FX_BUSY) ||
  264.                 (Status & FX_DRQ ) ||
  265.                 Calibrate) &&
  266.             --cMS);                                                  /*V@93531*/
  267.      /* enddo */                                                     /*V@93531*/
  268.                                                                      /*V@93531*/
  269.    return (cMS);                                                     /*V@93531*/
  270. }                                                                    /*V@93531*/
  271.  
  272.  
  273. /*
  274. ╔══════════════════════════════════════════════════════════════════╗
  275. ║                                                                  ║
  276. ║   VirtToPhys - Convert a virtual to physical address             ║
  277. ║                                                                  ║
  278. ║   Convert a virtual to a physical address.  This routine does    ║
  279. ║   not use DevHlp_VirtToPhys since that devhlp is not callable    ║
  280. ║   at interrupt time.                                             ║
  281. ║                                                                  ║
  282. ║   ULONG  VirtToPhys  (PBYTE VirtAddr)                            ║
  283. ║                                                                  ║
  284. ║   ENTRY:    VirtAddr         - 16:16 virutal address             ║
  285. ║                                                                  ║
  286. ║   RETURN:   ULONG            - 32 bit phys address               ║
  287. ║                                                                  ║
  288. ╚══════════════════════════════════════════════════════════════════╝
  289. */
  290.  
  291. ULONG VirtToPhys (PBYTE VirtAddr)
  292. {
  293.  
  294.    USHORT rc;
  295.    SCATGATENTRY ScatGatEntry;
  296.    ULONG VirtLinAddr;
  297.    ULONG ScatLinAddr;
  298.    ULONG PageListCount;
  299.  
  300.    rc = DevHelp_VirtToLin((USHORT) (SELECTOROF(VirtAddr)),
  301.                           (ULONG) (OFFSETOF(VirtAddr)),
  302.                           (PLIN) &VirtLinAddr);
  303.  
  304.    rc = DevHelp_VirtToLin((USHORT) ( ((ULONG)((PVOID) &ScatGatEntry)) >> 16),
  305.                           (ULONG)  ( (USHORT)((PVOID) &ScatGatEntry)),
  306.                           (PLIN) &ScatLinAddr);
  307.  
  308.    rc = DevHelp_LinToPageList(VirtLinAddr, 1, ScatLinAddr,
  309.                                               (PULONG) &PageListCount);
  310.  
  311.    return(ScatGatEntry.ppXferBuf);
  312.  
  313. }
  314.  
  315. /*
  316. ╔══════════════════════════════════╗
  317. ║                                  ║
  318. ║                                  ║
  319. ║                                  ║
  320. ║                                  ║
  321. ║                                  ║
  322. ╚══════════════════════════════════╝
  323. */
  324. VOID NEAR SelectUnit( NPACB npACB, USHORT UnitId )
  325. {
  326.    USHORT        Port;
  327.    USHORT        Data;
  328.  
  329.    Port                       = npACB->IOPorts[FI_PDRVSLCT];
  330.    npACB->IORegs[FI_PDRVSLCT] =
  331.                 DEFAULT_ATAPI_DRV_SLCT_REG | ((UnitId == 0) ? UNIT0 : UNIT1 );
  332.    Data                       = npACB->IORegs[FI_PDRVSLCT];
  333.  
  334.    outp( Port, Data );
  335.    IODelay();
  336. }
  337.  
  338. /*
  339. ╔══════════════════════════════════╗
  340. ║                                  ║
  341. ║                                  ║
  342. ║                                  ║
  343. ║                                  ║
  344. ║                                  ║
  345. ╚══════════════════════════════════╝
  346. */
  347. USHORT NEAR SuspendOtherAdd( NPACB npACB )
  348. {
  349.    PIORB_DEVICE_CONTROL  pIORB;
  350.    NPUSHORT              npUS;
  351.  
  352.    DISABLE
  353.    if ( npACB->iorbinuse )
  354.    {
  355.       _asm int 3
  356.    }
  357.    npACB->iorbinuse = 1;
  358.    ENABLE
  359.  
  360.    pIORB = (PIORB_DEVICE_CONTROL) &npACB->IORB;
  361.    setmem( (PVOID) pIORB, 0, sizeof(npACB->IORB));
  362.  
  363.    pIORB->iorbh.Length          = sizeof(IORB_DEVICE_CONTROL);
  364.    pIORB->iorbh.UnitHandle      = npACB->SharedDriverUnitHandle;
  365.    pIORB->iorbh.CommandCode     = IOCC_DEVICE_CONTROL;
  366.    pIORB->iorbh.CommandModifier = IOCM_SUSPEND;
  367.    pIORB->iorbh.RequestControl  = IORB_ASYNC_POST;
  368.    pIORB->iorbh.NotifyAddress   = NotifySuspendResumeDone;
  369.    pIORB->IRQHandlerAddress     = npACB->IRQHandler;                /*@V93531*/
  370.  
  371.    pIORB->Flags = DC_SUSPEND_DEFERRED | DC_SUSPEND_IRQADDR_VALID;   /*@V93531*/
  372.  
  373.    npUS = (NPUSHORT) pIORB->iorbh.DMWorkSpace;
  374.  
  375.    *npUS = (USHORT) npACB;
  376.  
  377.    (*npACB->SharedDriverEP) ((PVOID)(pIORB));
  378.  
  379. }
  380.  
  381. /*
  382. ╔══════════════════════════════════╗
  383. ║                                  ║
  384. ║                                  ║
  385. ║                                  ║
  386. ║                                  ║
  387. ║                                  ║
  388. ╚══════════════════════════════════╝
  389. */
  390. USHORT NEAR ResumeOtherAdd( NPACB npACB )
  391. {
  392.    PIORB_DEVICE_CONTROL  pIORB;
  393.    NPUSHORT              npUS;
  394.  
  395.    DISABLE
  396.    if ( npACB->iorbinuse )
  397.    {
  398.       _asm int 3
  399.    }
  400.    npACB->iorbinuse = 1;
  401.    ENABLE
  402.  
  403.    pIORB = (PIORB_DEVICE_CONTROL) &npACB->IORB;
  404.    setmem( (PVOID) pIORB, 0, sizeof(npACB->IORB));
  405.  
  406.    pIORB->iorbh.Length          = sizeof(IORB_DEVICE_CONTROL);
  407.    pIORB->iorbh.UnitHandle      = npACB->SharedDriverUnitHandle;
  408.    pIORB->iorbh.CommandCode     = IOCC_DEVICE_CONTROL;
  409.    pIORB->iorbh.CommandModifier = IOCM_RESUME;
  410.    pIORB->iorbh.RequestControl  = IORB_ASYNC_POST;
  411.    pIORB->iorbh.NotifyAddress   = NotifySuspendResumeDone;
  412.  
  413.    npUS = (NPUSHORT) pIORB->iorbh.DMWorkSpace;
  414.  
  415.    *npUS = (USHORT) npACB;
  416.  
  417.    (*npACB->SharedDriverEP) ((PVOID)(pIORB));
  418.  
  419. }
  420.  
  421. /*
  422. ╔══════════════════════════════════╗
  423. ║                                  ║
  424. ║                                  ║
  425. ║                                  ║
  426. ║                                  ║
  427. ║                                  ║
  428. ╚══════════════════════════════════╝
  429. */
  430. ULONG NEAR QueryOtherAdd( NPACB npACB )
  431. {
  432.    PIORB_DEVICE_CONTROL  pIORB;
  433.  
  434.    DISABLE
  435.    if ( npACB->iorbinuse )
  436.    {
  437.       _asm int 3
  438.    }
  439.    npACB->iorbinuse = 1;
  440.    ENABLE
  441.  
  442.    pIORB = (PIORB_DEVICE_CONTROL) &npACB->IORB;
  443.    setmem( (PVOID) pIORB, 0, sizeof(npACB->IORB));
  444.  
  445.    pIORB->iorbh.Length          = sizeof(IORB_DEVICE_CONTROL);
  446.    pIORB->iorbh.UnitHandle      = npACB->SharedDriverUnitHandle;
  447.    pIORB->iorbh.CommandCode     = IOCC_DEVICE_CONTROL;
  448.    pIORB->iorbh.CommandModifier = IOCM_GET_QUEUE_STATUS;
  449.    pIORB->iorbh.RequestControl  = 0;
  450.    pIORB->iorbh.NotifyAddress   = 0;
  451.  
  452.    (*npACB->SharedDriverEP) ((PVOID)(pIORB));
  453.    while ( !(pIORB->iorbh.Status & IORB_DONE) )  /* Wait till done */
  454.       ;
  455.  
  456.    npACB->iorbinuse = 0;
  457.    return( pIORB->QueueStatus );
  458. }
  459.  
  460. /*
  461. ╔══════════════════════════════════╗
  462. ║                                  ║
  463. ║                                  ║
  464. ║                                  ║
  465. ║                                  ║
  466. ║                                  ║
  467. ╚══════════════════════════════════╝
  468. */
  469. VOID   FAR  _loadds NotifySuspendResumeDone( PIORB pIORB )
  470. {
  471.    NPACB    npACB;
  472.  
  473.  
  474.    npACB = ((NPACB *) pIORB->DMWorkSpace)[0];
  475.  
  476.    npACB->iorbinuse = 0;
  477.  
  478.    StartOSM( npACB );
  479.  
  480. }
  481.  
  482. /*
  483. ╔══════════════════════════════════╗
  484. ║                                  ║
  485. ║                                  ║
  486. ║                                  ║
  487. ║ Note: can not be called at INT time
  488. ║                                  ║
  489. ╚══════════════════════════════════╝
  490. */
  491. VOID HookIRQ( NPACB npACB )
  492. {
  493.    DISABLE
  494.    if ( npACB->ResourceFlags & ACBRF_CURR_OWNER )
  495.    {
  496.       /* Already own IRQ */
  497.       _asm INT 3
  498.    }
  499.    else
  500.    {
  501.       npACB->ResourceFlags |= ACBRF_CURR_OWNER;
  502.       if ( DevHelp_SetIRQ( (NPFN)   npACB->IRQHandler,
  503.                            (USHORT) npACB->IRQLevel,
  504.                            (USHORT) 0                  ) )
  505.       {
  506.          /* Someone already has the IRQ */
  507.          _asm INT 3
  508.       }
  509.    }
  510.    ENABLE
  511. }
  512.  
  513. ///*
  514. //╔══════════════════════════════════╗
  515. //║                                  ║
  516. //║                                  ║
  517. //║                                  ║
  518. //║                                  ║
  519. //╚══════════════════════════════════╝
  520. //*/
  521. //VOID FAR Start_ResumeOtherAdd( NPACB npACB )
  522. //{
  523. //   ResumeOtherAdd( npACB );
  524. //}
  525.  
  526. /*
  527. ╔══════════════════════════════════╗
  528. ║                                  ║
  529. ║                                  ║
  530. ║                                  ║
  531. ║                                  ║
  532. ╚══════════════════════════════════╝
  533. */
  534. VOID FAR Start_HookIRQ( NPACB npACB )
  535. {
  536.    HookIRQ( npACB );
  537.    StartOSM( npACB );
  538. }
  539.  
  540. /*
  541. ╔══════════════════════════════════╗
  542. ║                                  ║
  543. ║                                  ║
  544. ║                                  ║
  545. ║ Note: can not be called at INT time
  546. ║                                  ║
  547. ╚══════════════════════════════════╝
  548. */
  549. VOID FAR Start_SuspendOtherAdd( NPACB npACB )
  550. {
  551.    SuspendOtherAdd( npACB );
  552. }
  553.  
  554. /*
  555. ╔══════════════════════════════════╗
  556. ║                                  ║
  557. ║                                  ║
  558. ║                                  ║
  559. ║ Note: can not be called at INT time
  560. ║                                  ║
  561. ╚══════════════════════════════════╝
  562. */
  563. VOID UnHookIRQ( NPACB npACB )
  564. {
  565.    DISABLE
  566.    if ( !( npACB->ResourceFlags & ACBRF_CURR_OWNER ) )
  567.    {
  568.       /* Don't own IRQ */
  569.       _asm INT 3
  570.    }
  571.    else
  572.    {
  573.       npACB->ResourceFlags &= ~ACBRF_CURR_OWNER;
  574.       DevHelp_UnSetIRQ ( npACB->IRQLevel );
  575.    }
  576.    ENABLE
  577. }
  578.  
  579.  
  580. /*
  581. ╔══════════════════════════════════╗
  582. ║                                  ║
  583. ║                                  ║
  584. ║                                  ║
  585. ║                                  ║
  586. ╚══════════════════════════════════╝
  587. */
  588. VOID   FAR PASCAL StateCtxHookRtn( VOID )
  589. {
  590.    NPACB    npACB;
  591.    VOID     (FAR *CtxHookRoutine)( NPACB npACB );
  592.  
  593.    _asm {  mov     npACB, ax
  594.  
  595.           _emit    66h
  596.            push    si
  597.  
  598.           _emit    66h
  599.            push    di
  600.  
  601.           _emit    66h
  602.            push    bx
  603.  
  604.         }
  605.  
  606.     DISABLE
  607.     if ( npACB->CtxHookRoutine )
  608.     {
  609.        CtxHookRoutine        = npACB->CtxHookRoutine;
  610.        npACB->CtxHookRoutine = 0;
  611.        ENABLE
  612.        (*CtxHookRoutine)( npACB );
  613.     }
  614.     ENABLE
  615.  
  616.    _asm { _emit    66h
  617.            pop     bx
  618.  
  619.           _emit    66h
  620.            pop     di
  621.  
  622.           _emit    66h
  623.            pop     si
  624.         }
  625. }
  626.  
  627.  
  628. /*
  629. ╔══════════════════════════════════╗
  630. ║                                  ║
  631. ║  IDECDStr                        ║
  632. ║                                  ║
  633. ║  Stategy Routine for IBMIDECD    ║
  634. ║                                  ║
  635. ║  Accepts only the Init Base      ║
  636. ║  device drivers command (0x1B).  ║
  637. ║  Returns unknown command for     ║
  638. ║  all others.                     ║
  639. ║                                  ║
  640. ╚══════════════════════════════════╝
  641. */
  642. VOID NEAR IDECDStr()
  643. {
  644.    PRPH     pRPH;
  645.    USHORT   Cmd;
  646.  
  647.    _asm {
  648.            mov word ptr pRPH[0], bx       /*  pRPH is initialized to          */
  649.            mov word ptr pRPH[2], es       /*  ES:BX passed from the kernel    */
  650.         }
  651.  
  652.    pRPH->Status = STATUS_DONE;
  653.    Cmd = pRPH->Cmd;
  654.  
  655.    if ( Cmd == CMDInitBase )
  656.  
  657.       DriverInit( (PRPINITIN) pRPH );
  658.  
  659.    else
  660.    {
  661.       if ( Cmd == CMDInit )
  662.       {
  663.          Device_Help = ((PRPINITIN)pRPH)->DevHlpEP;
  664.          TTYWrite ( UninstallMsg );
  665.          TTYWrite ( DevEqualsMsg );
  666.       }
  667.       pRPH->Status =  STATUS_DONE | STATUS_ERR_UNKCMD;
  668.    }
  669.    _asm {
  670.            leave
  671.            retf
  672.         }
  673. } /* IDECDStr */
  674.  
  675.