Ethin wrote:Does this mean that checking the STATESTS register (offset 0Ah), and determining what links are active, is the right path? Then, for each bit that is set, does this mean the offset from 80H?
My code never looks at the STATESTS register. It appears to be there partly to support machines with a detachable codec, but I don't expect to encounter any of those. It also refers to the whole codec, and it doesn't tell you the location of anything. When you reset the codec, you do it using CRST in the Global Control Register at 08h and there's no need to check STATESTS.
* Edit (important correction) - STATESTS is used to tell you which codecs are present and it enables you to work out the value for the CAd field in the commands that you send via CORB. I haven't worked with HDA for a few years so I've forgotten a lot of the details. (Expect more mistakes along the way - I'll put them right as we go.)
To help get you and Klakap started, I'll describe what my code originally did to get CORB and RIRB functioning. I always write directly in machine code and that is my source code, but I'll translate from there directly into English:-
(1) I start by putting the address of the memory mapped ports for HDA in register ESI (and you need to get that information from the PCI ports in advance). I later use instructions that take offsets to address different ports while keeping the value in ESI unchanged, as you'll see as we go along.
(2) I then load EAX with the address of the buffer I want to use for CORB.
(3) I post that address to ESI+40h which is the HDA register used by HDA to determine where my CORB buffer is. That's just the lower 32 bits of the address, but I send the upper bits later.
(4) I copy the address of the CORB buffer to register EDI for further use later when I start writing commands to it.
(5) I load EAX with the address of the buffer I want to use for RIRB.
(6) I post that address to ESI+50h which is the HDA register used by HDA to determine where my RIRB buffer is.
(7) I set EAX to 0 then post that to ESI+44h and also to ESI+54h to set the higher bits of both of the 64-bit buffer addresses.
(8) I then write lots of commands into my CORB buffer with the help of EDI which contains its address, starting with a null instruction in case the first instruction isn't run. I'll leave it to you to work out your own commands.
(9) I put the number of commands in AL, then post that value to ESI+48h to tell HDA how many commands it needs to process.
(10) I create a value in AX which has AL=0 and AH=80h, then push it onto the stack. (In other words, I set bit-15 and reset the rest.)
(11) I send that value to ESI+4A to reset the CORB read-pointer.
(12) I set up a delay loop value of 256 in ECX, then loop repeatedly to run it down to zero. I do this solely because I don't like hammering ports while waiting for things to be reset. The spec does not tell you to do this and it is likely completely unnecessary, but I've burned out ports in the past by polling them aggressively and so I don't take chances with them.
(13) I read the port back (ESI+4A) and jump back to repeat step (12) if it isn't ready. To tell if it's ready, I rotate bit-15 into the carry flag.
(14) I set AX to zero and send that to the same port (ESI+4A).
(15) I set up a delay loop as before and run it down to zero.
(16) I read the port back and jump back to step (15) if it isn't ready. Again I rotate bit-15 into the carry flag, but this time the value of the bit must be 0 before we can move on.
(17) I recover (to EAX) the value on the stack which was put there in step (10). I then post that value to ESI+58h to set the RIRB write-pointer to the right place for the replies from the codec.
(18) I read (into AL) RIRB's control register using ESI+5C. I then OR it with 2 (to set the bit that will start the DMA engine, then AND it with 250 (to make sure bits 0 and 2 are zero because I don't want interrupts generated), then write the result back to the same control register to start RIRB's DMA engine.
(19) I read (into AL) CORB's control register using ESI+4C. I then OR it with 2 (to set the bit that will start the DMA engine), then AND it with 254 (to make sure bit-0 is zero, again to avoid interrupts), then write the result back to the same control register to start CORB's DMA engine.
(20) I now wait for the codec's replies to appear in my RIRB buffer and watch for changes to the write-pointer to see when replies arrive. (Note that some responses can come in without responding to a command, such as when a microphone or headphones are plugged in or removed, so if you don't want to use interrupts at all, you'll want your software to check the write pointer perhaps once a second, but you don't have to worry about that at this stage.)
I later wrote more complex code to keep pace with CORB and RIRB write and read locations so that my device driver can send commands and read responses whenever it needs to, but you'll want to design code for all of that yourself. Whenever you need to send more commands, you simply write them at the current read location in the CORB buffer and then use port 48h to tell the DMA engine how many new commands it needs to process. You shouldn't need to use any ports other than the ones I used in those 20 steps for handling CORB and RIRB.