Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/pci Add multiple voice support to the ESS Allegro-1 ...



details:   https://anonhg.NetBSD.org/src/rev/a0ec1fd99de9
branches:  trunk
changeset: 523799:a0ec1fd99de9
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat Mar 16 14:34:00 2002 +0000

description:
Add multiple voice support to the ESS Allegro-1 / Maestro-3 family of
audio accelerators.

Mixing is done in hardware by the ASSP, but is limited to 4 simultaneous
channels due to the restricted "minisrc" image that we are currently
working with.

Due to limitations in the audio subsystem, I'm currently attaching multiple
'audio' devices to 'esa', one for each voice. Because of this hack, the
default ESA_NUM_VOICES is 1.

diffstat:

 sys/dev/pci/esa.c    |  532 ++++++++++++++++++++++++++++++++++----------------
 sys/dev/pci/esavar.h |   54 ++++-
 2 files changed, 411 insertions(+), 175 deletions(-)

diffs (truncated from 981 to 300 lines):

diff -r 78162572f819 -r a0ec1fd99de9 sys/dev/pci/esa.c
--- a/sys/dev/pci/esa.c Sat Mar 16 14:03:00 2002 +0000
+++ b/sys/dev/pci/esa.c Sat Mar 16 14:34:00 2002 +0000
@@ -1,7 +1,7 @@
-/* $NetBSD: esa.c,v 1.10 2002/03/10 14:57:31 jmcneill Exp $ */
+/* $NetBSD: esa.c,v 1.11 2002/03/16 14:34:00 jmcneill Exp $ */
 
 /*
- * Copyright (c) 2001, 2002 Jared D. McNeill <jmcneill%invisible.yi.org@localhost>
+ * Copyright (c) 2001, 2002 Jared D. McNeill <jmcneill%invisible.ca@localhost>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,12 @@
  * 
  * Based on the FreeBSD maestro3 driver and the NetBSD eap driver.
  * Original driver by Don Kim.
+ *
+ * The list management code could possibly be written better, but what
+ * we have right now does the job nicely. Thanks to Zach Brown <zab%zabbo.net@localhost>
+ * and Andrew MacDonald <amac%epsilon.yi.org@localhost> for helping me debug the
+ * problems with the original list management code present in the Linux
+ * driver.
  */
 
 #include <sys/types.h>
@@ -101,7 +107,7 @@
 int            esa_set_params(void *, int, int, struct audio_params *,
                               struct audio_params *);
 int            esa_round_blocksize(void *, int);
-int            esa_init_output(void *, void *, int);
+int            esa_commit_settings(void *);
 int            esa_halt_output(void *);
 int            esa_halt_input(void *);
 int            esa_set_port(void *, mixer_ctrl_t *);
@@ -144,15 +150,17 @@
 void           esa_enable_interrupts(struct esa_softc *);
 u_int32_t      esa_get_pointer(struct esa_softc *, struct esa_channel *);
 
+/* list management */
+int            esa_add_list(struct esa_voice *, struct esa_list *, u_int16_t,
+                            int);
+void           esa_remove_list(struct esa_voice *, struct esa_list *, int);
+
 /* power management */
 int            esa_power(struct esa_softc *, int);
 void           esa_powerhook(int, void *);
 int            esa_suspend(struct esa_softc *);
 int            esa_resume(struct esa_softc *);
 
