summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pci/azalia.c126
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;