Intel High Definition Audio: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
m (Correction relating to codec discovery method)
m (More little corrections and additions.)
Line 11: Line 11:
At one end is the HDAudio device itself, while at the other end are hardware codecs and the many widgets which they contain. Setting things up at the HDAudio device end is relatively easy, part of it being done by keyhole surgery through a couple of ordinary ports in the PCI device configuration space, while the rest is done through memory mapped ports located at an address found at index 10-17h (though the lowest four bits should be taken as zeros). Setting things up at the codec end is much more complicated because you have to interrogate them to find out what are and what functionality they offer, and then you have to work out how to set them up correctly. All your communications with the codecs and the many widgets they contain will be done by sending special commands via the link.
At one end is the HDAudio device itself, while at the other end are hardware codecs and the many widgets which they contain. Setting things up at the HDAudio device end is relatively easy, part of it being done by keyhole surgery through a couple of ordinary ports in the PCI device configuration space, while the rest is done through memory mapped ports located at an address found at index 10-17h (though the lowest four bits should be taken as zeros). Setting things up at the codec end is much more complicated because you have to interrogate them to find out what are and what functionality they offer, and then you have to work out how to set them up correctly. All your communications with the codecs and the many widgets they contain will be done by sending special commands via the link.


Data and commands are sent across the link in frames with strict timings and bit limits, but the work of packaging the different kinds of data into packets to go into these frames is all done for you, so all you need to do is set up a number of buffers. Two of these buffers are called CORB (command output ring buffer) and RIRB (response input ring buffer) - each buffer has a DMA engine dedicated to it which will in one case send commands from the CORB buffer across the link to codecs, and in the other case will write responses from codecs into the RIRB buffer. There will in many implementations also be an immediate command port which allows you to send commands to codecs/widgets and to receive responses from them without going through the CORB and RIRB mechanisms, but this route should probably only be used by the BIOS (or system management mode) to generate such things as low-battery-warning beeps without interfering with your CORB buffer.
Data and commands are sent across the link in frames with strict timings and bit limits, but the work of packaging the different kinds of data into packets to go into these frames is all done for you, so all you need to do is set up a number of buffers. Two of these buffers are called CORB (command output ring buffer) and RIRB (response input ring buffer) - each buffer has a DMA engine dedicated to it which will in one case send commands from the CORB buffer across the link to codecs, and in the other case will write responses from codecs into the RIRB buffer. There will in many implementations also be an immediate command port which allows you to send commands to codecs/widgets and to receive responses from them without going through the CORB and RIRB mechanisms, but this route cannot be used at the same time as CORB/RIRB and it should really be avoided.


