Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/netbsd-3]: src/sys/dev/pci Pull up revision 1.7 (requested by kent in ti...



details:   https://anonhg.NetBSD.org/src/rev/601a8259c05b
branches:  netbsd-3
changeset: 576414:601a8259c05b
user:      tron <tron%NetBSD.org@localhost>
date:      Sat Jul 02 16:41:49 2005 +0000

description:
Pull up revision 1.7 (requested by kent in ticket #494):
- free all of allocated resources when an error occurs
- code cleanup

diffstat:

 sys/dev/pci/azalia.c |  487 +++++++++++++++++++++++++++++++++-----------------
 1 files changed, 321 insertions(+), 166 deletions(-)

diffs (truncated from 951 to 300 lines):

diff -r ec61ed9b80a5 -r 601a8259c05b sys/dev/pci/azalia.c
--- a/sys/dev/pci/azalia.c      Sat Jul 02 16:41:27 2005 +0000
+++ b/sys/dev/pci/azalia.c      Sat Jul 02 16:41:49 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: azalia.c,v 1.7.2.7 2005/07/02 16:41:27 tron Exp $      */
+/*     $NetBSD: azalia.c,v 1.7.2.8 2005/07/02 16:41:49 tron Exp $      */
 
 /*-
  * Copyright (c) 2005 The NetBSD Foundation, Inc.
@@ -38,13 +38,13 @@
 
 /*
  * TO DO:
+ *  - S/PDIF
  *  - Volume Knob widget
  *  - power hook
- *  - detach
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: azalia.c,v 1.7.2.7 2005/07/02 16:41:27 tron Exp $");
+__KERNEL_RCSID(0, "$NetBSD: azalia.c,v 1.7.2.8 2005/07/02 16:41:49 tron Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -598,9 +598,11 @@
        struct device dev;
        struct device *audiodev;
 
+       pci_chipset_tag_t pc;
        void *ih;
        bus_space_tag_t iot;
        bus_space_handle_t ioh;
+       bus_size_t map_size;
        bus_dma_tag_t dmat;
 
        codec_t codecs[15];
@@ -630,12 +632,15 @@
 /* prototypes */
 static int     azalia_pci_match(struct device *, struct cfdata *, void *);
 static void    azalia_pci_attach(struct device *, struct device *, void *);
+static int     azalia_pci_activate(struct device *, enum devact);
 static int     azalia_pci_detach(struct device *, int);
 static int     azalia_intr(void *);
 static int     azalia_attach(azalia_t *);
 static void    azalia_attach_intr(struct device *);
 static int     azalia_init_corb(azalia_t *);
+static int     azalia_delete_corb(azalia_t *);
 static int     azalia_init_rirb(azalia_t *);
+static int     azalia_delete_rirb(azalia_t *);
 static int     azalia_set_command(const azalia_t *, nid_t, int, uint32_t,
        uint32_t);
 static int     azalia_get_response(azalia_t *, uint32_t *);
@@ -643,7 +648,11 @@
 static int     azalia_free_dmamem(const azalia_t *, azalia_dma_t*);
 
 static int     azalia_codec_init(codec_t *);
+static int     azalia_codec_delete(codec_t *);
+static int     azalia_codec_init_dacgroup(codec_t *);
+static int     azalia_codec_add_dacgroup(codec_t *, int, uint32_t);
 static int     azalia_codec_construct_format(codec_t *);
+static void    azalia_codec_add_bits(codec_t *, int, uint32_t, int);
 static void    azalia_codec_add_format(codec_t *, int, int, int, uint32_t,
        int32_t);
 static int     azalia_codec_find_pin(const codec_t *, int, int, uint32_t);
@@ -653,6 +662,7 @@
 static int     azalia_codec_connect_stream(codec_t *, int, uint16_t, int);
 
 static int     azalia_mixer_init(codec_t *);
+static int     azalia_mixer_delete(codec_t *);
 static int     azalia_mixer_get(const codec_t *, mixer_ctrl_t *);
 static int     azalia_mixer_set(codec_t *, const mixer_ctrl_t *);
 static int     azalia_mixer_ensure_capacity(codec_t *, size_t);
@@ -671,6 +681,7 @@
 static int     azalia_widget_init_connection(widget_t *, const codec_t *);
 
 static int     azalia_stream_init(stream_t *, azalia_t *, int, int, int);
+static int     azalia_stream_delete(stream_t *, azalia_t *);
 static int     azalia_stream_reset(stream_t *);
 static int     azalia_stream_start(stream_t *, void *, void *, int,
        void (*)(void *), void *, uint16_t);
@@ -702,7 +713,7 @@
 
 /* variables */
 CFATTACH_DECL(azalia, sizeof(azalia_t),
-    azalia_pci_match, azalia_pci_attach, azalia_pci_detach, NULL);
+    azalia_pci_match, azalia_pci_attach, azalia_pci_detach, azalia_pci_activate);
 
 static const struct audio_hw_if azalia_hw_if = {
        azalia_open,
@@ -768,7 +779,6 @@
 {
        azalia_t *sc;
        struct pci_attach_args *pa;
-       bus_size_t regsize;
        pcireg_t v;
        pci_intr_handle_t ih;
        const char *intrrupt_str;
@@ -780,7 +790,7 @@
        sc->dmat = pa->pa_dmat;
        aprint_normal(": Generic High Definition Audio Controller\n");
        if (pci_mapreg_map(pa, ICH_PCI_HDBARL, PCI_MAPREG_MEM_TYPE_64BIT, 0,
-                          &sc->iot, &sc->ioh, NULL, &regsize)) {
+                          &sc->iot, &sc->ioh, NULL, &sc->map_size)) {
                aprint_error("%s: can't map device i/o space\n", XNAME(sc));
                return;
        }
@@ -795,6 +805,7 @@
                aprint_error("%s: can't map interrupt\n", XNAME(sc));
                return;
        }
+       sc->pc = pa->pa_pc;
        intrrupt_str = pci_intr_string(pa->pa_pc, ih);
        sc->ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, azalia_intr, sc);
        if (sc->ih == NULL) {
@@ -818,18 +829,58 @@
 
        if (azalia_attach(sc)) {
                aprint_error("%s: initialization failure\n", XNAME(sc));
+               azalia_pci_detach(self, 0);
                return;
        }
        config_interrupts(self, azalia_attach_intr);
 }
 
 static int
