AC97 — Änderungen 11330 → 11331

Zeile 175: Zeile 175:
 
VIAs AC'97-Soundkarte ist Funktion 5 der Southbridge, die sich ihre IO-Adressräume mit dem integrierten Modem (MC97) in Funktion 6 teilt. Wir behandeln im Folgenden nur AC'97. Der für uns relevante IO-Raum für DMA residiert im ersten PCI-BAR.
 
VIAs AC'97-Soundkarte ist Funktion 5 der Southbridge, die sich ihre IO-Adressräume mit dem integrierten Modem (MC97) in Funktion 6 teilt. Wir behandeln im Folgenden nur AC'97. Der für uns relevante IO-Raum für DMA residiert im ersten PCI-BAR.
  
−
Die Karte bezieht Sounddaten aus aus mehreren Puffern, die in der SGD-Tabelle ("Scatter/Gather DMA Table") durch Deskriptoren folgenden Formats beschrieben werden. Die Basisadresse der Tabelle ist in das 32-bit-Register an Offset 0x4 zu schreiben und an 2-Byte-Grenzen auszurichten:
+
Die Karte bezieht Sounddaten aus aus mehreren Puffern, die in SGD-Tabellen ("Scatter/Gather DMA Table") durch Deskriptoren folgenden Formats beschrieben werden. Die physischen Adressen der Tabellen sind in die 32-bit-Register AC97_VIA_R_SGD_TABLE_BASE bzw. AC97_VIA_W_SGD_TABLE_BASE zu schreiben und an 2-Byte-Grenzen auszurichten:
 
<c>typedef struct
 
<c>typedef struct
 
{
 
{
Zeile 185: Zeile 185:
 
uint32_t eol      :  1; // Letzter Eintrag. Löst einen EOL-Interrupt aus.
 
uint32_t eol      :  1; // Letzter Eintrag. Löst einen EOL-Interrupt aus.
 
} __attribute__((packed)) ac97Via_SGDEntry_t;</c>
 
} __attribute__((packed)) ac97Via_SGDEntry_t;</c>
 +
 +
=== Zugriff auf den AC97-Codec ===
 +
 +
Der Zugriff auf den AC97-Codec gestaltet sich schwieriger als bei der o.g. AC97-Implementation von Intel, weil dessen Register nicht in einen eigenen Adressraum gemappt sind, sondern über das 4 Bytes lange Register an Offset 0x80 gelesen und geschrieben werden müssen. Der folgende Code implementiert den Zugriff auf diese Register:
 +
<c>void codec_sendCommand(ac97Via_t* ac97, uint8_t reg, bool primary, uint16_t data)
 +
{
 +
while (inl(ac97->iobase + AC97_VIA_ACCESS_CODEC) & AC97_VIA_CODEC_BUSY) // Warte, bis der Codec Zeit hat
 +
;
 +
if (primary)
 +
outl(ac97->iobase + AC97_VIA_ACCESS_CODEC, AC97_VIA_CODEC_SEL_PRIM | AC97_VIA_CODEC_WRITE | ((uint32_t)reg << 16) | data);
 +
else
 +
outl(ac97->iobase + AC97_VIA_ACCESS_CODEC, AC97_VIA_CODEC_SEL_SEC  | AC97_VIA_CODEC_WRITE | ((uint32_t)reg << 16) | data);
 +
}
 +
 +
uint16_t codec_readStatus(ac97Via_t* ac97, uint8_t reg, bool primary)
 +
{
 +
while (inl(ac97->iobase + AC97_VIA_ACCESS_CODEC) & AC97_VIA_CODEC_BUSY) // Warte, bis der Codec Zeit hat
 +
;
 +
if (primary)
 +
{
 +
outl(ac97->iobase + AC97_VIA_ACCESS_CODEC, AC97_VIA_CODEC_SEL_PRIM | AC97_VIA_CODEC_READ | AC97_VIA_CODEC_PRIM_VALID | ((uint32_t)reg << 16));
 +
while (!(inl(ac97->iobase + AC97_VIA_ACCESS_CODEC) & AC97_VIA_CODEC_PRIM_VALID)) // Warte, bis der Codec die Daten geliefert hat
 +
;
 +
return inl(ac97->iobase + AC97_VIA_ACCESS_CODEC) & 0xFFFF;
 +
}
 +
else
 +
{
 +
outl(ac97->iobase + AC97_VIA_ACCESS_CODEC, AC97_VIA_CODEC_SEL_SEC | AC97_VIA_CODEC_READ | AC97_VIA_CODEC_SEC_VALID | ((uint32_t)reg << 16));
 +
while (!(inl(ac97->iobase + AC97_VIA_ACCESS_CODEC) & AC97_VIA_CODEC_SEC_VALID)) // Warte, bis der Codec die Daten geliefert hat
 +
;
 +
return inl(ac97->iobase + AC97_VIA_ACCESS_CODEC) & 0xFFFF;
 +
}
 +
}</c>
 +
 +
=== Anhang ===
 +
Definitionen der oben verwendeten Konstanten:
 +
<c>// Register-Offsets
 +
#define AC97_VIA_R_SGD_CONTROL    0x01
 +
#define AC97_VIA_R_SGD_TABLE_BASE 0x04
 +
#define AC97_VIA_W_SGD_CONTROL    0x11
 +
#define AC97_VIA_W_SGD_TABLE_BASE 0x14
 +
#define AC97_VIA_ACCESS_CODEC    0x80
 +
 +
// Bits des AC97_VIA_ACCESS_CODEC-Registers
 +
#define AC97_VIA_CODEC_SEL_PRIM  0
 +
#define AC97_VIA_CODEC_PRIM_VALID BIT(25)
 +
#define AC97_VIA_CODEC_SEL_SEC    BIT(30)
 +
#define AC97_VIA_CODEC_SEC_VALID  BIT(27)
 +
#define AC97_VIA_CODEC_BUSY      BIT(24)
 +
#define AC97_VIA_CODEC_WRITE      0
 +
#define AC97_VIA_CODEC_READ      BIT(23)</c>
  
 
== Weblinks ==
 
== Weblinks ==