Changeset 64980 in vbox for trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
- Timestamp:
- Dec 21, 2016 1:21:11 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
r64570 r64980 31 31 # endif 32 32 # include <iprt/mem.h> 33 # include <iprt/semaphore.h> 33 34 # include <iprt/string.h> 34 35 # include <iprt/uuid.h> … … 45 46 * Defined Constants And Macros * 46 47 *********************************************************************************************************************************/ 48 49 /* 50 * Enables asynchronous audio data handling 51 * to speed up the actual DMA data routines and keeping up 52 * audio processing out of EMT as much as possible. 53 */ 54 #define VBOX_WITH_AUDIO_AC97_ASYNC_IO 47 55 48 56 #if 0 … … 63 71 #define AC97_SSM_VERSION 1 64 72 65 /** Timer frequency (in Hz)*/66 #define AC97_TIMER_HZ 20073 /** Default timer frequency (in Hz). */ 74 #define AC97_TIMER_HZ 100 67 75 68 76 #define AC97_SR_FIFOE RT_BIT(4) /* rwc, FIFO error. */ … … 281 289 } AC97BMREGS, *PAC97BMREGS; 282 290 283 /** 284 * Internal state of an AC'97 stream. 291 #ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 292 /** 293 * Structure keeping the AC'97 stream's state for asynchronous I/O. 294 */ 295 typedef struct AC97STREAMSTATEAIO 296 { 297 /** Thread handle for the actual I/O thread. */ 298 RTTHREAD Thread; 299 /** Event for letting the thread know there is some data to process. */ 300 RTSEMEVENT Event; 301 /** Critical section for synchronizing access. */ 302 RTCRITSECT CritSect; 303 /** Started indicator. */ 304 volatile bool fStarted; 305 /** Shutdown indicator. */ 306 volatile bool fShutdown; 307 uint32_t Padding1; 308 } AC97STREAMSTATEAIO, *PAC97STREAMSTATEAIO; 309 #endif 310 311 /** 312 * Structure for keeping the internal state of an AC'97 stream. 285 313 */ 286 314 typedef struct AC97STREAMSTATE 287 315 { 288 /** Temporary FIFO write buffer. */ 289 R3PTRTYPE(uint8_t *) au8FIFOW; 290 /** Size of the temporary FIFO write buffer. */ 291 uint32_t cbFIFOW; 292 /** Current write offset in FIFO write buffer. */ 293 uint32_t offFIFOW; 294 uint8_t Padding; 316 /** Circular buffer (FIFO) for holding DMA'ed data. */ 317 R3PTRTYPE(PRTCIRCBUF) pCircBuf; 318 #ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 319 /** Asynchronous I/O state members. */ 320 AC97STREAMSTATEAIO AIO; 321 #endif 295 322 } AC97STREAMSTATE, *PAC97STREAMSTATE; 296 323 297 324 /** 298 * Structure for keeping an AC'97 stream state.325 * Structure for an AC'97 stream. 299 326 */ 300 327 typedef struct AC97STREAM … … 310 337 } AC97STREAM, *PAC97STREAM; 311 338 312 typedef struct AC97INPUTSTREAM 313 { 314 /** Mixer handle for input stream. */ 315 R3PTRTYPE(PAUDMIXSTREAM) pMixStrm; 316 } AC97INPUTSTREAM, *PAC97INPUTSTREAM; 317 318 typedef struct AC97OUTPUTSTREAM 319 { 320 /** Mixer handle for output stream. */ 321 R3PTRTYPE(PAUDMIXSTREAM) pMixStrm; 322 } AC97OUTPUTSTREAM, *PAC97OUTPUTSTREAM; 339 typedef struct AC97STATE *PAC97STATE; 340 #ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 341 /** 342 * Structure for the async I/O thread context. 343 */ 344 typedef struct AC97STREAMTHREADCTX 345 { 346 PAC97STATE pThis; 347 PAC97STREAM pStream; 348 } AC97STREAMTHREADCTX, *PAC97STREAMTHREADCTX; 349 #endif 350 351 /** 352 * Structure defining a (host backend) driver stream. 353 * Each driver has its own instances of audio mixer streams, which then 354 * can go into the same (or even different) audio mixer sinks. 355 */ 356 typedef struct AC97DRIVERSTREAM 357 { 358 union 359 { 360 /** Desired playback destination (for an output stream). */ 361 PDMAUDIOPLAYBACKDEST Dest; 362 /** Desired recording source (for an input stream). */ 363 PDMAUDIORECSOURCE Source; 364 } DestSource; 365 uint8_t Padding1[4]; 366 /** Associated mixer stream handle. */ 367 R3PTRTYPE(PAUDMIXSTREAM) pMixStrm; 368 } AC97DRIVERSTREAM, *PAC97DRIVERSTREAM; 323 369 324 370 /** 325 371 * Struct for maintaining a host backend driver. 326 372 */ 327 typedef struct AC97STATE *PAC97STATE;328 373 typedef struct AC97DRIVER 329 374 { … … 344 389 /** Audio connector interface to the underlying host backend. */ 345 390 R3PTRTYPE(PPDMIAUDIOCONNECTOR) pConnector; 346 /** Stream for line input. */347 AC97 INPUTSTREAMLineIn;348 /** Stream for mic input. */349 AC97 INPUTSTREAMMicIn;350 /** Stream for output. */351 AC97 OUTPUTSTREAM Out;391 /** Driver stream for line input. */ 392 AC97DRIVERSTREAM LineIn; 393 /** Driver stream for mic input. */ 394 AC97DRIVERSTREAM MicIn; 395 /** Driver stream for output. */ 396 AC97DRIVERSTREAM Out; 352 397 } AC97DRIVER, *PAC97DRIVER; 353 398 399 /** 400 * Structure for maintaining an AC'97 device state. 401 */ 354 402 typedef struct AC97STATE 355 403 { … … 366 414 uint32_t last_samp; 367 415 uint8_t mixer_data[256]; 368 /** Stream statefor line-in. */416 /** AC'97 stream for line-in. */ 369 417 AC97STREAM StreamLineIn; 370 /** Stream statefor microphone-in. */418 /** AC'97 stream for microphone-in. */ 371 419 AC97STREAM StreamMicIn; 372 /** Stream statefor output. */420 /** AC'97 stream for output. */ 373 421 AC97STREAM StreamOut; 374 422 /** Number of active (running) SDn streams. */ … … 392 440 #endif 393 441 #ifdef VBOX_WITH_STATISTICS 394 uint8_t Padding1;395 442 STAMPROFILE StatTimer; 443 STAMPROFILE StatIn; 444 STAMPROFILE StatOut; 396 445 STAMCOUNTER StatBytesRead; 397 446 STAMCOUNTER StatBytesWritten; … … 425 474 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 426 475 427 static void ichac97DestroyIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource); 428 static void ichac97DestroyOut(PAC97STATE pThis); 429 DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID); 430 static int ichac97StreamInit(PAC97STREAM pStream, uint8_t u8Strm); 431 static void ichac97StreamDestroy(PAC97STREAM pStream); 432 static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream); 433 static int ichac97StreamReOpen(PAC97STATE pThis, PAC97STREAM pStream); 434 static void ichac97StreamClose(PAC97STREAM pStream); 476 DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID); 477 static int ichac97StreamCreate(PAC97STATE pThis, PAC97STREAM pStream, uint8_t u8Strm); 478 static void ichac97StreamDestroy(PAC97STATE pThis, PAC97STREAM pStream); 479 static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream); 480 static int ichac97StreamReOpen(PAC97STATE pThis, PAC97STREAM pStream); 481 static int ichac97StreamClose(PAC97STATE pThis, PAC97STREAM pStream); 482 435 483 static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns); 436 484 #ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS 437 static void ichac97TimerMaybeStart(PAC97STATE pThis);438 static void ichac97TimerMaybeStop(PAC97STATE pThis);485 static void ichac97TimerMaybeStart(PAC97STATE pThis); 486 static void ichac97TimerMaybeStop(PAC97STATE pThis); 439 487 static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser); 440 488 #endif 441 static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed); 489 static int ichac97DoDMA(PAC97STATE pThis, PAC97STREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t cbToProcess, uint32_t *pcbProcessed); 490 static void ichac97DoTransfers(PAC97STATE pThis); 491 492 #ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 493 static DECLCALLBACK(int) ichac97StreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser); 494 static int ichac97StreamAsyncIONotify(PAC97STATE pThis, PAC97STREAM pStream); 495 static void ichac97StreamAsyncIOLock(PAC97STREAM pStream); 496 static void ichac97StreamAsyncIOUnlock(PAC97STREAM pStream); 497 #endif 442 498 443 499 static void ichac97WarmReset(PAC97STATE pThis) … … 571 627 return VINF_SUCCESS; 572 628 573 const bool fIsEnabled = AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING; 574 575 LogFunc(("[SD%RU8] fEnable=%RTbool, fIsEnabled=%RTbool, DCH=%RTbool, cStreamsActive=%RU8\n", 576 pStream->u8Strm, fEnable, fIsEnabled, RT_BOOL(pStream->Regs.sr & AC97_SR_DCH), pThis->cStreamsActive)); 629 const AUDMIXSINKSTS stsSink = AudioMixerSinkGetStatus(pSink); 630 631 const bool fIsEnabled = stsSink & AUDMIXSINK_STS_RUNNING; 632 const bool fPendingDisable = stsSink & AUDMIXSINK_STS_PENDING_DISABLE; 633 634 LogFunc(("[SD%RU8] fEnable=%RTbool, fIsEnabled=%RTbool, fPendingDisable=%RTbool, DCH=%RTbool, cStreamsActive=%RU8\n", 635 pStream->u8Strm, fEnable, fIsEnabled, fPendingDisable, RT_BOOL(pStream->Regs.sr & AC97_SR_DCH), pThis->cStreamsActive)); 577 636 578 637 int rc = VINF_SUCCESS; 579 638 580 if (fEnable != fIsEnabled) 581 { 582 rc = ichac97StreamReOpen(pThis, pStream); 583 if (RT_SUCCESS(rc)) 584 rc = AudioMixerSinkCtl(ichac97IndexToSink(pThis, pStream->u8Strm), 585 fEnable ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE); 586 if (RT_SUCCESS(rc)) 587 { 588 if (!fEnable) 589 { 590 if (pThis->cStreamsActive) /* Disable can be called mupltiple times. */ 591 pThis->cStreamsActive--; 639 #ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 640 ichac97StreamAsyncIOLock(pStream); 641 #endif 642 643 if (fEnable) 644 rc = ichac97StreamOpen(pThis, pStream); 645 else 646 rc = ichac97StreamClose(pThis, pStream); 647 648 if (RT_SUCCESS(rc)) 649 rc = AudioMixerSinkCtl(ichac97IndexToSink(pThis, pStream->u8Strm), 650 fEnable ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE); 651 652 #ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 653 ichac97StreamAsyncIOUnlock(pStream); 654 #endif 655 656 if (RT_SUCCESS(rc)) 657 { 658 if (!fEnable) 659 { 660 if (pThis->cStreamsActive) /* Disable can be called mupltiple times. */ 661 pThis->cStreamsActive--; 592 662 593 663 #ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS 594 664 ichac97TimerMaybeStop(pThis); 595 665 #endif 596 597 598 599 666 } 667 else 668 { 669 pThis->cStreamsActive++; 600 670 #ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS 601 671 ichac97TimerMaybeStart(pThis); 602 672 #endif 603 }604 673 } 605 674 } … … 622 691 pRegs->lvi = 0; 623 692 624 ichac97StreamEnable(pThis, pStream, false /* f Active */);693 ichac97StreamEnable(pThis, pStream, false /* fEnable */); 625 694 626 695 ichac97StreamUpdateSR(pThis, pStream, AC97_SR_DCH); /** @todo Do we need to do that? */ … … 634 703 } 635 704 636 static int ichac97StreamInit(PAC97STREAM pStream, uint8_t u8Strm) 705 /** 706 * Creates an AC'97 stream. 707 * 708 * @returns IPRT status code. 709 * @param pThis AC'97 state. 710 * @param pStream AC'97 stream to create. 711 * @param u8Strm Stream ID to assign AC'97 stream to. 712 */ 713 static int ichac97StreamCreate(PAC97STATE pThis, PAC97STREAM pStream, uint8_t u8Strm) 637 714 { 638 715 AssertPtrReturn(pStream, VERR_INVALID_PARAMETER); … … 640 717 LogFunc(("[SD%RU8] pStream=%p\n", u8Strm, pStream)); 641 718 642 int rc = VINF_SUCCESS; 643 644 pStream->u8Strm = u8Strm; 645 pStream->State.cbFIFOW = _4K; /** @todo Make FIFOW size configurable. */ 646 pStream->State.offFIFOW = 0; 647 pStream->State.au8FIFOW = (uint8_t *)RTMemAllocZ(pStream->State.cbFIFOW); 648 if (pStream->State.au8FIFOW) 649 { 650 rc = RTCritSectInit(&pStream->CritSect); 651 } 652 else 653 rc = VERR_NO_MEMORY; 719 pStream->u8Strm = u8Strm; 720 721 int rc = RTCritSectInit(&pStream->CritSect); 722 if (RT_SUCCESS(rc)) 723 rc = RTCircBufCreate(&pStream->State.pCircBuf, _4K); /** @todo Make this configurable. */ 724 725 #ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 726 /* 727 * Create async I/O stuff. 728 */ 729 PAC97STREAMSTATEAIO pAIO = &pStream->State.AIO; 730 731 pAIO->fShutdown = false; 732 733 if (RT_SUCCESS(rc)) 734 { 735 rc = RTSemEventCreate(&pAIO->Event); 736 if (RT_SUCCESS(rc)) 737 { 738 rc = RTCritSectInit(&pAIO->CritSect); 739 if (RT_SUCCESS(rc)) 740 { 741 AC97STREAMTHREADCTX Ctx = { pThis, pStream }; 742 743 char szThreadName[64]; 744 RTStrPrintf2(szThreadName, sizeof(szThreadName), "ac97AIO%RU8", pStream->u8Strm); 745 746 /** @todo Create threads on demand? */ 747 748 rc = RTThreadCreate(&pAIO->Thread, ichac97StreamAsyncIOThread, &Ctx, 749 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, szThreadName); 750 if (RT_SUCCESS(rc)) 751 rc = RTThreadUserWait(pAIO->Thread, 10 * 1000 /* 10s timeout */); 752 } 753 } 754 } 755 #else 756 RT_NOREF(pThis); 757 #endif 654 758 655 759 return rc; 656 760 } 657 761 658 static void ichac97StreamDestroy(PAC97STREAM pStream) 762 /** 763 * Destroys an AC'97 stream. 764 * 765 * @returns IPRT status code. 766 * @param pThis AC'97 state. 767 * @param pStream AC'97 stream to destroy. 768 */ 769 static void ichac97StreamDestroy(PAC97STATE pThis, PAC97STREAM pStream) 659 770 { 660 771 LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm)); 661 772 662 if (pStream->State.au8FIFOW) 663 { 664 Assert(pStream->State.cbFIFOW); 665 RTMemFree(pStream->State.au8FIFOW); 666 pStream->State.au8FIFOW = NULL; 667 } 668 669 pStream->State.cbFIFOW = 0; 670 pStream->State.offFIFOW = 0; 671 672 if (RTCritSectIsInitialized(&pStream->CritSect)) 673 RTCritSectDelete(&pStream->CritSect); 674 } 675 773 int rc2 = RTCritSectDelete(&pStream->CritSect); 774 AssertRC(rc2); 775 776 if (pStream->State.pCircBuf) 777 { 778 RTCircBufDestroy(pStream->State.pCircBuf); 779 pStream->State.pCircBuf = NULL; 780 } 781 782 #ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 783 /* 784 * Destroy async I/O stuff. 785 */ 786 PAC97STREAMSTATEAIO pAIO = &pStream->State.AIO; 787 788 if (ASMAtomicReadBool(&pAIO->fStarted)) 789 { 790 ASMAtomicWriteBool(&pAIO->fShutdown, true); 791 792 rc2 = ichac97StreamAsyncIONotify(pThis, pStream); 793 AssertRC(rc2); 794 795 int rcThread; 796 rc2 = RTThreadWait(pAIO->Thread, 30 * 1000 /* 30s timeout */, &rcThread); 797 LogFunc(("Async I/O thread ended with %Rrc (%Rrc)\n", rc2, rcThread)); 798 799 if (RT_SUCCESS(rc2)) 800 { 801 rc2 = RTCritSectDelete(&pAIO->CritSect); 802 AssertRC(rc2); 803 804 rc2 = RTSemEventDestroy(pAIO->Event); 805 AssertRC(rc2); 806 807 pAIO->fStarted = false; 808 pAIO->fShutdown = false; 809 } 810 } 811 #else 812 RT_NOREF(pThis); 813 #endif 814 815 LogFlowFuncLeave(); 816 } 817 818 /** 819 * Creates all AC'97 streams for the device. 820 * 821 * @returns IPRT status code. 822 * @param pThis AC'97 state. 823 */ 676 824 static int ichac97StreamsCreate(PAC97STATE pThis) 677 825 { … … 685 833 int rc = AudioMixerCreateSink(pThis->pMixer, "[Recording] Line In", AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn); 686 834 if (RT_SUCCESS(rc)) 687 rc = ichac97Stream Init(&pThis->StreamLineIn, AC97SOUNDSOURCE_PI_INDEX);835 rc = ichac97StreamCreate(pThis, &pThis->StreamLineIn, AC97SOUNDSOURCE_PI_INDEX); 688 836 689 837 /* Microphone-In. */ … … 692 840 rc = AudioMixerCreateSink(pThis->pMixer, "[Recording] Microphone In", AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn); 693 841 if (RT_SUCCESS(rc)) 694 rc = ichac97Stream Init(&pThis->StreamMicIn, AC97SOUNDSOURCE_MC_INDEX);842 rc = ichac97StreamCreate(pThis, &pThis->StreamMicIn, AC97SOUNDSOURCE_MC_INDEX); 695 843 } 696 844 … … 700 848 rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOut); 701 849 if (RT_SUCCESS(rc)) 702 rc = ichac97Stream Init(&pThis->StreamOut, AC97SOUNDSOURCE_PO_INDEX);850 rc = ichac97StreamCreate(pThis, &pThis->StreamOut, AC97SOUNDSOURCE_PO_INDEX); 703 851 } 704 852 … … 727 875 LogFlowFuncEnter(); 728 876 729 ichac97DestroyIn(pThis, PDMAUDIORECSOURCE_LINE); 730 ichac97DestroyIn(pThis, PDMAUDIORECSOURCE_MIC); 731 ichac97DestroyOut(pThis); 732 733 ichac97StreamDestroy(&pThis->StreamLineIn); 734 ichac97StreamDestroy(&pThis->StreamMicIn); 735 ichac97StreamDestroy(&pThis->StreamOut); 877 ichac97StreamDestroy(pThis, &pThis->StreamLineIn); 878 ichac97StreamDestroy(pThis, &pThis->StreamMicIn); 879 ichac97StreamDestroy(pThis, &pThis->StreamOut); 880 } 881 882 /** 883 * Writes audio data from a mixer sink into an AC'97 stream's DMA buffer. 884 * 885 * @returns IPRT status code. 886 * @param pThis AC'97 state. 887 * @param pStream AC'97 stream to write to. 888 * @param pMixSink Mixer sink to get audio data to write from. 889 * @param cbToWrite Number of bytes to write. 890 * @param pcbWritten Number of bytes written. Optional. 891 */ 892 static int ichac97StreamWrite(PAC97STATE pThis, PAC97STREAM pDstStream, PAUDMIXSINK pSrcMixSink, uint32_t cbToWrite, 893 uint32_t *pcbWritten) 894 { 895 RT_NOREF(pThis); 896 897 PRTCIRCBUF pCircBuf = pDstStream->State.pCircBuf; 898 AssertPtr(pCircBuf); 899 900 void *pvDst; 901 size_t cbDst; 902 903 uint32_t cbRead = 0; 904 905 RTCircBufAcquireWriteBlock(pCircBuf, cbToWrite, &pvDst, &cbDst); 906 907 if (cbDst) 908 { 909 int rc2 = AudioMixerSinkRead(pSrcMixSink, AUDMIXOP_COPY, pvDst, (uint32_t)cbDst, &cbRead); 910 AssertRC(rc2); 911 912 #ifdef AC97_DEBUG_DUMP_PCM_DATA 913 RTFILE fh; 914 RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ichac97StreamWrite.pcm", 915 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 916 RTFileWrite(fh, pvDst, cbRead, NULL); 917 RTFileClose(fh); 918 #endif 919 } 920 921 RTCircBufReleaseWriteBlock(pCircBuf, cbRead); 922 923 if (pcbWritten) 924 *pcbWritten = cbRead; 925 926 return VINF_SUCCESS; 927 } 928 929 /** 930 * Reads audio data from an AC'97 stream's DMA buffer and writes into a specified mixer sink. 931 * 932 * @returns IPRT status code. 933 * @param pThis AC'97 state. 934 * @param pSrcStream AC'97 stream to read audio data from. 935 * @param pDstMixSink Mixer sink to write audio data to. 936 * @param cbToRead Number of bytes to read. 937 * @param pcbRead Number of bytes read. Optional. 938 */ 939 static int ichac97StreamRead(PAC97STATE pThis, PAC97STREAM pSrcStream, PAUDMIXSINK pDstMixSink, uint32_t cbToRead, 940 uint32_t *pcbRead) 941 { 942 RT_NOREF(pThis); 943 944 PRTCIRCBUF pCircBuf = pSrcStream->State.pCircBuf; 945 AssertPtr(pCircBuf); 946 947 void *pvSrc; 948 size_t cbSrc; 949 950 uint32_t cbWritten = 0; 951 952 RTCircBufAcquireReadBlock(pCircBuf, cbToRead, &pvSrc, &cbSrc); 953 954 if (cbSrc) 955 { 956 #ifdef AC97_DEBUG_DUMP_PCM_DATA 957 RTFILE fh; 958 RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97StreamRead.pcm", 959 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 960 RTFileWrite(fh, pvSrc, cbSrc, NULL); 961 RTFileClose(fh); 962 #endif 963 int rc2 = AudioMixerSinkWrite(pDstMixSink, AUDMIXOP_COPY, pvSrc, (uint32_t)cbSrc, &cbWritten); 964 AssertRC(rc2); 965 } 966 967 RTCircBufReleaseReadBlock(pCircBuf, cbWritten); 968 969 if (pcbRead) 970 *pcbRead = cbWritten; 971 972 return VINF_SUCCESS; 973 } 974 975 #ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 976 /** 977 * Asynchronous I/O thread for an AC'97 stream. 978 * This will do the heavy lifting work for us as soon as it's getting notified by another thread. 979 * 980 * @returns IPRT status code. 981 * @param hThreadSelf Thread handle. 982 * @param pvUser User argument. Must be of type PAC97STREAMTHREADCTX. 983 */ 984 static DECLCALLBACK(int) ichac97StreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser) 985 { 986 PAC97STREAMTHREADCTX pCtx = (PAC97STREAMTHREADCTX)pvUser; 987 AssertPtr(pCtx); 988 989 PAC97STATE pThis = pCtx->pThis; 990 AssertPtr(pThis); 991 992 PAC97STREAM pStream = pCtx->pStream; 993 AssertPtr(pStream); 994 995 PAC97STREAMSTATEAIO pAIO = &pCtx->pStream->State.AIO; 996 997 PRTCIRCBUF pCircBuf = pStream->State.pCircBuf; 998 AssertPtr(pCircBuf); 999 1000 PAUDMIXSINK pMixSink = ichac97IndexToSink(pThis, pStream->u8Strm); 1001 AssertPtr(pMixSink); 1002 1003 ASMAtomicXchgBool(&pAIO->fStarted, true); 1004 1005 RTThreadUserSignal(hThreadSelf); 1006 1007 LogFunc(("[SD%RU8]: Started\n", pStream->u8Strm)); 1008 1009 for (;;) 1010 { 1011 Log2Func(("[SD%RU8]: Waiting ...\n", pStream->u8Strm)); 1012 1013 int rc2 = RTSemEventWait(pAIO->Event, RT_INDEFINITE_WAIT); 1014 if (RT_FAILURE(rc2)) 1015 break; 1016 1017 if (ASMAtomicReadBool(&pAIO->fShutdown)) 1018 break; 1019 1020 size_t cbToProcess = RTCircBufUsed(pCircBuf); 1021 if (cbToProcess) 1022 { 1023 uint32_t cbProcessed = 0; 1024 1025 rc2 = RTCritSectEnter(&pAIO->CritSect); 1026 if (RT_SUCCESS(rc2)) 1027 { 1028 switch (pStream->u8Strm) 1029 { 1030 case AC97SOUNDSOURCE_PI_INDEX: 1031 case AC97SOUNDSOURCE_MC_INDEX: 1032 rc2 = ichac97StreamWrite(pThis, pStream, pMixSink, (uint32_t)cbToProcess, &cbProcessed); 1033 break; 1034 1035 case AC97SOUNDSOURCE_PO_INDEX: 1036 rc2 = ichac97StreamRead(pThis, pStream, pMixSink, (uint32_t)cbToProcess, &cbProcessed); 1037 break; 1038 1039 default: 1040 AssertFailedStmt(rc2 = VERR_NOT_SUPPORTED); 1041 break; 1042 } 1043 1044 if (RT_SUCCESS(rc2)) 1045 rc2 = AudioMixerSinkUpdate(pMixSink); 1046 1047 if (cbProcessed) 1048 { 1049 Assert(cbToProcess >= cbProcessed); 1050 cbToProcess -= cbProcessed; 1051 } 1052 1053 int rc3 = RTCritSectLeave(&pAIO->CritSect); 1054 AssertRC(rc3); 1055 } 1056 } 1057 1058 AssertRC(rc2); 1059 } 1060 1061 LogFunc(("[SD%RU8]: Ended\n", pStream->u8Strm)); 1062 1063 ASMAtomicXchgBool(&pAIO->fStarted, false); 1064 1065 return VINF_SUCCESS; 1066 } 1067 1068 /** 1069 * Lets the stream's async I/O thread know that there is some data to process. 1070 * 1071 * @returns IPRT status code. 1072 * @param pThis AC'97 state. 1073 * @param pStream AC'97 stream to notify async I/O thread for. 1074 */ 1075 static int ichac97StreamAsyncIONotify(PAC97STATE pThis, PAC97STREAM pStream) 1076 { 1077 RT_NOREF(pThis); 1078 1079 LogFunc(("[SD%RU8]\n", pStream->u8Strm)); 1080 return RTSemEventSignal(pStream->State.AIO.Event); 1081 } 1082 1083 static void ichac97StreamAsyncIOLock(PAC97STREAM pStream) 1084 { 1085 PAC97STREAMSTATEAIO pAIO = &pStream->State.AIO; 1086 1087 int rc2 = RTCritSectEnter(&pAIO->CritSect); 1088 AssertRC(rc2); 1089 } 1090 1091 static void ichac97StreamAsyncIOUnlock(PAC97STREAM pStream) 1092 { 1093 PAC97STREAMSTATEAIO pAIO = &pStream->State.AIO; 1094 1095 int rc2 = RTCritSectLeave(&pAIO->CritSect); 1096 AssertRC(rc2); 1097 } 1098 #endif /* VBOX_WITH_AUDIO_AC97_ASYNC_IO*/ 1099 1100 /** 1101 * Updates an AC'97 stream according to its usage (input / output). 1102 * 1103 * For an SDO (output) stream this means reading DMA data from the device to 1104 * the connected audio sink(s). 1105 * 1106 * For an SDI (input) stream this is reading audio data from the connected 1107 * audio sink(s) and writing it as DMA data to the device. 1108 * 1109 * @returns IPRT status code. 1110 * @param pThis AC'97 state. 1111 * @param pStream AC'97 stream to update. 1112 */ 1113 static int ichac97StreamUpdate(PAC97STATE pThis, PAC97STREAM pStream) 1114 { 1115 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1116 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 1117 1118 PAUDMIXSINK pMixSink = ichac97IndexToSink(pThis, pStream->u8Strm); 1119 if (!pMixSink) 1120 return VINF_SUCCESS; 1121 1122 if (AudioMixerSinkIsActive(pMixSink) == false) 1123 return VINF_SUCCESS; 1124 1125 PRTCIRCBUF pCircBuf = pStream->State.pCircBuf; 1126 AssertPtr(pCircBuf); 1127 1128 int rc = VINF_SUCCESS; 1129 1130 bool fDone = false; 1131 1132 LogFunc(("[SD%RU8] Started\n", pStream->u8Strm)); 1133 1134 while (!fDone) 1135 { 1136 int rc2; 1137 uint32_t cbProcessed = 0; 1138 1139 if (pStream->u8Strm == AC97SOUNDSOURCE_PO_INDEX) /* Output. */ 1140 { 1141 STAM_PROFILE_START(&pThis->StatOut, a); 1142 1143 void *pvDst; 1144 size_t cbDst; 1145 1146 RTCircBufAcquireWriteBlock(pCircBuf, 256 /** @todo */, &pvDst, &cbDst); 1147 1148 if (cbDst) 1149 { 1150 /* Do one DMA transfer with FIFOS size at a time. */ 1151 rc2 = ichac97DoDMA(pThis, pStream, pvDst, (uint32_t)cbDst, (uint32_t)cbDst /* cbToProcess */, &cbProcessed); 1152 AssertRC(rc2); 1153 } 1154 1155 RTCircBufReleaseWriteBlock(pCircBuf, cbProcessed); 1156 1157 if (cbProcessed) 1158 { 1159 #ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 1160 /* Let the asynchronous thread know that there is some new data to process. */ 1161 ichac97StreamAsyncIONotify(pThis, pStream); 1162 #else 1163 rc2 = ichac97StreamRead(pThis, pStream, pMixSink, cbProcessed, NULL /* pcbRead */); 1164 AssertRC(rc2); 1165 #endif 1166 } 1167 1168 if ( !cbProcessed 1169 #ifndef VBOX_WITH_AUDIO_AC97_ASYNC_IO 1170 && RTCircBufUsed(pCircBuf) == 0 1171 #endif 1172 ) 1173 { 1174 fDone = true; 1175 } 1176 1177 STAM_PROFILE_STOP(&pThis->StatOut, a); 1178 } 1179 else if ( pStream->u8Strm == AC97SOUNDSOURCE_PI_INDEX /* Input. */ 1180 || pStream->u8Strm == AC97SOUNDSOURCE_MC_INDEX) /* Input. */ 1181 { 1182 STAM_PROFILE_START(&pThis->StatIn, a); 1183 1184 void *pvSrc; 1185 size_t cbSrc; 1186 1187 RTCircBufAcquireReadBlock(pCircBuf, 256 /** @todo */, &pvSrc, &cbSrc); 1188 1189 if (cbSrc) 1190 { 1191 /* Do one DMA transfer with FIFOS size at a time. */ 1192 rc2 = ichac97DoDMA(pThis, pStream, pvSrc, (uint32_t)cbSrc, (uint32_t)cbSrc /* cbToProcess */, &cbProcessed); 1193 AssertRC(rc2); 1194 } 1195 1196 RTCircBufReleaseReadBlock(pCircBuf, cbProcessed); 1197 1198 if (cbProcessed) 1199 { 1200 #ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 1201 /* Let the asynchronous thread know that there is some new data to process. */ 1202 ichac97StreamAsyncIONotify(pThis, pStream); 1203 #else 1204 rc2 = ichac97StreamWrite(pThis, pStream, pMixSink, cbProcessed, NULL /* pcbWritten */); 1205 AssertRC(rc2); 1206 #endif 1207 } 1208 1209 STAM_PROFILE_STOP(&pThis->StatIn, a); 1210 } 1211 else 1212 AssertFailed(); 1213 1214 #ifndef VBOX_WITH_AUDIO_AC97_ASYNC_IO 1215 rc2 = AudioMixerSinkUpdate(pMixSink); 1216 AssertRC(rc2); 1217 #endif 1218 if (fDone) 1219 break; 1220 } 1221 1222 LogFunc(("[SD%RU8] End\n", pStream->u8Strm)); 1223 1224 return rc; 736 1225 } 737 1226 … … 763 1252 } 764 1253 765 static void ichac97DestroyIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource) 766 { 767 AssertPtrReturnVoid(pThis); 768 769 LogFlowFuncEnter(); 770 771 switch (enmRecSource) 772 { 773 case PDMAUDIORECSOURCE_MIC: 774 AudioMixerSinkDestroy(pThis->pSinkMicIn); 775 pThis->pSinkMicIn = NULL; 776 break; 777 778 case PDMAUDIORECSOURCE_LINE: 779 AudioMixerSinkDestroy(pThis->pSinkLineIn); 780 pThis->pSinkLineIn = NULL; 781 break; 782 783 default: 784 AssertMsgFailed(("Audio source %ld not supported\n", enmRecSource)); 785 return; 786 } 787 788 PAC97DRIVER pDrv; 789 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node) 790 { 791 PAC97INPUTSTREAM pStream; 792 if (enmRecSource == PDMAUDIORECSOURCE_MIC) /** @todo Refine this once we have more streams. */ 793 pStream = &pDrv->MicIn; 794 else 795 pStream = &pDrv->LineIn; 796 797 pStream->pMixStrm = NULL; 798 } 799 } 800 801 static void ichac97DestroyOut(PAC97STATE pThis) 802 { 803 AssertPtrReturnVoid(pThis); 804 805 LogFlowFuncEnter(); 806 807 AudioMixerSinkDestroy(pThis->pSinkOut); 808 pThis->pSinkOut = NULL; 809 810 PAC97DRIVER pDrv; 811 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node) 812 { 813 pDrv->Out.pMixStrm = NULL; 814 } 815 } 816 817 static int ichac97CreateIn(PAC97STATE pThis, 818 const char *pszName, PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOSTREAMCFG pCfg) 819 { 820 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 821 AssertPtrReturn(pszName, VERR_INVALID_POINTER); 822 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 823 824 PAUDMIXSINK pSink; 825 switch (enmRecSource) 826 { 827 case PDMAUDIORECSOURCE_MIC: 828 pSink = pThis->pSinkMicIn; 829 break; 830 case PDMAUDIORECSOURCE_LINE: 831 pSink = pThis->pSinkLineIn; 832 break; 833 default: 834 AssertMsgFailed(("Audio source %ld not supported\n", enmRecSource)); 835 return VERR_NOT_SUPPORTED; 836 } 1254 /** 1255 * Retrieves a specific driver stream of a AC'97 driver. 1256 * 1257 * @returns Pointer to driver stream if found, or NULL if not found. 1258 * @param pThis AC'97 state. 1259 * @param pDrv Driver to retrieve driver stream for. 1260 * @param enmDir Stream direction to retrieve. 1261 * @param dstSrc Stream destination / source to retrieve. 1262 */ 1263 static PAC97DRIVERSTREAM ichac97MixerGetDrvStream(PAC97STATE pThis, PAC97DRIVER pDrv, 1264 PDMAUDIODIR enmDir, PDMAUDIODESTSOURCE dstSrc) 1265 { 1266 RT_NOREF(pThis); 1267 1268 PAC97DRIVERSTREAM pDrvStream = NULL; 1269 1270 if (enmDir == PDMAUDIODIR_IN) 1271 { 1272 LogFunc(("enmRecSource=%d\n", dstSrc.Source)); 1273 1274 switch (dstSrc.Source) 1275 { 1276 case PDMAUDIORECSOURCE_LINE: 1277 pDrvStream = &pDrv->LineIn; 1278 break; 1279 case PDMAUDIORECSOURCE_MIC: 1280 pDrvStream = &pDrv->MicIn; 1281 break; 1282 default: 1283 AssertFailed(); 1284 break; 1285 } 1286 } 1287 else if (enmDir == PDMAUDIODIR_OUT) 1288 { 1289 LogFunc(("enmPlaybackDest=%d\n", dstSrc.Dest)); 1290 1291 switch (dstSrc.Dest) 1292 { 1293 case PDMAUDIOPLAYBACKDEST_FRONT: 1294 pDrvStream = &pDrv->Out; 1295 break; 1296 default: 1297 AssertFailed(); 1298 break; 1299 } 1300 } 1301 else 1302 AssertFailed(); 1303 1304 return pDrvStream; 1305 } 1306 1307 /** 1308 * Adds audio streams for all drivers to a specific mixer sink. 1309 * 1310 * @returns IPRT status code. 1311 * @param pThis AC'97 state. 1312 * @param pMixSink Mixer sink to add stream to. 1313 * @param pCfg Stream configuration to use. 1314 */ 1315 static int ichac97MixerAddDrvStreams(PAC97STATE pThis, PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg) 1316 { 1317 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1318 AssertPtrReturn(pMixSink, VERR_INVALID_POINTER); 1319 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 837 1320 838 1321 /* Update the sink's format. */ … … 840 1323 int rc = DrvAudioHlpStreamCfgToProps(pCfg, &PCMProps); 841 1324 if (RT_SUCCESS(rc)) 842 rc = AudioMixerSinkSetFormat(p Sink, &PCMProps);1325 rc = AudioMixerSinkSetFormat(pMixSink, &PCMProps); 843 1326 844 1327 if (RT_FAILURE(rc)) … … 848 1331 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node) 849 1332 { 850 if (!RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "[LUN#%RU8] %s", pDrv->uLUN, pszName)) 851 { 1333 PPDMAUDIOSTREAMCFG pStreamCfg = (PPDMAUDIOSTREAMCFG)RTMemDup(pCfg, sizeof(PDMAUDIOSTREAMCFG)); 1334 if (!pStreamCfg) 1335 { 1336 rc = VERR_NO_MEMORY; 1337 break; 1338 } 1339 1340 if (!RTStrPrintf(pStreamCfg->szName, sizeof(pStreamCfg->szName), "[LUN#%RU8] %s", pDrv->uLUN, pCfg->szName)) 1341 { 1342 RTMemFree(pStreamCfg); 1343 852 1344 rc = VERR_BUFFER_OVERFLOW; 853 1345 break; 854 1346 } 855 1347 856 PAC97INPUTSTREAM pStream; 857 if (enmRecSource == PDMAUDIORECSOURCE_MIC) /** @todo Refine this once we have more streams. */ 858 pStream = &pDrv->MicIn; 859 else 860 pStream = &pDrv->LineIn; 861 862 AudioMixerSinkRemoveStream(pSink, pStream->pMixStrm); 863 864 AudioMixerStreamDestroy(pStream->pMixStrm); 865 pStream->pMixStrm = NULL; 866 867 int rc2 = AudioMixerSinkCreateStream(pSink, pDrv->pConnector, pCfg, 0 /* fFlags */ , &pStream->pMixStrm); 868 if (RT_SUCCESS(rc2)) 869 { 870 rc2 = AudioMixerSinkAddStream(pSink, pStream->pMixStrm); 871 LogFlowFunc(("LUN#%RU8: Created input \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2)); 1348 LogFunc(("%s\n", pStreamCfg->szName)); 1349 1350 int rc2 = VINF_SUCCESS; 1351 1352 PAC97DRIVERSTREAM pDrvStream = ichac97MixerGetDrvStream(pThis, pDrv, pStreamCfg->enmDir, pStreamCfg->DestSource); 1353 if (pDrvStream) 1354 { 1355 AssertMsg(pDrvStream->pMixStrm == NULL, ("[LUN#%RU8] Driver stream already present when it must not\n", pDrv->uLUN)); 1356 1357 PAUDMIXSTREAM pMixStrm; 1358 rc2 = AudioMixerSinkCreateStream(pMixSink, pDrv->pConnector, pStreamCfg, 0 /* fFlags */, &pMixStrm); 1359 if (RT_SUCCESS(rc2)) 1360 { 1361 rc2 = AudioMixerSinkAddStream(pMixSink, pMixStrm); 1362 LogFlowFunc(("LUN#%RU8: Created stream \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2)); 1363 } 1364 1365 if (RT_SUCCESS(rc2)) 1366 pDrvStream->pMixStrm = pMixStrm; 872 1367 } 873 1368 874 1369 if (RT_SUCCESS(rc)) 875 1370 rc = rc2; 1371 1372 if (pStreamCfg) 1373 { 1374 RTMemFree(pStreamCfg); 1375 pStreamCfg = NULL; 1376 } 876 1377 } 877 1378 … … 880 1381 } 881 1382 882 static int ichac97CreateOut(PAC97STATE pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg) 883 { 884 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 885 AssertPtrReturn(pszName, VERR_INVALID_POINTER); 886 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 887 888 LogFunc(("%s\n", pszName)); 889 890 /* Update the sink's format. */ 891 PDMAUDIOPCMPROPS PCMProps; 892 int rc = DrvAudioHlpStreamCfgToProps(pCfg, &PCMProps); 893 if (RT_SUCCESS(rc)) 894 rc = AudioMixerSinkSetFormat(pThis->pSinkOut, &PCMProps); 895 896 if (RT_FAILURE(rc)) 897 return rc; 1383 /** 1384 * Removes specific audio streams for all drivers. 1385 * 1386 * @param pThis AC'97 state. 1387 * @param pMixSink Mixer sink to remove audio streams from. 1388 * @param enmDir Stream direction to remove. 1389 * @param dstSrc Stream destination / source to remove. 1390 */ 1391 static void ichac97MixerRemoveDrvStreams(PAC97STATE pThis, PAUDMIXSINK pMixSink, 1392 PDMAUDIODIR enmDir, PDMAUDIODESTSOURCE dstSrc) 1393 { 1394 AssertPtrReturnVoid(pThis); 1395 AssertPtrReturnVoid(pMixSink); 898 1396 899 1397 PAC97DRIVER pDrv; 900 1398 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node) 901 1399 { 902 if (!RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "[LUN#%RU8] %s (%RU32Hz, %RU8 %s)", 903 pDrv->uLUN, pszName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel")) 904 { 905 rc = VERR_BUFFER_OVERFLOW; 906 break; 907 } 908 909 AudioMixerSinkRemoveStream(pThis->pSinkOut, pDrv->Out.pMixStrm); 910 911 AudioMixerStreamDestroy(pDrv->Out.pMixStrm); 912 pDrv->Out.pMixStrm = NULL; 913 914 int rc2 = AudioMixerSinkCreateStream(pThis->pSinkOut, pDrv->pConnector, pCfg, 0 /* fFlags */, &pDrv->Out.pMixStrm); 915 if (RT_SUCCESS(rc2)) 916 { 917 rc2 = AudioMixerSinkAddStream(pThis->pSinkOut, pDrv->Out.pMixStrm); 918 LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2)); 919 } 920 921 if (RT_SUCCESS(rc)) 922 rc = rc2; 923 } 924 925 LogFlowFuncLeaveRC(rc); 926 return rc; 927 } 928 929 /** 930 * Opens an AC'97 stream, extended version. 1400 PAC97DRIVERSTREAM pDrvStream = ichac97MixerGetDrvStream(pThis, pDrv, enmDir, dstSrc); 1401 if (pDrvStream) 1402 { 1403 if (pDrvStream->pMixStrm) 1404 { 1405 AudioMixerSinkRemoveStream(pMixSink, pDrvStream->pMixStrm); 1406 1407 AudioMixerStreamDestroy(pDrvStream->pMixStrm); 1408 pDrvStream->pMixStrm = NULL; 1409 } 1410 } 1411 } 1412 } 1413 1414 /** 1415 * Opens an AC'97 stream with its current mixer settings. 931 1416 * 932 * @returns IPRT status code.933 * @param pThis AC'97 device state.934 * @param pStream Stream to initialize.935 * @param pCfg Audio stream configuration to initialize the stream with.936 */937 static int ichac97StreamOpenEx(PAC97STATE pThis, PAC97STREAM pStream, PPDMAUDIOSTREAMCFG pCfg)938 {939 AssertPtrReturn(pThis, VERR_INVALID_POINTER);940 AssertPtrReturn(pStream, VERR_INVALID_POINTER);941 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);942 943 LogFunc(("[SD%RU8] pCfg=%p\n", pStream->u8Strm, pCfg));944 945 int rc;946 switch (pStream->u8Strm)947 {948 case AC97SOUNDSOURCE_PI_INDEX:949 rc = ichac97CreateIn(pThis, "ac97.pi", PDMAUDIORECSOURCE_LINE, pCfg);950 break;951 952 case AC97SOUNDSOURCE_MC_INDEX:953 rc = ichac97CreateIn(pThis, "ac97.mc", PDMAUDIORECSOURCE_MIC, pCfg);954 break;955 956 case AC97SOUNDSOURCE_PO_INDEX:957 rc = ichac97CreateOut(pThis, "ac97.po", pCfg);958 break;959 960 default:961 AssertFailedStmt(rc = VERR_NOT_SUPPORTED);962 break;963 }964 965 if (RT_FAILURE(rc))966 LogRel2(("AC97: Error opening stream #%RU8, rc=%Rrc\n", pStream->u8Strm, rc));967 968 LogFlowFuncLeaveRC(rc);969 return rc;970 }971 972 /**973 * Opens an AC'97 stream.974 1417 * This will open an AC'97 stream with 2 (stereo) channels, 16-bit samples and 975 1418 * the last set sample rate in the AC'97 mixer for this stream. 976 1419 * 977 1420 * @returns IPRT status code. 978 * @param pThis AC'97 devicestate.979 * @param pStream Stream to initialize.1421 * @param pThis AC'97 state. 1422 * @param pStream AC'97 Stream to open. 980 1423 */ 981 1424 static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream) … … 988 1431 RT_ZERO(streamCfg); 989 1432 1433 PAUDMIXSINK pMixSink = NULL; 1434 990 1435 switch (pStream->u8Strm) 991 1436 { 992 1437 case AC97SOUNDSOURCE_PI_INDEX: 1438 { 993 1439 streamCfg.uHz = ichac97MixerGet(pThis, AC97_PCM_LR_ADC_Rate); 994 1440 streamCfg.enmDir = PDMAUDIODIR_IN; 995 1441 streamCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE; 1442 1443 RTStrPrintf2(streamCfg.szName, sizeof(streamCfg.szName), "Line-In"); 1444 1445 pMixSink = pThis->pSinkLineIn; 996 1446 break; 1447 } 997 1448 998 1449 case AC97SOUNDSOURCE_MC_INDEX: 1450 { 999 1451 streamCfg.uHz = ichac97MixerGet(pThis, AC97_MIC_ADC_Rate); 1000 1452 streamCfg.enmDir = PDMAUDIODIR_IN; 1001 1453 streamCfg.DestSource.Source = PDMAUDIORECSOURCE_MIC; 1454 1455 RTStrPrintf2(streamCfg.szName, sizeof(streamCfg.szName), "Mic-In"); 1456 1457 pMixSink = pThis->pSinkMicIn; 1002 1458 break; 1459 } 1003 1460 1004 1461 case AC97SOUNDSOURCE_PO_INDEX: 1462 { 1005 1463 streamCfg.uHz = ichac97MixerGet(pThis, AC97_PCM_Front_DAC_Rate); 1006 1464 streamCfg.enmDir = PDMAUDIODIR_OUT; 1007 1465 streamCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT; 1466 1467 RTStrPrintf2(streamCfg.szName, sizeof(streamCfg.szName), "Output"); 1468 1469 pMixSink = pThis->pSinkOut; 1008 1470 break; 1471 } 1009 1472 1010 1473 default: … … 1015 1478 if (RT_SUCCESS(rc)) 1016 1479 { 1017 if (streamCfg.uHz) 1480 if (streamCfg.uHz) /* Some valid rate set in the AC'97 mixer? */ 1018 1481 { 1019 1482 streamCfg.cChannels = 2; … … 1021 1484 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS; 1022 1485 1023 rc = ichac97StreamOpenEx(pThis, pStream, &streamCfg);1024 } 1025 else1026 rc = VERR_INVALID_PARAMETER;1486 ichac97MixerRemoveDrvStreams(pThis, pMixSink, streamCfg.enmDir, streamCfg.DestSource); 1487 1488 rc = ichac97MixerAddDrvStreams(pThis, pMixSink, &streamCfg); 1489 } 1027 1490 } 1028 1491 … … 1031 1494 } 1032 1495 1033 static void ichac97StreamClose(PAC97STREAM pStream) 1034 { 1496 /** 1497 * Closes an AC'97 stream. 1498 * 1499 * @returns IPRT status code. 1500 * @param pThis AC'97 state. 1501 * @param pStream AC'97 stream to close. 1502 */ 1503 static int ichac97StreamClose(PAC97STATE pThis, PAC97STREAM pStream) 1504 { 1505 RT_NOREF(pThis); 1035 1506 RT_NOREF(pStream); 1036 1507 1037 1508 LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm)); 1038 } 1039 1040 /** 1041 * Re-opens an AC'97 stream on the backend side with the current AC'97 mixer 1042 * settings for this stream. 1509 1510 return VINF_SUCCESS; 1511 } 1512 1513 /** 1514 * Re-opens (that is, closes and opens again) an AC'97 stream on the backend 1515 * side with the current AC'97 mixer settings for this stream. 1043 1516 * 1044 1517 * @returns IPRT status code. 1045 1518 * @param pThis AC'97 device state. 1046 * @param pStream Stream to re-open.1519 * @param pStream AC'97 stream to re-open. 1047 1520 */ 1048 1521 static int ichac97StreamReOpen(PAC97STATE pThis, PAC97STREAM pStream) … … 1050 1523 LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm)); 1051 1524 1052 ichac97StreamClose(pStream); 1053 1054 return ichac97StreamOpen(pThis, pStream); 1055 } 1056 1057 static void ichac97StreamReset(PAC97STATE pThis, PAC97STREAM pStrm) 1525 int rc = ichac97StreamClose(pThis, pStream); 1526 if (RT_SUCCESS(rc)) 1527 rc = ichac97StreamOpen(pThis, pStream); 1528 1529 return rc; 1530 } 1531 1532 /** 1533 * Resets an AC'97 stream. 1534 * 1535 * @returns IPRT status code. 1536 * @param pThis AC'97 state. 1537 * @param pStream AC'97 stream to reset. 1538 * @remark 1539 */ 1540 static void ichac97StreamReset(PAC97STATE pThis, PAC97STREAM pStream) 1058 1541 { 1059 1542 AssertPtrReturnVoid(pThis); 1060 AssertPtrReturnVoid(pStrm); 1061 1062 LogFlowFunc(("[SD%RU8]\n", pStrm->u8Strm)); 1063 1064 if (pStrm->State.au8FIFOW) 1065 { 1066 Assert(pStrm->State.cbFIFOW); 1067 RT_BZERO(pStrm->State.au8FIFOW, pStrm->State.cbFIFOW); 1068 } 1069 1070 pStrm->State.offFIFOW = 0; 1543 AssertPtrReturnVoid(pStream); 1544 1545 LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm)); 1546 1547 if (pStream->State.pCircBuf) 1548 RTCircBufReset(pStream->State.pCircBuf); 1071 1549 } 1072 1550 … … 1191 1669 case PDMAUDIORECSOURCE_VIDEO: return AC97_REC_VIDEO; 1192 1670 case PDMAUDIORECSOURCE_AUX: return AC97_REC_AUX; 1193 case PDMAUDIORECSOURCE_LINE: return AC97_REC_LINE_IN;1671 case PDMAUDIORECSOURCE_LINE: return AC97_REC_LINE_IN; 1194 1672 case PDMAUDIORECSOURCE_PHONE: return AC97_REC_PHONE; 1195 1673 default: … … 1273 1751 } 1274 1752 1275 /**1276 * Writes data from the device to the host backends.1277 *1278 * @return IPRT status code.1279 * @param pThis1280 * @param pStream1281 * @param cbMax1282 * @param pcbWritten1283 */1284 static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)1285 {1286 AssertPtrReturn(pThis, VERR_INVALID_POINTER);1287 AssertPtrReturn(pStream, VERR_INVALID_POINTER);1288 AssertReturn(cbToWrite, VERR_INVALID_PARAMETER);1289 /* pcbWritten is optional. */1290 1291 PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);1292 PAC97BMREGS pRegs = &pStream->Regs;1293 1294 uint32_t uAddr = pRegs->bd.addr;1295 1296 uint32_t cbWrittenTotal = 0;1297 1298 Log3Func(("PICB=%RU16, cbToWrite=%RU32\n", pRegs->picb, cbToWrite));1299 1300 uint32_t cbLeft = RT_MIN((uint32_t)(pRegs->picb << 1), cbToWrite); /** @todo r=andy Assumes 16bit sample size. */1301 if (!cbLeft)1302 {1303 if (pcbWritten)1304 *pcbWritten = 0;1305 return VINF_EOF;1306 }1307 1308 int rc = VINF_SUCCESS;1309 1310 Assert(pStream->State.offFIFOW <= pStream->State.cbFIFOW);1311 uint32_t cbFIFOW = pStream->State.cbFIFOW - pStream->State.offFIFOW;1312 uint8_t *pu8FIFOW = &pStream->State.au8FIFOW[pStream->State.offFIFOW];1313 1314 uint32_t cbWritten = 0;1315 1316 while (cbLeft)1317 {1318 uint32_t cbToRead = RT_MIN(cbLeft, cbFIFOW);1319 1320 PDMDevHlpPhysRead(pDevIns, uAddr, pu8FIFOW, cbToRead); /** @todo r=andy Check rc? */1321 1322 #ifdef AC97_DEBUG_DUMP_PCM_DATA1323 RTFILE fh;1324 RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97WriteAudio.pcm",1325 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);1326 RTFileWrite(fh, pu8FIFOW, cbToRead, NULL);1327 RTFileClose(fh);1328 #endif1329 /*1330 * Write data to the mixer sink.1331 */1332 rc = AudioMixerSinkWrite(pThis->pSinkOut, AUDMIXOP_COPY, pu8FIFOW, cbToRead, &cbWritten);1333 if (RT_FAILURE(rc))1334 break;1335 1336 /* Advance. */1337 Assert(cbLeft >= cbWritten);1338 cbLeft -= cbWritten;1339 cbWrittenTotal += cbWritten;1340 uAddr += cbWritten;1341 Assert(cbWrittenTotal <= cbToWrite);1342 1343 LogFlowFunc(("%RU32 / %RU32\n", cbWrittenTotal, cbToWrite));1344 }1345 1346 /* Set new buffer descriptor address. */1347 pRegs->bd.addr = uAddr;1348 1349 if (RT_SUCCESS(rc))1350 {1351 if (!cbLeft) /* All data written? */1352 {1353 if (cbWritten < 4)1354 {1355 AssertMsgFailed(("Unable to save last written sample, cbWritten < 4 (is %RU32)\n", cbWritten));1356 pThis->last_samp = 0;1357 }1358 else1359 pThis->last_samp = *(uint32_t *)&pStream->State.au8FIFOW[pStream->State.offFIFOW + cbWritten - 4];1360 }1361 1362 if (pcbWritten)1363 *pcbWritten = cbWrittenTotal;1364 }1365 1366 if (RT_FAILURE(rc))1367 LogFlowFunc(("Failed with %Rrc\n", rc));1368 1369 return rc;1370 }1371 1372 1753 static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed) 1373 1754 { 1755 return; 1756 1374 1757 LogFlowFunc(("cbElapsed=%RU32\n", cbElapsed)); 1375 1758 … … 1409 1792 } 1410 1793 1411 static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)1412 {1413 AssertPtrReturn(pThis, VERR_INVALID_POINTER);1414 AssertPtrReturn(pStream, VERR_INVALID_POINTER);1415 AssertReturn(cbToRead, VERR_INVALID_PARAMETER);1416 /* pcbRead is optional. */1417 1418 PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);1419 PAC97BMREGS pRegs = &pStream->Regs;1420 1421 /* Select audio sink to process. */1422 AssertMsg(pStream->u8Strm != AC97SOUNDSOURCE_PO_INDEX, ("Can't read from output\n"));1423 PAUDMIXSINK pSink = pStream->u8Strm == AC97SOUNDSOURCE_MC_INDEX ? pThis->pSinkMicIn : pThis->pSinkLineIn;1424 AssertPtr(pSink);1425 1426 uint32_t cbRead = 0;1427 1428 cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1),1429 RT_MIN(pStream->State.cbFIFOW, cbToRead)); /** @todo r=andy Assumes 16bit samples. */1430 1431 if (!cbToRead)1432 {1433 if (pcbRead)1434 *pcbRead = 0;1435 return VINF_EOF;1436 }1437 1438 int rc;1439 1440 rc = AudioMixerSinkRead(pSink, AUDMIXOP_BLEND, &pStream->State.au8FIFOW[pStream->State.offFIFOW], cbToRead, &cbRead);1441 if ( RT_SUCCESS(rc)1442 && cbRead)1443 {1444 PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, &pStream->State.au8FIFOW[pStream->State.offFIFOW], cbRead);1445 pRegs->bd.addr += cbRead;1446 }1447 1448 if (RT_SUCCESS(rc))1449 {1450 if (!cbRead)1451 rc = VINF_EOF;1452 1453 if (pcbRead)1454 *pcbRead = cbRead;1455 }1456 1457 return rc;1458 }1459 1460 1794 #ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS 1461 1462 1795 static void ichac97TimerMaybeStart(PAC97STATE pThis) 1463 1796 { … … 1468 1801 return; 1469 1802 1470 if (ASMAtomicReadBool(&pThis->fTimerActive) == true) /* Alre dy started? */1803 if (ASMAtomicReadBool(&pThis->fTimerActive) == true) /* Already started? */ 1471 1804 return; 1472 1805 1473 Log FlowFunc(("Starting timer\n"));1806 LogRel2(("AC97: Starting transfers\n")); 1474 1807 1475 1808 /* Set timer flag. */ … … 1479 1812 pThis->uTimerTS = TMTimerGet(pThis->pTimer); 1480 1813 1481 /* Fire off timer. */1482 TMTimerSet(pThis->pTimer, 0 /* u64Expire */);1814 /* Start transfers. */ 1815 ichac97DoTransfers(pThis); 1483 1816 } 1484 1817 … … 1494 1827 return; 1495 1828 1496 Log FlowFunc(("Stopping timer\n"));1829 LogRel2(("AC97: Stopping transfers\n")); 1497 1830 1498 1831 /* Set timer flag. */ … … 1500 1833 } 1501 1834 1835 static void ichac97DoTransfers(PAC97STATE pThis) 1836 { 1837 AssertPtrReturnVoid(pThis); 1838 1839 STAM_PROFILE_START(&pThis->StatTimer, a); 1840 1841 uint64_t cTicksNow = TMTimerGet(pThis->pTimer); 1842 1843 /* Update current time timestamp. */ 1844 pThis->uTimerTS = cTicksNow; 1845 1846 /* Flag indicating whether to kick the timer again for the next DMA transfer or sink processing. */ 1847 bool fKickTimer = false; 1848 1849 ichac97StreamUpdate(pThis, &pThis->StreamLineIn); 1850 ichac97StreamUpdate(pThis, &pThis->StreamMicIn); 1851 ichac97StreamUpdate(pThis, &pThis->StreamOut); 1852 1853 /* Do we need to kick the timer again? */ 1854 if ( AudioMixerSinkIsActive(ichac97IndexToSink(pThis, pThis->StreamLineIn.u8Strm)) 1855 || AudioMixerSinkIsActive(ichac97IndexToSink(pThis, pThis->StreamMicIn.u8Strm)) 1856 || AudioMixerSinkIsActive(ichac97IndexToSink(pThis, pThis->StreamOut.u8Strm))) 1857 { 1858 fKickTimer = true; 1859 } 1860 1861 if ( ASMAtomicReadBool(&pThis->fTimerActive) 1862 || fKickTimer) 1863 { 1864 /* Kick the timer again. */ 1865 uint64_t cTicks = pThis->cTimerTicks; 1866 /** @todo adjust cTicks down by now much cbOutMin represents. */ 1867 TMTimerSet(pThis->pTimer, cTicksNow + cTicks); 1868 } 1869 else 1870 LogRel2(("AC97: Stopped transfers\n")); 1871 1872 STAM_PROFILE_STOP(&pThis->StatTimer, a); 1873 } 1874 #endif /* !VBOX_WITH_AUDIO_AC97_CALLBACKS */ 1875 1502 1876 static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 1503 1877 { 1504 RT_NOREF(pDevIns); 1878 RT_NOREF(pDevIns, pTimer); 1879 1505 1880 PAC97STATE pThis = (PAC97STATE)pvUser; 1506 1881 Assert(pThis == PDMINS_2_DATA(pDevIns, PAC97STATE)); 1507 1882 AssertPtr(pThis); 1508 1883 1509 int rc = RTCritSectEnter(&pThis->csTimer); 1510 if (RT_SUCCESS(rc)) 1511 { 1512 STAM_PROFILE_START(&pThis->StatTimer, a); 1513 1514 uint64_t cTicksNow = TMTimerGet(pTimer); 1515 1516 /* Update current time timestamp. */ 1517 pThis->uTimerTS = cTicksNow; 1518 1519 /* Flag indicating whether to kick the timer again for the next DMA transfer or sink processing. */ 1520 bool fKickTimer = false; 1521 1522 uint32_t cbToProcess; 1523 1524 rc = AudioMixerSinkUpdate(pThis->pSinkLineIn); 1525 if (RT_SUCCESS(rc)) 1526 { 1527 cbToProcess = AudioMixerSinkGetReadable(pThis->pSinkLineIn); 1528 if (cbToProcess) 1529 rc = ichac97TransferAudio(pThis, &pThis->StreamLineIn, cbToProcess, NULL /* pcbProcessed */); 1530 1531 if (AudioMixerSinkGetStatus(pThis->pSinkLineIn) & AUDMIXSINK_STS_DIRTY) 1532 fKickTimer = true; 1533 } 1534 1535 rc = AudioMixerSinkUpdate(pThis->pSinkMicIn); 1536 if (RT_SUCCESS(rc)) 1537 { 1538 cbToProcess = AudioMixerSinkGetReadable(pThis->pSinkMicIn); 1539 if (cbToProcess) 1540 rc = ichac97TransferAudio(pThis, &pThis->StreamMicIn, cbToProcess, NULL /* pcbProcessed */); 1541 1542 if (AudioMixerSinkGetStatus(pThis->pSinkMicIn) & AUDMIXSINK_STS_DIRTY) 1543 fKickTimer = true; 1544 } 1545 1546 rc = AudioMixerSinkUpdate(pThis->pSinkOut); 1547 if (RT_SUCCESS(rc)) 1548 { 1549 cbToProcess = AudioMixerSinkGetWritable(pThis->pSinkOut); 1550 if (cbToProcess) 1551 rc = ichac97TransferAudio(pThis, &pThis->StreamOut, cbToProcess, NULL /* pcbProcessed */); 1552 1553 if (AudioMixerSinkGetStatus(pThis->pSinkOut) & AUDMIXSINK_STS_DIRTY) 1554 fKickTimer = true; 1555 } 1556 1557 if (fKickTimer) 1558 { 1559 /* Kick the timer again. */ 1560 uint64_t cTicks = pThis->cTimerTicks; 1561 /** @todo adjust cTicks down by now much cbOutMin represents. */ 1562 TMTimerSet(pThis->pTimer, cTicksNow + cTicks); 1563 } 1564 else 1565 { 1566 LogFunc(("Stopping timer\n")); 1567 LogRel3(("AC97: Stopping timer\n")); 1568 } 1569 1570 STAM_PROFILE_STOP(&pThis->StatTimer, a); 1571 1572 int rc2 = RTCritSectLeave(&pThis->csTimer); 1573 if (RT_SUCCESS(rc)) 1574 rc2 = rc; 1575 } 1576 } 1577 #endif /* !VBOX_WITH_AUDIO_AC97_CALLBACKS */ 1578 1579 static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed) 1884 ichac97DoTransfers(pThis); 1885 } 1886 1887 /** 1888 * Does a single DMA transfer for a specific AC'97 stream. 1889 * This either can be a read or write operation, depending on the AC'97 stream. 1890 * 1891 * @returns IPRT status code. 1892 * @param pThis AC'97 state. 1893 * @param pStream AC'97 stream to do the DMA transfer for. 1894 * @param pvBuf Pointer to buffer data to write data to / read data from. 1895 * @param cbBuf Size of buffer (in bytes). 1896 * @param cbToProcess Size (in bytes) to transfer (read/write). 1897 * @param pcbProcessed Size (in bytes) transferred (read/written). Optional. 1898 */ 1899 static int ichac97DoDMA(PAC97STATE pThis, PAC97STREAM pStream, void *pvBuf, uint32_t cbBuf, 1900 uint32_t cbToProcess, uint32_t *pcbProcessed) 1580 1901 { 1581 1902 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1582 1903 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 1583 1904 /* pcbProcessed is optional. */ 1584 1585 int rc = RTCritSectEnter(&pStream->CritSect);1586 if (RT_FAILURE(rc))1587 return rc;1588 1589 LogFunc(("[SD%RU8] cbToProcess=%RU32\n", pStream->u8Strm, cbToProcess));1590 1905 1591 1906 PAC97BMREGS pRegs = &pStream->Regs; … … 1609 1924 *pcbProcessed = 0; 1610 1925 1611 Log3Func(("[SD%RU8] Halted\n", pStream->u8Strm));1612 1613 rc = RTCritSectLeave(&pStream->CritSect);1614 AssertRC(rc);1615 1616 1926 return VINF_SUCCESS; 1617 1927 } … … 1625 1935 *pcbProcessed = 0; 1626 1936 1627 rc = RTCritSectLeave(&pStream->CritSect);1628 AssertRC(rc);1629 1630 1937 return VINF_SUCCESS; 1631 1938 } 1632 1939 1633 uint32_t cbLeft = RT_MIN((uint32_t)(pRegs->picb << 1), cbToProcess);1940 uint32_t cbLeft = RT_MIN((uint32_t)(pRegs->picb << 1), RT_MIN(cbToProcess, cbBuf)); 1634 1941 uint32_t cbTotal = 0; 1635 1636 Log3Func(("[SD%RU8] cbLeft=%RU32\n", pStream->u8Strm, cbLeft)); 1942 uint32_t cbChunk; 1943 1944 int rc = VINF_SUCCESS; 1945 1946 Log3Func(("[SD%RU8] cbToProcess=%RU32, cbLeft=%RU32\n", pStream->u8Strm, cbToProcess, cbLeft)); 1637 1947 1638 1948 while (cbLeft) … … 1640 1950 if (!pRegs->bd_valid) 1641 1951 { 1642 Log FlowFunc(("Invalid buffer descriptor, fetching next one ...\n"));1952 Log3Func(("Invalid buffer descriptor, fetching next one ...\n")); 1643 1953 ichac97StreamFetchBDLE(pThis, pStream); 1644 1954 } … … 1646 1956 if (!pRegs->picb) /* Got a new buffer descriptor, that is, the position is 0? */ 1647 1957 { 1648 Log FlowFunc(("Fresh buffer descriptor %RU8 is empty, addr=%#x, len=%#x, skipping\n",1649 1958 Log3Func(("Fresh buffer descriptor %RU8 is empty, addr=%#x, len=%#x, skipping\n", 1959 pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len)); 1650 1960 if (pRegs->civ == pRegs->lvi) 1651 1961 { … … 1665 1975 } 1666 1976 1667 uint32_t cbToTransfer, cbTransferred; 1977 cbChunk = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */ 1978 Assert(cbChunk); 1979 1668 1980 switch (pStream->u8Strm) 1669 1981 { 1670 case AC97SOUNDSOURCE_PO_INDEX: 1982 case AC97SOUNDSOURCE_PO_INDEX: /* Output */ 1671 1983 { 1672 cbToTransfer = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */ 1673 1674 rc = ichac97WriteAudio(pThis, pStream, cbToTransfer, &cbTransferred); 1675 if ( RT_SUCCESS(rc) 1676 && cbTransferred) 1677 { 1678 cbTotal += cbTransferred; 1679 Assert(cbLeft >= cbTransferred); 1680 cbLeft -= cbTransferred; 1681 Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */ 1682 pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */ 1683 } 1984 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pRegs->bd.addr, 1985 (uint8_t *)pvBuf + cbTotal, cbChunk); 1684 1986 break; 1685 1987 } 1686 1988 1687 case AC97SOUNDSOURCE_PI_INDEX: 1688 case AC97SOUNDSOURCE_MC_INDEX: 1989 case AC97SOUNDSOURCE_PI_INDEX: /* Input */ 1990 case AC97SOUNDSOURCE_MC_INDEX: /* Input */ 1689 1991 { 1690 cbToTransfer = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */ 1691 1692 rc = ichac97ReadAudio(pThis, pStream, cbToTransfer, &cbTransferred); 1693 if ( RT_SUCCESS(rc) 1694 && cbTransferred) 1695 { 1696 cbTotal += cbTransferred; 1697 Assert(cbLeft >= cbTransferred); 1698 cbLeft -= cbTransferred; 1699 Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */ 1700 pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */ 1701 } 1992 PDMDevHlpPhysWrite(pThis->CTX_SUFF(pDevIns), pRegs->bd.addr, 1993 (uint8_t *)pvBuf + cbTotal, cbChunk); 1702 1994 break; 1703 1995 } … … 1709 2001 } 1710 2002 1711 LogFlowFunc(("[SD%RU8]: %RU32 / %RU32, rc=%Rrc\n", pStream->u8Strm, cbTotal, cbToProcess, rc)); 2003 if (RT_FAILURE(rc)) 2004 break; 2005 2006 #ifdef AC97_DEBUG_DUMP_PCM_DATA 2007 RTFILE fh; 2008 RTFileOpen(&fh, 2009 pStream->u8Strm == AC97SOUNDSOURCE_PO_INDEX 2010 ? AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97DMARead.pcm" : AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97DMAWrite.pcm", 2011 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 2012 RTFileWrite(fh, (uint8_t *)pvBuf + cbTotal, cbChunk, NULL); 2013 RTFileClose(fh); 2014 #endif 2015 2016 if (cbChunk) 2017 { 2018 cbTotal += cbChunk; 2019 Assert(cbLeft >= cbChunk); 2020 cbLeft -= cbChunk; 2021 Assert((cbChunk & 1) == 0); /* Else the following shift won't work */ 2022 2023 pRegs->picb -= (cbChunk >> 1); /** @todo r=andy Assumes 16bit samples. */ 2024 pRegs->bd.addr += cbChunk; 2025 } 2026 2027 LogFlowFunc(("[SD%RU8]: cbChunk=%RU32, cbLeft=%RU32, cbTotal=%RU32, rc=%Rrc\n", 2028 pStream->u8Strm, cbChunk, cbLeft, cbTotal, rc)); 1712 2029 1713 2030 if (!pRegs->picb) … … 1748 2065 } 1749 2066 } 1750 1751 int rc2 = RTCritSectLeave(&pStream->CritSect);1752 AssertRC(rc2);1753 2067 1754 2068 if (RT_SUCCESS(rc)) … … 1989 2303 case MC_CR: 1990 2304 { 1991 if (u32Val & AC97_CR_RR) /* Busmaster reset */ 2305 Log3Func(("[SD%RU8] CR <- %#x (cr %#x)\n", pStream->u8Strm, u32Val, pRegs->cr)); 2306 2307 if (u32Val & AC97_CR_RR) /* Busmaster reset. */ 1992 2308 { 2309 Log3Func(("[SD%RU8] Reset\n", pStream->u8Strm)); 2310 2311 /* Make sure that Run/Pause Bus Master bit (RPBM) is cleared (0). */ 2312 Assert((pRegs->cr & AC97_CR_RPBM) == 0); 2313 1993 2314 ichac97StreamResetBMRegs(pThis, pStream); 1994 2315 } … … 1996 2317 { 1997 2318 pRegs->cr = u32Val & AC97_CR_VALID_MASK; 2319 1998 2320 if (!(pRegs->cr & AC97_CR_RPBM)) 1999 2321 { 2000 ichac97StreamEnable(pThis, pStream, false /* fActive */); 2322 Log3Func(("[SD%RU8] Disable\n", pStream->u8Strm)); 2323 2324 ichac97StreamEnable(pThis, pStream, false /* fEnable */); 2001 2325 2002 2326 pRegs->sr |= AC97_SR_DCH; … … 2004 2328 else 2005 2329 { 2330 Log3Func(("[SD%RU8] Enable\n", pStream->u8Strm)); 2331 2006 2332 pRegs->civ = pRegs->piv; 2007 2333 pRegs->piv = (pRegs->piv + 1) % 32; … … 2012 2338 ichac97StreamFetchBDLE(pThis, pStream); 2013 2339 2014 ichac97StreamEnable(pThis, pStream, true /* f Active */);2340 ichac97StreamEnable(pThis, pStream, true /* fEnable */); 2015 2341 } 2016 2342 } 2017 Log3Func(("[SD%RU8] CR <- %#x (cr %#x)\n", pStream->u8Strm, u32Val, pRegs->cr));2018 2343 break; 2019 2344 } … … 2233 2558 ichac97StreamReOpen(pThis, &pThis->StreamLineIn); 2234 2559 } 2560 else 2561 LogRel2(("AC97: Variable rate audio (VRA) is not supported\n")); 2562 2235 2563 if (!(u32Val & AC97_EACS_VRM)) 2236 2564 { … … 2238 2566 ichac97StreamReOpen(pThis, &pThis->StreamMicIn); 2239 2567 } 2568 else 2569 LogRel2(("AC97: Variable rate microphone audio (VRM) is not supported\n")); 2570 2240 2571 LogFunc(("Setting extended audio control to %#x\n", u32Val)); 2241 2572 ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, u32Val); … … 3061 3392 * Register statistics. 3062 3393 */ 3063 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer, STAMTYPE_PROFILE, "/Devices/AC97/Timer", STAMUNIT_TICKS_PER_CALL, "Profiling ichac97Timer."); 3064 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, "/Devices/AC97/BytesRead" , STAMUNIT_BYTES, "Bytes read from AC97 emulation."); 3065 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "/Devices/AC97/BytesWritten", STAMUNIT_BYTES, "Bytes written to AC97 emulation."); 3066 } 3394 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer, STAMTYPE_PROFILE, "/Devices/AC97/Timer", STAMUNIT_TICKS_PER_CALL, "Profiling ichac97Timer."); 3395 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn, STAMTYPE_PROFILE, "/Devices/AC97/Input", STAMUNIT_TICKS_PER_CALL, "Profiling input."); 3396 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatOut, STAMTYPE_PROFILE, "/Devices/AC97/Output", STAMUNIT_TICKS_PER_CALL, "Profiling output."); 3397 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, "/Devices/AC97/BytesRead" , STAMUNIT_BYTES, "Bytes read from AC97 emulation."); 3398 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "/Devices/AC97/BytesWritten", STAMUNIT_BYTES, "Bytes written to AC97 emulation."); 3399 } 3400 #endif 3401 3402 #ifdef AC97_DEBUG_DUMP_PCM_DATA 3403 RTFileDelete(AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97DMARead.pcm"); 3404 RTFileDelete(AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97DMAWrite.pcm"); 3405 RTFileDelete(AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97StreamRead.pcm"); 3406 RTFileDelete(AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97StreamWrite.pcm"); 3067 3407 #endif 3068 3408
Note:
See TracChangeset
for help on using the changeset viewer.