+azalia_pci_activate(struct device *self, enum devact act)
+{
+       azalia_t *sc;
+       int ret;
+
+       sc = (azalia_t*)self;
+       ret = 0;
+       switch (act) {
+       case DVACT_ACTIVATE:
+               return EOPNOTSUPP;
+       case DVACT_DEACTIVATE:
+               if (sc->audiodev != NULL)
+                       ret = config_deactivate(sc->audiodev);
+               return ret;
+       }
+       return EOPNOTSUPP;
+}
+
+static int
 azalia_pci_detach(struct device *self, int flags)
 {
        azalia_t *az;
+       int i;
 
        az = (azalia_t*)self;
-       azalia_free_dmamem(az, &az->corb_dma);
+       if (az->audiodev != NULL) {
+               config_detach(az->audiodev, flags);
+               az->audiodev = NULL;
+       }
+       azalia_stream_delete(&az->rstream, az);
+       azalia_stream_delete(&az->pstream, az);
+       for (i = 0; i < az->ncodecs; i++) {
+               azalia_codec_delete(&az->codecs[i]);
+       }
+       az->ncodecs = 0;
+       azalia_delete_corb(az);
+       azalia_delete_rirb(az);
+       if (az->ih != NULL) {
+               pci_intr_disestablish(az->pc, az->ih);
+               az->ih = NULL;
+       }
+       if (az->map_size != 0) {
+               bus_space_unmap(az->iot, az->ioh, az->map_size);
+               az->map_size = 0;
+       }
        return 0;
 }
 
