]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/pc/audioac97.c
devkbd: bits bad! revert repeat/delay, better patches welcome
[plan9front.git] / sys / src / 9 / pc / audioac97.c
index 193d31e8af21f98bc2c0c455f729690b773e413a..6d11f627934060959f4c64646ca3352e86b9f73c 100644 (file)
@@ -50,6 +50,9 @@ struct Ctlr {
 
        ulong port;
        ulong mixport;
+       uchar *mmreg;
+       uchar *mmmix;
+       int ismmio;
 
        Ring inring, micring, outring;
 
@@ -61,9 +64,6 @@ struct Ctlr {
        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,
@@ -192,12 +192,50 @@ writering(Ring *r, uchar *p, long n)
        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 *,
@@ -210,13 +248,12 @@ ac97waitcodec(Audio *adev)
        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
@@ -225,7 +262,10 @@ ac97mixw(Audio *adev, int port, ushort val)
        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
@@ -234,6 +274,8 @@ ac97mixr(Audio *adev, int port)
        Ctlr *ctlr;
        ac97waitcodec(adev);
        ctlr = adev->ctlr;
+       if(ctlr->ismmio)
+               return *(ushort*)(ctlr->mmmix+port);
        return ins(ctlr->mixport+port);
 }
 
@@ -242,24 +284,45 @@ ac97interrupt(Ureg *, void *arg)
 {
        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",
@@ -281,11 +344,18 @@ ac97status(Audio *adev, void *a, long n, vlong)
                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
@@ -296,6 +366,37 @@ outrate(void *arg)
        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)
 {
@@ -311,7 +412,7 @@ 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;
@@ -322,10 +423,27 @@ ac97write(Audio *adev, void *vp, long n, vlong)
                }
                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)
 {
@@ -394,21 +512,45 @@ ac97reset(Audio *adev)
 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;
@@ -498,7 +640,9 @@ Found:
 
        ac97mixreset(adev, ac97mixw, ac97mixr);
 
+       adev->read = ac97read;
        adev->write = ac97write;
+       adev->close = ac97close;
        adev->buffered = ac97buffered;
        adev->status = ac97status;