diff --git a/src/Home/Net/Drivers/PCNet.ZC b/src/Home/Net/Drivers/PCNet.ZC index 637956de..b06e3d60 100755 --- a/src/Home/Net/Drivers/PCNet.ZC +++ b/src/Home/Net/Drivers/PCNet.ZC @@ -1,5 +1,5 @@ /* AMD PCNetII Driver - Author: TomAwezome + Authors: ($TX,"minexew",HTML="https://github.com/minexew/"$), $TX,"TomAwezome",HTML="https://github.com/TomAwezome/"$, $TX,"TheTinkerer",HTML="https://github.com/tinkeros/"$ Driver is based on: - minexew's ShrineOS PCNet implementation @@ -13,12 +13,6 @@ - Clear documentation. */ -#define PCNET_CMDf_IOEN 0 -#define PCNET_CMDf_BMEN 2 - -#define PCNET_CMDF_IOEN (1 << PCNET_CMDf_IOEN) -#define PCNET_CMDF_BMEN (1 << PCNET_CMDf_BMEN) - #define PCNET_WD_RESET 0x14 // reset reg location when card is in 16-bit mode #define PCNET_DW_RDP 0x10 @@ -742,7 +736,7 @@ U0 PCNetInit() pcnet.pci->dev, pcnet.pci->fun, PCIR_COMMAND, - PCNET_CMDF_IOEN | PCNET_CMDF_BMEN); + PCI_CMDF_IOEN | PCI_CMDF_BMEN); PCNetReset; diff --git a/src/Home/Sound/AC97/AC97.ZC b/src/Home/Sound/AC97/AC97.ZC new file mode 100644 index 00000000..16439993 --- /dev/null +++ b/src/Home/Sound/AC97/AC97.ZC @@ -0,0 +1,240 @@ + +#define INT_LAST_VALID_ENTRY 1 << 2 +#define INT_IOC 1 << 3 +#define INT_FIFO_ERR 1 << 4 + +#define BDL_BUF_SIZE 2044 +#define MAX_BDLS 32 + +#define PCM_BUF_SIZE 2048 +#define PCM_IN 0 +#define PCM_OUT 1 +#define MIC_IN 2 + +// Native Audio Mixer registers (all U16) +#define RESET 0x00 // Reset Register +#define MASTER_VOL 0x02 // Set Master Output Volume +#define MIC_VOL 0x0E // Set Microphone Volume +#define PCM_VOL 0x18 // Set Output Volume of PCM patterns +#define REC_SLC 0x1A // Select Input Device +#define REC_GAIN 0x1C // Set Input Gain +#define MIC_GAIN 0x1E // Set Gain of Microphone +#define EXT_ID 0x28 // Supported extended functions +#define EXT_CTRL 0x2A // Enabling extended functions +#define EXT_FRONT_RATE 0x2C // Sample rate of front speaker + +// Native Audio Bus Master registers +#define PCM_INPUT_REG_BOX 0x00 // NABM register box for PCM IN (sizeof NABM register box) +#define PCM_OUTPUT_REG_BOX 0x10 // NABM register box for PCM OUT (sizeof NABM register box) +#define MIC_INPUT_REG_BOX 0x20 // NABM register box for Microphone (sizeof NABM register box) +#define GLOBAL_CTL 0x2C // Global Control Register (U32) +#define GLOBAL_STS 0x30 // Global Status Register (U32) + +// NABM register box registers +#define BUFFER_DSC_ADDR 0x00 // Physical Address of Buffer Descriptor List (U32) +#define CUR_ENTRY_VAL 0x04 // Number of Actual Processed Buffer Descriptor Entry (U8) +#define LAST_VALID_ENTRY 0x05 // Number of all Descriptor Entries (U8) +#define TRANSFER_STS 0x06 // Status of Transferring Data (U16) +#define CUR_IDX_PROC_SAMPLES 0x08 // Number of Transferred Samples in Actual Processed Entry (U16) +#define PRCSD_ENTRY 0x0A // Number of Actual Processed Buffer Entry (U8) +#define BUFFER_CNT 0x0B // Most Important Register for controlling Transfers (U8) + +class CAC97BufferDescriptorListEntry +{ + U32 addr; + U16 length; // length - 1 + U16 flags; +}; + +class CAC97BufferDescriptorList +{ + CAC97BufferDescriptorListEntry entries[32]; +}; + +class CAC97 +{ + CPCIInfo pci; + CAC97BufferDescriptorList *bdl[3]; + U16 nam; + U16 nabm; +}; + +CAC97 ac97; + +#define AUDIO_MAX_STREAMS 16 +#define AUDIO_OUTPUT_BUFFER_SIZE 1024 +#define AUDIO_STREAM_FIFO_SIZE 1048576 * 16 +#define AUDIO_STREAM_TYPE_INPUT 0 +#define AUDIO_STREAM_TYPE_OUTPUT 1 + +class CAudioStream +{ + CFifoI64 *data; +}; + +class CAudio +{ + CAudioStream output[AUDIO_MAX_STREAMS]; + I64 output_frames[AUDIO_MAX_STREAMS]; +}; + +CAudio audio; + +U0 AudioInit() +{ + I64 i = 0; + for (i = 0; i < AUDIO_MAX_STREAMS; i++) + audio.output[i].data = FifoI64New(AUDIO_STREAM_FIFO_SIZE, sys_task); +} + +AudioInit; + +I64 AudioAvailableOutputStreamGet() +{ + I64 stream = 0; + while (FifoI64Count(audio.output[stream].data)) + stream++; + if (stream > AUDIO_MAX_STREAMS - 1) + return -1; + return stream; +} + +I64 AudioSFXPlay(U32 *data, I64 length) +{ + I64 i; + I64 stream = AudioAvailableOutputStreamGet; + if (stream < 0) + return stream; + for (i = 0; i < length; i++) + FifoI64Ins(audio.output[stream].data, data[i]); + return stream; +} + +U0 AC97OutputMix(U32 *buf, I64 length = NULL) +{ + I64 i; + I64 j; + I64 acc_sample_L = 0; + I64 acc_sample_R = 0; + I64 acc_streams = 0; + U32 sample; + + if (!length) + length = AUDIO_OUTPUT_BUFFER_SIZE; + for (i = 0; i < length / 4; i++) + { + acc_sample_L = 0; + acc_sample_R = 0; + acc_streams = 0; + + for (j = 0; j < AUDIO_MAX_STREAMS; j++) + { + if (FifoI64Count(audio.output[j].data)) + { + FifoI64Remove(audio.output[j].data, &sample); + audio.output_frames[j]++; + acc_streams++; + acc_sample_L += sample.u16[0]; + acc_sample_R += sample.u16[1]; + } + } + + buf[i].i16[0] = ToI64(acc_sample_L / Sqrt(acc_streams)); + buf[i].i16[1] = ToI64(acc_sample_R / Sqrt(acc_streams)); + } +} + +U0 AC97BufferFill() +{ + I64 idx = InU8(ac97.nabm + PCM_OUTPUT_REG_BOX + LAST_VALID_ENTRY); + U32 *buf = ac97.bdl[PCM_OUT]->entries[idx].addr; + AC97OutputMix(buf, BDL_BUF_SIZE); + OutU8(ac97.nabm + PCM_OUTPUT_REG_BOX + LAST_VALID_ENTRY, ++idx); +} + +U0 AC97AudioProcess() +{ + U16 status = InU16(ac97.nabm + PCM_OUTPUT_REG_BOX + TRANSFER_STS); + if (status & INT_IOC) + { + AC97BufferFill; + OutU16(ac97.nabm + PCM_OUTPUT_REG_BOX + TRANSFER_STS, 0x1C); + } +} + +I64 AC97Init() +{ + I64 i; + I64 j; + // Scan for device + j = PCIClassFind(0x040100, 0); + if (j < 0) + { + device_not_found: SysLog("\n[AC'97] Device not found\n"); + return -1; + } + + PCIInfoGet(j, &ac97.pci); + + if (ac97.pci.vendor_id != 0x8086 || ac97.pci.device_id != 0x2415) + goto device_not_found; + + ac97.nam = ac97.pci.bar[0] &0xFFFFFF00; + ac97.nabm = ac97.pci.bar[1] &0xFFFFFF00; + + // Enable port IO, disable MMIO + PCIWriteU8(j.u8[2], j.u8[1], j.u8[0], 0x4, 5); + + OutU32(ac97.nabm + GLOBAL_CTL, 0x03); + OutU16(ac97.nam + RESET, 0xFFFF); + + // Set PCM Output to Max volume + OutU16(ac97.nam + PCM_VOL, 0x0000); + + // Allocate Buffer Descriptor Lists + ac97.bdl[PCM_IN] = CAllocAligned(sizeof(CAC97BufferDescriptorList), 4096, Fs->code_heap); + ac97.bdl[PCM_OUT] = CAllocAligned(sizeof(CAC97BufferDescriptorList), 4096, Fs->code_heap); + ac97.bdl[MIC_IN] = CAllocAligned(sizeof(CAC97BufferDescriptorList), 4096, Fs->code_heap); + + for (i = 0; i < MAX_BDLS; i++) + { + ac97.bdl[PCM_OUT]->entries[i].addr = + CAllocAligned(PCM_BUF_SIZE, 4096, Fs->code_heap); + ac97.bdl[PCM_OUT]->entries[i].length = BDL_BUF_SIZE / 2; + ac97.bdl[PCM_OUT]->entries[i].flags = 1 << 15; + } + + // Set addresses of Buffer Descriptor Lists + // OutU32(ac97.nabm + PCM_INPUT_REG_BOX + BUFFER_DSC_ADDR, ac97.bdl[PCM_IN]); + OutU32(ac97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_DSC_ADDR, ac97.bdl[PCM_OUT]); + // OutU32(ac97.nabm + MIC_INPUT_REG_BOX + BUFFER_DSC_ADDR, ac97.bdl[MIC_IN]); + + // Set Master Volume + OutU16(ac97.nam + MASTER_VOL, 0x0F0F); + + // Stop playing sound + OutU8(ac97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_CNT, 0); + + // Fill one buffers + AC97BufferFill; + + // Enable interrupt handler + //@pci_register_int_handler(&@ac97_int_handler); + + // Start playing sound + OutU8(ac97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_CNT, 1); + + return 0; +} + +U0 AC97Task() +{ + while (1) + { + AC97AudioProcess; + Sleep(1); + } +} + +AC97Init; +Spawn(&AC97Task,, "AC97 Task", 1); \ No newline at end of file diff --git a/src/Home/Sound/AC97/Pci.ZC b/src/Home/Sound/AC97/Pci.ZC new file mode 100644 index 00000000..f08266f9 --- /dev/null +++ b/src/Home/Sound/AC97/Pci.ZC @@ -0,0 +1,98 @@ + +#define PCI_INTH_MAX 16 + +U64 pci_int_handlers[PCI_INTH_MAX]; + +class CPCIInfo +{ + U16 vendor_id; + U16 device_id; + U16 command; + U16 status; + U32 _class; + U32 bar[6]; + U32 cap_pointer; +}; + +class CPCICapability +{ + U8 cap_vndr; /*Generic PCI field: PCI_CAP_ID_VNDR */ + U8 cap_next; /*Generic PCI field: next ptr. */ + U8 cap_len; /*Generic PCI field: capability length */ + U8 cfg_type; /*Identifies the structure. */ + U8 bar; /*Where to find it. */ + U8 padding[3]; /*Pad to full dword. */ + U32 offset; /*Offset within bar. */ + U32 length; /*Length of the structure, in bytes. */ +}; + +U0 PCIInfoGet(I64 i, CPCIInfo *pci) +{ + I64 j; + pci->vendor_id = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x0) &0xFFFF; + pci->device_id = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x0) >> 16; + pci->command = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x4) &0xFFFF; + pci->status = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x4) >> 16; + pci->_class = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x8) >> 24; + for (j = 0; j < 6; j++) + pci->bar[j] = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x10 + (0x04 * j)); +} + +U0 PCIGetCapability(I64 i, CPCICapability *cap, I64 idx) +{ + I64 base = 0x40 + (idx * 16); + U32 u32; + u32 = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base); + cap->cap_vndr = u32.u8[0]; + cap->cap_next = u32.u8[1]; + cap->cap_len = u32.u8[2]; + cap->cfg_type = u32.u8[3]; + u32 = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x04); + cap->bar = u32.u8[0]; + cap->offset = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x08); + cap->length = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x0c); +} + +U0 PCIInterruptReroute(I64 base, I64 cpu) +{ + I64 i; + U8 *da = dev.uncached_alias + IOAPIC_REG; + U32 *_d = dev.uncached_alias + IOAPIC_DATA; + + for (i = 0; i < 4; i++) + { + *da = IOREDTAB + i * 2 + 1; + *_d = dev.mp_apic_ids[cpu] << 24; + *da = IOREDTAB + i * 2; + *_d = 0x4000 + base + i; + } +} + +I64 PCIInterruptHandlerRegister(U64 handler) +{ + if (!handler) + return -1; + I64 i = 0; + while (pci_int_handlers[i]) + i++; + if (i > PCI_INTH_MAX - 1) + return -1; + pci_int_handlers[i] = handler; + return 0; +} + +interrupt U0 PCIInterruptHandler() +{ + I64 i; + for (i = 0; i < PCI_INTH_MAX; i++) + if (pci_int_handlers[i]) + Call(pci_int_handlers[i]); + *(dev.uncached_alias + LAPIC_EOI)(U32 *) = 0; +} + +MemSet(&pci_int_handlers, NULL, sizeof(U64) * PCI_INTH_MAX); +// IntEntrySet(0x40, &PCIInterruptHandler, IDTET_IRQ); +// IntEntrySet(0x41, &PCIInterruptHandler, IDTET_IRQ); +// IntEntrySet(0x42, &PCIInterruptHandler, IDTET_IRQ); +// IntEntrySet(0x43, &PCIInterruptHandler, IDTET_IRQ); +//PCIInterruptReroute(0x40, 0); \ No newline at end of file diff --git a/src/Home/Sound/API.DD b/src/Home/Sound/API.DD new file mode 100644 index 00000000..9b6c695f --- /dev/null +++ b/src/Home/Sound/API.DD @@ -0,0 +1,102 @@ + + + AC97 Functions: + +AudioInit +AudioAvailableOutputStreamGet +AudioSFXPlay +AC97OutputMix +AC97BufferFill +AC97AudioProcess +AC97Init +AC97Task + + AC97 Pci.ZC Functions: + +PCIInfoGet +PCIGetCapability +PCIInterruptReroute +PCIInterruptHandlerRegister +PCIInterruptHandler + + +================================================ + + HDAudio MakeSnd Functions: + +SoundTaskEndCB + + HDAudio SndMath Functions: + +Saw +FullSaw +Caw +FullCaw +Tri +FullTri +Note2Ona +Ona2Note +Ona2Octave +SinPhaseCont +SndWaveCtrlNew +SndWaveCtrlDel +SndWaveAddBuf + + HDAudio SndMusic Functions: + +tM +Beat +MusicSetOctave +MusicSetMeter +MusicSetNoteLen +Play +MusicSettingsReset +CurSongTask + + + HDAudio SndEffects Functions: + +SoundEffectEndTaskCB +SoundEffectTask +Noise +Sweep + + + HDAudio SndFile Functions: + +SndFileCreate + + HDAudio Functions: + +HDSyncCORB +HDWriteCORB +HDSyncRIRB +HDReadRIRB +HDWriteCORBSync +HDTestCORBSync +HDTraverse +HDRun +HDStop +HDSnd +HDFillBuf +HDAudioTaskEndCB +HDTonesInit +HDAudioTask +HDRst +HDAudioEnd +HDAudioUncachedInit +HDAudioInit +HDAudioScan + + HDAudio Cfg Functions: + +HDCfgConnectList +HDCfgTraverse +HDCfgRandomizeXYZ +HDCfgPopUpInfoTask +HDCfgPopUpInfo +HDCfgEdLink +HDCfgSave +HDCfg + +================================================ \ No newline at end of file diff --git a/src/Home/Sound/HDAudio1/Load.ZC b/src/Home/Sound/HDAudio1/Load.ZC new file mode 100644 index 00000000..cf89cafa --- /dev/null +++ b/src/Home/Sound/HDAudio1/Load.ZC @@ -0,0 +1,5 @@ +Cd(__DIR__); + +SysFile("Sup1CodeScraps/Mem/Mem2Meg.ZC"); +SysFile("Sup1Snd/MakeSnd.ZC"); +SysFile("Sup1HDAudio/HDAudio.ZC"); diff --git a/src/Home/Sound/HDAudio1/Sup1CodeScraps/Mem/Mem2Meg.ZC b/src/Home/Sound/HDAudio1/Sup1CodeScraps/Mem/Mem2Meg.ZC new file mode 100644 index 00000000..00233577 --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1CodeScraps/Mem/Mem2Meg.ZC @@ -0,0 +1,199 @@ +//Now, we use 1 Gig page table entries. + +//See $LK,"./UncachedAlloc.ZC"$ + +U8 *Mem2MegAlloc(I64 *_pages2Meg,CBlkPool *bp=NULL) +{/*Alloc 2Meg pages from BlkPool. Don't link to task. +(Linking to a task means they will be freed when the task dies.) +It might give you more than you asked for +so a ptr to a page count is passed. + +Return: NULL if out of memory. +*/ + I64 i,j,*pte,num=*_pages2Meg; + CMemBlk *res=NULL,*m,*m1; + + if (!bp) bp=sys_code_bp; + PUSHFD + CLI + while (LBts(&bp->locked_flags,BPlf_LOCKED)) + PAUSE + num<<=21-MEM_PAG_BITS; + + m=&bp->mem_free_2meg_list; + while (TRUE) { + if (!(res=m->next)) + break; + if (res->pagspags==num) { + m->next=res->next; + goto am_done; + } else { + res->pags-=num; + res(U8 *)+=res->pags<pags=num; + goto am_done; + } + } + } + + m=&bp->mem_free_list; + while (TRUE) { + if (!(res=m->next)) { + num=0; + res=NULL; //Out of memory + goto am_done; + } + if (res->pagspags==num) { + if (res(U8 *)&0x1FFFFF) + m=res; + else { + m->next=res->next; + goto am_done; + } + } else { + if (i=(res(U8 *)&0x1FFFFF)>>MEM_PAG_BITS) { + j=1<<(21-MEM_PAG_BITS)-i; + if (res->pagspags==num+j) { + res->pags-=num; + res(U8 *)+=res->pags<pags=num; + goto am_done; + } else { + m1=res; + res(U8 *)+=j<pags=num; + m=res(U8 *)+num<pags=m1->pags-num-j; + m1->pags=j; + m->next=m1->next; + m1->next=m; + m->mb_signature=MBS_UNUSED_SIGNATURE_VAL; + goto am_done; + } + } else { + m=m->next=res(U8 *)+num<next=res->next; + m->pags=res->pags-num; + m->mb_signature=MBS_UNUSED_SIGNATURE_VAL; + res->pags=num; + goto am_done; + } + } + } + } +am_done: + i=num<used_u8s+=i; + num>>=21-MEM_PAG_BITS; + *_pages2Meg=num; + m=res; + m1=m(U8 *)+i; + while (mlocked_flags,BPlf_LOCKED); + POPFD + return res; +} + +U8 *Mem2MegUncachedAlloc(I64 *_pages2Meg,CBlkPool *bp=NULL) +{/*Alloc 2Meg pages from BlkPool. Don't link to task. +(Linking to a task means they will be freed when the task dies.) +It will be marked uncached. It might give you more than you asked for +so a ptr to a page count is passed. + +Return: NULL if out of memory. +*/ + CMemBlk *res,*m,*m1; + I64 num=*_pages2Meg,*pte; + if (res=Mem2MegAlloc(_pages2Meg,bp)) { + num=*_pages2Meg; + m=res; + m1=m(U8 *)+num<<21; + while (mlocked_flags,BPlf_LOCKED)) + PAUSE + m->mb_signature=MBS_UNUSED_SIGNATURE_VAL; + m->pags=pages2Meg<<(21-MEM_PAG_BITS); + bp->used_u8s-=pages2Meg<<21; + m->next=bp->mem_free_2meg_list; + bp->mem_free_2meg_list=m; + LBtr(&bp->locked_flags,BPlf_LOCKED); + POPFD + } +} + +CHeapCtrl *HeapCtrlBPInit(CBlkPool *bp,I64 pags) +{//Make mem chunk into HeapCtrl and BlkPool. + I64 num; + CMemBlk *m; + CHeapCtrl *hc; + MemSet(bp,0,sizeof(CBlkPool)+sizeof(CHeapCtrl)); + hc=HeapCtrlInit(bp(U8 *)+sizeof(CBlkPool),,bp); + m=(bp(U8 *)+sizeof(CBlkPool)+sizeof(CHeapCtrl)+MEM_PAG_SIZE-1)& + ~(MEM_PAG_SIZE-1); + num=(bp(U8 *)+pags<>MEM_PAG_BITS; + bp->alloced_u8s=(pags-num)<task_end_cb; + Fs->task_end_cb=&BeatTaskEndCB; //Catch or Kill() task + start_buf_num=snd_obuf_num; + fp_old_fill_buf=fp_snd_fill_buf; + fp_snd_fill_buf=&BeatFillBuf; + try { + "Pick two frequencies within a few Hz of each other to hear beats.\n" + "Pick two frequencies a multiple of two for an octave harmonic.\n" + "$$FG,GREEN$$$$FG$$ to exit.\n"; + while (TRUE) { + freq1=440.0;//PmtF64("Freq #1 (%0.2fHz):",freq1,20,20000); + freq2=880.0;//PmtF64("Freq #2 (%0.2fHz):",freq2,20,20000); + Sleep(200); + } + } catch { //Catch , but pass it on to next higher handler. + fp_snd_fill_buf=fp_old_fill_buf; + Fs->task_end_cb=fp_task_end_cb; + } + beat_done=TRUE; + fp_snd_fill_buf=fp_old_fill_buf; + Fs->task_end_cb=fp_task_end_cb; +} + +BeatFreq; diff --git a/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Chords.ZC b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Chords.ZC new file mode 100644 index 00000000..208cd125 --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Chords.ZC @@ -0,0 +1,16 @@ +U0 Chords(Bool val=ON) +{ + if (snd_dev!=SD_HD_AUDIO) { + "Only works for HD Audio.\n"; + return; + } + HDTonesInit; + if (val) { + hda.tone_swcs[1]->freq_multiplier=4.0/3.0; + hda.tone_swcs[1]->amp_multiplier=1.0; + hda.tone_swcs[2]->freq_multiplier=(4.0/3.0)`2; + hda.tone_swcs[2]->amp_multiplier=1.0; + } +} + +Chords(ON); diff --git a/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Echo.ZC b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Echo.ZC new file mode 100644 index 00000000..d367b8a1 --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Echo.ZC @@ -0,0 +1,98 @@ +Bool echo_done; + +U0 (*fp_task_end_cb)(); +U0 (*fp_old_fill_buf)(SND_OUT_CONTAINER *buf,I64 buf_num)=NULL; +U0 (*fp_old_copy_buf)(SND_IN_CONTAINER *buf,I64 buf_num)=NULL; + +#define BUF_NUM 8 +SND_IN_CONTAINER my_buf[SND_BUF_LEN*BUF_NUM]; + +I64 my_ibuf_ptr,my_obuf_ptr; + +U0 EchoFillBuf(SND_OUT_CONTAINER *buf,I64) +{ + I64 j; + if (echo_done) return; + j=0; + while (jpix_height>>1; + dc->color=BLUE; + for (i=0;ipix_width/SND_BUF_LEN; + y1=cy-buf[i]*cy/I16_MAX; + GrLine(dc,x2,y2,x1,y1); + x2=x1; + y2=y1; + } +} + +U0 EchoDemo() +{ + if (snd_dev!=SD_HD_AUDIO) { + "Only works for HD Audio.\n"; + return; + } + SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$ + HDRun(TRUE,TRUE); + echo_done=FALSE; + fp_task_end_cb=Fs->task_end_cb; + Fs->task_end_cb=&EchoTaskEndCB; //Catch or Kill() task + my_ibuf_ptr=(BUF_NUM/2)*SND_BUF_LEN; + my_obuf_ptr=0; + fp_old_fill_buf=fp_snd_fill_buf; + fp_old_copy_buf=fp_snd_copy_buf; + fp_snd_fill_buf=&EchoFillBuf; + fp_snd_copy_buf=&EchoCopyBuf; + DocCursor; + DocClear; + Fs->draw_it=&DrawIt; + try + CharGet; + catch { //Catch , but pass it on to next higher handler. + fp_snd_fill_buf=fp_old_fill_buf; + fp_snd_copy_buf=fp_old_copy_buf; + Fs->task_end_cb=fp_task_end_cb; + } + echo_done=TRUE; + HDStop(TRUE,FALSE); + fp_snd_fill_buf=fp_old_fill_buf; + fp_snd_copy_buf=fp_old_copy_buf; + Fs->task_end_cb=fp_task_end_cb; + SettingsPop; +} + +EchoDemo; diff --git a/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Guitar.ZC b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Guitar.ZC new file mode 100644 index 00000000..03189739 --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Guitar.ZC @@ -0,0 +1,17 @@ +U0 Guitar(Bool val=ON,F64 à=0.7) +{ + I64 i; + F64 m; + if (snd_dev!=SD_HD_AUDIO) { + "Only works for HD Audio.\n"; + return; + } + HDTonesInit; + if (val) + for (i=0,m=1.0;ifreq_multiplier=i+1; + hda.tone_swcs[i]->amp_multiplier=m; + } +} + +Guitar(ON); diff --git a/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/PolyPhonic.ZC b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/PolyPhonic.ZC new file mode 100644 index 00000000..fe24da53 --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/PolyPhonic.ZC @@ -0,0 +1,96 @@ +Bool poly_done; +I64 start_buf_num; +U0 (*fp_task_end_cb)(); +U0 (*fp_old_fill_buf)(SND_OUT_CONTAINER *buf,I64 buf_num)=NULL; + +U0 PolyFillBuf(SND_OUT_CONTAINER *buf,I64 buf_num) +{ //Gets called by HD Audio task -- HDAudioTask(). + + //Note: the buffer is in uncached memory + //so you might want to avoid multiple + //accesses due to slow speed. (If you were + //to add a bunch of waveforms together, you + //might want to do it in a cached buffer + //and copy it once.) + + I64 j,m,r; + F64 t,d; + if (poly_done) return; + t=ToF64((buf_num-start_buf_num)*(SND_BUF_LEN/SND_OCHANNELS))/SND_SAMPLE_RATE; + j=0; + while (j4.0) { + if (0.908.0) { + if (0.7012.0) { + if (0.3016.0) + m+=0.3*I32_MAX*Caw(t,1.0/6)*Sin(440.0*(2*ã)*t); + } + } + } + + //Samples are 24-bit, placed in upper 24 bits of an I32. + m*=snd_vol; + buf[j++]=ToI64(m*d)&0xFFFFFF00; //Left + buf[j++]=ToI64(m*(1.0-d))&0xFFFFFF00; //Right + + t+=1.0/SND_SAMPLE_RATE; + } +} + +U0 PolyTaskEndCB() +{ + poly_done=TRUE; + fp_snd_fill_buf=fp_old_fill_buf; + if (fp_task_end_cb) + (*fp_task_end_cb)(); + else + Exit; +} + +U0 PolyPhonic() +{ + if (snd_dev!=SD_HD_AUDIO) { + "Only works for HD Audio.\n"; + return; + } + poly_done=FALSE; + fp_task_end_cb=Fs->task_end_cb; + Fs->task_end_cb=&PolyTaskEndCB; //Catch or Kill() task + start_buf_num=snd_obuf_num; + fp_old_fill_buf=fp_snd_fill_buf; + fp_snd_fill_buf=&PolyFillBuf; + try +#if __CMD_LINE__ + PressAKey; +#else + View; +#endif + catch { //Catch , but pass it on to next higher handler. + fp_snd_fill_buf=fp_old_fill_buf; + Fs->task_end_cb=fp_task_end_cb; +} +poly_done=TRUE; +fp_snd_fill_buf=fp_old_fill_buf; +Fs->task_end_cb=fp_task_end_cb; +} + +#if __CMD_LINE__ +PolyPhonic; +#endif diff --git a/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Record.ZC b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Record.ZC new file mode 100644 index 00000000..c81d8583 --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Record.ZC @@ -0,0 +1,117 @@ +Bool record_stop,record_done; + +U0 (*fp_old_copy_buf)(SND_IN_CONTAINER *buf,I64 buf_num)=NULL; + +#define RECORD_BUF_SIZE (SND_BUF_LEN*0x100) + +SND_IN_CONTAINER *record_buf[2]; +I64 record_buf_iptr,record_ibuf_num,record_obuf_num; + +U0 RecordCopyBuf(SND_IN_CONTAINER *buf,I64) +{ + I64 j; + SND_IN_CONTAINER *_s=record_buf[record_ibuf_num&1]; + j=0; + while (j=RECORD_BUF_SIZE) { + record_buf_iptr=0; + record_ibuf_num++; + } +} + +U0 DrawIt(CTask *task,CDC *dc) +{ + SND_IN_CONTAINER *buf=hda.istr0_buf[0]; + I64 i,x1,y1,x2=0,y2=0, + cy=task->pix_height>>1; + dc->color=BLUE; + for (i=0;ipix_width/SND_BUF_LEN; + y1=cy-buf[i]*cy/I16_MAX; + GrLine(dc,x2,y2,x1,y1); + x2=x1; + y2=y1; + } + dc->color=RED; +} + +U0 RecordTaskEndCB() +{ + fp_snd_copy_buf=fp_old_copy_buf; + HDStop(TRUE,FALSE); + Free(record_buf[0]); + Free(record_buf[1]); + record_done=TRUE; + Exit; +} + +U0 RecordTask(U8 *filename) +{ + Bool old_io_snd; + U8 *filename=StrNew(filename),*filename2; + TaskInitExt; //needed for disk access + record_buf[0]=CAlloc(RECORD_BUF_SIZE*sizeof(SND_IN_CONTAINER)); + record_buf[1]=CAlloc(RECORD_BUF_SIZE*sizeof(SND_IN_CONTAINER)); + FileExtRemove(filename); + record_buf_iptr=0; + record_ibuf_num=0; + record_obuf_num=0; + record_done=FALSE; + Fs->task_end_cb=&RecordTaskEndCB; + fp_old_copy_buf=fp_snd_copy_buf; + fp_snd_copy_buf=&RecordCopyBuf; + HDRun(TRUE,FALSE); + old_io_snd=IOSnd(OFF); + while (!record_stop) { + if (record_ibuf_num>record_obuf_num) { + filename2=MPrint("%s%04d.SNZ",filename,record_obuf_num); + SndFileWrite(filename2,record_buf[record_obuf_num&1],RECORD_BUF_SIZE); + record_obuf_num++; + Free(filename2); + } + Sleep(1); + } + filename2=MPrint("%s%04d.SNZ",filename,record_obuf_num); + SndFileWrite(filename2,record_buf[record_obuf_num&1],record_buf_iptr); + record_obuf_num++; + Free(filename2); + Free(filename); + IOSnd(old_io_snd); + record_done=TRUE; +} + +U0 RecordDemo(U8 *filename="~/Record.SNZ") +{ + if (snd_dev!=SD_HD_AUDIO) { + "Only works for HD Audio.\n"; + return; + } + record_done=FALSE; + record_stop=FALSE; + Spawn(&RecordTask,filename,"Record .SNZ",,Fs); + SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$ + DocCursor; + DocClear; + Fs->draw_it=&DrawIt; + try + CharGet; + catch //Catch , but pass it on to next higher handler. + record_stop=TRUE; + record_stop=TRUE; + while (record_done) + Yield; + SettingsPop; + while (TRUE) { + "\n\nPlay "; + if (YorN) + SndFilePlaySeq(filename,record_obuf_num); + else + break; + } + NewLine(2); +} + +RecordDemo; diff --git a/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/SndScope.ZC b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/SndScope.ZC new file mode 100644 index 00000000..52313a14 --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/SndScope.ZC @@ -0,0 +1,44 @@ +U0 DrawIt(CTask *task,CDC *dc) +{ + SND_OUT_CONTAINER *buf=hda.ostr0_buf[0]; + I64 i,x1,y1,x2,y2, + cy=task->pix_height>>1; + + dc->color=BLUE; + x2=0;y2=cy; + for (i=0;ipix_width/SND_BUF_LEN; + y1=cy-buf[i]*cy/snd_vol/I32_MAX; + GrLine(dc,x2,y2,x1,y1); + x2=x1;y2=y1; + } + + dc->color=GREEN; + x2=0;y2=cy; + for (i=1;ipix_width/SND_BUF_LEN; + y1=cy-buf[i]*cy/snd_vol/I32_MAX; + GrLine(dc,x2,y2,x1,y1); + x2=x1; y2=y1; + } +} + +U0 SndScope() +{ + if (snd_dev!=SD_HD_AUDIO) { + "Only works for HD Audio.\n"; + return; + } + SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$ + WinHorz(1,18); + WinVert(15,TEXT_ROWS-2); + DocCursor; + DocClear; + Fs->draw_it=&DrawIt; + CharGet; + SettingsPop; +} + +#if __CMD_LINE__ +SndScope; +#endif diff --git a/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Synth.ZC b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Synth.ZC new file mode 100644 index 00000000..48b2b47f --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1HDAudio/Examples/Synth.ZC @@ -0,0 +1,287 @@ +#define M_WAVEFORM 0 +#define M_FREQUENCY 1 +#define M_ENVELOPE 2 + +#define M_MODES_NUM 3 + +I64 mode; +Bool my_ms_down; +I64 last_x,last_y; + +Bool synth_done; + +U0 (*fp_task_end_cb)(); +U0 (*fp_old_fill_buf)(SND_OUT_CONTAINER *buf,I64 buf_num)=NULL; + +#define BUF_NUM 8 +SND_OUT_CONTAINER my_buf[SND_BUF_LEN*BUF_NUM]; + +#define WF_BUF_LEN 2048 +#define WF_Y_SCALE 2048.0 +I64 waveform_buf[WF_BUF_LEN]; + +#define FQ_BUF_LEN 2048 +#define FQ_Y_SCALE 2048.0 +I64 frequency_buf[FQ_BUF_LEN]; +F64 fq_scale; + +#define EL_BUF_LEN 2048 +#define EL_Y_SCALE 2048.0 +I64 envelope_buf[EL_BUF_LEN]; +F64 el_scale; + +U0 SynthFillBuf(SND_OUT_CONTAINER *buf,I64 buf_num) +{ + I64 i,j,l,k0,k1,k2,k3; + F64 d; + static F64 k=0; + if (synth_done) return; + j=0; + k0=buf_num*(SND_BUF_LEN/SND_OCHANNELS); + while (jpix_height>>1, + h_max=task->pix_width-1; + + if (!winmgr.show_menu) { + if (mouse.lb) { + if (my_ms_down) + switch (mode) { + case M_WAVEFORM: + Line(NULL, + (last_x-task->pix_left-task->scroll_x)*WF_BUF_LEN/h_max, + WF_Y_SCALE*(cy-last_y+task->pix_top+task->scroll_y)/cy,0, +// ( msx-task->pix_left-task->scroll_x)*WF_BUF_LEN/h_max, + ( mouse.pos.x-task->pix_left-task->scroll_x)*WF_BUF_LEN/h_max, +// WF_Y_SCALE*(cy-msy+task->pix_top+task->scroll_y)/cy,0, + WF_Y_SCALE*(cy-mouse.pos.y+task->pix_top+task->scroll_y)/cy,0, + &WFPlot); + break; + case M_FREQUENCY: + Line(NULL, + (last_x-task->pix_left-task->scroll_x)*FQ_BUF_LEN/h_max, + FQ_Y_SCALE*(cy-last_y+task->pix_top+task->scroll_y)/cy,0, +// ( msx-task->pix_left-task->scroll_x)*FQ_BUF_LEN/h_max, + ( mouse.pos.x-task->pix_left-task->scroll_x)*FQ_BUF_LEN/h_max, +// FQ_Y_SCALE*(cy-msy+task->pix_top+task->scroll_y)/cy,0, + FQ_Y_SCALE*(cy-mouse.pos.y+task->pix_top+task->scroll_y)/cy,0, + &FQPlot); + break; + case M_ENVELOPE: + Line(NULL, + (last_x-task->pix_left-task->scroll_x)*EL_BUF_LEN/h_max, + EL_Y_SCALE*(cy-last_y+task->pix_top+task->scroll_y)/cy,0, +// ( msx-task->pix_left-task->scroll_x)*EL_BUF_LEN/h_max, + ( mouse.pos.x-task->pix_left-task->scroll_x)*EL_BUF_LEN/h_max, +// EL_Y_SCALE*(cy-msy+task->pix_top+task->scroll_y)/cy,0, + EL_Y_SCALE*(cy-mouse.pos.y+task->pix_top+task->scroll_y)/cy,0, + &ELPlot); + break; + } + my_ms_down=TRUE; +// last_x=msx; +// last_y=msy; + last_x=mouse.pos.x; + last_y=mouse.pos.y; + } else + my_ms_down=FALSE; + } + + x2=-1; + if (mode==M_WAVEFORM && Blink) { + dc->color=ROPF_DITHER+WHITE<<16+RED; + GrPrint(dc,0,cy-FONT_HEIGHT,"Set Waveform."); + } else + dc->color=RED; + for (i=0;ipix_width/WF_BUF_LEN; + y1=cy-cy*waveform_buf[i]/WF_Y_SCALE; + if (x2>=0) + GrLine(dc,x2,y2,x1,y1); + x2=x1; + y2=y1; + } + + x2=-1; + if (mode==M_FREQUENCY && Blink) { + dc->color=ROPF_DITHER+WHITE<<16+BLUE; + GrPrint(dc,0,cy-FONT_HEIGHT,"Set Frequency."); + } else + dc->color=BLUE; + for (i=0;ipix_width/FQ_BUF_LEN; + y1=cy-cy*frequency_buf[i]/FQ_Y_SCALE; + if (x2>=0) + GrLine(dc,x2,y2,x1,y1); + GrLine(dc,x2,cy-(y2-cy),x1,cy-(y1-cy)); + x2=x1; + y2=y1; + } + + x2=-1; + if (mode==M_ENVELOPE && Blink) { + dc->color=ROPF_DITHER+WHITE<<16+GREEN; + GrPrint(dc,0,cy-FONT_HEIGHT,"Set Envelope."); + } else + dc->color=GREEN; + for (i=0;ipix_width/EL_BUF_LEN; + y1=cy-cy*envelope_buf[i]/EL_Y_SCALE; + if (x2>=0) + GrLine(dc,x2,y2,x1,y1); + GrLine(dc,x2,cy-(y2-cy),x1,cy-(y1-cy)); + x2=x1; + y2=y1; + } + + dc->color=BLACK; + GrLine(dc,0,cy,task->pix_width,cy); +} + +U0 SetMenu() +{ + MenuEntryFind(Fs->cur_menu,"Mode/Waveform")->checked=mode==M_WAVEFORM; + MenuEntryFind(Fs->cur_menu,"Mode/Frequency")->checked=mode==M_FREQUENCY; + MenuEntryFind(Fs->cur_menu,"Mode/Envelope")->checked=mode==M_ENVELOPE; +} + +U0 Init() +{ + my_ms_down=FALSE; + mode=M_WAVEFORM; + MemSetI64(&waveform_buf[0] ,-0.5 *WF_Y_SCALE,WF_BUF_LEN/2); + MemSetI64(&waveform_buf[WF_BUF_LEN/2] , 0.5 *WF_Y_SCALE,WF_BUF_LEN/2); + MemSetI64(frequency_buf , 0.25*FQ_Y_SCALE,FQ_BUF_LEN); + MemSetI64(envelope_buf , 0.75*EL_Y_SCALE,EL_BUF_LEN); + fq_scale=0.02; + el_scale=0.02; + SetMenu; +} + +U0 Synth() +{ + I64 arg1,arg2; + if (snd_dev!=SD_HD_AUDIO) { + "Only works for HD Audio.\n"; + return; + } + + SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$ + MenuPush( + "File {" + " New(,'\n');" + " Abort(,CH_SHIFT_ESC);" + " Exit(,CH_ESC);" + "}" + "Mode {" + " Waveform(,'1');" + " Frequency(,'2');" + " Envelope(,'3');" + "}" + ); + AutoComplete; + WinBorder; + WinMax; + DocCursor; + DocClear; + Fs->win_inhibit=WIG_TASK_DEFAULT-WIF_SELF_FOCUS-WIF_FOCUS_TASK_MENU; + + Init; + + synth_done=FALSE; + fp_task_end_cb=Fs->task_end_cb; + Fs->task_end_cb=&SynthTaskEndCB; //Catch or Kill() task + fp_old_fill_buf=fp_snd_fill_buf; + fp_snd_fill_buf=&SynthFillBuf; + Fs->draw_it=&DrawIt; + try { + while (TRUE) { + switch (MessageGet(&arg1,&arg2,1<, but pass it on to next higher handler. + fp_snd_fill_buf=fp_old_fill_buf; + Fs->task_end_cb=fp_task_end_cb; + } + synth_done=TRUE; + fp_snd_fill_buf=fp_old_fill_buf; + Fs->task_end_cb=fp_task_end_cb; + SettingsPop; +} + +Synth; diff --git a/src/Home/Sound/HDAudio1/Sup1HDAudio/HDAudio.ZC b/src/Home/Sound/HDAudio1/Sup1HDAudio/HDAudio.ZC new file mode 100644 index 00000000..407d5e38 --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1HDAudio/HDAudio.ZC @@ -0,0 +1,722 @@ +//SysFile("~/sup1hdaudio/Sup1CodeScraps/Mem/Mem2Meg.ZC"); + +#help_index "Sound/HDAudio" + +//snd devs +#define SD_PC_SPEAKER 0 +#define SD_HD_AUDIO 1 + +#define SND_SAMPLE_RATE 48000 +#define SND_SAMPLE_BITS 24 +#define SND_OCHANNELS 2 +#define SND_ICHANNELS 2 +#define SND_OUT_CONTAINER I32 +#define SND_IN_CONTAINER I16 +#define SND_BUF_LEN 0x400 +#define SND_BUF_TIME_mS (SND_BUF_LEN / SND_OCHANNELS * 1000.0 / SND_SAMPLE_RATE) + +F64 snd_freq = 0; +I64 snd_dev = SD_PC_SPEAKER; +Bool snd_record = FALSE; +F64 snd_vol = 0.1; +U0 (*fp_snd) (F64 freq, I64 waveform, F64 amp) = NULL; +U0 (*fp_snd_record)(F64 freq, I64 waveform, F64 amp) = NULL; +U0 (*fp_snd_fill_buf)(SND_OUT_CONTAINER *buf, I64 buf_num) = NULL; +U0 (*fp_snd_copy_buf)(SND_IN_CONTAINER *buf, I64 buf_num) = NULL; + +I64 snd_obuf_num, snd_ibuf_num; + +#define Sf_FILLING_OUT 0 +I64 snd_flags; + +#define HD_1_CHAN 0 +#define HD_2_CHAN 1 +#define HD_3_CHAN 2 +#define HD_4_CHAN 3 + +#define HD_8_BIT 0 +#define HD_16_BIT 1 +#define HD_20_BIT 2 +#define HD_24_BIT 3 +#define HD_32_BIT 4 +#define HD_48kHz 0 + +#define HD_DEFAULT_OUT_FMT (HD_2_CHAN + HD_24_BIT << 4 + HD_48kHz << 8) +#define HD_DEFAULT_IN_FMT (HD_2_CHAN + HD_16_BIT << 4 + HD_48kHz << 8) + +#define HD_POS_BUF_MULTIPLES 0x1000 + +#define HD_CORB_ENTRIES 256 +#define HD_RIRB_ENTRIES 256 +#define HD_BDL_ENTRIES 256 + +#define HD_GCTL 0x08 +#define HD_STATESTS 0x0E +#define HD_GSTS 0x10 +#define HD_CORBLBASE 0x40 +#define HD_CORBUBASE 0x44 +#define HD_CORBWP 0x48 +#define HD_CORBRP 0x4A +#define HD_CORBCTL 0x4C +#define HD_CORBST 0x4D +#define HD_RIRBLBASE 0x50 +#define HD_RIRBUBASE 0x54 +#define HD_RIRBWP 0x58 +#define HD_RIRBCTL 0x5C +#define HD_RIRBSTS 0x5D + +#define STRCTL 0x00 +#define STRSTS 0x03 +#define STRLPIB 0x04 +#define STRCBL 0x08 +#define STRLVI 0x0C +#define STRFIFOW 0x0E +#define STRFIFOS 0x10 +#define STRFMT 0x12 +#define STRBDPL 0x18 +#define STRBDPU 0x1C +#define ISTR0 0x080 +#define ISTR1 0x0A0 +#define ISTR2 0x0C0 +#define ISTR3 0x0E0 +#define OSTR0 0x100 +#define OSTR1 0x120 +#define OSTR2 0x140 +#define OSTR3 0x160 + +#define VERB_GET_PARAM 0xF0000 +#define VERB_CONNECT_SEL_GET 0xF0100 +#define VERB_CONNECT_SEL_SET 0x70100 +#define VERB_GET_CONNECT_LST 0xF0200 +#define VERB_PROCESS_STATE_GET 0xF0300 +#define VERB_PROCESS_STATE_SET 0x70300 +#define VERB_COEFF_IDX_GET 0xD0000 +#define VERB_COEFF_IDX_SET 0x50000 +#define VERB_PROCESS_COEFF_GET 0xC0000 +#define VERB_PROCESS_COEFF_SET 0x40000 +#define VERB_AMPLIFIER_GAIN_GET 0xB0000 +#define VERB_AMPLIFIER_GAIN_SET 0x30000 +#define VERB_STREAM_FMT_GET 0xA0000 +#define VERB_STREAM_FMT_SET 0x20000 +#define VERB_DIGIT_CONVERT1_GET 0xF0D00 +#define VERB_DIGIT_CONVERT1_SET 0x70D00 +#define VERB_DIGIT_CONVERT2_GET 0xF0D00 +#define VERB_DIGIT_CONVERT2_SET 0x70E00 +#define VERB_POWER_STATE_GET 0xF0500 +#define VERB_POWER_STATE_SET 0x70500 +#define VERB_CHAN_STREAM_ID_GET 0xF0600 +#define VERB_CHAN_STREAM_ID_SET 0x70600 +#define VERB_SDI_SEL_GET 0xF0400 +#define VERB_SDI_SEL_SET 0x70400 +#define VERB_PIN_WIDGET_CTL_GET 0xF0700 +#define VERB_PIN_WIDGET_CTL_SET 0x70700 +#define VERB_UNSOL_ENABLE_GET 0xF0800 +#define VERB_UNSOL_ENABLE_SET 0x70800 +#define VERB_PIN_SENSE_GET 0xF0900 +#define VERB_PIN_SENSE_SET 0x70900 +#define VERB_EAPDBTL_ENABLE_GET 0xF0C00 +#define VERB_EAPDBTL_ENABLE_SET 0x70C00 +#define VERB_BEEP_CTL_GET 0xF0A00 +#define VERB_BEEP_CTL_SET 0x70A00 +#define VERB_GPI_CTRL0_GET 0xF1000 +#define VERB_GPI_CTRL0_SET 0x71000 +#define VERB_GPI_CTRL1_GET 0xF1100 +#define VERB_GPI_CTRL1_SET 0x71100 +#define VERB_GPI_CTRL2_GET 0xF1200 +#define VERB_GPI_CTRL2_SET 0x71200 +#define VERB_GPI_CTRL3_GET 0xF1300 +#define VERB_GPI_CTRL3_SET 0x71300 +#define VERB_GPI_CTRL4_GET 0xF1400 +#define VERB_GPI_CTRL4_SET 0x71400 +#define VERB_GPI_CTRL5_GET 0xF1500 +#define VERB_GPI_CTRL5_SET 0x71500 +#define VERB_GPI_CTRL6_GET 0xF1600 +#define VERB_GPI_CTRL6_SET 0x71600 +#define VERB_GPI_CTRL7_GET 0xF1700 +#define VERB_GPI_CTRL7_SET 0x71700 +#define VERB_GPI_CTRL8_GET 0xF1800 +#define VERB_GPI_CTRL8_SET 0x71800 +#define VERB_GPI_CTRL9_GET 0xF1900 +#define VERB_GPI_CTRL9_SET 0x71900 +#define VERB_GPI_CTRLA_GET 0xF1A00 +#define VERB_GPI_CTRLA_SET 0x71A00 +#define VERB_VOL_CTL_GET 0xF0F00 +#define VERB_VOL_CTL_SET 0x70F00 +#define VERB_SUB_SYS_ID0_GET 0xF2000 +#define VERB_SUB_SYS_ID0_SET 0x72000 +#define VERB_SUB_SYS_ID1_GET 0xF2000 +#define VERB_SUB_SYS_ID1_SET 0x72100 +#define VERB_SUB_SYS_ID2_GET 0xF2000 +#define VERB_SUB_SYS_ID2_SET 0x72200 +#define VERB_SUB_SYS_ID3_GET 0xF2000 +#define VERB_SUB_SYS_ID3_SET 0x72300 +#define VERB_CFG_DEFAULT0_GET 0xF1C00 +#define VERB_CFG_DEFAULT0_SET 0x71C00 +#define VERB_CFG_DEFAULT1_GET 0xF1C00 +#define VERB_CFG_DEFAULT1_SET 0x71D00 +#define VERB_CFG_DEFAULT2_GET 0xF1C00 +#define VERB_CFG_DEFAULT2_SET 0x71E00 +#define VERB_CFG_DEFAULT3_GET 0xF1C00 +#define VERB_CFG_DEFAULT3_SET 0x71F00 +#define VERB_STRIPE_CTL_GET 0xF2400 +#define VERB_STRIPE_CTL_SET 0x72400 +#define VERB_RST 0x7FF00 + +//Parameters +#define P_VENDOR_ID 0x00 +#define P_REVISION_ID 0x02 +#define P_SUBNODE_CNT 0x04 +#define P_FUN_GRP_TYPE 0x05 +#define P_AUDIO_FUN_CAP 0x08 +#define P_AUDIO_WIDGET_CAP 0x09 +#define P_SAMPLE_SIZE_RATE_CAP 0x0A +#define P_STREAM_FMTS 0x0B +#define P_PIN_CAP 0x0C +#define P_INPUT_AMP_CAP 0x0D +#define P_OUTPUT_AMP_CAP 0x12 +#define P_CONNECT_LST_LEN 0x0E +#define P_POWER_STATES 0x0F +#define P_PROCESSING_CAP 0x10 +#define P_GPIO_CNT 0x11 +#define P_VOL_KNOB_CAP 0x13 + +//Function Group Types +//00 reserved +#define FGT_AUDIO 1 +#define FGT_VENDOR_MODEM 2 +//03-7F reserved +//80-FF vendor function group + +//Audio Widget Types +#define AWT_OUTPUT 0x0 +#define AWT_INPUT 0x1 +#define AWT_MIXER 0x2 +#define AWT_SELECTOR 0x3 +#define AWT_PIN_COMPLEX 0x4 +#define AWT_POWER_WIDGET 0x5 +#define AWT_VOL_KNOB_WIDGET 0x6 +#define AWT_BEEP_GEN_WIDGET 0x7 +#define AWT_VENDOR 0xF +#define AWT_NODE 0x10 +DefineListLoad("ST_AUDIO_WIDGET_TYPES", + "Output\0" + "Input\0" + "Mixer\0" + "Selector\0" + "Pin Complex\0" + "Power Widget\0" + "Vol Knob\0" + "Beep Gen\0" + " \0" + " \0" + " \0" + " \0" + " \0" + " \0" + " \0" + "Vendor\0" + "Node\0"); + +class CHDBufDesc +{ + I32 *buf; + U32 len; + U32 ctrl; +}; + +#define HD_TONES 8 + +class CHDAudioCtrl +{ + U8 *bar; + CBlkPool *bp; + CHeapCtrl *hc; + I64 cad; + U32 *corb; + I64 *rirb; + CHDBufDesc *ostr0_bdl, + *istr0_bdl; + SND_OUT_CONTAINER *ostr0_buf[2], + *o_tmp_buf; + SND_IN_CONTAINER *istr0_buf[2]; + CTask *task; + I64 waveform; + F64 freq, amp; + CSndWaveCtrl *tone_swcs[HD_TONES]; + U8 rirb_rp, corb_wp; + Bool audio_task_started, in_running, out_running; +} hda; + +MemSet(&hda, 0, sizeof(CHDAudioCtrl)); + +U0 HDAudioRegWriteU32(U16 hd_reg, U32 val) +{ + U32 *dest = hda.bar + hd_reg; + *dest = val; +} + +U0 HDAudioRegWriteU16(U16 hd_reg, U16 val) +{ + U16 *dest = hda.bar + hd_reg; + *dest = val; +} + +U0 HDAudioRegWriteU8(U16 hd_reg, U8 val) +{ + U8 *dest = hda.bar + hd_reg; + *dest = val; +} + +U32 HDAudioRegReadU32(U16 hd_reg) +{ + U32 *dest = hda.bar + hd_reg; + return *dest; +} + +U16 HDAudioRegReadU16(U16 hd_reg) +{ + U16 *dest = hda.bar + hd_reg; + return *dest; +} + +U8 HDAudioRegReadU8(U16 hd_reg) +{ + U8 *dest = hda.bar + hd_reg; + return *dest; +} + +U0 HDSyncCORB() +{ + HDAudioRegWriteU16(HD_CORBWP, hda.corb_wp); + while (HDAudioRegReadU16(HD_CORBRP) & 0xFF != hda.corb_wp) + Yield; +} + +U0 HDWriteCORB(I64 cad, I64 nid, U32 val) +{ + val |= cad << 28 + nid << 20; + hda.corb[++hda.corb_wp] = val; +} + +I64 HDSyncRIRB() +{ + I64 wp = HDAudioRegReadU16(HD_RIRBWP), res = 0; + + while (hda.rirb_rp != wp) + res = hda.rirb[++hda.rirb_rp]; + + return res; +} + +I64 HDReadRIRB() +{ + I64 wp, res = 0; + + do + { + Yield; + wp = HDAudioRegReadU16(HD_RIRBWP); + } while (wp == hda.rirb_rp); + res = hda.rirb[++hda.rirb_rp]; + + return res; +} + +I64 HDWriteCORBSync(I64 cad, I64 nid, U32 val) +{ + HDSyncCORB; + HDSyncRIRB; + HDWriteCORB(cad, nid, val); + HDSyncCORB; + return HDReadRIRB; +} + +Bool HDTestCORBSync(I64 cad, I64 nid, U32 val) +{ + //Checks for a response + I64 wp; + + HDSyncCORB; + HDSyncRIRB; + HDWriteCORB(cad, nid, val); + HDSyncCORB; + + Sleep(1); + wp = HDAudioRegReadU16(HD_RIRBWP); + if (wp == hda.rirb_rp) + return FALSE; + HDReadRIRB; + + return TRUE; +} + +U0 HDTraverse(I64 cad, I64 nid) +{ + I64 i, len, aud_cap, type; + HDWriteCORBSync(cad, nid, VERB_POWER_STATE_SET + 0x00); //0 is on + HDWriteCORBSync(cad, nid, VERB_EAPDBTL_ENABLE_SET + 0x02); + HDWriteCORBSync(cad, nid, VERB_PROCESS_STATE_SET + 0x02); + HDWriteCORBSync(cad, nid, VERB_CONNECT_SEL_SET + 0x00); + aud_cap = HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_SUBNODE_CNT); + if (aud_cap.u16[0]) + { + for (i = aud_cap.u16[1]; i < aud_cap.u16[1] + aud_cap.u16[0]; i++) + HDTraverse(cad, i); + } + else + { + aud_cap = HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_AUDIO_WIDGET_CAP); + type = aud_cap >> 20 & 15; + if (Bt(&aud_cap, 8)) + len = HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_CONNECT_LST_LEN) & 127; + else + len = 0; + HDWriteCORBSync(cad, nid, VERB_AMPLIFIER_GAIN_SET + 0xF07F); //set I/O amp #0 + for (i = 1; i < len; i++) + //Set IN amps to mute + HDWriteCORBSync(cad, nid, VERB_AMPLIFIER_GAIN_SET + 0x7080 + i << 8); + switch (type) + { + case AWT_OUTPUT: +// if (FALSE) //if disabled // ???? +// HDWriteCORBSync(cad, nid, VERB_CHAN_STREAM_ID_SET + 0x00); +// else + HDWriteCORBSync(cad, nid, VERB_CHAN_STREAM_ID_SET + 0x10); + HDWriteCORBSync(cad, nid, VERB_STREAM_FMT_SET + HD_DEFAULT_OUT_FMT); // TODO: check format streams support ? + HDWriteCORBSync(cad, nid, VERB_PROCESS_STATE_SET + 0x01); + break; + case AWT_INPUT: +// if (TRUE) //if disabled // ???? + HDWriteCORBSync(cad, nid, VERB_CHAN_STREAM_ID_SET + 0x00); +// else +// HDWriteCORBSync(cad, nid, VERB_CHAN_STREAM_ID_SET + 0x20); + HDWriteCORBSync(cad, nid, VERB_STREAM_FMT_SET + HD_DEFAULT_IN_FMT); // TODO: check format streams support ? + HDWriteCORBSync(cad, nid, VERB_PROCESS_STATE_SET + 0x01); + break; + case AWT_PIN_COMPLEX: + HDWriteCORBSync(cad, nid, VERB_PIN_WIDGET_CTL_SET + 0xE2); + break; + } + } +} + +U0 HDRun(Bool in, Bool out) +{ + if (hda.bar) + { + if (out) + { + HDAudioRegWriteU32(OSTR0 + STRCTL, 0x100002); // ?? + hda.out_running = TRUE; + } + + if (in) + { + HDAudioRegWriteU32(ISTR0 + STRCTL, 0x200002); // ?? + hda.in_running = TRUE; + } + } +} + +U0 HDStop(Bool in, Bool out) +{ + if (hda.bar) + { + if (out) + { + HDAudioRegWriteU32(OSTR0 + STRCTL, 0); // ?? + hda.out_running = FALSE; + } + + if (in) + { + HDAudioRegWriteU32(ISTR0 + STRCTL, 0); // ?? + hda.in_running = FALSE; + } + } +} + +U0 HDSnd(F64 freq, I64 waveform = WF_SQUARE, F64 amp = 1.0) +{ + hda.waveform = waveform; + hda.amp = amp; + hda.freq = freq; +} + +U0 HDFillBuf(SND_OUT_CONTAINER *buf, I64) +{ + I64 i, size = SND_BUF_LEN * sizeof(SND_OUT_CONTAINER); + + if (!hda.o_tmp_buf) + hda.o_tmp_buf = SysMAlloc(size); + MemSet(hda.o_tmp_buf, 0, size); + for (i = 0; i < HD_TONES; i++) + SndWaveAddBuf(hda.tone_swcs[i], hda.o_tmp_buf, SND_BUF_LEN / SND_OCHANNELS, hda.freq, hda.waveform, snd_vol * hda.amp); + MemCopy(buf, hda.o_tmp_buf, size); +} + +U0 HDAudioTaskEndCB() +{ + I64 i; + + HDStop(FALSE, TRUE); + fp_snd = NULL; + for (i = 0; i < HD_TONES; i++) + { + SndWaveCtrlDel(hda.tone_swcs[i]); + hda.tone_swcs[i] = NULL; + } + + Exit; +} + +public U0 HDTonesInit() +{ + I64 i; + + if (hda.bar) + { + for (i = 0; i < HD_TONES; i++) + { + hda.tone_swcs[i]->freq_multiplier = 1.0; + hda.tone_swcs[i]->amp_multiplier = 0; + } + + hda.tone_swcs[0]->amp_multiplier = 1.0; + } +} + +U0 HDAudioTask(I64) +{ + //I didn't feel like messing around with PCI interrupts + //so this task polls every millisecond to know when to + //switch buffers. + I64 i, next_obuf_trigger = SND_BUF_LEN * sizeof(SND_OUT_CONTAINER) / 2, + obuf_rollover = 0, + next_ibuf_trigger = SND_BUF_LEN * sizeof(SND_IN_CONTAINER), + ibuf_rollover = 0; + U32 *pos_in_obuf = hda.bar + OSTR0 + STRLPIB, + *pos_in_ibuf = hda.bar + ISTR0 + STRLPIB; + + Fs->task_end_cb = &HDAudioTaskEndCB; + for (i = 0; i < HD_TONES; i++) + hda.tone_swcs[i] = SndWaveCtrlNew; + HDTonesInit; + hda.freq = 0; + Sound; + fp_snd = &HDSnd; + fp_snd_fill_buf = &HDFillBuf; + fp_snd_copy_buf = NULL; + snd_obuf_num = 1; + snd_ibuf_num = 1; + HDRun(FALSE, TRUE); + hda.audio_task_started = TRUE; //This flag is probably not necessary + while (TRUE) + { + if (next_obuf_trigger - obuf_rollover <= + *pos_in_obuf < + next_obuf_trigger - obuf_rollover + (HD_POS_BUF_MULTIPLES - 1) * SND_BUF_LEN * sizeof(SND_OUT_CONTAINER)) + { + next_obuf_trigger += SND_BUF_LEN * sizeof(SND_OUT_CONTAINER); + if (next_obuf_trigger - obuf_rollover >= HD_POS_BUF_MULTIPLES * SND_BUF_LEN * sizeof(SND_OUT_CONTAINER)) + obuf_rollover += HD_POS_BUF_MULTIPLES * SND_BUF_LEN * sizeof(SND_OUT_CONTAINER); + if (fp_snd_fill_buf) + { + LBts(&snd_flags, Sf_FILLING_OUT); + (*fp_snd_fill_buf)(hda.ostr0_buf[snd_obuf_num & 1], snd_obuf_num); + if (IsMute) + MemSet(hda.ostr0_buf[snd_obuf_num & 1], 0, SND_BUF_LEN * sizeof(SND_OUT_CONTAINER)); + LBtr(&snd_flags, Sf_FILLING_OUT); + } + + snd_obuf_num++; + } + + if (next_ibuf_trigger - ibuf_rollover <= + *pos_in_ibuf < + next_ibuf_trigger - ibuf_rollover + (HD_POS_BUF_MULTIPLES - 1) * SND_BUF_LEN * sizeof(SND_IN_CONTAINER)) + { + next_ibuf_trigger += SND_BUF_LEN* sizeof(SND_IN_CONTAINER); + if (next_ibuf_trigger - ibuf_rollover >= HD_POS_BUF_MULTIPLES * SND_BUF_LEN * sizeof(SND_IN_CONTAINER)) + ibuf_rollover += HD_POS_BUF_MULTIPLES * SND_BUF_LEN * sizeof(SND_IN_CONTAINER); + if (fp_snd_copy_buf) + (*fp_snd_copy_buf)(hda.istr0_buf[snd_obuf_num & 1], snd_ibuf_num); + snd_ibuf_num++; + } + + Sleep(1); + } +} + +U0 HDReset() +{ + U32 d; + + HDStop(TRUE, TRUE); + HDAudioRegWriteU32(HD_GCTL, 0); //rst // ?? + do + { + Sleep(1); + d = HDAudioRegReadU32(HD_GCTL); + } while (d & 1); + HDAudioRegWriteU32(HD_GCTL, 1); //?? + do + { + Sleep(1); + d = HDAudioRegReadU32(HD_GCTL); + } while (!(d & 1)); + Sleep(1); +} + +public U0 HDAudioEnd(Bool rst = TRUE) +{ + snd_dev = SD_PC_SPEAKER; + if (hda.bar) + { + Kill(hda.task); + hda.task = NULL; + if (rst) + HDReset; + FreeAll(hda.corb, hda.rirb, hda.o_tmp_buf, hda.ostr0_buf[0], hda.ostr0_buf[1], hda.istr0_buf[0], hda.istr0_buf[1], + hda.ostr0_bdl, hda.istr0_bdl); + Mem32DevFree(hda.bar); + hda.bar = NULL; + } +} + +U0 HDAudioUncachedInit() +{ + I64 shared_blks = 1; + hda.bp = Mem2MegUncachedAlloc(&shared_blks); + hda.hc = HeapCtrlBPInit(hda.bp, shared_blks << 12); +} + +public Bool HDAudioInit(I64 hd_bus, I64 hd_dev, I64 hd_fun) +{ + I64 i; + U16 w, val; + + if (hda.bar) + HDAudioEnd; + else + HDAudioUncachedInit; + if (PCIReadU16(hd_bus, hd_dev, hd_fun, PCIR_VENDOR_ID) == 0x8086 && + (hda.bar = dev.uncached_alias + PCIReadU32(hd_bus, hd_dev, hd_fun, PCIR_BASE0) & ~0x1F)) + { + /* Set HDAudio PCI device command + register IO Enable, Bus + Master Enable, Memory Space,and + Interrupt Disable bits. */ + val = PCIReadU16(hd_bus, hd_dev, hd_fun, PCIR_COMMAND); + val |= PCI_CMDF_IOEN | PCI_CMDF_BMEN | PCI_CMDF_INTD | PCI_CMDF_MSEN; + PCIWriteU16(hd_bus, hd_dev, hd_fun, PCIR_COMMAND, val); + + HDReset; + + hda.corb = CAllocAligned(HD_CORB_ENTRIES * sizeof(U32), 128, hda.hc); + HDAudioRegWriteU32(HD_CORBLBASE, hda.corb(I64).u32[0]); + HDAudioRegWriteU32(HD_CORBUBASE, hda.corb(I64).u32[1]); + + hda.rirb = CAllocAligned(HD_RIRB_ENTRIES * sizeof(I64), 128, hda.hc); + HDAudioRegWriteU32(HD_RIRBLBASE, hda.rirb(I64).u32[0]); + HDAudioRegWriteU32(HD_RIRBUBASE, hda.rirb(I64).u32[1]); + + HDAudioRegWriteU16(HD_CORBRP, 0x8000); //Rst read ptr // ?? + do + { + Yield; + w = HDAudioRegReadU16(HD_CORBRP); + } while (!(w & 0x8000)); + HDAudioRegWriteU16(HD_CORBRP, 0x0000); //Rst read ptr // ?? + do + { + Yield; + w = HDAudioRegReadU16(HD_CORBRP); + } while (w & 0x8000); + + HDAudioRegWriteU16(HD_RIRBWP, 0x8000); //Rst write ptr // ?? + + HDAudioRegWriteU8(HD_CORBCTL, 0x02); //Run // ?? + HDAudioRegWriteU8(HD_RIRBCTL, 0x02); //Run // ?? + + hda.corb_wp = HDAudioRegReadU16(HD_CORBWP); + hda.rirb_rp = HDAudioRegReadU16(HD_RIRBWP); + + hda.ostr0_bdl = CAllocAligned(HD_BDL_ENTRIES * sizeof(CHDBufDesc), 128, hda.hc); + HDAudioRegWriteU32(OSTR0 + STRBDPL, hda.ostr0_bdl(I64).u32[0]); + HDAudioRegWriteU32(OSTR0 + STRBDPU, hda.ostr0_bdl(I64).u32[1]); + for (i = 0; i < 2; i++) + { + hda.ostr0_bdl[i].buf = hda.ostr0_buf[i] = CAllocAligned(SND_BUF_LEN * sizeof(SND_OUT_CONTAINER), 128, hda.hc); + hda.ostr0_bdl[i].len = SND_BUF_LEN * sizeof(SND_OUT_CONTAINER); + hda.ostr0_bdl[i].ctrl = 1; + } + + hda.istr0_bdl = CAllocAligned(HD_BDL_ENTRIES * sizeof(CHDBufDesc), 128, hda.hc); + HDAudioRegWriteU32(ISTR0 + STRBDPL, hda.istr0_bdl(I64).u32[0]); + HDAudioRegWriteU32(ISTR0 + STRBDPU, hda.istr0_bdl(I64).u32[1]); + for (i = 0; i < 2; i++) + { + hda.istr0_bdl[i].buf = hda.istr0_buf[i] = CAllocAligned(SND_BUF_LEN * sizeof(SND_IN_CONTAINER), 128, hda.hc); + hda.istr0_bdl[i].len = SND_BUF_LEN * sizeof(SND_IN_CONTAINER); + hda.istr0_bdl[i].ctrl = 1; + } + + w = HDAudioRegReadU16(HD_STATESTS); + while (w) + { + hda.cad = Bsf(w); + if (HDTestCORBSync(hda.cad, 0, VERB_GET_PARAM + P_SUBNODE_CNT)) + { + HDTraverse(hda.cad, 0); + + HDAudioRegWriteU32(OSTR0 + STRLPIB, 0); + HDAudioRegWriteU32(OSTR0 + STRCBL, HD_POS_BUF_MULTIPLES * SND_BUF_LEN * sizeof(SND_OUT_CONTAINER)); + HDAudioRegWriteU16(OSTR0 + STRLVI, 1); //last valid idx // ?? + HDAudioRegWriteU16(OSTR0 + STRFMT, HD_DEFAULT_OUT_FMT); + + HDAudioRegWriteU32(ISTR0 + STRLPIB, 0); + HDAudioRegWriteU32(ISTR0 + STRCBL, HD_POS_BUF_MULTIPLES * SND_BUF_LEN * sizeof(SND_IN_CONTAINER)); + HDAudioRegWriteU16(ISTR0 + STRLVI, 1); //last valid idx // ?? + HDAudioRegWriteU16(ISTR0 + STRFMT, HD_DEFAULT_IN_FMT); + + LBts(&sys_semas[SEMA_SOUND], 0); //turn off until cfg completed + LBtr(&snd_flags, Sf_FILLING_OUT); + hda.audio_task_started = FALSE; + if (mp_count > 1) + hda.task = Spawn(&HDAudioTask, NULL, "HD Audio", mp_count - 1); + else + hda.task = Spawn(&HDAudioTask, NULL, "HD Audio"); + while (!hda.audio_task_started) + Yield; + snd_dev = SD_HD_AUDIO; + return TRUE; + } + + Btr(&w, hda.cad); + } + + HDAudioEnd(FALSE); + } + else + hda.bar = NULL; + return FALSE; +} + +Bool HDAudioScan() +{ + I64 i = -1, bdf; + while (TRUE) + { + bdf = PCIClassFind(PCIC_MULTIMEDIA << 16 | PCISC_AUDIO << 8, ++i); + if (bdf < 0) + return FALSE; + + if (HDAudioInit(bdf.u8[2], bdf.u8[1], bdf.u8[0])) + return TRUE; + } +} + +HDAudioScan; + +#help_index "" \ No newline at end of file diff --git a/src/Home/Sound/HDAudio1/Sup1HDAudio/HDCfg.ZC b/src/Home/Sound/HDAudio1/Sup1HDAudio/HDCfg.ZC new file mode 100644 index 00000000..e6520cf8 --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1HDAudio/HDCfg.ZC @@ -0,0 +1,720 @@ + +#define CONNECTS_NUM 16 + +class MyMass: CMass +{ + F64 radius; + U8 nid, type, num_connects, cur_connect; + U32 audio_widget_capabilities; + U8 connect_lst[CONNECTS_NUM]; + U8 gain_lst[CONNECTS_NUM]; + U32 pin_capabilities, pin_sense, + pcm_size_rates, + in_amp_cap, out_amp_cap; + U8 pin_widget_ctl; + Bool disabled; +}; + +class MySpring: CSpring +{ + I64 color; +}; + +CMathODE *ode = NULL; + +#define BORDER 10 + +U0 DrawIt(CTask *task, CDC *dc) +{ + Bool old_suspend; + I16 * buf; + I64 i, cxx, cyy, + cy = task->pix_height >> 1; + F64 dx, dy, d; + MyMass * tmpm; + MySpring * tmps; + + old_suspend = Suspend(task); + tmps = ode->next_spring; + while (tmps != &ode->next_spring) + { + dc->color = tmps->color; + GrLine(dc, tmps->end1->x, tmps->end1->y, + tmps->end2->x, tmps->end2->y); + cxx = (tmps->end1->x + tmps->end2->x) / 2; + cyy = (tmps->end1->y + tmps->end2->y) / 2; + dx = tmps->end1->x - tmps->end2->x; + dy = tmps->end1->y - tmps->end2->y; + d = Sqrt(dx *dx + dy *dy); + dx /= d; + dy /= d; + GrLine(dc, cxx, cyy, cxx + 3.0 *dy - 3.0 *dx, cyy - 3.0 *dx - 3.0 *dy); + GrLine(dc, cxx, cyy, cxx - 3.0 *dy - 3.0 *dx, cyy + 3.0 *dx - 3.0 *dy); + tmps = tmps->next; + } + + tmpm = ode->next_mass; + while (tmpm != &ode->next_mass) + { + if (tmpm->disabled) + dc->color = BLUE; + else + dc->color = LTBLUE; + GrCircle(dc, tmpm->x, tmpm->y, tmpm->radius); + GrPrint(dc, tmpm->x, tmpm->y - FONT_HEIGHT / 2, "%02X%3tZ", + tmpm->nid, tmpm->type, + "ST_AUDIO_WIDGET_TYPES"); + tmpm = tmpm->next; + } + + Suspend(task, old_suspend); + dc->color = BLUE; + buf = hda.istr0_buf[0]; + for (i = 0; i < SND_BUF_LEN; i++) + GrPlot(dc, i *task->pix_width / SND_BUF_LEN, + cy - buf[i] *cy / I16_MAX); +} + +U0 MyDerivative(CMathODE *ode, F64, COrder2D3 *, COrder2D3 *) +{ + //The forces due to springs and drag are + //automatically handled by the + //ode code.We can add new forces + //here. + CTask *task = ode->win_task; + I64 h = task->pix_width, v = task->pix_height; + F64 d, dd; + CD3 p; + MyMass *tmpm1, *tmpm2; + + tmpm1 = ode->next_mass; + while (tmpm1 != &ode->next_mass) + { + tmpm2 = tmpm1->next; + while (tmpm2 != &ode->next_mass) + { + D3Sub(&p, &tmpm2->state->x, &tmpm1->state->x); + dd = D3NormSqr(&p); + if (dd <= Sqr(tmpm1->radius + tmpm2->radius)) + { + d = Sqrt(dd) + 0.0001; + dd = 10.0* Sqr(Sqr(Sqr(tmpm1->radius + tmpm2->radius) - dd)); + D3MulEqu(&p, dd / d); + D3AddEqu(&tmpm2->DstateDt->DxDt, &p); + D3SubEqu(&tmpm1->DstateDt->DxDt, &p); + } + else + { + D3MulEqu(&p, 100000.0 / dd); + D3AddEqu(&tmpm2->DstateDt->DxDt, &p); + D3SubEqu(&tmpm1->DstateDt->DxDt, &p); + } + + tmpm2 = tmpm2->next; + } + + if (tmpm1->state->x < BORDER) + tmpm1->DstateDt->DxDt += 1000* Sqr(tmpm1->state->x - BORDER); + if (tmpm1->state->y < BORDER) + tmpm1->DstateDt->DyDt += 1000* Sqr(tmpm1->state->y - BORDER); + if (tmpm1->state->x > h - BORDER - FONT_WIDTH *6) + tmpm1->DstateDt->DxDt -= 1000 * + Sqr(tmpm1->state->x - (h - BORDER - FONT_WIDTH *6)); + if (tmpm1->state->y > v - BORDER) + tmpm1->DstateDt->DyDt -= 1000* Sqr(tmpm1->state->y - (v - BORDER)); + tmpm1 = tmpm1->next; + } +} + +MyMass* PlaceMass(I64 nid) +{ + MyMass *tmpm = CAlloc(sizeof(MyMass)); + tmpm->mass = 1.0; + tmpm->drag_profile_factor = 100.0; + tmpm->radius = 5; + tmpm->nid = nid; + tmpm->gain_lst[0] = 0x7F; + MemSet(tmpm->gain_lst + 1, 0x80, (CONNECTS_NUM - 1) *sizeof(U8)); + QueueInsert(tmpm, ode->last_mass); + return tmpm; +} + +MyMass* FindMassByNID(I64 nid) +{ + MyMass * tmpm; + tmpm = ode->next_mass; + while (tmpm != &ode->next_mass) + { + if (tmpm->nid == nid) + return tmpm; + tmpm = tmpm->next; + } + + return NULL; +} + +MyMass* FindMassByXY(I64 x, I64 y) +{ + I64 dd, best_dd = I64_MAX; + MyMass *tmpm, *res = NULL; + tmpm = ode->next_mass; + while (tmpm != &ode->next_mass) + { + dd = SqrI64(tmpm->x - x) + SqrI64(tmpm->y - y); + if (dd < best_dd) + { + res = tmpm; + best_dd = dd; + } + + tmpm = tmpm->next; + } + + return res; +} + +I64 FindConnectIndex(MyMass *tmpm, I64 nid) +{ + I64 i; + for (i = 0; i < tmpm->num_connects; i++) + if (tmpm->connect_lst[i] == nid) + return i; + return -1; +} + +MySpring* PlaceSpring(MyMass *tmpm1, MyMass *tmpm2) +{ + MySpring *tmps = CAlloc(sizeof(MySpring)); + tmps->end1 = tmpm1; + tmps->end2 = tmpm2; + tmps->const = 10; + tmps->rest_len = 0; + tmps->color = LTGRAY; + QueueInsert(tmps, ode->last_spring); + return tmps; +} + +U0 RedoSprings() +{ + I64 i, k; + MyMass *tmpm, *tmpm1; + MySpring * tmps; + + QueueDel(&ode->next_spring, TRUE); + tmpm = ode->next_mass; + while (tmpm != &ode->next_mass) + { + for (i = 0; i < tmpm->num_connects; i++) + { + if ((k = tmpm->connect_lst[i]) && + (tmpm1 = FindMassByNID(k))) + { + tmps = PlaceSpring(tmpm, tmpm1); + switch (tmpm->type) + { + case AWT_MIXER: + if (!(tmpm->gain_lst[i] &0x80)) + { + //If not mute + tmps->color = GREEN; + tmps->const = 100; + } + + break; + case AWT_INPUT: + case AWT_SELECTOR: + case AWT_PIN_COMPLEX: + case AWT_VENDOR: + if (i == tmpm->cur_connect) + { + tmps->color = RED; + tmps->const = 100; + } + + break; + } + } + } + + tmpm = tmpm->next; + } +} + +U0 Init() +{ + ode = ODENew(0, 1e-4, ODEF_HAS_MASSES); + ode->derive = &MyDerivative; + ode->drag_v2 = 0.002; + ode->drag_v3 = 0.00001; + ode->acceleration_limit = 5e3; + + QueueInsert(ode, Fs->last_ode); +} + +U0 CleanUp() +{ + QueueRemove(ode); + QueueDel(&ode->next_mass, TRUE); + QueueDel(&ode->next_spring, TRUE); + ODEDel(ode); +} + +U0 HDCfgConnectLst(MyMass *tmpm, I64 cad, I64 nid) +{ + I64 i, j, connection_lst_len; + j = HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_CONNECT_LST_LEN); + connection_lst_len = j &127; + if (j & 128) + { + //Long form? + for (i = 0; i < connection_lst_len; i += 2) + { + j = HDWriteCORBSync(cad, nid, VERB_GET_CONNECT_LST + i); + tmpm->connect_lst[tmpm->num_connects++] = j.u16[0]; + if (i + 1 < connection_lst_len) + tmpm->connect_lst[tmpm->num_connects++] = j.u16[1]; + } + } + else + { + for (i = 0; i < connection_lst_len; i += 4) + { + j = HDWriteCORBSync(cad, nid, VERB_GET_CONNECT_LST + i); + tmpm->connect_lst[tmpm->num_connects++] = j.u8[0]; + if (i + 1 < connection_lst_len) + tmpm->connect_lst[tmpm->num_connects++] = j.u8[1]; + if (i + 2 < connection_lst_len) + tmpm->connect_lst[tmpm->num_connects++] = j.u8[2]; + if (i + 3 < connection_lst_len) + tmpm->connect_lst[tmpm->num_connects++] = j.u8[3]; + } + } +} + +U0 HDCfgTraverse(I64 cad, I64 nid) +{ + I64 i, j; + MyMass *tmpm = PlaceMass(nid); + j = HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_SUBNODE_CNT); + if (j.u16[0]) + { + tmpm->type = AWT_NODE; + for (i = j.u16[1]; i < j.u16[1] + j.u16[0]; i++) + HDCfgTraverse(cad, i); + } + else + { + tmpm->audio_widget_capabilities = + HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_AUDIO_WIDGET_CAP); + tmpm->pcm_size_rates = + HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_SAMPLE_SIZE_RATE_CAP); + tmpm->in_amp_cap = HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_INPUT_AMP_CAP); + tmpm->out_amp_cap = HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_OUTPUT_AMP_CAP); + tmpm->type = tmpm->audio_widget_capabilities >> 20 &15; + switch (tmpm->type) + { + case AWT_PIN_COMPLEX: + tmpm->pin_widget_ctl = + HDWriteCORBSync(cad, nid, VERB_PIN_WIDGET_CTL_GET); + tmpm->pin_capabilities = + HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_PIN_CAP); + if (Bt(&tmpm->pin_capabilities, 0) || + Bt(&tmpm->pin_capabilities, 2)) + tmpm->pin_sense = HDWriteCORBSync(cad, nid, VERB_PIN_SENSE_GET); + HDWriteCORBSync(cad, nid, VERB_CONNECT_SEL_SET + 0x00); + break; + case AWT_INPUT: + tmpm->disabled = TRUE; + case AWT_SELECTOR: + case AWT_VENDOR: + HDWriteCORBSync(cad, nid, VERB_CONNECT_SEL_SET + 0x00); + break; + } + + if (Bt(&tmpm->audio_widget_capabilities, 8)) + HDCfgConnectLst(tmpm, cad, nid); + } +} + +U0 HDCfgRandomizeXY() +{ + I64 h = Fs->pix_width, v = Fs->pix_height; + MyMass * tmpm; + tmpm = ode->next_mass; + while (tmpm != &ode->next_mass) + { + tmpm->x = RandU32 % (h - 2 *BORDER - FONT_WIDTH *6) + BORDER; + tmpm->y = RandU32 % (v - 2 *BORDER) + BORDER; + tmpm = tmpm->next; + } +} + +U0 HDCfgPopUpInfoTask(MyMass *tmpm) +{ + I64 i; + "$$FG,RED$$NID:$$FG$$0x%02X$$FG,RED$$Type:$$FG$$%Z\n", + tmpm->nid, tmpm->type, "ST_AUDIO_WIDGET_TYPES"; + + i = tmpm->audio_widget_capabilities; + "\n$$FG,RED$$Audio Widget Capabilities:$$FG$$\n"; + if (Bt(&i, 0)) + "Stereo,"; + if (Bt(&i, 1)) + "In Amp,"; + if (Bt(&i, 2)) + "Out Amp,"; + if (Bt(&i, 3)) + "AmpOverride,"; + if (Bt(&i, 4)) + "FmtOverride,"; + if (Bt(&i, 5)) + "Stripe,"; + if (Bt(&i, 6)) + "Proc Wgt,"; + if (Bt(&i, 7)) + "Unsolicited,"; + if (Bt(&i, 8)) + "Cnt Lst,"; + if (Bt(&i, 9)) + "Digital,"; + if (Bt(&i, 10)) + "Power Ctrl,"; + if (Bt(&i, 11)) + "Left/Right Swap,"; + "Delay:%d\n", i.u16[1] &0xF; + + i = tmpm->in_amp_cap; + "\n$$FG,RED$$Input Amp Capabilities:$$FG$$\n" + "Offset:0x%02X Steps:0x%02X StepSize:%5.2fdB Mutable:%d\n", + i &127, i.u8[1] &127 + 1, 0.25 *(i.u16[1] &127), Bt(&i, 31); + + i = tmpm->out_amp_cap; + "\n$$FG,RED$$Output Amp Capabilities:$$FG$$\n" + "Offset:0x%02X Steps:0x%02X StepSize:%5.2fdB Mutable:%d\n", + i &127, i.u8[1] &127 + 1, 0.25 *(i.u16[1] &127), Bt(&i, 31); + + "\n$$FG,RED$$Size Rates Capabilities:$$FG$$\n"; + for (i = 0; i < 21; i++) + if (Bt(&tmpm->pcm_size_rates, i)) + "%z", i, + " 8.0kHz\0 11.025kHz\0 16.0kHz\0 22.05kHz\0" + " 32.0kHz\0 44.1kHz\0 48.0kHz\0 88.2kHz\0" + " 96.0kHz\0 176.4kHz\0 192.0kHz\0 384kHz\0" + "\0\0\0\0" + " 8Bit\0 16bit\0 20Bit\0 24Bit\0 32Bit\0"; + '\n'; + + "\n$$FG,RED$$Connection Lst:$$FG$$\n"; + for (i = 0; i < tmpm->num_connects; i++) + "%02X,", tmpm->connect_lst[i]; + '\n'; + + "\n$$FG,RED$$Gain Lst:$$FG$$\n"; + for (i = 0; i < tmpm->num_connects; i++) + "%02X,", tmpm->gain_lst[i]; + '\n'; + + switch (tmpm->type) + { + case AWT_PIN_COMPLEX: + "\n$$FG,RED$$Pin Capabilities:$$FG$$\n"; + i = tmpm->pin_capabilities; + if (Bt(&i, 0)) + "Impedance Sense,"; + if (Bt(&i, 1)) + "Trigger Required,"; + if (Bt(&i, 2)) + "Presence Detect,"; + if (Bt(&i, 3)) + "Headphone Drive,"; + if (Bt(&i, 4)) + "Output,"; + if (Bt(&i, 5)) + "Input,"; + if (Bt(&i, 6)) + "Balanced,"; + if (Bt(&i, 16)) + "EAPD,"; + "Vref:%02X\n\n", i.u8[1]; + if (Bt(&tmpm->pin_capabilities, 0) || + Bt(&tmpm->pin_capabilities, 2)) + tmpm->pin_sense = HDWriteCORBSync(hda.cad, + tmpm->nid, VERB_PIN_SENSE_GET); + if (Bt(&tmpm->pin_capabilities, 0)) + "Impedance Measurement:%08X\n", tmpm->pin_sense &0x7FFFFFFF; + if (Bt(&tmpm->pin_capabilities, 2)) + "Presence:%d\n", Bt(&tmpm->pin_sense, 31); + "\n\nPin widget ctrl bits:\n" + "7: High phn enable (low impedance output amp)\n" + "6: Output Enable\n" + "5: Input Enable\n" + "0-2: Vref 0=HiZ 1=50% 2=Gnd 4=80% 5=100%\n"; + tmpm->pin_widget_ctl = I64Get("Widget Ctrl (0x%02X):", + tmpm->pin_widget_ctl, 0, 0xFF); + HDWriteCORBSync(hda.cad, tmpm->nid, + VERB_PIN_WIDGET_CTL_SET + tmpm->pin_widget_ctl); + break; + case AWT_INPUT: + "Disable"; + if (tmpm->disabled = YorN) + HDWriteCORBSync(hda.cad, tmpm->nid, VERB_CHAN_STREAM_ID_SET + 0x00); + else + HDWriteCORBSync(hda.cad, tmpm->nid, VERB_CHAN_STREAM_ID_SET + 0x20); + '\n'; + break; + case AWT_OUTPUT: + "Disable"; + if (tmpm->disabled = YorN) + HDWriteCORBSync(hda.cad, tmpm->nid, VERB_CHAN_STREAM_ID_SET + 0x00); + else + HDWriteCORBSync(hda.cad, tmpm->nid, VERB_CHAN_STREAM_ID_SET + 0x10); + '\n'; + break; + } +} + +U0 HDCfgPopUpInfo(MyMass *tmpm) +{ + U8 buf[STR_LEN]; + StrPrint(buf, + "HDCfgPopUpInfoTask(0x%X);\"\\n\\nPress SHIFT-ESC\\n\\n\\n\\n\";View;", + tmpm); + Fs->win_inhibit |= WIF_SELF_ODE; + Fs->draw_it = NULL; + Refresh; + PopUp(buf, Fs); + Fs->win_inhibit &= ~WIF_SELF_ODE; + Fs->draw_it = &DrawIt; +} + +U0 HDCfgEdLink(MyMass *tmpm_out, MyMass *tmpm_in) +{ + I64 i, j; + if ((i = FindConnectIndex(tmpm_in, tmpm_out->nid)) >= 0) + { + switch (tmpm_in->type) + { + case AWT_MIXER: + MemSet(tmpm_in->gain_lst, 0x80, sizeof(U8) *CONNECTS_NUM); + tmpm_in->gain_lst[i] = 0x7F; + for (j = 0; j < tmpm_in->num_connects; j++) + HDWriteCORBSync(hda.cad, tmpm_in->nid, + VERB_AMPLIFIER_GAIN_SET + 0x7000 + tmpm_in->gain_lst[j] + j << 8); + break; + case AWT_INPUT: + case AWT_SELECTOR: + case AWT_PIN_COMPLEX: + case AWT_VENDOR: + tmpm_in->cur_connect = i; + HDWriteCORBSync(hda.cad, tmpm_in->nid, VERB_CONNECT_SEL_SET + i); + break; + } + + RedoSprings; + } +} + +U0 HDCfgSave() +{ + CDoc *doc = DocNew; + I64 i; + MyMass * tmpm; + DocPrint(doc, "//This file was generated by " + "$$LK,\"::/TempleOS/Adam/Sound/HDCfg.ZC.Z\"," + "\"FI:::/TempleOS/Adam/Sound/HDCfg.ZC\"$$\n\n" + "U0 MyHDCfg()\n{\n"); + tmpm = ode->next_mass; + while (tmpm != &ode->next_mass) + { + DocPrint(doc, " //0x%02X %Z\n", tmpm->nid, tmpm->type, + "ST_AUDIO_WIDGET_TYPES"); + if (tmpm->num_connects) + { + DocPrint(doc, "//Connection Lst:"); + for (i = 0; i < tmpm->num_connects; i++) + { + if (i == tmpm->cur_connect) + DocPrint(doc, "*"); + DocPrint(doc, "0x%02X ", tmpm->connect_lst[i]); + } + + DocPrint(doc, "\n"); + if (tmpm->type == AWT_MIXER) + { + DocPrint(doc, "//Gain Lst:"); + for (i = 0; i < tmpm->num_connects; i++) + DocPrint(doc, "0x%02X ", tmpm->gain_lst[i]); + DocPrint(doc, "\n"); + } + } + + switch (tmpm->type) + { + case AWT_OUTPUT: + if (tmpm->disabled) + DocPrint(doc, + "HDWriteCORBSync(hda.cad,0x%02X," + "VERB_CHAN_STREAM_ID_SET+0x00);\n", + tmpm->nid); + else + DocPrint(doc, + "HDWriteCORBSync(hda.cad,0x%02X," + "VERB_CHAN_STREAM_ID_SET+0x10);\n", + tmpm->nid); + break; + case AWT_MIXER: + DocPrint(doc, + "HDWriteCORBSync(hda.cad,0x%02X," + "VERB_AMPLIFIER_GAIN_SET+0xB07F);\n", + tmpm->nid); + for (i = 0; i < tmpm->num_connects; i++) + DocPrint(doc, + "HDWriteCORBSync(hda.cad,0x%02X," + "VERB_AMPLIFIER_GAIN_SET+0x%04X);\n", + tmpm->nid, 0x7000 + tmpm->gain_lst[i] + i << 8); + break; + case AWT_INPUT: + if (tmpm->disabled) + DocPrint(doc, + "HDWriteCORBSync(hda.cad,0x%02X," + "VERB_CHAN_STREAM_ID_SET+0x00);\n", + tmpm->nid); + else + DocPrint(doc, + "HDWriteCORBSync(hda.cad,0x%02X," + "VERB_CHAN_STREAM_ID_SET+0x20);\n", + tmpm->nid); + goto here; + case AWT_PIN_COMPLEX: + DocPrint(doc, + "HDWriteCORBSync(hda.cad,0x%02X," + "VERB_PIN_WIDGET_CTL_SET+0x%02X);\n", + tmpm->nid, tmpm->pin_widget_ctl); + case AWT_SELECTOR: + case AWT_VENDOR: + here: + if (tmpm->num_connects > 1) + DocPrint(doc, + "HDWriteCORBSync(hda.cad,0x%02X," + "VERB_CONNECT_SEL_SET+0x%02X);\n", + tmpm->nid, tmpm->cur_connect); + break; + } + + DocPrint(doc, "\n"); + tmpm = tmpm->next; + } + + DocPrint(doc, "LBtr(&sys_semas[SEMA_SND],0);\n" + "}\n\nif (snd_dev==SD_HD_AUDIO)\n" + "MyHDCfg;\n"); + StrCopy(doc->filename.name, "~/HDAudioCfg.ZC.Z"); + DocWrite(doc); + DocDel(doc); +} + +U0 HDCfg() +{ + I64 arg1, arg2; + MyMass *tmpm1 = NULL, *tmpm2 = NULL; + + if (snd_dev != SD_HD_AUDIO) + { + "HD Audio not detected\n"; + return; + } + MenuPush( "File {" + " Abort(,CH_SHIFT_ESC);" + " Exit(,CH_ESC);" + "}" + "Edit {" + " Randomize(,'\n');" + " Options(,CH_SPACE);" + "}" +); + SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$ + DocBottom; + AutoComplete; + WinBorder; + WinMax; + DocCursor; + DocClear; + Fs->win_inhibit = WIF_SELF_MS_L | WIF_SELF_MS_R | WIG_DBL_CLICK | WIF_SELF_DOC; + Init; + + HDCfgTraverse(hda.cad, 0); + HDCfgRandomizeXY; + RedoSprings; + Fs->draw_it = &DrawIt; + PopUpOk( "This is a tool to cfgure\n" + "HD Audio.It creates $$FG,RED$$~/HDAudioCfg.ZC.Z$$FG$$\n" + "which you should $$FG,GREEN$$ +#include$$FG$$ in your\n" + "$$FG,RED$$~/HomeSnd.ZC.Z$$FG$$ file.\n\n\n" + "Left click to see info and cfgure a widget.\n" + "Right click drag to connect output to input.\n\n" + "You will need to set input and output amplifier\n" + "gains by hand -- edit $$FG,RED$$~/HDAudioCfg.ZC.Z$$FG$$.\n\n" + "The $$FG,BLUE$$BLUE$$FG$$ line in the middle is microphone waveform.\n\n" +); + + HDRun(TRUE, TRUE); //run input output + + try + { + while (TRUE) + { + switch (MessageGet(&arg1, &arg2, + 1 << MESSAGE_MS_L_UP | 1 << MESSAGE_MS_R_DOWN | 1 << MESSAGE_MS_R_UP | 1 << MESSAGE_KEY_DOWN)) + { + case MESSAGE_MS_L_UP: + if (tmpm1 = FindMassByXY(arg1, arg2)) + HDCfgPopUpInfo(tmpm1); + tmpm1 = NULL; + break; + case MESSAGE_MS_R_DOWN: + tmpm1 = FindMassByXY(arg1, arg2); + break; + case MESSAGE_MS_R_UP: + tmpm2 = FindMassByXY(arg1, arg2); + if (tmpm1 && tmpm2) + HDCfgEdLink(tmpm1, tmpm2); + break; + case MESSAGE_KEY_DOWN: + switch (arg1) + { + case CH_SPACE: + if (tmpm1 = FindMassByXY( mouse.pos.x - Fs->pix_left - Fs->scroll_x, + mouse.pos.y - Fs->pix_top - Fs->scroll_y)) + HDCfgPopUpInfo(tmpm1); + tmpm1 = NULL; + break; + case '\n': + HDCfgRandomizeXY; + break; + case CH_ESC: + HDCfgSave; + case CH_SHIFT_ESC: + goto hd_done; + } + + break; + } + } + + hd_done: //Don't goto out of try + MessageGet(,, 1 << MESSAGE_KEY_UP); + } + + catch + Fs->catch_except = TRUE; + SettingsPop; + HDStop(TRUE, FALSE); //stop input + CleanUp; + MenuPop; + "$$BK,1$$Note: +#include \"~/HDAudioCfg\" in your start-up scripts." + "$$BK,0$$\n"; +} + +HDCfg; \ No newline at end of file diff --git a/src/Home/Sound/HDAudio1/Sup1Snd/MakeSnd.ZC b/src/Home/Sound/HDAudio1/Sup1Snd/MakeSnd.ZC new file mode 100644 index 00000000..0db0b214 --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1Snd/MakeSnd.ZC @@ -0,0 +1,21 @@ +Cd(__DIR__);; + +#help_index "Sound" +class CSndWaveCtrl +{ + I64 sample_rate,sample_bits,channels; + F64 freq_multiplier,amp_multiplier; + F64 phase,last_y,last_dydt,next_y; +}; + +public U0 SoundTaskEndCB() +{//Will turn-off snd when a task gets killed. + Sound; + Exit; +} + +#include "SndMath" +#include "SndMusic" +#include "SndEffects" +#include "SndFile" +Cd("..");; diff --git a/src/Home/Sound/HDAudio1/Sup1Snd/SndEffects.ZC b/src/Home/Sound/HDAudio1/Sup1Snd/SndEffects.ZC new file mode 100644 index 00000000..a6dee171 --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1Snd/SndEffects.ZC @@ -0,0 +1,80 @@ +#help_index "Sound" + +#define SE_NOISE 0 +#define SE_SWEEP 1 + +class CSoundEffectFrame +{ + I32 type; + I8 ona1,ona2; + F64 duration; +}; + +U0 SoundEffectEndTaskCB() +{ + Free(FramePtr("CSoundEffectFrame")); + music.mute--; + SoundTaskEndCB; +} + +U0 SoundEffectTask(CSoundEffectFrame *ns) +{ + I64 i,ona; + F64 t0=tS,t,timeout=t0+ns->duration; + FramePtrAdd("CSoundEffectFrame",ns); + Fs->task_end_cb=&SoundEffectEndTaskCB; + switch (ns->type) { + case SE_NOISE: + i=MaxI64(ns->ona2-ns->ona1,1); + while (tSona1; + Sound(ona); + t=Clamp(3000.0/Ona2Freq(ona),1.0,50.0); + if (t+tS>timeout) + t=timeout-tS; + Sleep(t); + } + break; + case SE_SWEEP: + while (tSduration; + ona=(1.0-t)*ns->ona1+t*ns->ona2; + Sound(ona); + t=Clamp(3000.0/Ona2Freq(ona),1.0,50.0); + if (t+tS>timeout) + t=timeout-tS; + Sleep(t); + } + break; + } +} + +public CTask *Noise(I64 mS,F64 min_ona,F64 max_ona) +{//Make white noise for given number of mS. + CSoundEffectFrame *ns; + if (mS>0) { + ns=MAlloc(sizeof(CSoundEffectFrame)); + ns->type=SE_NOISE; + ns->duration=mS/1000.0; + ns->ona1=min_ona; + ns->ona2=max_ona; + music.mute++; + return Spawn(&SoundEffectTask,ns,"Noise",,Fs); + } else + return NULL; +} + +public CTask *Sweep(I64 mS,F64 ona1,F64 ona2) +{//Sweep through freq range in given number of mS. + CSoundEffectFrame *ns; + if (mS>0) { + ns=MAlloc(sizeof(CSoundEffectFrame)); + ns->type=SE_SWEEP; + ns->duration=mS/1000.0; + ns->ona1=ona1; + ns->ona2=ona2; + music.mute++; + return Spawn(&SoundEffectTask,ns,"Noise",,Fs); + } else + return NULL; +} diff --git a/src/Home/Sound/HDAudio1/Sup1Snd/SndFile.ZC b/src/Home/Sound/HDAudio1/Sup1Snd/SndFile.ZC new file mode 100644 index 00000000..97c3fbf1 --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1Snd/SndFile.ZC @@ -0,0 +1,137 @@ +#help_index "Sound/Sound Files" +#define SNDFILE_SAMPLE_RATE 8000 +//Header for a ".SND" file +class CFileSND +{//big endian + U32 signature; //0x646e732e + U32 offset; //24 + U32 data_size; + U32 coding; //3=16bit uncompressed + U32 sample_rate; //Hz + U32 channels; //1=mono + I16 body[1]; +}; + +//Windows media constraint. +//#define SND_FILE_DATA_MAX 0x0007FF00 +#define SND_FILE_DATA_MAX 0x7FFFFF00 + +public I64 SndFileCreate(U8 *base_filename,F64 normalized_vol=1.0, + F64 averaging=0.0,I64 waveform=WF_SQUARE, + F64 reverb_delay=0,F64 reverb_intensity=0,F64 time_shift=0) +{//Use "screencast.record" flag to start or stop recording, then call this routine. +//Averaging should be a num from 0.0 to 0.999. + //Vol should be from 0.0 to 1.0. + //Set reverb_delay to like 0.3 sec and reverb_intensity to like 0.4. + I64 i,i1,k,cnt,cnt2,level,file_num; + F64 avg,dt; + CFileSND *s; + CSndWaveCtrl *swc=SndWaveCtrlNew(SNDFILE_SAMPLE_RATE,16,1); + CSoundData *d,*d1; + U8 *name,*name2; + + screencast.record=FALSE; + + dt=screencast.sound_head.last->tS-screencast.sound_head.next->tS; + if (!dt) return 0; + cnt=dt*SNDFILE_SAMPLE_RATE; + cnt++; //Terminator + + name=StrNew(base_filename); + FileExtRemove(name); + + s=CAlloc(offset(CFileSND.body)+cnt*sizeof(I16)); + s->signature=0x646e732e; + s->offset=EndianU32(offset(CFileSND.body)); + s->coding=EndianU32(3); + s->sample_rate=EndianU32(SNDFILE_SAMPLE_RATE); + s->channels=EndianU32(1); + + if (time_shift) { + d=screencast.sound_head.next; + d->tS-=time_shift; + while (d->next!=&screencast.sound_head) { + d1=d->next; + dt=d1->tS-d->tS; + if (dt<0) { + QueueRemove(d1); + Free(d1); + } else + break; + } + } + + d=screencast.sound_head.next; + k=0; + i=d->tS*SNDFILE_SAMPLE_RATE; + while (d->next!=&screencast.sound_head) { + d1=d->next; + i1=d1->tS*SNDFILE_SAMPLE_RATE; + if (i1-i) { + SndWaveAddBuf(swc,&s->body[k],i1-i, + Ona2Freq(d->ona),waveform,normalized_vol); + k+=i1-i; + i=i1; + } + QueueRemove(d); + Free(d); + d=d1; + } + + //Average + if (averaging) { + avg=0; + for (i=0;ibody[i]=avg=LowPass1(averaging,avg,s->body[i],1.0); + } + + //Reverb + if (reverb_intensity) { + if (dt=reverb_delay*SNDFILE_SAMPLE_RATE) + for (i=dt;ibody[i]+=reverb_intensity*s->body[i-dt]; + } + + //Get rid of D.C. component + for (k=0;k<3;k++) { + level=0; + for (i=0;ibody[i]; + level/=cnt-1; + for (i=0;ibody[i]=ClampI64(s->body[i]-level,I16_MIN,I16_MAX); + } + + for (i=0;ibody[i]=EndianU16(s->body[i]); + + s->body[cnt-1]=0; + + d=screencast.sound_head.next; + while (d!=&screencast.sound_head) { + d1=d->next; + QueueRemove(d); + Free(d); + d=d1; + } + + name2=MAlloc(StrLen(name)+3+1+3+1); + cnt2=cnt; + file_num=0; + while (cnt2>0) { + i=cnt2; + if (i>SND_FILE_DATA_MAX) + i=SND_FILE_DATA_MAX; + s->data_size=EndianU32(i*sizeof(I16)); + MemCopy(s->body,&s->body[file_num*SND_FILE_DATA_MAX],i*sizeof(I16)); + StrPrint(name2,"%s%03d.SND",name,file_num++); + FileWrite(name2,s,offset(CFileSND.body)+i*sizeof(I16)); + cnt2-=i; + } + Free(s); + Free(name); + Free(name2); + + SndWaveCtrlDel(swc); + return cnt; +} diff --git a/src/Home/Sound/HDAudio1/Sup1Snd/SndMath.ZC b/src/Home/Sound/HDAudio1/Sup1Snd/SndMath.ZC new file mode 100644 index 00000000..c767d4df --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1Snd/SndMath.ZC @@ -0,0 +1,248 @@ +#help_index "Sound/Math;Math" +public F64 Saw(F64 t,F64 period) +{//Sawtooth. 0.0 - 1.0 think "(Sin+1)/2" + if (period) { + if (t>=0.0) + return t%period/period; + else + return 1.0+t%period/period; + } else + return 0.0; +} + +public F64 FullSaw(F64 t,F64 period) +{//Plus&Minus Sawtooth. 1.0 - -1.0 think "Sin" + if (period) { + if (t>=0.0) + return 2.0*(t%period/period)-1.0; + else + return 2.0*(t%period/period)+1.0; + } else + return 0.0; +} + +public F64 Caw(F64 t,F64 period) +{//Cawtooth. 1.0 - 0.0 think "(Cos+1)/2" + if (period) { + if (t>=0.0) + return 1.0-t%period/period; + else + return -(t%period)/period; + } else + return 1.0; +} + +public F64 FullCaw(F64 t,F64 period) +{//Plus&Minus Cawtooth. 1.0 - -1.0 think "Cos" + if (period) { + if (t>=0.0) + return -2.0*(t%period/period)+1.0; + else + return -2.0*(t%period/period)-1.0; + } else + return 1.0; +} + +public F64 Tri(F64 t,F64 period) +{//Triangle waveform. 0.0 - 1.0 - 0.0 + if (period) { + t=2.0*(Abs(t)%period)/period; + if (t<=1.0) + return t; + else + return 2.0-t; + } else + return 0.0; +} + +public F64 FullTri(F64 t,F64 period) +{//Plus&Minus Triangle waveform. 0.0 - 1.0 - 0.0 - -1.0 -0.0 + if (period) { + t=4.0*(t%period)/period; + if (t<=-1.0) { + if (t<=-3.0) + return t+4.0; + else + return -2.0-t; + } else { + if (t<=1.0) + return t; + else if (t<=3.0) + return 2.0-t; + else + return t-4.0; + } + } else + return 0.0; +} + +#help_index "Sound/Math" + +public I8 Note2Ona(I64 note,I64 octave=4) +{//Note to ona. Mid C is ona=51, note=3 and octave=4. + if (note<3) + return (octave+1)*12+note; + else + return octave*12+note; +} + +public I8 Ona2Note(I8 ona) +{//Ona to note in octave. Mid C is ona=51, note=3 and octave=4. + return ona%12; +} + +public I8 Ona2Octave(I8 ona) +{//Ona to octave. Mid C is ona=51, note=3 and octave=4. + I64 note=ona%12,octave=ona/12; + if (note<3) + return octave-1; + else + return octave; +} + +F64 SinPhaseCont(F64 last_y,F64 last_dydt, + F64 current_amp,F64 phase_offset) +{//Next sample of sin waveform. + F64 phase; + phase=last_y/current_amp; + if (phase>1.0) phase=1.0; + if (phase<-1.0) phase=-1.0; + if (last_dydt<0) + phase=ã-ASin(phase); + else + phase=ASin(phase); + return phase-phase_offset; +} + +public CSndWaveCtrl *SndWaveCtrlNew(I64 sample_rate=8000,I64 sample_bits=24, + I64 channels=2,CTask *mem_task=NULL) +{//MAlloc ctrl struct for generating waveforms. + CSndWaveCtrl *swc=CAlloc(sizeof(CSndWaveCtrl),mem_task); + swc->freq_multiplier=1.0; + swc->amp_multiplier=1.0; + swc->sample_rate=sample_rate; + swc->sample_bits=sample_bits; + swc->channels=channels; + swc->last_dydt=1.0; + return swc; +} + +public U0 SndWaveCtrlDel(CSndWaveCtrl *swc) +{//Free waveform ctrl. + Free(swc); +} + +#define WF_NULL 0 +#define WF_SQUARE 1 +#define WF_SINE 2 +#define WF_TRI 3 +#define WF_SAWTOOTH 4 +#define WF_NOISE 5 +#define WF_WAVEFORMS_NUM 6 + +public U0 SndWaveAddBuf(CSndWaveCtrl *swc,U8 *buf,I64 num_samples, + F64 _freq,I64 _waveform=WF_SQUARE,F64 _amp=1.0,F64 _left=1.0, F64 _right=1.0) +{//Add waveform to buffer. +//num_samples is multiplied by channels to get buf_len. + //left,right range from 0.0-1.0 + //Supports 16,24 and 32 bits + I64 reg i,reg j,reg k; + F64 a,f,amp,reg phase; + if (!swc) return; + _freq*=swc->freq_multiplier; + _amp*=swc->amp_multiplier; + if (!_freq||!_amp) { + swc->last_y=swc->phase=0; + swc->last_dydt=1.0; + } else { + phase=swc->phase; + i=0; + amp=Min(I32_MAX,I32_MAX*_amp); + f=2*ã/swc->sample_rate*_freq; + switch (_waveform) { + case WF_NOISE: + a=2.0/ã*amp; + break; + case WF_SAWTOOTH: + a=amp/ã; + break; + case WF_SINE: + phase=SinPhaseCont(swc->last_y,swc->last_dydt,amp,0.0); + break; + } + while (phase<0) + phase+=2*ã; + while (phase>=2*ã) + phase-=2*ã; + num_samples*=swc->channels; + while (i=ã) + j=-amp; + else + j=amp; + break; + case WF_SINE: + j=amp*Sin(phase); + break; + case WF_TRI: + if (phase>=ã) { + swc->last_y=swc->next_y; + swc->next_y=-amp*Sign(swc->last_y)+.00001; + phase-=ã; + } + j=(swc->last_y*(ã-phase)+swc->next_y*phase)/ã; + break; + case WF_SAWTOOTH: + j=a*(phase-ã); + break; + case WF_NOISE: + if (phase<ã) { + if (phaselast_y=swc->next_y; + swc->next_y=a*RandI16/U16_MAX; + } + j=swc->last_y*(ã-phase)+swc->next_y*phase; + } else { + if (phase-ãlast_y=swc->next_y; + swc->next_y=a*RandI16/U16_MAX; + } + j=swc->last_y*(2.0*ã-phase)+swc->next_y*(phase-ã); + } + break; + } +//left channel + k=j*_left; + if (swc->sample_bits==16) { + k>>=16; + buf(I16 *)[i++]+=k; + } else { + if (swc->sample_bits==24) + k&=0xFFFFFF00; + buf(I32 *)[i++]+=k; + } +//right channel + if (swc->channels==2) { + k=j*_right; + if (swc->sample_bits==16) { + k>>=16; + buf(I16 *)[i++]+=k; + } else { + if (swc->sample_bits==24) + k&=0xFFFFFF00; + buf(I32 *)[i++]+=k; + } + } + phase+=f; + while (phase>=2*ã) + phase-=2*ã; + } + if (_waveform==WF_SINE) { + swc->last_y=amp*Sin(phase); + swc->last_dydt=Cos(phase); + } + swc->phase=phase; + } +} diff --git a/src/Home/Sound/HDAudio1/Sup1Snd/SndMusic.ZC b/src/Home/Sound/HDAudio1/Sup1Snd/SndMusic.ZC new file mode 100644 index 00000000..464aff6b --- /dev/null +++ b/src/Home/Sound/HDAudio1/Sup1Snd/SndMusic.ZC @@ -0,0 +1,224 @@ +#help_index "Sound/Music" + +public class CMusicGlbls +{ + U8 *cur_song; + CTask *cur_song_task; + I64 octave; + F64 note_len; + U8 note_map[7]; + Bool mute; + I64 meter_top,meter_bottom; + F64 tempo,stacatto_factor; + + //If you wish to sync with a + //note in a Play() string. 0 is the start + I64 play_note_num; + + F64 tM_correction,last_Beat,last_tM; +} music={NULL,NULL,4,1.0,{0,2,3,5,7,8,10},FALSE,4,4,2.5,0.9,0,0,0,0}; + +#help_index "Sound/Music;Time/Seconds" +public F64 tM() +{//Time in seconds synced to music subsystem. + return (counts.jiffies+music.tM_correction)/JIFFY_FREQ; +} + +public F64 Beat() +{//Time in music beats. + F64 res,cur_tM; + PUSHFD + CLI + if (mp_count>1) + while (LBts(&sys_semas[SEMA_TMBEAT],0)) + PAUSE + cur_tM=tM; + res=music.last_Beat; + if (music.tempo) + res+=(cur_tM-music.last_tM)*music.tempo; + music.last_tM=cur_tM; + music.last_Beat=res; + LBtr(&sys_semas[SEMA_TMBEAT],0); + POPFD + return res; +} + +#help_index "Sound/Music" +U8 *MusicSetOctave(U8 *st) +{ + I64 ch; + ch=*st++; + while ('0'<=ch<='9') { + music.octave=ch-'0'; + ch=*st++; + } + return --st; +} + +U8 *MusicSetMeter(U8 *st) +{ + I64 ch; + ch=*st++; + while (ch=='M') { + ch=*st++; + if ('0'<=ch<='9') { + music.meter_top=ch-'0'; + ch=*st++; + } + if (ch=='/') + ch=*st++; + if ('0'<=ch<='9') { + music.meter_bottom=ch-'0'; + ch=*st++; + } + } + return --st; +} + +U8 *MusicSetNoteLen(U8 *st) +{ + Bool cont=TRUE; + do { + switch (*st++) { + case 'w': music.note_len=4.0; break; + case 'h': music.note_len=2.0; break; + case 'q': music.note_len=1.0; break; + case 'e': music.note_len=0.5; break; + case 's': music.note_len=0.25; break; + case 't': music.note_len=2.0*music.note_len/3.0; break; + case '.': music.note_len=1.5*music.note_len; break; + default: + st--; + cont=FALSE; + } + } while (cont); + return st; +} + +public U0 Play(U8 *st,U8 *words=NULL) +{/* Notes are entered with a capital letter. + +Octaves are entered with a digit and +stay set until changed. Mid C is octave 4. + +Durations are entered with +'w' whole note +'h' half note +'q' quarter note +'e' eighth note +'t' sets to 2/3rds the current duration +'.' sets to 1.5 times the current duration +durations stay set until changed. + +'(' tie, placed before the note to be extended + +$LK,"music.meter_top",A="MN:CMusicGlbls"$,$LK,"music.meter_bottom",A="MN:CMusicGlbls"$ is set with +"M3/4" +"M4/4" +etc. + +Sharp and flat are done with '#' or 'b'. + +The var music.stacatto_factor can +be set to a range from 0.0 to 1.0. + +The var music.tempo is quarter-notes +per second.It defaults to +2.5 and gets faster when bigger. +*/ + U8 *word,*last_st; + I64 note,octave,i=0,ona,timeout_val,timeout_val2; + Bool tie; + F64 d,on_jiffies,off_jiffies; + music.play_note_num=0; + while (*st) { + timeout_val=counts.jiffies; + tie=FALSE; + + do { + last_st=st; + if (*st=='(') { + tie=TRUE; + st++; + } else { + st=MusicSetMeter(st); + st=MusicSetOctave(st); + st=MusicSetNoteLen(st); + } + } while (st!=last_st); + + if (!*st) break; + note=*st++-'A'; + if (note<7) { + note=music.note_map[note]; + octave=music.octave; + if (*st=='b') { + note--; + if (note==2) + octave--; + st++; + } else if (*st=='#') { + note++; + if (note==3) + octave++; + st++; + } + ona=Note2Ona(note,octave); + } else + ona=0; + if (words && (word=ListSub(i++,words)) && StrCompare(word,"")) + "%s",word; + d=JIFFY_FREQ*music.note_len/music.tempo; + if (tie) { + on_jiffies =d; + off_jiffies =0; + } else { + on_jiffies =d*music.stacatto_factor; + off_jiffies =d*(1.0-music.stacatto_factor); + } + timeout_val+=on_jiffies; + timeout_val2=timeout_val+off_jiffies; + + if (!music.mute) + Sound(ona); + SleepUntil(timeout_val); + music.tM_correction+=on_jiffies-ToI64(on_jiffies); + + if (!music.mute) + Sound; + SleepUntil(timeout_val2); + music.tM_correction+=off_jiffies-ToI64(off_jiffies); + + music.play_note_num++; + } +} + +U0 MusicSettingsReset() +{ + music.play_note_num=0; + music.stacatto_factor=0.9; + music.tempo=2.5; + music.octave=4; + music.note_len=1.0; + music.meter_top=4; + music.meter_bottom=4; + SoundReset; + PUSHFD + CLI + if (mp_count>1) + while (LBts(&sys_semas[SEMA_TMBEAT],0)) + PAUSE + music.last_tM=tM; + music.last_Beat=0.0; + LBtr(&sys_semas[SEMA_TMBEAT],0); + POPFD +} + +MusicSettingsReset; + +U0 CurSongTask() +{ + Fs->task_end_cb=&SoundTaskEndCB; + while (TRUE) + Play(music.cur_song); +} diff --git a/src/Kernel/KernelA.HH b/src/Kernel/KernelA.HH index 94aa3200..e1b91c84 100755 --- a/src/Kernel/KernelA.HH +++ b/src/Kernel/KernelA.HH @@ -2663,12 +2663,25 @@ class CSMBIOSBatteryInfo #define PCIR_MIN_GRANT 0x3E #define PCIR_MAX_LATENCY 0x3F +// PCI Command Register bit flags +#define PCI_CMDf_IOEN 0 // I/O Space Enable +#define PCI_CMDf_MSEN 1 // Memory Space Enable +#define PCI_CMDf_BMEN 2 // Bus Master Enable +#define PCI_CMDf_INTD 10 // Interrupt Disable + +#define PCI_CMDF_IOEN (1 << PCI_CMDf_IOEN) +#define PCI_CMDF_MSEN (1 << PCI_CMDf_MSEN) +#define PCI_CMDF_BMEN (1 << PCI_CMDf_BMEN) +#define PCI_CMDF_INTD (1 << PCI_CMDf_INTD) + //PCI class codes #define PCIC_STORAGE 0x1 #define PCIC_NETWORK 0x2 +#define PCIC_MULTIMEDIA 0x4 //PCI subclass codes #define PCISC_ETHERNET 0x0 +#define PCISC_AUDIO 0x3 #define PCISC_AHCI 0x6 //PCI I/O ports diff --git a/src/Kernel/PCI.ZC b/src/Kernel/PCI.ZC index 8d7c5d87..14fdfaed 100755 --- a/src/Kernel/PCI.ZC +++ b/src/Kernel/PCI.ZC @@ -69,14 +69,14 @@ U0 PCIWriteU32(I64 bus, I64 dev, I64 fun, I64 rg, I64 val) } } - U0 PCIWriteU8(I64 bus, I64 dev, I64 fun, I64 rg, I64 val) {//Write U8 in PCI configspace at bus, dev, fun, reg. if (sys_pci_services) PCIBIOSWriteU8(bus, dev, fun, rg, val); else { - PCIWriteU32(bus, dev, fun, rg, val & 0xFF); + val = PCIReadU32(bus, dev, fun, rg) & ~0xFF | val & 0xFF; + PCIWriteU32(bus, dev, fun, rg, val); } } @@ -86,7 +86,8 @@ U0 PCIWriteU16(I64 bus, I64 dev, I64 fun, I64 rg, I64 val) PCIBIOSWriteU16(bus, dev, fun, rg, val); else { - PCIWriteU32(bus, dev, fun, rg, val & 0xFFFF); + val = PCIReadU32(bus, dev, fun, rg) & ~0xFFFF | val & 0xFFFF; + PCIWriteU32(bus, dev, fun, rg, val); } }