@@ -958,18 +1009,20 @@
        for (i = 0; i < az->ncodecs; i++) {
                err = azalia_codec_init(&az->codecs[i]);
                if (err)
-                       return;
+                       goto err_exit;
        }
 
        if (azalia_stream_init(&az->pstream, az, az->nistreams + 0,
            1, AUMODE_PLAY))
-               return;
+               goto err_exit;
        if (azalia_stream_init(&az->rstream, az, 0, 2, AUMODE_RECORD))
-               return;
+               goto err_exit;
 
        az->audiodev = audio_attach_mi(&azalia_hw_if, az, &az->dev);
        return;
-       /* XXX deallocation on errors */
+err_exit:
+       azalia_pci_detach(self, 0);
+       return;
 }
 
 static int
@@ -1064,6 +1117,27 @@
 }
 
 static int
+azalia_delete_corb(azalia_t *az)
+{
+       int i;
+       uint8_t corbctl;
+
+       if (az->corb_dma.addr == NULL)
+               return 0;
+       /* stop the CORB */
+       corbctl = AZ_READ_1(az, CORBCTL);
+       AZ_WRITE_1(az, CORBCTL, corbctl & ~HDA_CORBCTL_CORBRUN);
+       for (i = 5000; i >= 0; i--) {
+               DELAY(10);
+               corbctl = AZ_READ_1(az, CORBCTL);
+               if ((corbctl & HDA_CORBCTL_CORBRUN) == 0)
+                       break;
+       }
+       azalia_free_dmamem(az, &az->corb_dma);
+       return 0;
+}
+
+static int
 azalia_init_rirb(azalia_t *az)
 {
        int entries, err, i;
@@ -1137,6 +1211,27 @@
 }
 
 static int
+azalia_delete_rirb(azalia_t *az)
+{
+       int i;
+       uint8_t rirbctl;
+
+       if (az->rirb_dma.addr == NULL)
+               return 0;
+       /* stop the RIRB */
+       rirbctl = AZ_READ_1(az, RIRBCTL);
+       AZ_WRITE_1(az, RIRBCTL, rirbctl & ~HDA_RIRBCTL_RIRBDMAEN);
+       for (i = 5000; i >= 0; i--) {
+               DELAY(10);
+               rirbctl = AZ_READ_1(az, RIRBCTL);
+               if ((rirbctl & HDA_RIRBCTL_RIRBDMAEN) == 0)
+                       break;
+       }
+       azalia_free_dmamem(az, &az->rirb_dma);
+       return 0;
+}
+
+static int
 azalia_set_command(const azalia_t *az, int caddr, nid_t nid, uint32_t control,
                   uint32_t param)
 {
@@ -1242,16 +1337,20 @@
        bus_dmamem_unmap(az->dmat, d->addr, size);
 free:
        bus_dmamem_free(az->dmat, d->segments, 1);
+       d->addr = NULL;
        return err;
 }
 
 static int
 azalia_free_dmamem(const azalia_t *az, azalia_dma_t* d)
 {
+       if (d->addr == NULL)
+               return 0;
        bus_dmamap_unload(az->dmat, d->map);
        bus_dmamap_destroy(az->dmat, d->map);
        bus_dmamem_unmap(az->dmat, d->addr, d->size);
        bus_dmamem_free(az->dmat, d->segments, 1);
+       d->addr = NULL;
        return 0;
 }
 
@@ -1262,9 +1361,8 @@
 static int
 azalia_codec_init(codec_t *this)
 {
-       uint32_t rev, result, digital;
-       int err, addr, n, i, j;
-       int assoc, dac, seq, group;
+       uint32_t rev, result;
+       int err, addr, n, i;
 
        this->comresp = azalia_codec_comresp;
 
@@ -1343,6 +1441,32 @@
                        return err;
        }
 
+       azalia_codec_init_dacgroup(this);
+       err = azalia_codec_construct_format(this);
+       if (err)
+               return err;
+
+       return azalia_mixer_init(this);
+}



Home | Main Index | Thread Index | Old Index