-struct device *        audio_attach_mi_lkm(struct audio_hw_if *, void *,
-                                   struct device *);
-
 static audio_encoding_t esa_encoding[] = {
        { 0, AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0 },
        { 1, AudioEmulaw, AUDIO_ENCODING_ULAW, 8,
@@ -178,9 +186,9 @@
        esa_query_encoding,
        esa_set_params,
        esa_round_blocksize,
-       NULL,                   /* commit_settings */
-       esa_init_output,
-       NULL,                   /* esa_init_input */
+       esa_commit_settings,
+       NULL,                   /* init_output */
+       NULL,                   /* init_input */
        NULL,                   /* start_output */
        NULL,                   /* start_input */
        esa_halt_output,
@@ -238,11 +246,10 @@
 esa_set_params(void *hdl, int setmode, int usemode, struct audio_params *play,
               struct audio_params *rec)
 {
-       struct esa_softc *sc = hdl;
+       struct esa_voice *vc = hdl;
+       //struct esa_softc *sc = (struct esa_softc *)vc->parent;
        struct esa_channel *ch;
        struct audio_params *p;
-       u_int32_t data;
-       u_int32_t freq;
        int mode;
 
        for (mode = AUMODE_RECORD; mode != -1;
@@ -253,11 +260,11 @@
                switch (mode) {
                case AUMODE_PLAY:
                        p = play;
-                       ch = &sc->play;
+                       ch = &vc->play;
                        break;
                case AUMODE_RECORD:
                        p = rec;
-                       ch = &sc->rec;
+                       ch = &vc->rec;
                        break;
                }
 
@@ -312,64 +319,123 @@
                default:
                        return (EINVAL);
                }
-       
-               if (p->channels == 1)
-                       data = 1;
-               else
-                       data = 0;
-               esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
-                              ch->data_offset + ESA_SRC3_MODE_OFFSET,
-                   data);
-       
-               if (play->precision * play->factor == 8)
-                       data = 1;
-               else
-                       data = 0;
-               esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
-                              ch->data_offset + ESA_SRC3_WORD_LENGTH_OFFSET,
-                              data);
 
-               if ((freq = ((p->sample_rate << 15) + 24000) / 48000) != 0) {
-                       freq--;
-               }
-               esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
-                              ch->data_offset + ESA_CDATA_FREQUENCY, freq);
+               ch->mode = *p;
        }
 
        return (0);
 }
 
 int
+esa_commit_settings(void *hdl)
+{
+       struct esa_voice *vc = hdl;
+       struct esa_softc *sc = (struct esa_softc *)vc->parent;
+       struct audio_params *p = &vc->play.mode;
+       struct audio_params *r = &vc->rec.mode;
+       u_int32_t data;
+       u_int32_t freq;
+       int data_bytes = (((ESA_MINISRC_TMP_BUFFER_SIZE & ~1) +
+                          (ESA_MINISRC_IN_BUFFER_SIZE & ~1) +
+                          (ESA_MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255)
+                          &~ 255;
+
+       /* playback */
+       vc->play.data_offset = ESA_DAC_DATA + (data_bytes * vc->index);
+       if (p->channels == 1)
+               data = 1;
+       else
+               data = 0;
+       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
+                      vc->play.data_offset + ESA_SRC3_MODE_OFFSET,
+                      data);
+       if (p->precision * p->factor == 8)
+               data = 1;
+       else
+               data = 0;
+       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
+                      vc->play.data_offset + ESA_SRC3_WORD_LENGTH_OFFSET,
+                      data);
+       if ((freq = ((p->sample_rate << 15) + 24000) / 48000) != 0) {
+               freq--;
+       }
+       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
+                      vc->play.data_offset + ESA_CDATA_FREQUENCY, freq);
+
+       /* recording */
+       vc->rec.data_offset = ESA_DAC_DATA + (data_bytes * vc->index) +
+                             (data_bytes / 2);
+       if (r->channels == 1)
+               data = 1;
+       else
+               data = 0;
+       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
+                      vc->rec.data_offset + ESA_SRC3_MODE_OFFSET,
+                      data);
+       if (r->precision * r->factor == 8)
+               data = 1;
+       else
+               data = 0;
+       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
+                      vc->rec.data_offset + ESA_SRC3_WORD_LENGTH_OFFSET,
+                      data);
+       if ((freq = ((r->sample_rate << 15) + 24000) / 48000) != 0) {
+               freq--;
+       }
+       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
+                      vc->rec.data_offset + ESA_CDATA_FREQUENCY, freq);
+
+       return (0);
+};
+
+int
 esa_round_blocksize(void *hdl, int bs)
 {
-       struct esa_softc *sc = hdl;
-
-       sc->play.blksize = sc->rec.blksize = 4096;
+       struct esa_voice *vc = hdl;
 
-       return (sc->play.blksize);
-}
+       /*
+        * Surely there has to be a better solution...
+        */
+       vc->play.blksize = vc->rec.blksize = 4096;
 
