Make snd_maestro3(4) mpsafe
- Let m3_pchan_trigger()/m3_rchan_trigger() acquire lock and call m3_pchan_trigger_locked()/m3_rchan_trigger_locked() respectivly. - Mark interrupt handler INTR_MPSAFE. - Add locks in sound/channel interface. Tested by: nork
This commit is contained in:
parent
8e7b8f0de7
commit
5e20a003d4
@ -86,6 +86,8 @@ static struct m3_card_type {
|
||||
{ 0, 0, 0, 0, NULL }
|
||||
};
|
||||
|
||||
#define M3_BUFSIZE_MIN 1024
|
||||
#define M3_BUFSIZE_MAX 65536
|
||||
#define M3_BUFSIZE_DEFAULT 4096
|
||||
#define M3_PCHANS 4 /* create /dev/dsp0.[0-N] to use more than one */
|
||||
#define M3_RCHANS 1
|
||||
@ -142,8 +144,14 @@ struct sc_info {
|
||||
int pch_active_cnt;
|
||||
unsigned int bufsz;
|
||||
u_int16_t *savemem;
|
||||
|
||||
struct mtx *sc_lock;
|
||||
};
|
||||
|
||||
#define M3_LOCK(_sc) snd_mtxlock((_sc)->sc_lock)
|
||||
#define M3_UNLOCK(_sc) snd_mtxunlock((_sc)->sc_lock)
|
||||
#define M3_LOCK_ASSERT(_sc) snd_mtxassert((_sc)->sc_lock)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/* play channel interface */
|
||||
@ -153,6 +161,7 @@ static int m3_pchan_setformat(kobj_t, void *, u_int32_t);
|
||||
static int m3_pchan_setspeed(kobj_t, void *, u_int32_t);
|
||||
static int m3_pchan_setblocksize(kobj_t, void *, u_int32_t);
|
||||
static int m3_pchan_trigger(kobj_t, void *, int);
|
||||
static int m3_pchan_trigger_locked(kobj_t, void *, int);
|
||||
static int m3_pchan_getptr(kobj_t, void *);
|
||||
static struct pcmchan_caps *m3_pchan_getcaps(kobj_t, void *);
|
||||
|
||||
@ -163,6 +172,7 @@ static int m3_rchan_setformat(kobj_t, void *, u_int32_t);
|
||||
static int m3_rchan_setspeed(kobj_t, void *, u_int32_t);
|
||||
static int m3_rchan_setblocksize(kobj_t, void *, u_int32_t);
|
||||
static int m3_rchan_trigger(kobj_t, void *, int);
|
||||
static int m3_rchan_trigger_locked(kobj_t, void *, int);
|
||||
static int m3_rchan_getptr(kobj_t, void *);
|
||||
static struct pcmchan_caps *m3_rchan_getcaps(kobj_t, void *);
|
||||
|
||||
@ -351,31 +361,36 @@ m3_pchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel
|
||||
struct sc_info *sc = devinfo;
|
||||
struct sc_pchinfo *ch;
|
||||
u_int32_t bus_addr, i;
|
||||
int idx, data_bytes, dac_data;
|
||||
int dsp_in_size, dsp_out_size, dsp_in_buf, dsp_out_buf;
|
||||
|
||||
int idx = sc->pch_cnt; /* dac instance number, no active reuse! */
|
||||
int data_bytes = (((MINISRC_TMP_BUFFER_SIZE & ~1) +
|
||||
(MINISRC_IN_BUFFER_SIZE & ~1) +
|
||||
(MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255) &~ 255;
|
||||
int dac_data = 0x1100 + (data_bytes * idx);
|
||||
|
||||
int dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2);
|
||||
int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2);
|
||||
int dsp_in_buf = dac_data + (MINISRC_TMP_BUFFER_SIZE/2);
|
||||
int dsp_out_buf = dsp_in_buf + (dsp_in_size/2) + 1;
|
||||
|
||||
M3_LOCK(sc);
|
||||
idx = sc->pch_cnt; /* dac instance number, no active reuse! */
|
||||
M3_DEBUG(CHANGE, ("m3_pchan_init(dac=%d)\n", idx));
|
||||
|
||||
if (dir != PCMDIR_PLAY) {
|
||||
M3_UNLOCK(sc);
|
||||
device_printf(sc->dev, "m3_pchan_init not PCMDIR_PLAY\n");
|
||||
return NULL;
|
||||
return (NULL);
|
||||
}
|
||||
ch = &sc->pch[idx];
|
||||
|
||||
data_bytes = (((MINISRC_TMP_BUFFER_SIZE & ~1) +
|
||||
(MINISRC_IN_BUFFER_SIZE & ~1) +
|
||||
(MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255) &~ 255;
|
||||
dac_data = 0x1100 + (data_bytes * idx);
|
||||
|
||||
dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2);
|
||||
dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2);
|
||||
dsp_in_buf = dac_data + (MINISRC_TMP_BUFFER_SIZE/2);
|
||||
dsp_out_buf = dsp_in_buf + (dsp_in_size/2) + 1;
|
||||
|
||||
ch = &sc->pch[idx];
|
||||
ch->dac_idx = idx;
|
||||
ch->dac_data = dac_data;
|
||||
if (ch->dac_data + data_bytes/2 >= 0x1c00) {
|
||||
M3_UNLOCK(sc);
|
||||
device_printf(sc->dev, "m3_pchan_init: revb mem exhausted\n");
|
||||
return NULL;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ch->buffer = b;
|
||||
@ -383,10 +398,12 @@ m3_pchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel
|
||||
ch->channel = c;
|
||||
ch->fmt = AFMT_U8;
|
||||
ch->spd = DSP_DEFAULT_SPEED;
|
||||
M3_UNLOCK(sc); /* XXX */
|
||||
if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) != 0) {
|
||||
device_printf(sc->dev, "m3_pchan_init chn_allocbuf failed\n");
|
||||
return NULL;
|
||||
return (NULL);
|
||||
}
|
||||
M3_LOCK(sc);
|
||||
ch->bufsize = sndbuf_getsize(ch->buffer);
|
||||
|
||||
/* host dma buffer pointers */
|
||||
@ -444,11 +461,15 @@ m3_pchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel
|
||||
m3_wr_assp_data(sc, KDATA_MIXER_XFER0 + sc->pch_cnt,
|
||||
ch->dac_data >> DP_SHIFT_COUNT);
|
||||
|
||||
m3_pchan_trigger(NULL, ch, PCMTRIG_START); /* gotta start before stop */
|
||||
m3_pchan_trigger(NULL, ch, PCMTRIG_STOP); /* silence noise on load */
|
||||
/* gotta start before stop */
|
||||
m3_pchan_trigger_locked(NULL, ch, PCMTRIG_START);
|
||||
/* silence noise on load */
|
||||
m3_pchan_trigger_locked(NULL, ch, PCMTRIG_STOP);
|
||||
|
||||
sc->pch_cnt++;
|
||||
return ch;
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (ch);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -457,6 +478,7 @@ m3_pchan_free(kobj_t kobj, void *chdata)
|
||||
struct sc_pchinfo *ch = chdata;
|
||||
struct sc_info *sc = ch->parent;
|
||||
|
||||
M3_LOCK(sc);
|
||||
M3_DEBUG(CHANGE, ("m3_pchan_free(dac=%d)\n", ch->dac_idx));
|
||||
|
||||
/*
|
||||
@ -468,9 +490,10 @@ m3_pchan_free(kobj_t kobj, void *chdata)
|
||||
m3_wr_assp_data(sc, KDATA_DMA_XFER0 +
|
||||
(sc->pch_cnt - 1) + sc->rch_cnt, 0);
|
||||
m3_wr_assp_data(sc, KDATA_MIXER_XFER0 + (sc->pch_cnt-1), 0);
|
||||
|
||||
sc->pch_cnt--;
|
||||
return 0;
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -480,6 +503,7 @@ m3_pchan_setformat(kobj_t kobj, void *chdata, u_int32_t format)
|
||||
struct sc_info *sc = ch->parent;
|
||||
u_int32_t data;
|
||||
|
||||
M3_LOCK(sc);
|
||||
M3_DEBUG(CHANGE,
|
||||
("m3_pchan_setformat(dac=%d, format=0x%x{%s-%s})\n",
|
||||
ch->dac_idx, format,
|
||||
@ -495,7 +519,9 @@ m3_pchan_setformat(kobj_t kobj, void *chdata, u_int32_t format)
|
||||
m3_wr_assp_data(sc, ch->dac_data + SRC3_WORD_LENGTH_OFFSET, data);
|
||||
|
||||
ch->fmt = format;
|
||||
return 0;
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -505,6 +531,7 @@ m3_pchan_setspeed(kobj_t kobj, void *chdata, u_int32_t speed)
|
||||
struct sc_info *sc = ch->parent;
|
||||
u_int32_t freq;
|
||||
|
||||
M3_LOCK(sc);
|
||||
M3_DEBUG(CHANGE, ("m3_pchan_setspeed(dac=%d, speed=%d)\n",
|
||||
ch->dac_idx, speed));
|
||||
|
||||
@ -513,9 +540,11 @@ m3_pchan_setspeed(kobj_t kobj, void *chdata, u_int32_t speed)
|
||||
}
|
||||
|
||||
m3_wr_assp_data(sc, ch->dac_data + CDATA_FREQUENCY, freq);
|
||||
|
||||
ch->spd = speed;
|
||||
return speed; /* return closest possible speed */
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
/* return closest possible speed */
|
||||
return (speed);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -531,11 +560,26 @@ m3_pchan_setblocksize(kobj_t kobj, void *chdata, u_int32_t blocksize)
|
||||
|
||||
static int
|
||||
m3_pchan_trigger(kobj_t kobj, void *chdata, int go)
|
||||
{
|
||||
struct sc_pchinfo *ch = chdata;
|
||||
struct sc_info *sc = ch->parent;
|
||||
int ret;
|
||||
|
||||
M3_LOCK(sc);
|
||||
ret = m3_pchan_trigger_locked(kobj, chdata, go);
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
m3_pchan_trigger_locked(kobj_t kobj, void *chdata, int go)
|
||||
{
|
||||
struct sc_pchinfo *ch = chdata;
|
||||
struct sc_info *sc = ch->parent;
|
||||
u_int32_t data;
|
||||
|
||||
M3_LOCK_ASSERT(sc);
|
||||
M3_DEBUG(go == PCMTRIG_START ? CHANGE :
|
||||
go == PCMTRIG_STOP ? CHANGE :
|
||||
go == PCMTRIG_ABORT ? CHANGE :
|
||||
@ -599,15 +643,17 @@ m3_pchan_getptr(kobj_t kobj, void *chdata)
|
||||
{
|
||||
struct sc_pchinfo *ch = chdata;
|
||||
struct sc_info *sc = ch->parent;
|
||||
u_int32_t hi, lo, bus_crnt;
|
||||
u_int32_t bus_base = sndbuf_getbufaddr(ch->buffer);
|
||||
u_int32_t hi, lo, bus_base, bus_crnt;
|
||||
|
||||
M3_LOCK(sc);
|
||||
bus_base = sndbuf_getbufaddr(ch->buffer);
|
||||
hi = m3_rd_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTH);
|
||||
lo = m3_rd_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTL);
|
||||
bus_crnt = lo | (hi << 16);
|
||||
|
||||
M3_DEBUG(CALL, ("m3_pchan_getptr(dac=%d) result=%d\n",
|
||||
ch->dac_idx, bus_crnt - bus_base));
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (bus_crnt - bus_base); /* current byte offset of channel */
|
||||
}
|
||||
@ -632,30 +678,35 @@ m3_rchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel
|
||||
struct sc_rchinfo *ch;
|
||||
u_int32_t bus_addr, i;
|
||||
|
||||
int idx = sc->rch_cnt; /* adc instance number, no active reuse! */
|
||||
int data_bytes = (((MINISRC_TMP_BUFFER_SIZE & ~1) +
|
||||
(MINISRC_IN_BUFFER_SIZE & ~1) +
|
||||
(MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255) &~ 255;
|
||||
int adc_data = 0x1100 + (data_bytes * idx) + data_bytes/2;
|
||||
|
||||
int dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2);
|
||||
int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2);
|
||||
int dsp_in_buf = adc_data + (MINISRC_TMP_BUFFER_SIZE / 2);
|
||||
int dsp_out_buf = dsp_in_buf + (dsp_in_size / 2) + 1;
|
||||
int idx, data_bytes, adc_data;
|
||||
int dsp_in_size, dsp_out_size, dsp_in_buf, dsp_out_buf;
|
||||
|
||||
M3_LOCK(sc);
|
||||
idx = sc->rch_cnt; /* adc instance number, no active reuse! */
|
||||
M3_DEBUG(CHANGE, ("m3_rchan_init(adc=%d)\n", idx));
|
||||
|
||||
if (dir != PCMDIR_REC) {
|
||||
M3_UNLOCK(sc);
|
||||
device_printf(sc->dev, "m3_pchan_init not PCMDIR_REC\n");
|
||||
return NULL;
|
||||
return (NULL);
|
||||
}
|
||||
ch = &sc->rch[idx];
|
||||
|
||||
data_bytes = (((MINISRC_TMP_BUFFER_SIZE & ~1) +
|
||||
(MINISRC_IN_BUFFER_SIZE & ~1) +
|
||||
(MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255) &~ 255;
|
||||
adc_data = 0x1100 + (data_bytes * idx) + data_bytes/2;
|
||||
dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2);
|
||||
dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2);
|
||||
dsp_in_buf = adc_data + (MINISRC_TMP_BUFFER_SIZE / 2);
|
||||
dsp_out_buf = dsp_in_buf + (dsp_in_size / 2) + 1;
|
||||
|
||||
ch = &sc->rch[idx];
|
||||
ch->adc_idx = idx;
|
||||
ch->adc_data = adc_data;
|
||||
if (ch->adc_data + data_bytes/2 >= 0x1c00) {
|
||||
M3_UNLOCK(sc);
|
||||
device_printf(sc->dev, "m3_rchan_init: revb mem exhausted\n");
|
||||
return NULL;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ch->buffer = b;
|
||||
@ -663,10 +714,12 @@ m3_rchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel
|
||||
ch->channel = c;
|
||||
ch->fmt = AFMT_U8;
|
||||
ch->spd = DSP_DEFAULT_SPEED;
|
||||
M3_UNLOCK(sc); /* XXX */
|
||||
if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) != 0) {
|
||||
device_printf(sc->dev, "m3_rchan_init chn_allocbuf failed\n");
|
||||
return NULL;
|
||||
return (NULL);
|
||||
}
|
||||
M3_LOCK(sc);
|
||||
ch->bufsize = sndbuf_getsize(ch->buffer);
|
||||
|
||||
/* host dma buffer pointers */
|
||||
@ -719,11 +772,15 @@ m3_rchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel
|
||||
m3_wr_assp_data(sc, KDATA_ADC1_XFER0 + sc->rch_cnt,
|
||||
ch->adc_data >> DP_SHIFT_COUNT);
|
||||
|
||||
m3_rchan_trigger(NULL, ch, PCMTRIG_START); /* gotta start before stop */
|
||||
m3_rchan_trigger(NULL, ch, PCMTRIG_STOP); /* stop on init */
|
||||
/* gotta start before stop */
|
||||
m3_rchan_trigger_locked(NULL, ch, PCMTRIG_START);
|
||||
/* stop on init */
|
||||
m3_rchan_trigger_locked(NULL, ch, PCMTRIG_STOP);
|
||||
|
||||
sc->rch_cnt++;
|
||||
return ch;
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (ch);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -732,6 +789,7 @@ m3_rchan_free(kobj_t kobj, void *chdata)
|
||||
struct sc_rchinfo *ch = chdata;
|
||||
struct sc_info *sc = ch->parent;
|
||||
|
||||
M3_LOCK(sc);
|
||||
M3_DEBUG(CHANGE, ("m3_rchan_free(adc=%d)\n", ch->adc_idx));
|
||||
|
||||
/*
|
||||
@ -743,9 +801,10 @@ m3_rchan_free(kobj_t kobj, void *chdata)
|
||||
m3_wr_assp_data(sc, KDATA_DMA_XFER0 +
|
||||
(sc->rch_cnt - 1) + sc->pch_cnt, 0);
|
||||
m3_wr_assp_data(sc, KDATA_ADC1_XFER0 + (sc->rch_cnt - 1), 0);
|
||||
|
||||
sc->rch_cnt--;
|
||||
return 0;
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -755,6 +814,7 @@ m3_rchan_setformat(kobj_t kobj, void *chdata, u_int32_t format)
|
||||
struct sc_info *sc = ch->parent;
|
||||
u_int32_t data;
|
||||
|
||||
M3_LOCK(sc);
|
||||
M3_DEBUG(CHANGE,
|
||||
("m3_rchan_setformat(dac=%d, format=0x%x{%s-%s})\n",
|
||||
ch->adc_idx, format,
|
||||
@ -768,9 +828,10 @@ m3_rchan_setformat(kobj_t kobj, void *chdata, u_int32_t format)
|
||||
/* 8bit word */
|
||||
data = ((format & AFMT_U8) || (format & AFMT_S8)) ? 1 : 0;
|
||||
m3_wr_assp_data(sc, ch->adc_data + SRC3_WORD_LENGTH_OFFSET, data);
|
||||
|
||||
ch->fmt = format;
|
||||
return 0;
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -780,6 +841,7 @@ m3_rchan_setspeed(kobj_t kobj, void *chdata, u_int32_t speed)
|
||||
struct sc_info *sc = ch->parent;
|
||||
u_int32_t freq;
|
||||
|
||||
M3_LOCK(sc);
|
||||
M3_DEBUG(CHANGE, ("m3_rchan_setspeed(adc=%d, speed=%d)\n",
|
||||
ch->adc_idx, speed));
|
||||
|
||||
@ -788,9 +850,11 @@ m3_rchan_setspeed(kobj_t kobj, void *chdata, u_int32_t speed)
|
||||
}
|
||||
|
||||
m3_wr_assp_data(sc, ch->adc_data + CDATA_FREQUENCY, freq);
|
||||
|
||||
ch->spd = speed;
|
||||
return speed; /* return closest possible speed */
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
/* return closest possible speed */
|
||||
return (speed);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -806,11 +870,26 @@ m3_rchan_setblocksize(kobj_t kobj, void *chdata, u_int32_t blocksize)
|
||||
|
||||
static int
|
||||
m3_rchan_trigger(kobj_t kobj, void *chdata, int go)
|
||||
{
|
||||
struct sc_rchinfo *ch = chdata;
|
||||
struct sc_info *sc = ch->parent;
|
||||
int ret;
|
||||
|
||||
M3_LOCK(sc);
|
||||
ret = m3_rchan_trigger_locked(kobj, chdata, go);
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
m3_rchan_trigger_locked(kobj_t kobj, void *chdata, int go)
|
||||
{
|
||||
struct sc_rchinfo *ch = chdata;
|
||||
struct sc_info *sc = ch->parent;
|
||||
u_int32_t data;
|
||||
|
||||
M3_LOCK_ASSERT(sc);
|
||||
M3_DEBUG(go == PCMTRIG_START ? CHANGE :
|
||||
go == PCMTRIG_STOP ? CHANGE :
|
||||
go == PCMTRIG_ABORT ? CHANGE :
|
||||
@ -869,15 +948,17 @@ m3_rchan_getptr(kobj_t kobj, void *chdata)
|
||||
{
|
||||
struct sc_rchinfo *ch = chdata;
|
||||
struct sc_info *sc = ch->parent;
|
||||
u_int32_t hi, lo, bus_crnt;
|
||||
u_int32_t bus_base = sndbuf_getbufaddr(ch->buffer);
|
||||
u_int32_t hi, lo, bus_base, bus_crnt;
|
||||
|
||||
M3_LOCK(sc);
|
||||
bus_base = sndbuf_getbufaddr(ch->buffer);
|
||||
hi = m3_rd_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTH);
|
||||
lo = m3_rd_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTL);
|
||||
bus_crnt = lo | (hi << 16);
|
||||
|
||||
M3_DEBUG(CALL, ("m3_rchan_getptr(adc=%d) result=%d\n",
|
||||
ch->adc_idx, bus_crnt - bus_base));
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (bus_crnt - bus_base); /* current byte offset of channel */
|
||||
}
|
||||
@ -903,9 +984,12 @@ m3_intr(void *p)
|
||||
|
||||
M3_DEBUG(INTR, ("m3_intr\n"));
|
||||
|
||||
M3_LOCK(sc);
|
||||
status = m3_rd_1(sc, HOST_INT_STATUS);
|
||||
if (!status)
|
||||
if (!status) {
|
||||
M3_UNLOCK(sc);
|
||||
return;
|
||||
}
|
||||
|
||||
m3_wr_1(sc, HOST_INT_STATUS, 0xff); /* ack the int? */
|
||||
|
||||
@ -946,14 +1030,20 @@ m3_intr(void *p)
|
||||
|
||||
for (i=0 ; i<sc->pch_cnt ; i++) {
|
||||
if (sc->pch[i].active) {
|
||||
M3_UNLOCK(sc);
|
||||
chn_intr(sc->pch[i].channel);
|
||||
M3_LOCK(sc);
|
||||
}
|
||||
}
|
||||
for (i=0 ; i<sc->rch_cnt ; i++) {
|
||||
if (sc->rch[i].active) {
|
||||
M3_UNLOCK(sc);
|
||||
chn_intr(sc->rch[i].channel);
|
||||
M3_LOCK(sc);
|
||||
}
|
||||
}
|
||||
|
||||
M3_UNLOCK(sc);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@ -965,6 +1055,7 @@ m3_power(struct sc_info *sc, int state)
|
||||
u_int32_t data;
|
||||
|
||||
M3_DEBUG(CHANGE, ("m3_power(%d)\n", state));
|
||||
M3_LOCK_ASSERT(sc);
|
||||
|
||||
data = pci_read_config(sc->dev, 0x34, 1);
|
||||
if (pci_read_config(sc->dev, data, 1) == 1) {
|
||||
@ -980,6 +1071,7 @@ m3_init(struct sc_info *sc)
|
||||
u_int32_t data, i, size;
|
||||
u_int8_t reset_state;
|
||||
|
||||
M3_LOCK_ASSERT(sc);
|
||||
M3_DEBUG(CHANGE, ("m3_init\n"));
|
||||
|
||||
/* diable legacy emulations. */
|
||||
@ -1095,7 +1187,13 @@ m3_pci_attach(device_t dev)
|
||||
|
||||
sc->dev = dev;
|
||||
sc->type = pci_get_devid(dev);
|
||||
|
||||
sc->sc_lock = snd_mtxcreate(device_get_nameunit(dev),
|
||||
"sound softc");
|
||||
if (sc->sc_lock == NULL) {
|
||||
device_printf(dev, "cannot create mutex\n");
|
||||
free(sc, M_DEVBUF);
|
||||
return (ENXIO);
|
||||
}
|
||||
for (card = m3_card_types ; card->pci_id ; card++) {
|
||||
if (sc->type == card->pci_id) {
|
||||
sc->which = card->which;
|
||||
@ -1133,29 +1231,37 @@ m3_pci_attach(device_t dev)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (snd_setup_intr(dev, sc->irq, 0, m3_intr, sc, &sc->ih)) {
|
||||
if (snd_setup_intr(dev, sc->irq, INTR_MPSAFE, m3_intr, sc, &sc->ih)) {
|
||||
device_printf(dev, "unable to setup interrupt\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
sc->bufsz = pcm_getbuffersize(dev, 1024, M3_BUFSIZE_DEFAULT, 65536);
|
||||
sc->bufsz = pcm_getbuffersize(dev, M3_BUFSIZE_MAX, M3_BUFSIZE_DEFAULT,
|
||||
M3_BUFSIZE_MAX);
|
||||
|
||||
if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
|
||||
/*lowaddr*/M3_MAXADDR,
|
||||
/*highaddr*/BUS_SPACE_MAXADDR,
|
||||
/*filter*/NULL, /*filterarg*/NULL,
|
||||
/*maxsize*/sc->bufsz, /*nsegments*/1,
|
||||
/*maxsegz*/0x3ffff,
|
||||
/*flags*/0, /*lockfunc*/busdma_lock_mutex,
|
||||
/*lockarg*/&Giant, &sc->parent_dmat) != 0) {
|
||||
if (bus_dma_tag_create(
|
||||
NULL, /* parent */
|
||||
2, 0, /* alignment, boundary */
|
||||
M3_MAXADDR, /* lowaddr */
|
||||
BUS_SPACE_MAXADDR, /* highaddr */
|
||||
NULL, NULL, /* filtfunc, filtfuncarg */
|
||||
sc->bufsz, /* maxsize */
|
||||
1, /* nsegments */
|
||||
0x3ffff, /* maxsegz */
|
||||
0, /* flags */
|
||||
NULL, /* lockfunc */
|
||||
NULL, /* lockfuncarg */
|
||||
&sc->parent_dmat) != 0) {
|
||||
device_printf(dev, "unable to create dma tag\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
M3_LOCK(sc);
|
||||
m3_power(sc, 0); /* power up */
|
||||
|
||||
/* init chip */
|
||||
if (m3_init(sc) == -1) {
|
||||
i = m3_init(sc);
|
||||
M3_UNLOCK(sc);
|
||||
if (i == -1) {
|
||||
device_printf(dev, "unable to initialize the card\n");
|
||||
goto bad;
|
||||
}
|
||||
@ -1190,8 +1296,9 @@ m3_pci_attach(device_t dev)
|
||||
}
|
||||
}
|
||||
snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
|
||||
(sc->regtype == SYS_RES_IOPORT)? "io" : "memory",
|
||||
rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_maestro3));
|
||||
(sc->regtype == SYS_RES_IOPORT)? "io" : "memory",
|
||||
rman_get_start(sc->reg), rman_get_start(sc->irq),
|
||||
PCM_KLDSTRING(snd_maestro3));
|
||||
if (pcm_setstatus(dev, status)) {
|
||||
device_printf(dev, "attach: pcm_setstatus error\n");
|
||||
goto bad;
|
||||
@ -1211,21 +1318,18 @@ m3_pci_attach(device_t dev)
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
if (codec) {
|
||||
if (codec)
|
||||
ac97_destroy(codec);
|
||||
}
|
||||
if (sc->reg) {
|
||||
bus_release_resource(dev, sc->regtype, sc->regid, sc->reg);
|
||||
}
|
||||
if (sc->ih) {
|
||||
if (sc->ih)
|
||||
bus_teardown_intr(dev, sc->irq, sc->ih);
|
||||
}
|
||||
if (sc->irq) {
|
||||
if (sc->irq)
|
||||
bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
|
||||
}
|
||||
if (sc->parent_dmat) {
|
||||
if (sc->reg)
|
||||
bus_release_resource(dev, sc->regtype, sc->regid, sc->reg);
|
||||
if (sc->parent_dmat)
|
||||
bus_dma_tag_destroy(sc->parent_dmat);
|
||||
}
|
||||
if (sc->sc_lock)
|
||||
snd_mtxfree(sc->sc_lock);
|
||||
free(sc, M_DEVBUF);
|
||||
return ENXIO;
|
||||
}
|
||||
@ -1241,15 +1345,19 @@ m3_pci_detach(device_t dev)
|
||||
if ((r = pcm_unregister(dev)) != 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
M3_LOCK(sc);
|
||||
m3_uninit(sc); /* shutdown chip */
|
||||
m3_power(sc, 3); /* power off */
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
bus_release_resource(dev, sc->regtype, sc->regid, sc->reg);
|
||||
bus_teardown_intr(dev, sc->irq, sc->ih);
|
||||
bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
|
||||
bus_release_resource(dev, sc->regtype, sc->regid, sc->reg);
|
||||
bus_dma_tag_destroy(sc->parent_dmat);
|
||||
|
||||
free(sc->savemem, M_DEVBUF);
|
||||
snd_mtxfree(sc->sc_lock);
|
||||
free(sc, M_DEVBUF);
|
||||
return 0;
|
||||
}
|
||||
@ -1262,14 +1370,17 @@ m3_pci_suspend(device_t dev)
|
||||
|
||||
M3_DEBUG(CHANGE, ("m3_pci_suspend\n"));
|
||||
|
||||
M3_LOCK(sc);
|
||||
for (i=0 ; i<sc->pch_cnt ; i++) {
|
||||
if (sc->pch[i].active) {
|
||||
m3_pchan_trigger(NULL, &sc->pch[i], PCMTRIG_STOP);
|
||||
m3_pchan_trigger_locked(NULL, &sc->pch[i],
|
||||
PCMTRIG_STOP);
|
||||
}
|
||||
}
|
||||
for (i=0 ; i<sc->rch_cnt ; i++) {
|
||||
if (sc->rch[i].active) {
|
||||
m3_rchan_trigger(NULL, &sc->rch[i], PCMTRIG_STOP);
|
||||
m3_rchan_trigger_locked(NULL, &sc->rch[i],
|
||||
PCMTRIG_STOP);
|
||||
}
|
||||
}
|
||||
DELAY(10 * 1000); /* give things a chance to stop */
|
||||
@ -1288,6 +1399,7 @@ m3_pci_suspend(device_t dev)
|
||||
|
||||
/* Power down the card to D3 state */
|
||||
m3_power(sc, 3);
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1301,6 +1413,7 @@ m3_pci_resume(device_t dev)
|
||||
|
||||
M3_DEBUG(CHANGE, ("m3_pci_resume\n"));
|
||||
|
||||
M3_LOCK(sc);
|
||||
/* Power the card back to D0 */
|
||||
m3_power(sc, 0);
|
||||
|
||||
@ -1326,23 +1439,28 @@ m3_pci_resume(device_t dev)
|
||||
|
||||
m3_enable_ints(sc);
|
||||
|
||||
M3_UNLOCK(sc); /* XXX */
|
||||
if (mixer_reinit(dev) == -1) {
|
||||
device_printf(dev, "unable to reinitialize the mixer\n");
|
||||
return ENXIO;
|
||||
return (ENXIO);
|
||||
}
|
||||
M3_LOCK(sc);
|
||||
|
||||
/* Turn the channels back on */
|
||||
for (i=0 ; i<sc->pch_cnt ; i++) {
|
||||
if (sc->pch[i].active) {
|
||||
m3_pchan_trigger(NULL, &sc->pch[i], PCMTRIG_START);
|
||||
m3_pchan_trigger_locked(NULL, &sc->pch[i],
|
||||
PCMTRIG_START);
|
||||
}
|
||||
}
|
||||
for (i=0 ; i<sc->rch_cnt ; i++) {
|
||||
if (sc->rch[i].active) {
|
||||
m3_rchan_trigger(NULL, &sc->rch[i], PCMTRIG_START);
|
||||
m3_rchan_trigger_locked(NULL, &sc->rch[i],
|
||||
PCMTRIG_START);
|
||||
}
|
||||
}
|
||||
|
||||
M3_UNLOCK(sc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1353,7 +1471,10 @@ m3_pci_shutdown(device_t dev)
|
||||
|
||||
M3_DEBUG(CALL, ("m3_pci_shutdown\n"));
|
||||
|
||||
M3_LOCK(sc);
|
||||
m3_power(sc, 3); /* power off */
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1362,6 +1483,8 @@ m3_assp_halt(struct sc_info *sc)
|
||||
{
|
||||
u_int8_t data, reset_state;
|
||||
|
||||
M3_LOCK_ASSERT(sc);
|
||||
|
||||
data = m3_rd_1(sc, DSP_PORT_CONTROL_REG_B);
|
||||
reset_state = data & ~REGB_STOP_CLOCK; /* remember for continue */
|
||||
DELAY(10 * 1000);
|
||||
@ -1377,6 +1500,7 @@ m3_config(struct sc_info *sc)
|
||||
u_int32_t data, hv_cfg;
|
||||
int hint;
|
||||
|
||||
M3_LOCK_ASSERT(sc);
|
||||
/*
|
||||
* The volume buttons can be wired up via two different sets of pins.
|
||||
* This presents a problem since we can't tell which way it's
|
||||
@ -1437,6 +1561,8 @@ m3_amp_enable(struct sc_info *sc)
|
||||
u_int32_t gpo, polarity_port, polarity;
|
||||
u_int16_t data;
|
||||
|
||||
M3_LOCK_ASSERT(sc);
|
||||
|
||||
switch (sc->which) {
|
||||
case ESS_ALLEGRO_1:
|
||||
polarity_port = 0x1800;
|
||||
@ -1466,6 +1592,7 @@ m3_codec_reset(struct sc_info *sc)
|
||||
u_int16_t data, dir;
|
||||
int retry = 0;
|
||||
|
||||
M3_LOCK_ASSERT(sc);
|
||||
do {
|
||||
data = m3_rd_2(sc, GPIO_DIRECTION);
|
||||
dir = data | 0x10; /* assuming pci bus master? */
|
||||
|
Loading…
x
Reference in New Issue
Block a user