There are also buffers and DMA engines dedicated to four input streams and four output streams (well, it's four of each in current implementations, but your software should check the actual number), each stream needing a descriptor buffer which must contain two or more descriptors which define a list of data buffers used by that stream, and the data buffers which these descriptors define will contain the actual sound samples (or have samples written into them) structured like the content of .wav files (though 20 and 24-bit samples must be padded out with zeros at the lsb end to make them all 32-bits long). The combined length of the sound data buffers can be anything up to 4GiB, so you could set things up to play a very long sound file and leave it going all by itself. In reality though, you'll probably work with chunks of memory a just few megabytes in size as one megabyte gives you room for about five seconds of 16-bit stereo data at 41.1KHz.
There are also buffers and DMA engines dedicated to four input streams and four output streams (well, it's four of each in current implementations, but your software should check the actual number), each stream needing a descriptor buffer which must contain two or more descriptors which define a list of data buffers used by that stream, and the data buffers which these descriptors define will contain the actual sound samples (or have samples written into them) structured like the content of .wav files (though 20 and 24-bit samples must be padded out with zeros at the lsb end to make them all 32-bits long). The combined length of the sound data buffers can be anything up to 4GiB, so you could set things up to play a very long sound file and leave it going all by itself. In reality though, you'll probably work with chunks of memory a just few megabytes in size (or smaller) as one megabyte gives you room for about five seconds of 16-bit stereo data at 41.1KHz. For performance reasons, making the length of these data buffers a multiple of 128 bytes is recommended.


With all these buffers, the DMA engines jump back to the start and carry on running from there infinitely until you stop them, although with CORB there is a register which stores the last valid command which the DMA engine must stop at (after sending that command) and it will only move on again when that register is modified (by you) to enable more commands to be sent. It is the job of your software to collect data from input buffers before they are overwritten on the next lap. The set of data buffers defined by descriptors for a single stream collectively comprise a cyclic stream buffer, but it's divided up into chunks defined by descriptors to enable an interrupt to be generated at the end of each chunk (interrupt optional) so that you can write new data into an output buffer that's just been sent before the DMA engine returns to that buffer on the next lap, or to copy data out of an input buffer that's just been written by a DMA engine to make way for more data to be written on the next lap.
With all these buffers, the DMA engines jump back to the start and carry on running from there infinitely until you stop them, although with CORB there is a register which stores the last valid command which the DMA engine must stop at (after sending that command) and it will only move on again when that register is modified (by you) to enable more commands to be sent. It is the job of your software to collect data from input buffers before they are overwritten on the next lap. The set of data buffers defined by descriptors for a single stream collectively comprise a cyclic stream buffer, but it's divided up into chunks defined by descriptors to enable an interrupt to be generated at the end of each chunk (interrupt optional) so that you can write new data into an output buffer that's just been sent before the DMA engine returns to that buffer on the next lap, or to copy data out of an input buffer that's just been written by a DMA engine to make way for more data to be written on the next lap.


At the codec end, you will need to start out by interrogating the root node of each of 15 possible codecs. The STATESTS register at offset 0Eh indicates which codec addresses have codecs at the end of them. The verb F00h will then be used with an 8-bit parameter to request information such as vendor ID, device ID and the starting node number and number of nodes for the function groups in the codec. Having found the function groups, you can use the same verb to interrogate them to find out the starting node number and number of nodes of their widgets, and also the type of the function group itself - AFG (audio function group) is the one you probably want unless you're looking for a modem. You can then interrogate each widget to ask it what its type is (e.g. output, input, mixer, selector, pin complex, power widget, volume knob). Another verb, F02h, allows you to get a connection list of other widgets in the same function group directly connected to the widget you're interrogating, though you need to use verb F00h first and the parameter at 0Eh to get the connection list length. On the Netbook I program on there is only one codec, one function group (AFG) and 37 widgets. Don't expect there to be a volume control widget: the volume can be controlled by setting different amplifier levels at the input and output controllers instead.
At the codec end, you will need to start out by interrogating the root node of each of 15 possible codecs. The STATESTS register at offset 0Eh indicates which codec addresses have codecs at the end of them. The verb F00h will then be used with an 8-bit parameter to request information such as vendor ID, device ID and the starting node number and number of nodes for the function groups in the codec. Having found the function groups, you can use the same verb to interrogate them to find out the starting node number and number of nodes of their widgets, and also the type of the function group itself - AFG (audio function group) is the one you probably want unless you're looking for a modem. You can then interrogate each widget to ask it what its type is (e.g. output, input, mixer, selector, pin complex, power widget, volume knob). Another verb, F02h, allows you to get a connection list of other widgets in the same function group directly connected to the widget you're interrogating, though you need to use verb F00h first and the parameter at 0Eh to get the connection list length. On the Netbook I program on there is only one codec, one function group (AFG) and 37 widgets (about half of which are vendor defined audio widgets). Don't expect there to be a volume control widget: the volume can be controlled by setting different amplifier levels at the input and output controllers instead.


== Device Registers ==
== Device Registers ==

Revision as of 15:58, 7 May 2013

Intel High Definition Audio refers to the specification released by Intel for delivering high-definition audio that is capable of playing back more channels at higher quality than previous integrated audio codecs like AC97.

Technical Details

All HDAudio devices appear on the PCI bus with a specific VendorID and DeviceID. All HDAudio devices will have a Vendor ID of 8086, and a Device ID of 2668 or 27D8. The PCI device configuration space contains two 32-bit base address registers (BAR0 and BAR1) that combine to form the 64-bit address of the memory mapped registers that control the device.

Overview

The HDAudio specification (link at the bottom of this page) details how to set up devices at the two ends of a link and there is no substitute for working from it, but it takes several readings through its 200+ pages before a clear picture eventually begins to emerge from it, so this overview is aimed at making the most frustrating parts clear from the outset.

At one end is the HDAudio device itself, while at the other end are hardware codecs and the many widgets which they contain. Setting things up at the HDAudio device end is relatively easy, part of it being done by keyhole surgery through a couple of ordinary ports in the PCI device configuration space, while the rest is done through memory mapped ports located at an address found at index 10-17h (though the lowest four bits should be taken as zeros). Setting things up at the codec end is much more complicated because you have to interrogate them to find out what are and what functionality they offer, and then you have to work out how to set them up correctly. All your communications with the codecs and the many widgets they contain will be done by sending special commands via the link.

Data and commands are sent across the link in frames with strict timings and bit limits, but the work of packaging the different kinds of data into packets to go into these frames is all done for you, so all you need to do is set up a number of buffers. Two of these buffers are called CORB (command output ring buffer) and RIRB (response input ring buffer) - each buffer has a DMA engine dedicated to it which will in one case send commands from the CORB buffer across the link to codecs, and in the other case will write responses from codecs into the RIRB buffer. There will in many implementations also be an immediate command port which allows you to send commands to codecs/widgets and to receive responses from them without going through the CORB and RIRB mechanisms, but this route cannot be used at the same time as CORB/RIRB and it should really be avoided.

There are also buffers and DMA engines dedicated to four input streams and four output streams (well, it's four of each in current implementations, but your software should check the actual number), each stream needing a descriptor buffer which must contain two or more descriptors which define a list of data buffers used by that stream, and the data buffers which these descriptors define will contain the actual sound samples (or have samples written into them) structured like the content of .wav files (though 20 and 24-bit samples must be padded out with zeros at the lsb end to make them all 32-bits long). The combined length of the sound data buffers can be anything up to 4GiB, so you could set things up to play a very long sound file and leave it going all by itself. In reality though, you'll probably work with chunks of memory a just few megabytes in size (or smaller) as one megabyte gives you room for about five seconds of 16-bit stereo data at 41.1KHz. For performance reasons, making the length of these data buffers a multiple of 128 bytes is recommended.

With all these buffers, the DMA engines jump back to the start and carry on running from there infinitely until you stop them, although with CORB there is a register which stores the last valid command which the DMA engine must stop at (after sending that command) and it will only move on again when that register is modified (by you) to enable more commands to be sent. It is the job of your software to collect data from input buffers before they are overwritten on the next lap. The set of data buffers defined by descriptors for a single stream collectively comprise a cyclic stream buffer, but it's divided up into chunks defined by descriptors to enable an interrupt to be generated at the end of each chunk (interrupt optional) so that you can write new data into an output buffer that's just been sent before the DMA engine returns to that buffer on the next lap, or to copy data out of an input buffer that's just been written by a DMA engine to make way for more data to be written on the next lap.

At the codec end, you will need to start out by interrogating the root node of each of 15 possible codecs. The STATESTS register at offset 0Eh indicates which codec addresses have codecs at the end of them. The verb F00h will then be used with an 8-bit parameter to request information such as vendor ID, device ID and the starting node number and number of nodes for the function groups in the codec. Having found the function groups, you can use the same verb to interrogate them to find out the starting node number and number of nodes of their widgets, and also the type of the function group itself - AFG (audio function group) is the one you probably want unless you're looking for a modem. You can then interrogate each widget to ask it what its type is (e.g. output, input, mixer, selector, pin complex, power widget, volume knob). Another verb, F02h, allows you to get a connection list of other widgets in the same function group directly connected to the widget you're interrogating, though you need to use verb F00h first and the parameter at 0Eh to get the connection list length. On the Netbook I program on there is only one codec, one function group (AFG) and 37 widgets (about half of which are vendor defined audio widgets). Don't expect there to be a volume control widget: the volume can be controlled by setting different amplifier levels at the input and output controllers instead.

Device Registers

Offset (Hex) Name Description
00 GCAP Global Capabilities
02 VMIN Minor Version
03 VMAJ Major Version
04 OUTPAY Output Payload Capacity
06 INPAY Input Payload Capacity
08 GCTL Global Control
0C WAKEEN Wake Enable
0E STATESTS State Change Status

External links