OSDev.org
https://forum.osdev.org/

How to play sound Intel HD Audio?
https://forum.osdev.org/viewtopic.php?f=1&t=34525
Page 4 of 5

Author:  Ethin [ Wed Oct 30, 2019 6:41 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

Apologies for bumping this topic, but I've got the CORB and RIRB set up and all works (I think, anyway). This is what I do:
1) I reset the controller by setting the CRST bit and waiting for that to show as set. I do not clear this bit (the specification does not say I need to do so).
2) I sleep for an additional 10 RTC ticks, which on my OS is about 1.221 µs (to allow all codecs -- even slow ones -- to initialize). The specification only says that 521 Us is required, but I wait a bit longer just in case.
3) I set bits 14:0 on WAKEEN and post that to the controller.
4) I clear bits 1:0 on corbctl and post that.
5) I set corbsize to 0100 to allow 256 entries (thank you, Linux) and post that.
6) I generate a random 64-bit address for the CORB and align it on a 128-byte boundry as the specification indicates. I double-verify this alignment before submitting it, and if bits 63:48 are set, I clear them to avoid a processor exception. I write bits 31:0 of the address to Corblbase and bits 63:32 to corbubase. A similar process occurs with the RIRB.
7) Before I set up the RIRB, I set Corbwp to 0 and reset Corbrp.
8) I set up the RIRB following an identical address and size setting process as above. When setting Rirbctl, I clear bits 2:0.
9) I set bit 1 in Corbctl and Rirbctl to start both engines.
10) I perform a final check by verifying that bit 0 of Corbsts is clear. If its set, I know I've hit a CMEI and panic.
At this point I think I've got everything initialized and ready to go. The only issue is exactly how to send a command to a node. Bits 31:28 are the codec address; is there a way I can determine this? Similar question for the node index.

