ulong port;
ulong mixport;
+ uchar *mmreg;
+ uchar *mmmix;
+ int ismmio;
Ring inring, micring, outring;
Ctlr *next;
};
-#define iorl(c, r) (inl((c)->port+(r)))
-#define iowl(c, r, l) (outl((c)->port+(r), (ulong)(l)))
-
enum {
In = 0x00,
Out = 0x10,
return n0 - n;
}
-#define csr8r(c, r) (inb((c)->port+(r)))
-#define csr16r(c, r) (ins((c)->port+(r)))
-#define csr32r(c, r) (inl((c)->port+(r)))
-#define csr8w(c, r, b) (outb((c)->port+(r), (int)(b)))
-#define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))
-#define csr32w(c, r, w) (outl((c)->port+(r), (ulong)(w)))
+static uchar
+csr8r(Ctlr *c, int r){
+ if(c->ismmio)
+ return *(uchar*)(c->mmreg+r);
+ return inb(c->port+r);
+}
+
+static ushort
+csr16r(Ctlr *c, int r){
+ if(c->ismmio)
+ return *(ushort*)(c->mmreg+r);
+ return ins(c->port+r);
+}
+
+static ulong
+csr32r(Ctlr *c, int r){
+ if(c->ismmio)
+ return *(ulong*)(c->mmreg+r);
+ return inl(c->port+r);
+}
+
+static void
+csr8w(Ctlr *c, int r, uchar v){
+ if(c->ismmio)
+ *(uchar*)(c->mmreg+r) = v;
+ else
+ outb(c->port+r, (int)v);
+}
+
+static void
+csr16w(Ctlr *c, int r, ushort v){
+ if(c->ismmio)
+ *(ushort*)(c->mmreg+r) = v;
+ else
+ outs(c->port+r, v);
+}
+
+static void
+csr32w(Ctlr *c, int r, ulong v){
+ if(c->ismmio)
+ *(ulong*)(c->mmreg+r) = v;
+ else
+ outl(c->port+r, v);
+}
/* audioac97mix */
extern void ac97mixreset(Audio *,
Ctlr *ctlr;
int i;
ctlr = adev->ctlr;
- for(i = 0; i < Maxbusywait/10; i++){
+ for(i = 0; i <= Maxbusywait/10; i++){
if((csr8r(ctlr, Cas) & Casp) == 0)
- break;
+ return;
microdelay(10);
}
- if(i == Maxbusywait)
- print("#A%d: ac97 exhausted waiting codec access\n", adev->ctlrno);
+ print("#A%d: ac97 exhausted waiting codec access\n", adev->ctlrno);
}
static void
Ctlr *ctlr;
ac97waitcodec(adev);
ctlr = adev->ctlr;
- outs(ctlr->mixport+port, val);
+ if(ctlr->ismmio)
+ *(ushort*)(ctlr->mmmix+port) = val;
+ else
+ outs(ctlr->mixport+port, val);
}
static ushort
Ctlr *ctlr;
ac97waitcodec(adev);
ctlr = adev->ctlr;
+ if(ctlr->ismmio)
+ return *(ushort*)(ctlr->mmmix+port);
return ins(ctlr->mixport+port);
}
{
Audio *adev;
Ctlr *ctlr;
- Ring *ring;
ulong stat;
adev = arg;
ctlr = adev->ctlr;
stat = csr32r(ctlr, Sta);
stat &= S2ri | Sri | Pri | Mint | Point | Piint | Moint | Miint | Gsci;
- if(stat & Point){
+ if(stat & (Point|Piint|Mint)){
ilock(ctlr);
- if(ctlr->sis7012)
- csr16w(ctlr, Out + Picb, csr16r(ctlr, Out + Picb) & ~Dch);
- else
- csr16w(ctlr, Out + Sr, csr16r(ctlr, Out + Sr) & ~Dch);
- ring = &ctlr->outring;
- ring->ri = csr8r(ctlr, Out + Civ) * Blocksize;
+ if(stat & Point){
+ ctlr->outring.ri = csr8r(ctlr, Out + Civ) * Blocksize;
+ wakeup(&ctlr->outring.r);
+
+ if(ctlr->sis7012)
+ csr16w(ctlr, Out + Picb, csr16r(ctlr, Out + Picb) & ~Dch);
+ else
+ csr16w(ctlr, Out + Sr, csr16r(ctlr, Out + Sr) & ~Dch);
+ stat &= ~Point;
+ }
+ if(stat & Piint){
+ ctlr->inring.wi = csr8r(ctlr, In + Civ) * Blocksize;
+ wakeup(&ctlr->inring.r);
+
+ if(ctlr->sis7012)
+ csr16w(ctlr, In + Picb, csr16r(ctlr, In + Picb) & ~Dch);
+ else
+ csr16w(ctlr, In + Sr, csr16r(ctlr, In + Sr) & ~Dch);
+ stat &= ~Piint;
+ }
+ if(stat & Mint){
+ ctlr->micring.wi = csr8r(ctlr, Mic + Civ) * Blocksize;
+ wakeup(&ctlr->micring.r);
+
+ if(ctlr->sis7012)
+ csr16w(ctlr, Mic + Picb, csr16r(ctlr, Mic + Picb) & ~Dch);
+ else
+ csr16w(ctlr, Mic + Sr, csr16r(ctlr, Mic + Sr) & ~Dch);
+ stat &= ~Mint;
+ }
iunlock(ctlr);
- wakeup(&ring->r);
- stat &= ~Point;
}
if(stat) /* have seen 0x400, which is sdin0 resume */
iprint("#A%d: ac97 unhandled interrupt(s): stat 0x%lux\n",
Blocksize, buffered(&ctlr->outring));
}
+static int
+inavail(void *arg)
+{
+ Ring *r = arg;
+ return buffered(r) > 0;
+}
+
static int
outavail(void *arg)
{
- Ctlr *ctlr = arg;
- return available(&ctlr->outring);
+ Ring *r = arg;
+ return available(r) > 0;
}
static int
return (delay <= 0) || (buffered(&ctlr->outring) <= delay);
}
+static long
+ac97read(Audio *adev, void *vp, long n, vlong)
+{
+ uchar *p, *e;
+ Ctlr *ctlr;
+ Ring *ring;
+ ulong oi, ni;
+
+ p = vp;
+ e = p + n;
+ ctlr = adev->ctlr;
+ ring = &ctlr->inring;
+ while(p < e) {
+ oi = ring->ri / Blocksize;
+ if((n = readring(ring, p, e - p)) <= 0){
+ csr8w(ctlr, In + Lvi, (oi - 1) % Ndesc);
+ csr8w(ctlr, In + Cr, Ioce | Rpbm);
+ sleep(&ring->r, inavail, ring);
+ continue;
+ }
+ ni = ring->ri / Blocksize;
+ while(oi != ni){
+ csr8w(ctlr, In + Lvi, (oi - 1) % Ndesc);
+ csr8w(ctlr, In + Cr, Ioce | Rpbm);
+ oi = (oi + 1) % Ndesc;
+ }
+ p += n;
+ }
+ return p - (uchar*)vp;
+}
+
static long
ac97write(Audio *adev, void *vp, long n, vlong)
{
while(p < e) {
oi = ring->wi / Blocksize;
if((n = writering(ring, p, e - p)) <= 0){
- sleep(&ring->r, outavail, ctlr);
+ sleep(&ring->r, outavail, ring);
continue;
}
ni = ring->wi / Blocksize;
}
p += n;
}
- sleep(&ring->r, outrate, ctlr);
+ while(outrate(ctlr) == 0)
+ sleep(&ring->r, outrate, ctlr);
return p - (uchar*)vp;
}
+static void
+ac97close(Audio *adev, int mode)
+{
+ Ctlr *ctlr;
+ Ring *ring;
+
+ if(mode == OREAD)
+ return;
+
+ ctlr = adev->ctlr;
+ ring = &ctlr->outring;
+ while(ring->wi % Blocksize)
+ if(writering(ring, (uchar*)"", 1) <= 0)
+ break;
+}
+
static Pcidev*
ac97match(Pcidev *p)
{
Found:
adev->ctlr = ctlr;
ctlr->adev = adev;
- if(p->vid == 0x1039 && p->did == 0x7012)
- ctlr->sis7012 = 1;
- if(p->mem[0].size == 64){
- ctlr->port = p->mem[0].bar & ~3;
- ctlr->mixport = p->mem[1].bar & ~3;
- } else if(p->mem[1].size == 64){
- ctlr->port = p->mem[1].bar & ~3;
- ctlr->mixport = p->mem[0].bar & ~3;
- } else if(p->mem[0].size == 256){ /* sis7012 */
+ /* ICH4 through ICH7 may use memory-type base address registers */
+ if(p->vid == 0x8086 &&
+ (p->did == 0x24c5 || p->did == 0x24d5 || p->did == 0x266e || p->did == 0x27de) &&
+ (p->mem[2].bar != 0 && p->mem[3].bar != 0) &&
+ ((p->mem[2].bar & 1) == 0 && (p->mem[3].bar & 1) == 0)){
+ ctlr->mmmix = vmap(p->mem[2].bar & ~0xf, p->mem[2].size);
+ if(ctlr->mmmix == nil){
+ print("ac97: vmap failed for mmmix 0x%08lux\n", p->mem[2].bar);
+ return -1;
+ }
+ ctlr->mmreg = vmap(p->mem[3].bar & ~0xf, p->mem[3].size);
+ if(ctlr->mmreg == nil){
+ print("ac97: vmap failed for mmreg 0x%08lux\n", p->mem[3].bar);
+ vunmap(ctlr->mmmix, p->mem[2].size);
+ return -1;
+ }
+ ctlr->ismmio = 1;
+ }else{
+ if((p->mem[0].bar & 1) == 0 || (p->mem[1].bar & 1) == 0){
+ print("ac97: not i/o regions 0x%04lux 0x%04lux\n", p->mem[0].bar, p->mem[1].bar);
+ return -1;
+ }
+
+ if(p->vid == 0x1039 && p->did == 0x7012){
+ ctlr->sis7012 = 1; /* i/o bars swapped? */
+ }
+
ctlr->port = p->mem[1].bar & ~3;
+ if(ioalloc(ctlr->port, p->mem[1].size, 0, "ac97") < 0){
+ print("ac97: ioalloc failed for port 0x%04lux\n", ctlr->port);
+ return -1;
+ }
ctlr->mixport = p->mem[0].bar & ~3;
- } else if(p->mem[1].size == 256){
- ctlr->port = p->mem[0].bar & ~3;
- ctlr->mixport = p->mem[1].bar & ~3;
+ if(ioalloc(ctlr->mixport, p->mem[0].size, 0, "ac97mix") < 0){
+ print("ac97: ioalloc failed for mixport 0x%04lux\n", ctlr->mixport);
+ iofree(ctlr->port);
+ return -1;
+ }
}
irq = p->intl;
ac97mixreset(adev, ac97mixw, ac97mixr);
+ adev->read = ac97read;
adev->write = ac97write;
+ adev->close = ac97close;
adev->buffered = ac97buffered;
adev->status = ac97status;