home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / audiopdd.zip / stream.c < prev    next >
C/C++ Source or Header  |  1999-02-27  |  32KB  |  1,058 lines

  1. //
  2. // stream.c
  3. // 27-Jan-99
  4. //
  5. // VOID    streamReturnBuffer(STREAM *streamPtr);
  6. // VOID    streamReturnBuffers(STREAM *streamPtr);
  7. // USHORT  streamPauseTime(STREAM *streamPtr);
  8. // USHORT  streamResumeTime(STREAM *streamPtr);
  9. // USHORT  streamRegister(DDCMDREGISTER __far *cmdPtr, STREAM *streamPtr);
  10. // VOID    streamDeregister(STREAM *streamPtr);
  11. // USHORT  streamRead(UCHAR __far *bufferPtr, ULONG length, STREAM *streamPtr);
  12. // USHORT  streamWrite(UCHAR __far *bufferPtr, ULONG length, STREAM *streamPtr);
  13. // USHORT  streamInit(USHORT streamType, STREAM *streamPtr);
  14. // USHORT  streamDeinit(STREAM *streamPtr);
  15. // STREAM *streamFindActive(USHORT streamType);
  16. // STREAM *streamFindStreamSFN(ULONG SFN);
  17. // STREAM *streamFindStreamHandle(HSTREAM streamH);
  18. // STREAM_BUFFER *sbHead(STREAM_BUFFER_ANCHOR *sbaPtr);
  19. // STREAM_BUFFER *sbTail(STREAM_BUFFER_ANCHOR *sbaPtr);
  20. // VOID    sbPushOnHead(STREAM_BUFFER *sbPtr, STREAM_BUFFER_ANCHOR *sbaPtr);
  21. // VOID    sbPushOnTail(STREAM_BUFFER *sbPtr, STREAM_BUFFER_ANCHOR *sbaPtr);
  22. // STREAM_BUFFER *sbPopHead(STREAM_BUFFER_ANCHOR *sbaPtr);
  23. // STREAM_BUFFER *sbPopTail(STREAM_BUFFER_ANCHOR *sbaPtr);
  24. // USHORT  sbDestroyElement(STREAM_BUFFER *sbPtr, STREAM_BUFFER_ANCHOR *sbaPtr);
  25. // STREAM_BUFFER *sbPopElement(STREAM_BUFFER *match_sbPtr, STREAM_BUFFER_ANCHOR *sbaPtr);
  26. // USHORT  sbNotEmpty(STREAM_BUFFER_ANCHOR *sbaPtr);
  27. // STREAM *streamHead(VOID);
  28. // STREAM *streamTail(VOID);
  29. // VOID    streamPushOnHead(STREAM *sPtr);
  30. // VOID    streamPushOnTail(STREAM *sPtr);
  31. // STREAM *streamPopHead(VOID);
  32. // STREAM *streamPopTail(VOID);
  33. // USHORT  streamDestroyElement(STREAM *sPtr);
  34. // STREAM *streamPopElement(STREAM *match_sPtr);
  35. // USHORT  streamNotEmpty(VOID);
  36. //
  37. // to init queue set headPtr/tailPtr = 0
  38. // which is accomplished by simply MEMSET()'ing the allocation
  39. // ie, the contructor (doesn't seem to be a destructor for the QUEUE class)
  40. //
  41. // ----------------------------------------- NOTE -------------------------------------------
  42. // the following event-support routines are not yet done (stubs, all now have STREAM * as parm)
  43. // parm list subject change (:
  44. //
  45. //VOID streamProcessEvents(STREAM *streamPtr) ;
  46. //VOID streamEnableEvent(DDCMDCONTROL __far *ddcmdPtr, STREAM *streamPtr);
  47. //VOID streamDisableEvent(DDCMDCONTROL __far *ddcmdPtr, STREAM *streamPtr);
  48. //VOID streamSetNextEvent(STREAM *streamPtr);
  49.  
  50.  
  51. #include "cs40.h"
  52.  
  53. static STREAM_ANCHOR streamList = {0,0}; // head of list (has .headPtr and .tailPtr to STREAM structures)
  54.  
  55. // ---------------------------------------------------------------------
  56. // in: streamPtr -> stream from which to remove head buffer of done list
  57. //out: n/a
  58. //nts: frees stream buffer that was at head of done list
  59.  
  60. VOID streamReturnBuffer(STREAM *streamPtr) {
  61.  
  62.  static SHD_REPORTINT shdri = {SHD_REPORT_INT,0,0,0,0,0};  // structure to return buffers to SHD
  63.  
  64.  STREAM_BUFFER *tsbPtr = sbPopHead(&streamPtr->sbaDone);  // was STREAM_BUFFER *tsbPtr = (PSTREAMBUFFER)qhDone.PopHead();
  65.  
  66. // !!!
  67. //ddprintf("@streamReturnBuffer, streamPtr=%x\n",streamPtr);
  68.  
  69.  if (tsbPtr) {
  70.  
  71.     if (streamPtr->streamType & STREAM_WRITE) {
  72.  
  73.        // this is a write (playback): tell stream handler that we played all of the buffer
  74.  
  75.        shdri.ulFlag = SHD_WRITE_COMPLETE;
  76.        shdri.ulStatus = tsbPtr->bufferSize;
  77.     }
  78.     else {
  79.  
  80.        // this is a capture: tell stream hamdler how much data we wrote to the buffer
  81.  
  82.        shdri.ulFlag = SHD_READ_COMPLETE;
  83.        shdri.ulStatus = tsbPtr->bufferCurrPos;
  84.     }
  85.  
  86.     shdri.hStream = streamPtr->streamH;
  87.     shdri.pBuffer = tsbPtr->bufferPtr;
  88.  
  89.     // wavestreamGetCurrentTime() needs to access stream's parent WAVESTREAM structure --
  90.     // this is the only case (so far) where a stream operation needs to look at what's
  91.     // in WAVSTREAM (specifically, abPtr, needed by this get time call) -- had to add
  92.     // this member to the STREAM structure (1-Feb-99), and set it up in streamInit(),
  93.     // which is called by wavestreamInit() (WAVESTREAM constructor) by IoctlAudioInit()...
  94.     // ugh, the driver docs just plain suck
  95.  
  96.     shdri.ulStreamTime = wavestreamGetCurrentTime(streamPtr->wsParentPtr);
  97.  
  98. #ifdef TRACE_RETBUFFER
  99.  tracePerf(TRACE_RETBUFFER_IN, _IF());
  100. #endif
  101.  
  102.     streamPtr->pfnSHD(&shdri);  // function call
  103.  
  104. #ifdef TRACE_RETBUFFER
  105.  tracePerf(TRACE_RETBUFFER_OUT,_IF());
  106. #endif
  107.  
  108.     free(tsbPtr); // this is what lots and lots of allocations come from
  109.  
  110. // !!!
  111. //ddprintf("~streamReturnBuffer:free:%x\n",tsbPtr);
  112.  
  113.  }
  114.  
  115.  return;
  116. }
  117.  
  118.  
  119. // --------------------------------------------------------
  120. // in: streamPtr -> stream from which to remove head buffer
  121. //out: n/a
  122. //nts: returns (and frees) all stream buffers
  123.  
  124. VOID streamReturnBuffers(STREAM *streamPtr) {
  125.  
  126.  STREAM_BUFFER *tsbPtr;
  127.  
  128.  while(sbNotEmpty(&streamPtr->sbaProc)) {       // likely gets inlined so use sbNotEmpty()
  129.     tsbPtr = sbPopHead(&streamPtr->sbaProc);    // rather than sbPopHead() until it returns 0
  130.     sbPushOnTail(tsbPtr, &streamPtr->sbaDone);  // pop from proc list and push on done list since...
  131.  }
  132.  
  133.  while(sbNotEmpty(&streamPtr->sbaDone)) {       // stream buffers were moved to the done list
  134.     streamReturnBuffer(streamPtr);              // because that's what streamReturnBuffer() uses
  135.  }                                              // namely, the head of the done list
  136.  
  137.  return;
  138. }
  139.  
  140.  
  141. // ---------------------------------------------------
  142. // in: streamPtr -> stream to pause/resume time counter
  143. //out: always 0, for okay 
  144. //nts: returns USHORT though caller (ssm_idc.c) expects ULONG to return back to MMPM
  145.  
  146. USHORT streamPauseTime(STREAM *streamPtr) {
  147.  streamPtr->counterIncFlag = 0;
  148.  return 0;
  149. }
  150.  
  151. USHORT streamResumeTime(STREAM *streamPtr) {
  152.  streamPtr->counterIncFlag = 1;
  153.  return 0;
  154. }
  155.  
  156.  
  157. // ---------------------------------------------------
  158. // in: cmdPtr -> DDCMDREGISTER pack (far ptr)
  159. //     streamPtr -> stream working on
  160. //out: always 0, for okay 
  161. //nts: returns USHORT though caller (ssm_idc.c) expects ULONG to return back to MMPM
  162. //
  163. // ulBufSize: Specifies VSD or PDD output buffer size in bytes that will be sent to
  164. //            the driver. The caller will fill in a default value. If the device driver
  165. //            does not override this value, it will be used to determine the buffer size.
  166. //
  167. // Note:  The device driver sets this field to indicate the buffer size that it would like to
  168. // receive from the streaming subsystem. For MIDI, this field is usually set to 512. For DMA-based
  169. // audio or other systems where the interrupt rate equals the buffer rate, this field should
  170. // be set to about 1/30 the quantity of data consumed or produced per second. This field supplies
  171. // the system with a minimal buffer size for wave audio. Because other system elements also
  172. // negotiate to determine buffer size and for software motion video, the system might provide
  173. // buffers smaller than the size requested.
  174.   
  175. USHORT streamRegister(DDCMDREGISTER __far *cmdPtr, STREAM *streamPtr) {
  176.  
  177.  streamPtr->streamH = cmdPtr->hStream;
  178.  streamPtr->pfnSHD =  (T_PFNSHD) cmdPtr->pSHDEntryPoint;  // need cast since using a __cdecl cc
  179.  
  180.  cmdPtr->ulAddressType = ADDRESS_TYPE_VIRTUAL;  // type of buffer pointer want to get from SSM
  181.  cmdPtr->mmtimePerUnit = 0;     // not used
  182.  cmdPtr->ulBytesPerUnit = 0;    // not used
  183.  
  184.  // suggestions:
  185.  cmdPtr->ulNumBufs = 0x00000006;  // 6 default buffers, at 60K each, is about 2 secs
  186.  cmdPtr->ulBufSize = 0x0000F000;  // see Note above
  187.  
  188.  return 0;
  189. }
  190.  
  191.  
  192. // ---------------------------------------------------
  193. // in: streamPtr -> stream to deregister
  194. //out: n/a
  195. //nts:
  196.  
  197. VOID streamDeregister(STREAM *streamPtr) {
  198.  
  199.  streamPtr->streamH = 0;
  200.  streamPtr->pfnSHD = 0;
  201.  
  202.  return;
  203. }
  204.  
  205.  
  206. // ---------------------------------------------
  207. // in: bufferPtr -> stream buffer data (far ptr)
  208. //     bufferSize = size of empty buffer (passed down as ULONG from kernel, org was short)
  209. //     wsPtr -> WAVESTREAM structure
  210. //out: 0 if okay, else rc (no memory, eg)
  211. //nts: called by DDCMD_READ
  212. //     original was getting length as "unsigned" as in USHORT
  213. //     similar to streamWrite()
  214. //     was called Read(), was also in wavestrm.c but why?  so moved here, to stream.c
  215. //     (when it was in wavestrm.c, it was using &wsPtr->streamPtr->sbaProc... otherwise same)
  216.  
  217. USHORT streamRead(UCHAR __far *bufferPtr, ULONG length, STREAM *streamPtr) {
  218.  
  219.  USHORT rc = 0;
  220.  STREAM_BUFFER *newsbPtr = malloc(sizeof(STREAM_BUFFER));
  221.  
  222. // !!!
  223. //ddprintf("@streamRead:newsbPtr=%x\n",newsbPtr);
  224.  
  225.  if (newsbPtr) {
  226.     newsbPtr->nextPtr = 0;
  227.     newsbPtr->rsv2 = 0;
  228.     newsbPtr->bufferPtr = bufferPtr;
  229.     newsbPtr->bufferSize = length;
  230.     newsbPtr->bufferCurrPos = 0;
  231.     newsbPtr->bufferDonePos = 0;
  232.  
  233.     sbPushOnTail(newsbPtr, &streamPtr->sbaProc);
  234.  }
  235.  else {
  236.     rc = 8;
  237.  }
  238.  
  239.  return rc;
  240. }
  241.  
  242.  
  243. // ---------------------------------------------------
  244. // in: bufferPtr -> streaming buffer to add
  245. //     length = size of streaming buffer to add
  246. //     streamPtr -> stream to add stream buffer to
  247. //out: 0 if okay, else rc (no memory, eg)
  248. //nts: original was getting length as "unsigned" as in USHORT
  249. //     org was also always in stream.c, unlike Read() which was in wavestrm.c
  250.  
  251. USHORT streamWrite(UCHAR __far *bufferPtr, ULONG length, STREAM *streamPtr) {
  252.  
  253.  USHORT rc = 0;
  254.  STREAM_BUFFER *newsbPtr = malloc(sizeof(STREAM_BUFFER));
  255.  
  256. // !!!
  257. //ddprintf("@streamWrite:newsbPtr=%x\n",newsbPtr);
  258.  
  259.  if (newsbPtr) {
  260.     newsbPtr->nextPtr = 0;
  261.     newsbPtr->rsv2 = 0;
  262.     newsbPtr->bufferPtr = bufferPtr;
  263.     newsbPtr->bufferSize = length;
  264.     newsbPtr->bufferCurrPos = 0;
  265.     newsbPtr->bufferDonePos = 0;
  266.  
  267.     sbPushOnTail(newsbPtr, &streamPtr->sbaProc);
  268.  }
  269.  else {
  270.     rc = 8;
  271.  }
  272.  
  273.  return rc;
  274. }
  275.  
  276.  
  277. // ---------------------------------------------------
  278. // in: streamType = eg, STREAM_WAVE_CAPTURE (==AUDIOHW_WAVE_CAPTURE)(org ULONG)
  279. //     streamPtr -> stream structure
  280. //out: always 0 for now
  281. //nts:
  282. //
  283. // actually, STREAM constructor is called as part of WAVESTREAM constructor (STREAM
  284. // constructor is done first, though) so this (streamInit()) will be called by
  285. // wavestreamInit()...
  286.  
  287. USHORT streamInit(USHORT streamType, STREAM *streamPtr) {
  288.  
  289.  streamPushOnTail(streamPtr);
  290.  streamPtr->streamType = streamType;
  291.  
  292.  // already have verified that streamType is a supported type in IOCtl audio init
  293.  // so ahwPtr will be valid (so don't need to check here)
  294.  
  295.  streamPtr->streamH = 0;        // ensure won't match yet on FindStream()
  296.  streamPtr->SFN = 0;            // ditto (since these are not yet operational streams)
  297.  streamPtr->counterIncFlag = 1;
  298.  streamPtr->currentTime = 0;    // this is updated when DDCMD_STATUS gotten
  299.  streamPtr->streamState = STREAM_STOPPED;
  300.  
  301.  return 0;
  302. }
  303.  
  304.  
  305. // ---------------------------------------------------
  306. // in: streamPtr -> stream structure
  307. //out: always 0 for now
  308. //nts: stream destructor (does not free(streamPtr) though...that's done in wavestreamDeinit)
  309.  
  310. USHORT streamDeinit(STREAM *streamPtr) {
  311.  
  312.  USHORT rc = 0;
  313.  STREAM_BUFFER *tsbPtr;
  314.  
  315.  if (streamPtr->streamState == STREAM_STREAMING) {
  316.  
  317.     // this has been replaced...
  318.     // streamPtr->wsParentPtr->waPtr->ahwPtr->xStop(); // yipes, talk about an indirect function call
  319.     // by this:
  320.  
  321.     if (streamPtr->wsParentPtr->waPtr->devType == AUDIOHW_WAVE_PLAY) {
  322.        rc = waveplayStop(streamPtr->wsParentPtr);
  323.     }
  324.     else {
  325.        rc = waverecStop(streamPtr->wsParentPtr);
  326.     }
  327.  }
  328.  
  329.  // destroy all stream buffers and events still associated with this stream
  330.  
  331.  while(sbNotEmpty(&streamPtr->sbaProc)) {
  332.     tsbPtr = sbHead(&streamPtr->sbaProc);
  333.     sbDestroyElement(tsbPtr, &streamPtr->sbaProc);
  334.  }
  335.  
  336.  while(sbNotEmpty(&streamPtr->sbaDone)) {
  337.     tsbPtr = sbHead(&streamPtr->sbaDone);
  338.     sbDestroyElement(tsbPtr, &streamPtr->sbaDone);
  339.  }
  340.  
  341.  // can do this event processing code now since won't do anything (always empty for now)
  342.  
  343.  while(sbNotEmpty(&streamPtr->sbaEvent)) {
  344.     tsbPtr = sbHead(&streamPtr->sbaEvent);
  345.     sbDestroyElement(tsbPtr, &streamPtr->sbaEvent);
  346.  }
  347.  
  348.  streamPopElement(streamPtr);   // remove this stream from list
  349.  
  350.  return 0;
  351. }
  352.  
  353.  
  354. // ---------------------------------------------------
  355. // in: streamType (was ULONG)
  356. //out: streamPtr -> active stream
  357. //nts: finds first active stream of matching type
  358.  
  359. STREAM *streamFindActive(USHORT streamType) {
  360.  
  361.  STREAM *streamPtr = streamList.headPtr;
  362.  
  363.  while (streamPtr) {
  364.     if (streamPtr->streamType == streamType && streamPtr->streamState == STREAM_STREAMING) break;
  365.     streamPtr = streamPtr->nextPtr;
  366.  }
  367.  
  368.  return streamPtr;
  369. }
  370.  
  371.  
  372. // ---------------------------------------------------
  373. // in: SFN (was ULONG)
  374. //out: streamPtr -> stream with this SFN
  375. //nts: map SFN to stream object
  376.  
  377. STREAM *streamFindStreamSFN(USHORT SFN) {
  378.  
  379.  STREAM *streamPtr = streamList.headPtr;
  380.  
  381.  while (streamPtr) {
  382.     if (streamPtr->SFN == SFN) break;
  383.     streamPtr = streamPtr->nextPtr;
  384.  }
  385.  
  386.  return streamPtr;
  387. }
  388.  
  389.  
  390. // ---------------------------------------------------
  391. // in: streamH
  392. //out: streamPtr -> stream with this handle
  393. //nts: map stream handle to stream object
  394.  
  395. STREAM *streamFindStreamHandle(HSTREAM streamH) {
  396.  
  397.  STREAM *streamPtr = streamList.headPtr;
  398.  
  399.  while (streamPtr) {
  400.     if (streamPtr->streamH == streamH) break;
  401.     streamPtr = streamPtr->nextPtr;
  402.  }
  403.  
  404.  return streamPtr;
  405. }
  406.  
  407.  
  408. // -----------------------------------------------------------------------------
  409. // Queue support for STREAM_BUFFER objects (STREAM objects follows this, below)
  410. // -----------------------------------------------------------------------------
  411.  
  412. // -----------------------------------------------------------------------------
  413. // in: streamBufferAnchorPtr -> queue anchor to either proc, done, or event queues
  414. //out: stream_buffer pointer -> head
  415. //nts: sort of like PopHead() but doesn't remove head
  416. //
  417. // eg,
  418. // STREAM_BUFFER *DoneHeadPtr = sbHead(&streamPtr->sbaDone);
  419.  
  420. STREAM_BUFFER *sbHead(STREAM_BUFFER_ANCHOR *sbaPtr) {
  421.  
  422.  STREAM_BUFFER *tempPtr = sbaPtr->headPtr;
  423.  
  424.  return tempPtr;
  425. }
  426.  
  427.  
  428. // -------------------------------------------------------------------
  429. // in: streamBufferAnchorPtr -> queue anchor to either proc, done, or event queues
  430. //out: stream_buffer pointer -> tail
  431. //nts: sort of like PopTail() but doesn't remove tail
  432. //
  433. // eg,
  434. // STREAM_BUFFER *DoneHeadPtr = sbTail(&streamPtr->sbaDone);
  435.  
  436. STREAM_BUFFER *sbTail(STREAM_BUFFER_ANCHOR *sbaPtr) {
  437.  
  438.  STREAM_BUFFER *tempPtr = sbaPtr->tailPtr;
  439.  
  440.  return tempPtr;
  441. }
  442.  
  443.  
  444. // -----------------------------------------------------------------------------
  445. // in: stream buffer ptr -> stream buffer item to put on head of queue
  446. //     streamBufferAnchorPtr -> queue anchor to either proc, done, or event queues
  447. //out: n/a
  448. //nts:
  449. //
  450. // eg,
  451. // sbPushOnHead(sbPtr, &streamPtr->sbaDone);
  452.  
  453. VOID sbPushOnHead(STREAM_BUFFER *sbPtr, STREAM_BUFFER_ANCHOR *sbaPtr) {
  454.  
  455.  if (sbaPtr->headPtr == 0) {            // empty list so just put it on
  456.     sbPtr->nextPtr = 0;
  457.     sbaPtr->headPtr = sbPtr;
  458.     sbaPtr->tailPtr = sbPtr;
  459.  }
  460.  else {
  461.     sbPtr->nextPtr = sbaPtr->headPtr;   // set buffer's nextPtr to current head
  462.     sbaPtr->headPtr = sbPtr;            // and make this buffer the new head
  463.  }
  464.  
  465.  return;
  466. }
  467.  
  468.  
  469. // -----------------------------------------------------------------------------
  470. // in: stream buffer ptr -> stream buffer item to put on tail of queue
  471. //     streamBufferAnchorPtr -> queue anchor to either proc, done, or event queues
  472. //out: n/a
  473. //nts:
  474. //
  475. // eg,
  476. // sbPushOnTail(sbPtr, &streamPtr->sbaDone);
  477.  
  478. VOID sbPushOnTail(STREAM_BUFFER *sbPtr, STREAM_BUFFER_ANCHOR *sbaPtr) {
  479.  
  480.  sbPtr->nextPtr = 0;
  481.  if (sbaPtr->headPtr == 0) {            // empty list so just put it on
  482.     sbaPtr->headPtr = sbPtr;
  483.     sbaPtr->tailPtr = sbPtr;
  484.  }
  485.  else {
  486.     sbaPtr->tailPtr->nextPtr = sbPtr;   // set current tail's nextPtr to new tail
  487.     sbaPtr->tailPtr = sbPtr;            // and make this buffer the new tail
  488.  }
  489.  
  490.  return;
  491. }
  492.  
  493.  
  494. // -----------------------------------------------------------------------------
  495. // in: streamBufferAnchorPtr -> queue anchor to either proc, done, or event queues
  496. //out: stream_buffer pointer -> what was at head of the queue
  497. //nts:
  498. //
  499. // eg,
  500. // STREAM_BUFFER *DoneHeadPtr = sbPopHead(&streamPtr->sbaDone);
  501.  
  502. STREAM_BUFFER *sbPopHead(STREAM_BUFFER_ANCHOR *sbaPtr) {
  503.  
  504.  STREAM_BUFFER *tempPtr = sbaPtr->headPtr;
  505.  
  506.  if (tempPtr) {
  507.     sbaPtr->headPtr = tempPtr->nextPtr;
  508.     if (sbaPtr->headPtr == 0) sbaPtr->tailPtr = 0;
  509.     tempPtr->nextPtr = 0;
  510.  }
  511.  
  512.  return tempPtr;
  513. }
  514.  
  515.  
  516. // -----------------------------------------------------------------------------
  517. // in: streamBufferAnchorPtr -> queue anchor to either proc, done, or event queues
  518. //out: stream_buffer pointer -> what was at tail of the queue
  519. //nts:
  520. //
  521. // eg,
  522. // STREAM_BUFFER *DoneTailPtr = sbPopTail(&streamPtr->sbaDone);
  523.  
  524. STREAM_BUFFER *sbPopTail(STREAM_BUFFER_ANCHOR *sbaPtr) {
  525.  
  526.  STREAM_BUFFER *tempPtr = sbaPtr->tailPtr;
  527.  STREAM_BUFFER *temp2Ptr = sbaPtr->headPtr;
  528.  
  529.  if (tempPtr == temp2Ptr) {
  530.  
  531.     // only one item in list, or it's empty
  532.  
  533.     sbaPtr->headPtr = 0;
  534.     sbaPtr->tailPtr = 0;
  535.     if (tempPtr) tempPtr->nextPtr = 0;  // set the old tail's nextPtr to 0
  536.  }
  537.  else {
  538.     if (tempPtr) {
  539.        while (temp2Ptr->nextPtr != tempPtr) { 
  540.           temp2Ptr = temp2Ptr->nextPtr; // scan down list to just before tail
  541.        }
  542.        sbaPtr->tailPtr = temp2Ptr;      // set the new tail to be that one
  543.  
  544.        if (sbaPtr->tailPtr == 0) {      // hm, can this happen (seem like has to only
  545.           sbaPtr->headPtr = 0;          // have one item for it to, and that's covered above)
  546.        }
  547.        else {
  548.           sbaPtr->tailPtr->nextPtr = 0; // mark new tail's nextPtr as 0 (since it's the tail!)
  549.        }
  550.        tempPtr->nextPtr = 0;            // set the old tail's nextPtr to 0
  551.     }
  552.  }
  553.  
  554.  return tempPtr;
  555. }
  556.  
  557.  
  558. // -----------------------------------------------------------------------------
  559. // in: sbPtr -> stream buffer to destroy
  560. //     streamBufferAnchorPtr -> queue anchor to either proc, done, or event queues
  561. //out: 1 if destroyed it, else not there
  562. //nts: frees memory allocated at sbPtr
  563. //
  564. // eg,
  565. // destroyedItFlag = sbDestroyElement(sbPtr, &streamPtr->sbaDone);
  566.  
  567. USHORT sbDestroyElement(STREAM_BUFFER *sbPtr, STREAM_BUFFER_ANCHOR *sbaPtr) {
  568.  
  569.  USHORT rc = 0;
  570.  
  571.  if (sbPopElement(sbPtr,sbaPtr)) {
  572.     free(sbPtr);
  573.  
  574. // !!!
  575. //ddprintf("@sbDestroyElement:free:%x\n",sbPtr);
  576.  
  577.     rc = 1;
  578.  }
  579.  
  580.  return rc;
  581. }
  582.  
  583.  
  584. // -----------------------------------------------------------------------------
  585. // in: match_sbPtr -> stream buffer to remove for queue (based on address)
  586. //     streamBufferAnchorPtr -> queue anchor to either proc, done, or event queues
  587. //out: returns match_sbPtr (same as entry) if found/removed, else 0 if not there
  588. //nts: see below
  589. //
  590. // eg,
  591. // sbPtr = sbPopElement(sbPtr, &streamPtr->sbaDone);
  592.  
  593. STREAM_BUFFER *sbPopElement(STREAM_BUFFER *match_sbPtr, STREAM_BUFFER_ANCHOR *sbaPtr) {
  594.  
  595.  STREAM_BUFFER *tempPtr = 0;
  596.  
  597.  if (sbaPtr->headPtr == 0) {            // empty queue
  598.     return 0;
  599.  }
  600.  
  601.  if (match_sbPtr == sbaPtr->headPtr) {  // if matches head, pop head
  602.     tempPtr = sbPopHead(sbaPtr);
  603.     return tempPtr;
  604.  }
  605.  
  606.  if (match_sbPtr == sbaPtr->tailPtr) {  // if matches tail, pop tail
  607.     tempPtr = sbPopTail(sbaPtr);
  608.     return tempPtr;
  609.  }
  610.  
  611.  // this next section scans items, check the nextPtrs of each -- when a nextPtr points
  612.  // to the match_sbPtr it's known that the item is there, so set that nextPtr to point
  613.  // to the item's nextPtr rather than the item itself (item is match_sbPtr in this case)
  614.  // effectively removing the item from the list
  615.  
  616.  tempPtr = sbaPtr->headPtr;
  617.  while (tempPtr->nextPtr != match_sbPtr && tempPtr->nextPtr != 0) {
  618.     tempPtr = tempPtr->nextPtr;         // scan elements until find it in someone's nextPtr...
  619.  }
  620.  if (tempPtr == 0) return 0;            // not found at all
  621.  
  622.  tempPtr->nextPtr = match_sbPtr->nextPtr; // now set links so the item is removed from the list
  623.  
  624.  return match_sbPtr;
  625. }
  626.  
  627.  
  628. // -----------------------------------------------------------------------------
  629. // in: streamBufferAnchorPtr -> queue anchor to either proc, done, or event queues
  630. //out: 0 if the list is empty, otherwise 1
  631. //nts: original returned a ULONG for some reason
  632. //
  633. // eg,
  634. // notEmpty = sbNotEmpty(&streamPtr->sbaDone);
  635.  
  636. USHORT sbNotEmpty(STREAM_BUFFER_ANCHOR *sbaPtr) {
  637.  
  638.  USHORT rc = 0;
  639.  
  640.  if (sbaPtr->headPtr) rc = 1;
  641.  
  642.  return rc;
  643. }
  644.  
  645. // -------------------------------------
  646. // to init queue set headPtr/tailPtr = 0
  647. // which is accomplished by simply MEMSET()'ing the allocation
  648. // ie, the contructor (doesn't seem to be a destructor for the QUEUE class)
  649.  
  650.  
  651. // -----------------------------------------------------------------------------
  652. // Queue support for STREAM objects
  653. // -----------------------------------------------------------------------------
  654. // note: unlike STREAM_BUFFER queue support, don't need to pass anchor pointer
  655. //       since it's known to be streamList
  656.  
  657.  
  658. // -----------------------------------------------------------------------------
  659. // in: n/a
  660. //out: stream pointer -> head
  661. //nts: sort of like PopHead() but doesn't remove head
  662. //
  663. // eg,
  664. // STREAM *HeadPtr = streamHead();
  665.  
  666. STREAM *streamHead(VOID) {
  667.  
  668.  STREAM *tempPtr = streamList.headPtr;
  669.  
  670.  return tempPtr;
  671. }
  672.  
  673.  
  674. // -------------------------------------------------------------------
  675. // in: n/a
  676. //out: stream pointer -> tail
  677. //nts: sort of like PopTail() but doesn't remove tail
  678. //
  679. // eg,
  680. // STREAM *TailPtr = streamTail();
  681.  
  682. STREAM *streamTail(VOID) {
  683.  
  684.  STREAM *tempPtr = streamList.tailPtr;
  685.  
  686.  return tempPtr;
  687. }
  688.  
  689.  
  690. // -----------------------------------------------------------------------------
  691. // in: stream ptr -> stream item to put on head of queue
  692. //out: n/a
  693. //nts:
  694. //
  695. // eg,
  696. // streamPushOnHead(sPtr);
  697.  
  698. VOID streamPushOnHead(STREAM *sPtr) {
  699.  
  700.  if (streamList.headPtr == 0) {         // empty list so just put it on
  701.     sPtr->nextPtr = 0;
  702.     streamList.headPtr = sPtr;
  703.     streamList.tailPtr = sPtr;
  704.  }
  705.  else {
  706.     sPtr->nextPtr = streamList.headPtr; // set stream's nextPtr to current head
  707.     streamList.headPtr = sPtr;          // and make this buffer the new head
  708.  }
  709.  
  710.  return;
  711. }
  712.  
  713.  
  714. // -----------------------------------------------------------------------------
  715. // in: stream ptr -> stream item to put on tail of queue
  716. //out: n/a
  717. //nts:
  718. //
  719. // eg,
  720. // streamPushOnTail(sPtr);
  721.  
  722. VOID streamPushOnTail(STREAM *sPtr) {
  723.  
  724.  sPtr->nextPtr = 0;
  725.  if (streamList.headPtr == 0) {         // empty list so just put it on
  726.     streamList.headPtr = sPtr;
  727.     streamList.tailPtr = sPtr;
  728.  }
  729.  else {
  730.     streamList.tailPtr->nextPtr = sPtr; // set current tail's nextPtr to new tail
  731.     streamList.tailPtr = sPtr;          // and make this buffer the new tail
  732.  }
  733.  
  734.  return;
  735. }
  736.  
  737.  
  738. // -----------------------------------------------------------------------------
  739. // in: n/a
  740. //out: stream pointer -> what was at head of the queue
  741. //nts:
  742. //
  743. // eg,
  744. // STREAM *HeadPtr = streamPopHead();
  745.  
  746. STREAM *streamPopHead(VOID) {
  747.  
  748.  STREAM *tempPtr = streamList.headPtr;
  749.  
  750.  if (tempPtr) {
  751.     streamList.headPtr = tempPtr->nextPtr;
  752.     if (streamList.headPtr == 0) streamList.tailPtr = 0;
  753.     tempPtr->nextPtr = 0;
  754.  }
  755.  
  756.  return tempPtr;
  757. }
  758.  
  759.  
  760. // -----------------------------------------------------------------------------
  761. // in: n/a
  762. //out: stream pointer -> what was at tail of the queue
  763. //nts:
  764. //
  765. // eg,
  766. // STREAM *TailPtr = streamPopTail();
  767.  
  768. STREAM *streamPopTail(VOID) {
  769.  
  770.  STREAM *tempPtr = streamList.tailPtr;
  771.  STREAM *temp2Ptr = streamList.headPtr;
  772.  
  773.  if (tempPtr == temp2Ptr) {
  774.  
  775.     // only one item in list, or it's empty
  776.  
  777.     streamList.headPtr = 0;
  778.     streamList.tailPtr = 0;
  779.     if (tempPtr) tempPtr->nextPtr = 0;  // set the old tail's nextPtr to 0
  780.  }
  781.  else {
  782.     if (tempPtr) {
  783.        while (temp2Ptr->nextPtr != tempPtr) { 
  784.           temp2Ptr = temp2Ptr->nextPtr; // scan down list to just before tail
  785.        }
  786.        streamList.tailPtr = temp2Ptr;   // set the new tail to be that one
  787.  
  788.        if (streamList.tailPtr == 0) {   // hm, can this happen (seem like has to only
  789.           streamList.headPtr = 0;       // have one item for it to, and that's covered above)
  790.        }
  791.        else {
  792.           streamList.tailPtr->nextPtr = 0; // mark new tail's nextPtr as 0 (since it's the tail!)
  793.        }
  794.        tempPtr->nextPtr = 0;            // set the old tail's nextPtr to 0
  795.     }
  796.  }
  797.  
  798.  return tempPtr;
  799. }
  800.  
  801.  
  802. // -----------------------------------------------------------------------------
  803. // in: sPtr -> stream to destroy
  804. //out: 1 if destroyed it, else not there
  805. //nts: frees memory allocated at sPtr
  806. //
  807. // eg,
  808. // destroyedItFlag = streamDestroyElement(sPtr);
  809.  
  810. USHORT streamDestroyElement(STREAM *sPtr) {
  811.  
  812.  USHORT rc = 0;
  813.  
  814.  if (streamPopElement(sPtr)) {
  815.     free(sPtr);
  816.  
  817. // !!!
  818. //ddprintf("@streamDestroyElement:free:%x\n",sPtr);
  819.  
  820.     rc = 1;
  821.  }
  822.  
  823.  return rc;
  824. }
  825.  
  826.  
  827. // -----------------------------------------------------------------------------
  828. // in: match_sPtr -> stream to remove for queue (based on address)
  829. //out: returns match_sPtr (same as entry) if found/removed, else 0 if not there
  830. //nts: see below
  831. //
  832. // eg,
  833. // sPtr = streamPopElement(sPtr);
  834.  
  835. STREAM *streamPopElement(STREAM *match_sPtr) {
  836.  
  837.  STREAM *tempPtr = 0;
  838.  
  839.  if (streamList.headPtr == 0) {         // empty queue
  840.     return 0;
  841.  }
  842.  
  843.  if (match_sPtr == streamList.headPtr) { // if matches head, pop head
  844.     tempPtr = streamPopHead();
  845.     return tempPtr;
  846.  }
  847.  
  848.  if (match_sPtr == streamList.tailPtr) { // if matches tail, pop tail
  849.     tempPtr = streamPopTail();
  850.     return tempPtr;
  851.  }
  852.  
  853.  // this next section scans items, check the nextPtrs of each -- when a nextPtr points
  854.  // to the match_sPtr it's known that the item is there, so set that nextPtr to point
  855.  // to the item's nextPtr rather than the item itself (item is match_sPtr in this case)
  856.  // effectively removing the item from the list
  857.  
  858.  tempPtr = streamList.headPtr;
  859.  while (tempPtr->nextPtr != match_sPtr && tempPtr->nextPtr != 0) {
  860.     tempPtr = tempPtr->nextPtr;         // scan elements until find it in someone's nextPtr...
  861.  }
  862.  if (tempPtr == 0) return 0;            // not found at all
  863.  
  864.  tempPtr->nextPtr = match_sPtr->nextPtr; // now set links so the item is removed from the list
  865.  
  866.  return match_sPtr;
  867. }
  868.  
  869.  
  870. // -----------------------------------------------------------------------------
  871. // in: n/a
  872. //out: 0 if the list is empty, otherwise 1
  873. //nts: original returned a ULONG for some reason
  874. //
  875. // eg,
  876. // notEmpty = streamNotEmpty();
  877.  
  878. USHORT streamNotEmpty(VOID) {
  879.  
  880.  USHORT rc = 0;
  881.  
  882.  if (streamList.headPtr) rc = 1;
  883.  
  884.  return rc;
  885. }
  886.  
  887.  
  888. // ---------------------------------
  889. // in: streamPtr -> stream structure
  890. //out:
  891. //nts:
  892.  
  893. VOID streamProcessEvents(STREAM *streamPtr) {
  894.  
  895.  return;
  896.  streamPtr;
  897. }
  898.  
  899.  
  900. // --------------------------------------
  901. // in: ddcmdPtr -> DDCMDCONTROL structure (far ptr)
  902. //     streamPtr -> stream structure
  903. //out:
  904. //nts:
  905.  
  906. VOID streamEnableEvent(DDCMDCONTROL __far *ddcmdPtr, STREAM *streamPtr) {
  907.  
  908.  return;
  909.  ddcmdPtr;
  910.  streamPtr;
  911. }
  912.  
  913.  
  914. // --------------------------------------
  915. // in: ddcmdPtr -> DDCMDCONTROL structure (far ptr)
  916. //     streamPtr -> stream structure
  917. //out:
  918. //nts:
  919.  
  920. VOID streamDisableEvent(DDCMDCONTROL __far *ddcmdPtr, STREAM *streamPtr) {
  921.  
  922.  return;
  923.  ddcmdPtr;
  924.  streamPtr;
  925. }
  926.  
  927.  
  928. // --------------------------------------
  929. // in: streamPtr -> stream structure
  930. //out:
  931. //nts:
  932.  
  933. VOID streamSetNextEvent(STREAM *streamPtr) {
  934.  
  935.  return;
  936.  streamPtr;
  937. }
  938.  
  939.  
  940. #if 0
  941.  
  942. // -----------------------------------------------------------------------------
  943. // -----------------------------------------------------------------------------
  944. // -----------------------------------------------------------------------------
  945. // -----------------------------------------------------------------------------
  946. // -----------------------------------------------------------------------------
  947. // -----------------------------------------------------------------------------
  948.  
  949. // the following event-support routines are not yet done
  950. //  void STREAM::ProcessEvents(void)
  951. //  ULONG STREAM::EnableEvent(PDDCMDCONTROL pControl)
  952. //  ULONG STREAM::DisableEvent(PDDCMDCONTROL pControl)
  953. //  void STREAM::SetNextEvent(void)
  954.  
  955.  
  956. class EVENT;
  957.  
  958.  
  959. // ProcessEvents
  960. // called by the Process at interrupt time to see if there are
  961. // any events that have timed out
  962. //
  963. void STREAM::ProcessEvents(void)
  964. {
  965.    if (qhEvent.IsElements()) {
  966.       PEVENT pnextevent = (PEVENT)qhEvent.Head();
  967.       ULONG time = GetCurrentTime();
  968.       ULONG eventtime = pnextevent->GetEventTime();
  969.       if (eventtime <= time)
  970.          pnextevent->Report(time);
  971.    }
  972.  
  973. }
  974. ULONG STREAM::EnableEvent(PDDCMDCONTROL pControl)
  975. {
  976.  
  977.    // see if the event already exists on the event queue
  978.    // call FindEvent if we get back an address (event exists)
  979.    // call the UpdateEvent member function and get the event info updated.
  980.    // if Findevent returns NULL (no event on queue) then call the construct
  981.    // a new event and put it on the tail of the event queue. then call
  982.    // SetNextEvent to update the next event to time out....
  983.  
  984.    PEVENT pevent = FindEvent(pControl->hEvent, &qhEvent);
  985.    if (pevent)
  986.       pevent->UpdateEvent(this,pControl->hEvent,(PCONTROL_PARM)pControl->pParm);
  987.    else {
  988.       pevent= new EVENT(this,pControl->hEvent,(PCONTROL_PARM)pControl->pParm);
  989.    }
  990.    if (!pevent)
  991.       return ERROR_TOO_MANY_EVENTS;
  992.  
  993.    SetNextEvent();
  994.    return NO_ERROR;
  995. }
  996.  
  997. ULONG STREAM::DisableEvent(PDDCMDCONTROL pControl)
  998. {
  999.    pTrace->vLog(DDCMD_DisableEvent,pControl->hEvent);
  1000.    PEVENT pevent = FindEvent(pControl->hEvent, &qhEvent);
  1001.    if (!pevent)
  1002.       return ERROR_INVALID_EVENT;
  1003.  
  1004.     // destroying an event may change things that get referenced in the ISR
  1005.     // so we really need to cli/sti around the call to DestroyElement
  1006.    _cli_();
  1007.    qhEvent.DestroyElement((PQUEUEELEMENT)pevent);
  1008.    if (qhEvent.Head() != qhEvent.Tail())
  1009.       SetNextEvent();
  1010.    _sti_();
  1011.    return NO_ERROR;
  1012. }
  1013.  
  1014.  
  1015.  
  1016. /**@internal SetNextEvent
  1017.  * @param    None
  1018.  * @return   None
  1019.  * @notes
  1020.  * the function walks the event list and finds the next event to timeout.
  1021.  * the event is moved to the head of the event queue.
  1022.  *
  1023.  */
  1024. void STREAM::SetNextEvent(void)
  1025. {
  1026.  
  1027.    // if there are no events or only one event on the
  1028.    // queue just return
  1029.    if ((qhEvent.Head()) == (qhEvent.Tail()))
  1030.        return;
  1031.  
  1032.    PQUEUEELEMENT pele1 = qhEvent.Head();
  1033.    PQUEUEELEMENT pele2 = NULL;
  1034.    ULONG ulTimeToBeat = -1;     // -1 equals 0xFFFFFFFF the maximum time
  1035.  
  1036.    while (pele1) {
  1037.       if (((PEVENT)pele1)->GetEventTime() <= ulTimeToBeat) {
  1038.          pele2 = pele1;
  1039.          ulTimeToBeat = ((PEVENT)pele1)->GetEventTime();
  1040.       }
  1041.       pele1 = pele1->pNext;
  1042.    }
  1043.    // pele2 should now contain the address of the next
  1044.    // event to time out.. if it is not already on
  1045.    // the head of the Event queue then put it there
  1046.    if (pele2 != qhEvent.Head()) {
  1047.       _cli_();
  1048.       qhEvent.PopElement(pele2);
  1049.       qhEvent.PushOnHead(pele2);
  1050.       _sti_();
  1051.    }
  1052. }
  1053.  
  1054.  
  1055. #endif
  1056.  
  1057.  
  1058.