Author:  DavidCooper [ Thu Oct 31, 2019 2:12 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

Good to see that you've got so far with it. You should know the codec number from STATESTS. From the top of page 61 we have:-

Code:
4.3 Codec Discovery
When the link is enabled by the assertion of CRST, the codecs will detect the de-assertion of the RESET# signal and request a status change and enumeration by the controller.  As the controller hardware detects these requests, it will provide the codecs with their unique addresses and set the controller STATESTS bits to indicate that a Status Change event was detected on the appropriate SDATA_INx signals.  Software can use these bits to determine the addresses of the codecs attached to the link.  A 1 in a given bit position indicates that a codec at that associated address is present.  For instance, a value of 05h means that there are codecs with addresses 0 and 2 attached to the link.


And the offset for that is 0Eh:-

Code:
3.3.9  Offset 0Eh:  STATESTS – State Change Status Length: 2 bytes
Table 10. Wake Status

Bit: 15
Type: RsvdZ
Reset: 0‟s
Description: Reserved

Bits: 14:0
Type: RW1CS, RSM
Reset: 0‟s
Description: SDIN State Change Status Flags (SDIWAKE):  Flag bits that indicate which SDIN signal(s) received a “State Change” event.  The bits are cleared by writing 1‟s to them.  The SDATA_IN[0] line corresponds to bit 0, etc. These bits are only cleared by a power-on reset.

The SDIWAKE bits are used to indicate that a “Status Change” event has occurred on the link, which usually indicates that either the codec has just come out of reset and is requesting an address, or that a codec is signaling a wake event.  The controller hardware will perform the resulting address cycle on the bus, and set this bit to inform the software that the event has occurred.  The setting of this bit may cause a processor interrupt to occur if the appropriate WAKEEN bits (Section 3.3.8) are set.


The node index (NID) is 0 for the root node, so you start with that set to zero and use it with verb F00h and paramater 04h to return the range of NIDs representing function groups. You then change the NID to that of a function group to ask it if it's an AFG (using F00h again but with parameter 05h), and once you've found the AFG group (the response will have the lowest byte = 1 for the AFG group) you can use parameter 04h with that NID to get it to return the range of NIDs that are HDA widgets. When interpreting the response for parameter 04h, the byte using bits 23-16 are the first NID in the range of relevant NIDs, and the byte using bits 7-0 holds the number of nodes (the range of relevant NIDs, including the first one). When you use this with the root node, you'll likely only find one group and it will be the AFG group. When you use it with the AFG group node, you should find a range covering two to three dozen widgets.

Author:  Ethin [ Thu Oct 31, 2019 6:10 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

DavidCooper wrote:
Good to see that you've got so far with it. You should know the codec number from STATESTS. From the top of page 61 we have:-

Code:
4.3 Codec Discovery
When the link is enabled by the assertion of CRST, the codecs will detect the de-assertion of the RESET# signal and request a status change and enumeration by the controller.  As the controller hardware detects these requests, it will provide the codecs with their unique addresses and set the controller STATESTS bits to indicate that a Status Change event was detected on the appropriate SDATA_INx signals.  Software can use these bits to determine the addresses of the codecs attached to the link.  A 1 in a given bit position indicates that a codec at that associated address is present.  For instance, a value of 05h means that there are codecs with addresses 0 and 2 attached to the link.


And the offset for that is 0Eh:-

Code:
3.3.9  Offset 0Eh:  STATESTS – State Change Status Length: 2 bytes
Table 10. Wake Status

Bit: 15
Type: RsvdZ
Reset: 0‟s
Description: Reserved

Bits: 14:0
Type: RW1CS, RSM
Reset: 0‟s
Description: SDIN State Change Status Flags (SDIWAKE):  Flag bits that indicate which SDIN signal(s) received a “State Change” event.  The bits are cleared by writing 1‟s to them.  The SDATA_IN[0] line corresponds to bit 0, etc. These bits are only cleared by a power-on reset.

The SDIWAKE bits are used to indicate that a “Status Change” event has occurred on the link, which usually indicates that either the codec has just come out of reset and is requesting an address, or that a codec is signaling a wake event.  The controller hardware will perform the resulting address cycle on the bus, and set this bit to inform the software that the event has occurred.  The setting of this bit may cause a processor interrupt to occur if the appropriate WAKEEN bits (Section 3.3.8) are set.


The node index (NID) is 0 for the root node, so you start with that set to zero and use it with verb F00h and paramater 04h to return the range of NIDs representing function groups. You then change the NID to that of a function group to ask it if it's an AFG (using F00h again but with parameter 05h), and once you've found the AFG group (the response will have the lowest byte = 1 for the AFG group) you can use parameter 04h with that NID to get it to return the range of NIDs that are HDA widgets. When interpreting the response for parameter 04h, the byte using bits 23-16 are the first NID in the range of relevant NIDs, and the byte using bits 7-0 holds the number of nodes (the range of relevant NIDs, including the first one). When you use this with the root node, you'll likely only find one group and it will be the AFG group. When you use it with the AFG group node, you should find a range covering two to three dozen widgets.

Thanks! Just one last question: is the interrupt for HDA always interrupt Bh, as my system indicates on the PCI bus for the interrupt line, which corresponds to interrupt 2Bh on my PIC (I haven't transitioned to using ACPI/APIC yet)? I ask this because I'm not really sure how to dynamically update my IDT. I was thinking about having a driver submit an add interrupt request to my interrupts handler subsystem, but I don't know if I can do that.

Author:  DavidCooper [ Fri Nov 01, 2019 1:33 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

I haven't attempted to use interrupts with HDA because there's so little to gain from doing so. If you want them though and are using the PIC, I think it's just a matter of changing the value in offset 3Ch in the HDA configuration space (its a four byte register, and you want to set bits 7-0). This is from the wiki's PCI page:-

Code:
Interrupt handling:-

If you're using the old PIC, your life is really easy. You have the Interrupt Line field of the header, which is read/write (you can change it's value!) and it says which interrupt will the PCI device fire when it needs attention.

If you plan to use the I/O APIC, your life will be a nightmare. You have 4 new IRQs called INTA#, INTB#, INTC# and INTD#. You can find which IRQ the device will use in the Interrupt Line field. In the ACPI AML Tables you will find (using ACPICA) that INTA# is connected to a specified interrupt line, INTB# to another, etc...

So far so good. You have, say, 20 devices. 10 of those are using INTA#, 5 for INTB#, 5 for INTC#, and none for INTD#. So when the IRQ number related to #INTC you have to scan the 5 devices to understand who was the interested one. So there is a LOT of IRQ sharing, expecially for INTA#.

With time manufacturers started to use mainly INTA#, forgetting the existence of other pins. So you will likely have 18 devices on INTA# and 2 on INTB#. Motherboard manufacturers decided take the situation in control. So at boot the INTx# are remapped, so that you will have 5 devices for INTA#, 5 for INTB#, 5 for INTC#, and 5 for INTD# (in the best case). That's great! IRQs are balanced and IRQ sharing is reduced. The only problem is that you don't know what devices where mapped. If you read the Interrupt Pin you still get INTA#. You now need to parse the MP Tables or the ACPI ones to solve the mess. Good luck.

Author:  Ethin [ Fri Nov 01, 2019 3:56 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

I don't mind asking my PIC timer interrupt to do all the handling and requests for polling to the HDA driver. That can easily be done. Thank you for all the help -- I'll try and implement what you said! :)

Author:  johnsa [ Mon Nov 04, 2019 8:17 am ]
Post subject:  Re: How to play sound Intel HD Audio?

Some more feedback on progress from my side with regards to the mac, the reason the DMA was still not running is that on these machines there is an IO-MMU. The IO-MMU had been configured by the firmware to remap DMA!
So the buffers I thought I was pointing my DMA at were in fact not in the right place. After writing a small io-mmu driver and switching off dma remapping, I now have pio and dma modes working on all machines.

Author:  DavidCooper [ Mon Nov 04, 2019 11:54 am ]
Post subject:  Re: How to play sound Intel HD Audio?

Well done. It's good to see perseverance rewarded. I admire your patience.

Author:  Ethin [ Sat Jan 04, 2020 5:32 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

Bringing this topic back up because I've done everything that DavidCooper has outlined. I don't submit any commands yet to the CORB, and so don't check the RIRB. Instead I try to follow the HDA specification and, after I've gotten everything set up, I check SDINS. However, my kernel never sees any codecs. Am I supposed to write a command to tell thecodecs to start themselves? The specification, if I recall correctly, indicates that I need to wait for codecs to be available, but I see none. I even have a loop in my code to run up to 1000 before I check and still nothing. Thoughts?

Author:  DavidCooper [ Sun Jan 05, 2020 3:29 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

It might be worth making your code available, preferably as a disk image too so that other people can run it in QEMU on their machine. The installation of QEMU that you're using might be faulty, and that's the first thing that needs to be checked.

Author:  Ethin [ Sun Jan 05, 2020 7:24 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

I'm using Qemu v. 4.2.0. I can't use an older version, so I'll do the insane thing and build qemu from source to see if that fixes the problem or ot. :)
My code is publicly available on github, though I haven't pushed the latest changes yet. I'll do that after this test.

Author:  Ethin [ Sun Jan 05, 2020 9:12 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

OK, so I built Qemu and attempted running it. Needless to say it didn't boot at all. Then again, this was a build of the git repo so I'm not overly surprised it broke. I have no way of running older versions of the emulator, sadly. The code for my HDA driver is at https://github.com/ethindp/kernel/blob/ ... und/hda.rs.

Author:  DavidCooper [ Tue Jan 07, 2020 12:22 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

If the problem's with the installation of QEMU on your machine, then there may be no errors in your code and no one's going to search through it carefully until they're sure there's something there to be found, so you need to make a disk image available for someone else to test on the version of QEMU that they have on their machine and which they already know works correctly for HDA. I know that such people exist and I'm sure they will help if you provide the disk image.

(Alternatively, you could run your code directly on real hardware, though I'm guessing that may be hard to do until you have have added enough support to it to support visual impairment issues, which leads back to your need for a working HDA driver first before you can debug that HDA driver - a vicious circle of impossibility unless you can find someone local to work with to get past this barrier.)

Author:  Ethin [ Tue Jan 07, 2020 5:04 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

Attached is the bootable image. You'll need to boot it with the -hda option and with either -cpu host or -cpu max (or provide a CPU with the RDRAND instruction -- the system will throw an error if your processor doesn't support it). Typically for this kind of scenario I boot it with:
Code:
qemu-system-x86_64 -hda bootimage-kernel.bin -cpu max -soundhw hda

You shouldn't have to do any other more arguments than that. The kernel automatically initializes a serial port even if one is not available which may cause some problems. If so, just add a serial port and you'll be fine.
Edit: apparently it didn't like me attaching it (it just never attached, LOL) so here's a link instead:
https://ethindp.keybase.pub/bootimage-kernel.bin

Author:  DavidCooper [ Thu Jan 09, 2020 4:46 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

For anyone who has successfully run their own HDA code on QEMU and who could test Ethin's disk image, please do so. (I only have a faulty version of QEMU sitting in an old XP machine that's been so damaged by updates that it barely manages to boot before getting stuck, so I can't do the testing.)

Author:  Ethin [ Thu Jan 16, 2020 8:52 pm ]
Post subject:  Re: How to play sound Intel HD Audio?

Any update on this?

Page 4 of 5 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/