-int
-esa_init_output(void *hdl, void *buffer, int size)
-{
-
-       return (0);
+       return (vc->play.blksize);
 }
 
 int
 esa_halt_output(void *hdl)
 {
-       struct esa_softc *sc = hdl;
+       struct esa_voice *vc = hdl;
+       struct esa_softc *sc = (struct esa_softc *)vc->parent;
+       bus_space_tag_t iot = sc->sc_iot;
+       bus_space_handle_t ioh = sc->sc_ioh;
+       u_int16_t data;
 
-       if (sc->play.active == 0)
+       if (vc->play.active == 0)
                return (0);
 
-       sc->play.active = 0;
+       vc->play.active = 0;
 
        esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
-                      ESA_KDATA_INSTANCE0_MINISRC, 0);
-       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, ESA_KDATA_DMA_XFER0, 0);
-       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, ESA_KDATA_MIXER_XFER0, 0);
+                      ESA_CDATA_INSTANCE_READY + vc->play.data_offset, 0);
+
+       sc->sc_ntimers--;
+       if (sc->sc_ntimers == 0) {
+               esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
+                              ESA_KDATA_TIMER_COUNT_RELOAD, 0);
+               esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
+                              ESA_KDATA_TIMER_COUNT_CURRENT, 0);
+               data = bus_space_read_2(iot, ioh, ESA_HOST_INT_CTRL);
+               bus_space_write_2(iot, ioh, ESA_HOST_INT_CTRL,
+                   data & ~ESA_CLKRUN_GEN_ENABLE);
+       }
+
+       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
+                      ESA_KDATA_MIXER_TASK_NUMBER,
+                      sc->mixer_list.indexmap[vc->index]);
+       /* remove ourselves from the packed lists */
+       esa_remove_list(vc, &sc->mixer_list, vc->index);
+       esa_remove_list(vc, &sc->dma_list, vc->index);
+       esa_remove_list(vc, &sc->msrc_list, vc->index);
 
        return (0);
 }
@@ -377,25 +443,37 @@
 int
 esa_halt_input(void *hdl)
 {
-       struct esa_softc *sc = hdl;
+       struct esa_voice *vc = hdl;
+       struct esa_softc *sc = (struct esa_softc *)vc->parent;
        bus_space_tag_t iot = sc->sc_iot;
        bus_space_handle_t ioh = sc->sc_ioh;
        u_int32_t data;
        
-       if (sc->rec.active == 0)
+       if (vc->rec.active == 0)
                return (0);
                
-       sc->rec.active = 0;
+       vc->rec.active = 0;
        
-       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
-                      ESA_KDATA_TIMER_COUNT_RELOAD, 0);
-       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, ESA_KDATA_TIMER_COUNT_CURRENT, 0);
-       data = bus_space_read_2(iot, ioh, ESA_HOST_INT_CTRL);
-       bus_space_write_2(iot, ioh, ESA_HOST_INT_CTRL, data & ~ESA_CLKRUN_GEN_ENABLE);
-       
-       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, sc->rec.data_offset +
+       sc->sc_ntimers--;
+       if (sc->sc_ntimers == 0) {
+               esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
+                              ESA_KDATA_TIMER_COUNT_RELOAD, 0);
+               esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
+                              ESA_KDATA_TIMER_COUNT_CURRENT, 0);
+               data = bus_space_read_2(iot, ioh, ESA_HOST_INT_CTRL);
+               bus_space_write_2(iot, ioh, ESA_HOST_INT_CTRL,
+                                 data & ~ESA_CLKRUN_GEN_ENABLE);
+       }
+
+       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, vc->rec.data_offset +
                       ESA_CDATA_INSTANCE_READY, 0);
-       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, ESA_KDATA_ADC1_REQUEST, 0);
+       esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, ESA_KDATA_ADC1_REQUEST,
+                      0);
+



Home | Main Index | Thread Index | Old Index