diff options
-rw-r--r-- | sys/dev/pci/azalia.c | 126 |
1 files changed, 43 insertions, 83 deletions
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c index 849223b6ac7..b81b51bdf6d 100644 --- a/sys/dev/pci/azalia.c +++ b/sys/dev/pci/azalia.c @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.c,v 1.193 2011/04/08 19:26:07 deraadt Exp $ */ +/* $OpenBSD: azalia.c,v 1.194 2011/04/10 17:10:08 jakemsr Exp $ */ /* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */ /*- @@ -161,8 +161,9 @@ typedef struct azalia_t { codec_t *codecs; int ncodecs; /* number of codecs */ int codecno; /* index of the using codec */ - int detached; /* nonzero if audio(4) is not attached */ - + int detached; /* 1 if failed to initialize, 2 if + * azalia_pci_detach has run + */ azalia_dma_t corb_dma; int corb_entries; uint8_t corbsize; @@ -209,10 +210,8 @@ int azalia_init_streams(azalia_t *); void azalia_shutdown(void *); int azalia_halt_corb(azalia_t *); int azalia_init_corb(azalia_t *, int); -int azalia_delete_corb(azalia_t *); int azalia_halt_rirb(azalia_t *); int azalia_init_rirb(azalia_t *, int); -int azalia_delete_rirb(azalia_t *); int azalia_set_command(azalia_t *, nid_t, int, uint32_t, uint32_t); int azalia_get_response(azalia_t *, uint32_t *); void azalia_rirb_kick_unsol_events(void *); @@ -250,7 +249,6 @@ void azalia_widget_print_audio(const widget_t *, const char *); void azalia_widget_print_pin(const widget_t *); int azalia_stream_init(stream_t *, azalia_t *, int, int, int); -int azalia_stream_delete(stream_t *, azalia_t *); int azalia_stream_reset(stream_t *); int azalia_stream_start(stream_t *); int azalia_stream_halt(stream_t *); @@ -534,9 +532,8 @@ azalia_pci_attach(struct device *parent, struct device *self, void *aux) return; err_exit: - printf("%s: initialization failure, detaching\n", XNAME(sc)); - azalia_pci_detach(self, 0); sc->detached = 1; + azalia_pci_detach(self, 0); } int @@ -569,26 +566,38 @@ azalia_pci_activate(struct device *self, int act) int azalia_pci_detach(struct device *self, int flags) { - azalia_t *az; + azalia_t *az = (azalia_t*)self; uint32_t gctl; int i; DPRINTF(("%s\n", __func__)); - az = (azalia_t*)self; + + /* + * this function is called if the device could not be supported, + * in which case az->detached == 1. check if this function has + * already cleaned up. + */ + if (az->detached > 1) + return 0; + if (az->audiodev != NULL) { config_detach(az->audiodev, flags); az->audiodev = NULL; } - /* disable unsolicited response */ - gctl = AZ_READ_4(az, GCTL); - AZ_WRITE_4(az, GCTL, gctl & ~(HDA_GCTL_UNSOL)); + /* disable unsolicited responses if soft detaching */ + if (az->detached == 1) { + gctl = AZ_READ_4(az, GCTL); + AZ_WRITE_4(az, GCTL, gctl &~(HDA_GCTL_UNSOL)); + } timeout_del(&az->unsol_to); DPRINTF(("%s: delete streams\n", __func__)); - azalia_stream_delete(&az->rstream, az); - azalia_stream_delete(&az->pstream, az); + if (az->rstream.bdlist.addr != NULL) + azalia_free_dmamem(az, &az->rstream.bdlist); + if (az->pstream.bdlist.addr != NULL) + azalia_free_dmamem(az, &az->pstream.bdlist); DPRINTF(("%s: delete codecs\n", __func__)); for (i = 0; i < az->ncodecs; i++) { @@ -601,16 +610,25 @@ azalia_pci_detach(struct device *self, int flags) } DPRINTF(("%s: delete CORB and RIRB\n", __func__)); - azalia_delete_corb(az); - azalia_delete_rirb(az); + if (az->corb_dma.addr != NULL) + azalia_free_dmamem(az, &az->corb_dma); + if (az->rirb_dma.addr != NULL) + azalia_free_dmamem(az, &az->rirb_dma); + if (az->unsolq != NULL) { + free(az->unsolq, M_DEVBUF); + az->unsolq = NULL; + } - DPRINTF(("%s: disable interrupts\n", __func__)); - AZ_WRITE_4(az, INTCTL, 0); + /* disable interrupts if soft detaching */ + if (az->detached == 1) { + DPRINTF(("%s: disable interrupts\n", __func__)); + AZ_WRITE_4(az, INTCTL, 0); - DPRINTF(("%s: clear interrupts\n", __func__)); - AZ_WRITE_4(az, INTSTS, HDA_INTSTS_CIS | HDA_INTSTS_GIS); - AZ_WRITE_2(az, STATESTS, HDA_STATESTS_SDIWAKE); - AZ_WRITE_1(az, RIRBSTS, HDA_RIRBSTS_RINTFL | HDA_RIRBSTS_RIRBOIS); + DPRINTF(("%s: clear interrupts\n", __func__)); + AZ_WRITE_4(az, INTSTS, HDA_INTSTS_CIS | HDA_INTSTS_GIS); + AZ_WRITE_2(az, STATESTS, HDA_STATESTS_SDIWAKE); + AZ_WRITE_1(az, RIRBSTS, HDA_RIRBSTS_RINTFL | HDA_RIRBSTS_RIRBOIS); + } DPRINTF(("%s: delete PCI resources\n", __func__)); if (az->ih != NULL) { @@ -621,6 +639,8 @@ azalia_pci_detach(struct device *self, int flags) bus_space_unmap(az->iot, az->ioh, az->map_size); az->map_size = 0; } + + az->detached = 2; return 0; } @@ -1011,27 +1031,6 @@ azalia_init_corb(azalia_t *az, int resuming) } 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; -} - -int azalia_halt_rirb(azalia_t *az) { int i; @@ -1113,31 +1112,6 @@ azalia_init_rirb(azalia_t *az, int resuming) } int -azalia_delete_rirb(azalia_t *az) -{ - int i; - uint8_t rirbctl; - - if (az->unsolq != NULL) { - free(az->unsolq, M_DEVBUF); - az->unsolq = NULL; - } - 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; -} - -int azalia_comresp(const codec_t *codec, nid_t nid, uint32_t control, uint32_t param, uint32_t* result) { @@ -3656,20 +3630,6 @@ azalia_stream_init(stream_t *this, azalia_t *az, int regindex, int strnum, } int -azalia_stream_delete(stream_t *this, azalia_t *az) -{ - if (this->bdlist.addr == NULL) - return 0; - - /* disable stream interrupts */ - STR_WRITE_1(this, CTL, STR_READ_1(this, CTL) | - ~(HDA_SD_CTL_DEIE | HDA_SD_CTL_FEIE | HDA_SD_CTL_IOCE)); - - azalia_free_dmamem(az, &this->bdlist); - return 0; -} - -int azalia_stream_reset(stream_t *this) { int i; |