summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/sound/pci/via8233.c54
1 files changed, 45 insertions, 9 deletions
diff --git a/sys/dev/sound/pci/via8233.c b/sys/dev/sound/pci/via8233.c
index 8dca294..a05f9cf 100644
--- a/sys/dev/sound/pci/via8233.c
+++ b/sys/dev/sound/pci/via8233.c
@@ -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];
@@ -707,16 +708,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);
@@ -727,9 +738,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);
@@ -765,6 +786,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;
@@ -842,6 +866,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");
@@ -933,10 +958,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
OpenPOWER on IntegriCloud