MFC (revision 1.24)
Add support for (latest) VIA VT8251 audio controller. A slight difference of this chip from its previous siblings is that it need a gentle "wake up" on every (full) DMA buffer completion to avoid stalled interrupt handler. Thanks to George Hartzell for permission on doing remote debugging. PR: i386/95949 Tested by: [1] George Hartzel myself (remotely) Approved by: re (hrs) [1] http://lists.freebsd.org/pipermail/freebsd-multimedia/2006-April/004003.html
This commit is contained in:
parent
7735df0379
commit
9c393c5830
@ -54,6 +54,7 @@ SND_DECLARE_FILE("$FreeBSD$");
|
||||
#define VIA8233_REV_ID_8233A 0x40
|
||||
#define VIA8233_REV_ID_8235 0x50
|
||||
#define VIA8233_REV_ID_8237 0x60
|
||||
#define VIA8233_REV_ID_8251 0x70
|
||||
|
||||
#define SEGS_PER_CHAN 2 /* Segments per channel */
|
||||
#define NDXSCHANS 4 /* No of DXS channels */
|
||||
@ -100,7 +101,7 @@ struct via_info {
|
||||
struct ac97_info *codec;
|
||||
|
||||
unsigned int bufsz;
|
||||
int dxs_src;
|
||||
int dxs_src, dma_eol_wake;
|
||||
|
||||
struct via_chinfo pch[NDXSCHANS + NMSGDCHANS];
|
||||
struct via_chinfo rch[NWRCHANS];
|
||||
@ -711,16 +712,26 @@ static void
|
||||
via_intr(void *p)
|
||||
{
|
||||
struct via_info *via = p;
|
||||
int i, stat;
|
||||
int i, reg, stat;
|
||||
|
||||
/* Poll playback channels */
|
||||
snd_mtxlock(via->lock);
|
||||
for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
|
||||
if (via->pch[i].channel == NULL)
|
||||
continue;
|
||||
stat = via->pch[i].rbase + VIA_RP_STATUS;
|
||||
if (via_rd(via, stat, 1) & SGD_STATUS_INTR) {
|
||||
via_wr(via, stat, SGD_STATUS_INTR, 1);
|
||||
reg = via->pch[i].rbase + VIA_RP_STATUS;
|
||||
stat = via_rd(via, reg, 1);
|
||||
if (stat & SGD_STATUS_INTR) {
|
||||
if (via->dma_eol_wake && ((stat & SGD_STATUS_EOL) ||
|
||||
!(stat & SGD_STATUS_ACTIVE))) {
|
||||
via_wr(via,
|
||||
via->pch[i].rbase + VIA_RP_CONTROL,
|
||||
SGD_CONTROL_START |
|
||||
SGD_CONTROL_AUTOSTART |
|
||||
SGD_CONTROL_I_EOL |
|
||||
SGD_CONTROL_I_FLAG, 1);
|
||||
}
|
||||
via_wr(via, reg, stat, 1);
|
||||
snd_mtxunlock(via->lock);
|
||||
chn_intr(via->pch[i].channel);
|
||||
snd_mtxlock(via->lock);
|
||||
@ -731,9 +742,19 @@ via_intr(void *p)
|
||||
for (i = 0; i < NWRCHANS; i++) {
|
||||
if (via->rch[i].channel == NULL)
|
||||
continue;
|
||||
stat = via->rch[i].rbase + VIA_RP_STATUS;
|
||||
if (via_rd(via, stat, 1) & SGD_STATUS_INTR) {
|
||||
via_wr(via, stat, SGD_STATUS_INTR, 1);
|
||||
reg = via->rch[i].rbase + VIA_RP_STATUS;
|
||||
stat = via_rd(via, reg, 1);
|
||||
if (stat & SGD_STATUS_INTR) {
|
||||
if (via->dma_eol_wake && ((stat & SGD_STATUS_EOL) ||
|
||||
!(stat & SGD_STATUS_ACTIVE))) {
|
||||
via_wr(via,
|
||||
via->rch[i].rbase + VIA_RP_CONTROL,
|
||||
SGD_CONTROL_START |
|
||||
SGD_CONTROL_AUTOSTART |
|
||||
SGD_CONTROL_I_EOL |
|
||||
SGD_CONTROL_I_FLAG, 1);
|
||||
}
|
||||
via_wr(via, reg, stat, 1);
|
||||
snd_mtxunlock(via->lock);
|
||||
chn_intr(via->rch[i].channel);
|
||||
snd_mtxlock(via->lock);
|
||||
@ -769,6 +790,9 @@ via_probe(device_t dev)
|
||||
case VIA8233_REV_ID_8237:
|
||||
device_set_desc(dev, "VIA VT8237");
|
||||
return BUS_PROBE_DEFAULT;
|
||||
case VIA8233_REV_ID_8251:
|
||||
device_set_desc(dev, "VIA VT8251");
|
||||
return BUS_PROBE_DEFAULT;
|
||||
default:
|
||||
device_set_desc(dev, "VIA VT8233X"); /* Unknown */
|
||||
return BUS_PROBE_DEFAULT;
|
||||
@ -846,6 +870,7 @@ via_attach(device_t dev)
|
||||
struct via_info *via = 0;
|
||||
char status[SND_STATUSLEN];
|
||||
int i, via_dxs_disabled, via_dxs_src, via_dxs_chnum, via_sgd_chnum;
|
||||
uint32_t revid;
|
||||
|
||||
if ((via = malloc(sizeof *via, M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
|
||||
device_printf(dev, "cannot allocate softc\n");
|
||||
@ -937,10 +962,21 @@ via_attach(device_t dev)
|
||||
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
|
||||
rman_get_start(via->reg), rman_get_start(via->irq),PCM_KLDSTRING(snd_via8233));
|
||||
|
||||
revid = pci_get_revid(dev);
|
||||
|
||||
/*
|
||||
* VIA8251 lost its interrupt after DMA EOL, and need
|
||||
* a gentle spank on its face within interrupt handler.
|
||||
*/
|
||||
if (revid == VIA8233_REV_ID_8251)
|
||||
via->dma_eol_wake = 1;
|
||||
else
|
||||
via->dma_eol_wake = 0;
|
||||
|
||||
/*
|
||||
* Decide whether DXS had to be disabled or not
|
||||
*/
|
||||
if (pci_get_revid(dev) == VIA8233_REV_ID_8233A) {
|
||||
if (revid == VIA8233_REV_ID_8233A) {
|
||||
/*
|
||||
* DXS channel is disabled. Reports from multiple users
|
||||
* that it plays at half-speed. Do not see this behaviour
|
||||
|
Loading…
Reference in New Issue
Block a user