diff --git a/sys/dev/sbus/dbri.c b/sys/dev/sbus/dbri.c index f5b8ffc33688..ff3367cddf1e 100644 --- a/sys/dev/sbus/dbri.c +++ b/sys/dev/sbus/dbri.c @@ -1,4 +1,4 @@ -/* $NetBSD: dbri.c,v 1.12 2007/03/11 08:52:12 macallan Exp $ */ +/* $NetBSD: dbri.c,v 1.13 2007/03/14 05:40:35 macallan Exp $ */ /* * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) @@ -42,7 +42,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: dbri.c,v 1.12 2007/03/11 08:52:12 macallan Exp $"); +__KERNEL_RCSID(0, "$NetBSD: dbri.c,v 1.13 2007/03/14 05:40:35 macallan Exp $"); #include "audio.h" #if NAUDIO > 0 @@ -144,6 +144,7 @@ static int dbri_set_params(void *, int, int, struct audio_params *, struct audio_params *,stream_filter_list_t *, stream_filter_list_t *); static int dbri_round_blocksize(void *, int, int, const audio_params_t *); static int dbri_halt_output(void *); +static int dbri_halt_input(void *); static int dbri_getdev(void *, struct audio_device *); static int dbri_set_port(void *, mixer_ctrl_t *); static int dbri_get_port(void *, mixer_ctrl_t *); @@ -158,6 +159,8 @@ static void setup_ring(struct dbri_softc *, int, int, int, int, static int dbri_trigger_output(void *, void *, void *, int, void (*)(void *), void *, const struct audio_params *); +static int dbri_trigger_input(void *, void *, void *, int, + void (*)(void *), void *, const struct audio_params *); static void *dbri_malloc(void *, int, size_t, struct malloc_type *, int); static void dbri_free(void *, void *, struct malloc_type *); @@ -188,7 +191,7 @@ struct audio_hw_if dbri_hw_if = { NULL, /* start_output */ NULL, /* start_input */ dbri_halt_output, - NULL, /* halt_input */ + dbri_halt_input, NULL, /* speaker_ctl */ dbri_getdev, NULL, /* setfd */ @@ -201,7 +204,7 @@ struct audio_hw_if dbri_hw_if = { dbri_mappage, dbri_get_props, dbri_trigger_output, - NULL /* trigger_input */ + dbri_trigger_input }; CFATTACH_DECL(dbri, sizeof(struct dbri_softc), @@ -226,18 +229,18 @@ static const struct audio_format dbri_formats[DBRI_NFORMATS] = { }; enum { - DBRI_MONITOR_CLASS, + DBRI_OUTPUT_CLASS, DBRI_VOL_OUTPUT, DBRI_ENABLE_MONO, DBRI_ENABLE_HEADPHONE, - DBRI_ENABLE_LINE -/* + DBRI_ENABLE_LINE, + DBRI_MONITOR_CLASS, + DBRI_VOL_MONITOR, DBRI_INPUT_CLASS, - DBRI_RECORD_CLASS, DBRI_INPUT_GAIN, DBRI_INPUT_SELECT, + DBRI_RECORD_CLASS, DBRI_ENUM_LAST -*/ }; /* @@ -277,7 +280,7 @@ dbri_attach_sbus(struct device *parent, struct device *self, void *aux) sc->sc_powerstate = PWR_RESUME; pwr = prom_getpropint(sa->sa_node,"pwr-on-auxio",0); - printf(": rev %s\n", ver); + aprint_normal(": rev %s\n", ver); if (pwr) { /* @@ -361,7 +364,9 @@ dbri_attach_sbus(struct device *parent, struct device *self, void *aux) sc->sc_locked = 0; sc->sc_desc_used = 0; - + sc->sc_open = 0; + sc->sc_playing = 0; + sc->sc_pmgrstate = PWR_RESUME; config_interrupts(self, &dbri_config_interrupts); return; @@ -386,7 +391,7 @@ dbri_set_power(struct dbri_softc *sc, int state) *AUXIO4M_REG |= (AUXIO4M_MMX); splx(s); delay(10000); - DPRINTF("done (%02x})\n", *AUXIO4M_REG); + DPRINTF("done (%02x)\n", *AUXIO4M_REG); } else { DPRINTF("%s: powering down\n", sc->sc_dev.dv_xname); s = splhigh(); @@ -668,8 +673,8 @@ dbri_process_interrupt(struct dbri_softc *sc, int32_t i) val = reverse_bytes(val, sc->sc_pipe[channel].length); if (sc->sc_pipe[channel].prec) *(sc->sc_pipe[channel].prec) = val; +#ifndef DBRI_SPIN DPRINTF("%s: wakeup %p\n", sc->sc_dev.dv_xname, sc); -#if 0 wakeup(sc); #endif break; @@ -685,7 +690,8 @@ dbri_process_interrupt(struct dbri_softc *sc, int32_t i) DPRINTF("dbri_intr: BRDY\n"); if (rd < 0 || rd >= DBRI_NUM_DESCRIPTORS) { - printf("%s: invalid rd on pipe\n", sc->sc_dev.dv_xname); + aprint_error("%s: invalid rd on pipe\n", + sc->sc_dev.dv_xname); break; } @@ -800,8 +806,6 @@ mmcodec_init(struct dbri_softc *sc) mmcodec_init_data(sc); - sc->sc_open = 0; - return (0); } @@ -876,8 +880,15 @@ mmcodec_default(struct dbri_softc *sc) */ mm->d.bdata[0] = sc->sc_latt = 0x20 | CS4215_HE | CS4215_LE; mm->d.bdata[1] = sc->sc_ratt = 0x20 | CS4215_SE; - mm->d.bdata[2] = CS4215_LG(0x08) | CS4215_IS | CS4215_PIO0 | CS4215_PIO1; - mm->d.bdata[3] = CS4215_RG(0x08) | CS4215_MA(0x0f); + sc->sc_linp = 128; + sc->sc_rinp = 128; + sc->sc_monitor = 0; + sc->sc_input = 1; /* line */ + mm->d.bdata[2] = (CS4215_LG((sc->sc_linp >> 4)) & 0x0f) | + ((sc->sc_input == 2) ? CS4215_IS : 0) | CS4215_PIO0 | CS4215_PIO1; + mm->d.bdata[3] = (CS4215_RG((sc->sc_rinp >> 4) & 0x0f)) | + CS4215_MA(15 - ((sc->sc_monitor >> 4) & 0x0f)); + /* * control time slots 1-4 @@ -903,25 +914,23 @@ mmcodec_setgain(struct dbri_softc *sc, int mute) sc->sc_mm.d.bdata[0] = sc->sc_latt | 63; sc->sc_mm.d.bdata[1] = sc->sc_ratt | 63; } else { - /* - * We should be setting the proper output here.. for now, - * use the speaker. Possible outputs: - * Headphones: - * data[0] |= CS4215_HE; - * Line out: - * data[0] |= CS4215_LE; - * Speaker: - * data[1] |= CS4215_SE; - */ + sc->sc_mm.d.bdata[0] = sc->sc_latt; sc->sc_mm.d.bdata[1] = sc->sc_ratt; } + /* input stuff */ + sc->sc_mm.d.bdata[2] = CS4215_LG((sc->sc_linp >> 4) & 0x0f) | + ((sc->sc_input == 2) ? CS4215_IS : 0) | CS4215_PIO0 | CS4215_PIO1; + sc->sc_mm.d.bdata[3] = (CS4215_RG((sc->sc_rinp >> 4)) & 0x0f) | + (CS4215_MA(15 - ((sc->sc_monitor >> 4) & 0x0f))); + if (sc->sc_powerstate == 0) return; pipe_transmit_fixed(sc, 20, sc->sc_mm.d.ldata); - /* give the chip some time to execure the command */ + DPRINTF("mmcodec_setgain: %08x\n", sc->sc_mm.d.ldata); + /* give the chip some time to execute the command */ delay(250); return; @@ -934,7 +943,7 @@ mmcodec_setcontrol(struct dbri_softc *sc) bus_space_handle_t ioh = sc->sc_ioh; u_int32_t val; u_int32_t tmp; -#if 1 +#if DBRI_SPIN int i; #endif @@ -981,7 +990,7 @@ mmcodec_setcontrol(struct dbri_softc *sc) tmp |= DBRI_CHI_ACTIVATE; bus_space_write_4(iot, ioh, DBRI_REG0, tmp); -#if 1 +#if DBRI_SPIN i = 1024; while (((sc->sc_mm.status & 0xe4) != 0x20) && --i) { delay(125); @@ -1602,8 +1611,8 @@ dbri_halt_output(void *hdl) { struct dbri_softc *sc = hdl; + sc->sc_playing = 0; pipe_reset(sc, 4); - return (0); } @@ -1646,6 +1655,21 @@ dbri_set_port(void *hdl, mixer_ctrl_t *mc) } else latt &= ~CS4215_LE; break; + case DBRI_VOL_MONITOR: + if (mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] == + sc->sc_monitor) + return 0; + sc->sc_monitor = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; + break; + case DBRI_INPUT_GAIN: + sc->sc_linp = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; + sc->sc_rinp = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; + break; + case DBRI_INPUT_SELECT: + if (mc->un.mask == sc->sc_input) + return 0; + sc->sc_input = mc->un.mask; + break; } sc->sc_latt = latt; @@ -1677,6 +1701,16 @@ dbri_get_port(void *hdl, mixer_ctrl_t *mc) case DBRI_ENABLE_LINE: /* line out */ mc->un.ord = (sc->sc_latt & CS4215_LE) ? 1 : 0; return 0; + case DBRI_VOL_MONITOR: + mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = sc->sc_monitor; + return 0; + case DBRI_INPUT_GAIN: + mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = sc->sc_linp; + mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = sc->sc_rinp; + return 0; + case DBRI_INPUT_SELECT: + mc->un.mask = sc->sc_input; + return 0; } return (EINVAL); } @@ -1692,17 +1726,45 @@ dbri_query_devinfo(void *hdl, mixer_devinfo_t *di) di->type = AUDIO_MIXER_CLASS; di->next = di->prev = AUDIO_MIXER_LAST; return 0; + case DBRI_OUTPUT_CLASS: + di->mixer_class = DBRI_OUTPUT_CLASS; + strcpy(di->label.name, AudioCoutputs); + di->type = AUDIO_MIXER_CLASS; + di->next = di->prev = AUDIO_MIXER_LAST; + return 0; + case DBRI_INPUT_CLASS: + di->mixer_class = DBRI_INPUT_CLASS; + strcpy(di->label.name, AudioCinputs); + di->type = AUDIO_MIXER_CLASS; + di->next = di->prev = AUDIO_MIXER_LAST; + return 0; case DBRI_VOL_OUTPUT: /* master volume */ - di->mixer_class = DBRI_MONITOR_CLASS; + di->mixer_class = DBRI_OUTPUT_CLASS; di->next = di->prev = AUDIO_MIXER_LAST; strcpy(di->label.name, AudioNmaster); di->type = AUDIO_MIXER_VALUE; di->un.v.num_channels = 2; strcpy(di->un.v.units.name, AudioNvolume); return (0); - case DBRI_ENABLE_MONO: /* built-in speaker */ + case DBRI_INPUT_GAIN: /* input gain */ + di->mixer_class = DBRI_INPUT_CLASS; + di->next = di->prev = AUDIO_MIXER_LAST; + strcpy(di->label.name, AudioNrecord); + di->type = AUDIO_MIXER_VALUE; + di->un.v.num_channels = 2; + strcpy(di->un.v.units.name, AudioNvolume); + return (0); + case DBRI_VOL_MONITOR: /* monitor volume */ di->mixer_class = DBRI_MONITOR_CLASS; di->next = di->prev = AUDIO_MIXER_LAST; + strcpy(di->label.name, AudioNmonitor); + di->type = AUDIO_MIXER_VALUE; + di->un.v.num_channels = 1; + strcpy(di->un.v.units.name, AudioNvolume); + return (0); + case DBRI_ENABLE_MONO: /* built-in speaker */ + di->mixer_class = DBRI_OUTPUT_CLASS; + di->next = di->prev = AUDIO_MIXER_LAST; strcpy(di->label.name, AudioNmono); di->type = AUDIO_MIXER_ENUM; di->un.e.num_mem = 2; @@ -1712,7 +1774,7 @@ dbri_query_devinfo(void *hdl, mixer_devinfo_t *di) di->un.e.member[1].ord = 1; return (0); case DBRI_ENABLE_HEADPHONE: /* headphones output */ - di->mixer_class = DBRI_MONITOR_CLASS; + di->mixer_class = DBRI_OUTPUT_CLASS; di->next = di->prev = AUDIO_MIXER_LAST; strcpy(di->label.name, AudioNheadphone); di->type = AUDIO_MIXER_ENUM; @@ -1723,7 +1785,7 @@ dbri_query_devinfo(void *hdl, mixer_devinfo_t *di) di->un.e.member[1].ord = 1; return (0); case DBRI_ENABLE_LINE: /* line out */ - di->mixer_class = DBRI_MONITOR_CLASS; + di->mixer_class = DBRI_OUTPUT_CLASS; di->next = di->prev = AUDIO_MIXER_LAST; strcpy(di->label.name, AudioNline); di->type = AUDIO_MIXER_ENUM; @@ -1733,6 +1795,17 @@ dbri_query_devinfo(void *hdl, mixer_devinfo_t *di) strcpy(di->un.e.member[1].label.name, AudioNon); di->un.e.member[1].ord = 1; return (0); + case DBRI_INPUT_SELECT: + di->mixer_class = DBRI_INPUT_CLASS; + strcpy(di->label.name, AudioNsource); + di->type = AUDIO_MIXER_SET; + di->prev = di->next = AUDIO_MIXER_LAST; + di->un.s.num_mem = 2; + strcpy(di->un.s.member[0].label.name, AudioNline); + di->un.s.member[0].mask = 1 << 0; + strcpy(di->un.s.member[1].label.name, AudioNmicrophone); + di->un.s.member[1].mask = 1 << 1; + return 0; } return (ENXIO); @@ -1781,11 +1854,52 @@ dbri_trigger_output(void *hdl, void *start, void *end, int blksize, if (current < sc->sc_desc_used) { setup_ring(sc, 4, current, num, blksize, intr, intrarg); + sc->sc_playing = 1; return 0; } return EINVAL; } +static int +dbri_halt_input(void *cookie) +{ + return 0; +} + +static int +dbri_trigger_input(void *hdl, void *start, void *end, int blksize, + void (*intr)(void *), void *intrarg, + const struct audio_params *param) +{ +#if notyet + struct dbri_softc *sc = hdl; + unsigned long count, current, num; + + count = (unsigned long)(((char *)end - (char *)start)); + num = count / blksize; + + DPRINTF("trigger_input(%lx %lx) : %d %ld %ld\n", + (unsigned long)intr, + (unsigned long)intrarg, blksize, count, num); + + sc->sc_params = *param; + + mmcodec_setcontrol(sc); + mmcodec_init_data(sc); + current = 0; + while ((current < sc->sc_desc_used) && + (sc->sc_desc[current].buf != start)) + current++; + + if (current < sc->sc_desc_used) { + setup_ring(sc, 4, current, num, blksize, intr, intrarg); + return 0; + } +#endif + return EINVAL; +} + + static u_int32_t reverse_bytes(u_int32_t b, int len) { @@ -1885,6 +1999,7 @@ dbri_open(void *cookie, int flags) struct dbri_softc *sc = cookie; dbri_bring_up(sc); + sc->sc_open = 1; return 0; } @@ -1893,6 +2008,7 @@ dbri_close(void *cookie) { struct dbri_softc *sc = cookie; + sc->sc_open = 0; dbri_set_power(sc, 0); } @@ -1901,16 +2017,40 @@ dbri_powerhook(int why, void *cookie) { struct dbri_softc *sc = cookie; + if (why == sc->sc_pmgrstate) + return; + switch(why) { case PWR_SUSPEND: - case PWR_STANDBY: dbri_set_power(sc, 0); break; case PWR_RESUME: - dbri_bring_up(sc); + DPRINTF("resume: %d\n", sc->sc_open); + sc->sc_pmgrstate = PWR_RESUME; + if (sc->sc_open == 1) { + dbri_bring_up(sc); + if (sc->sc_playing) { + volatile u_int32_t *cmd; + int s; + + s = splaudio(); + cmd = dbri_command_lock(sc); + *(cmd++) = DBRI_CMD(DBRI_COMMAND_SDP, + 0, sc->sc_pipe[4].sdp | + DBRI_SDP_VALID_POINTER | + DBRI_SDP_EVERY | DBRI_SDP_CLEAR); + *(cmd++) = sc->sc_dmabase + + dbri_dma_off(desc, 0); + dbri_command_send(sc, cmd); + splx(s); + } + } break; + default: + return; } + sc->sc_pmgrstate = why; } #endif /* NAUDIO > 0 */ diff --git a/sys/dev/sbus/dbrivar.h b/sys/dev/sbus/dbrivar.h index 1e5f05659e76..dbb772d037c0 100644 --- a/sys/dev/sbus/dbrivar.h +++ b/sys/dev/sbus/dbrivar.h @@ -1,4 +1,4 @@ -/* $NetBSD: dbrivar.h,v 1.5 2007/03/04 06:02:40 christos Exp $ */ +/* $NetBSD: dbrivar.h,v 1.6 2007/03/14 05:40:35 macallan Exp $ */ /* * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) @@ -114,7 +114,8 @@ struct dbri_softc { bus_dma_segment_t sc_dmaseg; int sc_have_powerctl; - int sc_powerstate; + int sc_powerstate; /* DBRI's powered up or not */ + int sc_pmgrstate; /* PWR_RESUME etc. */ int sc_burst; /* DVMA burst size in effect */ bus_addr_t sc_dmabase; /* VA of buffer we provide */ @@ -126,6 +127,7 @@ struct dbri_softc { int sc_waitseen; int sc_open; + int sc_playing; int sc_liu_state; void (*sc_liu)(void *); @@ -135,7 +137,11 @@ struct dbri_softc { struct dbri_desc sc_desc[DBRI_NUM_DESCRIPTORS]; struct cs4215_state sc_mm; - int sc_latt, sc_ratt; + int sc_latt, sc_ratt; /* output attenuation */ + int sc_linp, sc_rinp; /* input volume */ + int sc_monitor; /* monitor volume */ + int sc_input; /* 0 - line, 1 - mic */ + int sc_ctl_mode; uint32_t sc_version; diff --git a/sys/dev/sbus/files.sbus b/sys/dev/sbus/files.sbus index 2163b756df34..9d700f528140 100644 --- a/sys/dev/sbus/files.sbus +++ b/sys/dev/sbus/files.sbus @@ -1,4 +1,4 @@ -# $NetBSD: files.sbus,v 1.27 2007/03/11 00:35:32 macallan Exp $ +# $NetBSD: files.sbus,v 1.28 2007/03/14 05:40:35 macallan Exp $ # # Config file and device description for machine-independent SBUS code. # Included by ports that need it. @@ -130,7 +130,7 @@ file dev/sbus/p9100.c pnozz needs-flag # SUNW,DBRI audio defflag opt_sbus_dbri.h DBRI_DEBUG -defflag opt_sbus_dbri.h DBRI_BIG_BUFFER +defflag opt_sbus_dbri.h DBRI_BIG_BUFFER DBRI_SPIN device dbri { }: audiobus, auconv attach dbri at sbus file dev/sbus/dbri.c dbri