Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/pci/hdaudio Add support for formats other than 16bit...



details:   https://anonhg.NetBSD.org/src/rev/b93358124911
branches:  trunk
changeset: 747262:b93358124911
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Mon Sep 07 16:21:08 2009 +0000

description:
Add support for formats other than 16bit/48kHz.

diffstat:

 sys/dev/pci/hdaudio/hdaudio.c     |   87 +++++++++++++-
 sys/dev/pci/hdaudio/hdaudio_afg.c |  219 +++++++++++++++++++++++++++++--------
 sys/dev/pci/hdaudio/hdaudiovar.h  |    3 +-
 3 files changed, 248 insertions(+), 61 deletions(-)

diffs (truncated from 497 to 300 lines):

diff -r b3ea102b47df -r b93358124911 sys/dev/pci/hdaudio/hdaudio.c
--- a/sys/dev/pci/hdaudio/hdaudio.c     Mon Sep 07 15:12:03 2009 +0000
+++ b/sys/dev/pci/hdaudio/hdaudio.c     Mon Sep 07 16:21:08 2009 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: hdaudio.c,v 1.2 2009/09/06 17:33:53 sborrill Exp $ */
+/* $NetBSD: hdaudio.c,v 1.3 2009/09/07 16:21:08 jmcneill Exp $ */
 
 /*
  * Copyright (c) 2009 Precedence Technologies Ltd <support%precedence.co.uk@localhost>
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hdaudio.c,v 1.2 2009/09/06 17:33:53 sborrill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hdaudio.c,v 1.3 2009/09/07 16:21:08 jmcneill Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -948,6 +948,77 @@
        mutex_exit(&sc->sc_stream_mtx);
 }
 
+/*
+ * Convert most of audio_params_t to stream fmt descriptor; noticably missing
+ * is the # channels bits, as this is encoded differently in codec and
+ * stream descriptors.
+ *
+ * TODO: validate that the stream and selected codecs can handle the fmt
+ */
+uint16_t
+hdaudio_stream_param(struct hdaudio_stream *st, const audio_params_t *param)
+{
+       uint16_t fmt = 0;
+
+       switch (param->sample_rate) {
+       case 8000:
+               fmt |= HDAUDIO_FMT_BASE_48 | HDAUDIO_FMT_MULT(1) |
+                   HDAUDIO_FMT_DIV(6);
+               break;
+       case 11025:
+               fmt |= HDAUDIO_FMT_BASE_44 | HDAUDIO_FMT_MULT(1) |
+                   HDAUDIO_FMT_DIV(4);
+               break;
+       case 16000:
+               fmt |= HDAUDIO_FMT_BASE_48 | HDAUDIO_FMT_MULT(1) |
+                   HDAUDIO_FMT_DIV(3);
+               break;
+       case 22050:
+               fmt |= HDAUDIO_FMT_BASE_44 | HDAUDIO_FMT_MULT(1) |
+                   HDAUDIO_FMT_DIV(2);
+               break;
+       case 32000:
+               fmt |= HDAUDIO_FMT_BASE_48 | HDAUDIO_FMT_MULT(2) |
+                   HDAUDIO_FMT_DIV(3);
+               break;
+       case 44100:
+               fmt |= HDAUDIO_FMT_BASE_44 | HDAUDIO_FMT_MULT(1);
+               break;
+       case 48000:
+               fmt |= HDAUDIO_FMT_BASE_48 | HDAUDIO_FMT_MULT(1);
+               break;
+       case 88200:
+               fmt |= HDAUDIO_FMT_BASE_44 | HDAUDIO_FMT_MULT(2);
+               break;
+       case 96000:
+               fmt |= HDAUDIO_FMT_BASE_48 | HDAUDIO_FMT_MULT(2);
+               break;
+       case 176400:
+               fmt |= HDAUDIO_FMT_BASE_44 | HDAUDIO_FMT_MULT(4);
+               break;
+       case 192000:
+               fmt |= HDAUDIO_FMT_BASE_48 | HDAUDIO_FMT_MULT(4);
+               break;
+       default:
+               return 0;
+       }
+
+       if (param->precision == 16 && param->validbits == 8)
+               fmt |= HDAUDIO_FMT_BITS_8_16;
+       else if (param->precision == 16 && param->validbits == 16)
+               fmt |= HDAUDIO_FMT_BITS_16_16;
+       else if (param->precision == 32 && param->validbits == 20)
+               fmt |= HDAUDIO_FMT_BITS_20_32;
+       else if (param->precision == 32 && param->validbits == 24)
+               fmt |= HDAUDIO_FMT_BITS_24_32;
+       else if (param->precision == 32 && param->validbits == 32)
+               fmt |= HDAUDIO_FMT_BITS_32_32;
+       else
+               return 0;
+
+       return fmt;
+}
+
 void
 hdaudio_stream_reset(struct hdaudio_stream *st)
 {
@@ -996,6 +1067,7 @@
        struct hdaudio_bdl_entry *bdl;
        uint64_t dmaaddr;
        uint32_t intctl;
+       uint16_t fmt;
        uint8_t ctl0, ctl2;
        int cnt, snum = st->st_shift;
 
@@ -1050,15 +1122,10 @@
 
        /*
         * Program stream format
-        *
-        * XXX 48kHz, 16-bit, stereo for now
         */
-       hda_write2(sc, HDAUDIO_SD_FMT(snum),
-           HDAUDIO_FMT_BASE_48 | HDAUDIO_FMT_MULT(1) |
-           HDAUDIO_FMT_DIV(1) | HDAUDIO_FMT_BITS_16_16 |
-           HDAUDIO_FMT_CHAN(params->channels));
-
-       /* XXX program codecs for stream number */
+       fmt = hdaudio_stream_param(st, params) |
+           HDAUDIO_FMT_CHAN(params->channels);
+       hda_write2(sc, HDAUDIO_SD_FMT(snum), fmt);
 
        /*
         * Switch on interrupts for this stream
diff -r b3ea102b47df -r b93358124911 sys/dev/pci/hdaudio/hdaudio_afg.c
--- a/sys/dev/pci/hdaudio/hdaudio_afg.c Mon Sep 07 15:12:03 2009 +0000
+++ b/sys/dev/pci/hdaudio/hdaudio_afg.c Mon Sep 07 16:21:08 2009 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: hdaudio_afg.c,v 1.5 2009/09/07 11:59:53 jmcneill Exp $ */
+/* $NetBSD: hdaudio_afg.c,v 1.6 2009/09/07 16:21:08 jmcneill Exp $ */
 
 /*
  * Copyright (c) 2009 Precedence Technologies Ltd <support%precedence.co.uk@localhost>
@@ -60,7 +60,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hdaudio_afg.c,v 1.5 2009/09/07 11:59:53 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hdaudio_afg.c,v 1.6 2009/09/07 16:21:08 jmcneill Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -151,7 +151,7 @@
        "Other"
 };
 
-#define        HDAUDIO_MAXFORMATS      10
+#define        HDAUDIO_MAXFORMATS      24
 #define        HDAUDIO_MAXCONNECTIONS  32
 #define        HDAUDIO_MAXPINS         16
 #define        HDAUDIO_PARSE_MAXDEPTH  10
@@ -285,7 +285,7 @@
        struct hdaudio_mixer            *sc_mixers;
 
        int                             sc_pchan, sc_rchan;
-       int                             sc_curpchan, sc_currchan;
+       audio_params_t                  sc_pparam, sc_rparam;
 
        struct callout                  sc_jack_callout;
 
@@ -378,12 +378,12 @@
 hdaudio_afg_append_formats(struct hdaudio_audiodev *ad,
     const struct audio_format *format)
 {
-       struct hdaudio_afg_softc *sc = ad->ad_sc;
-       if (ad->ad_nformats >= HDAUDIO_MAXFORMATS) {
-               hda_error(sc, "too many formats\n");
-               return EINVAL;
+       if (ad->ad_nformats + 1 >= HDAUDIO_MAXFORMATS) {
+               hda_print1(ad->ad_sc, "[ENOMEM] ");
+               return ENOMEM;
        }
        ad->ad_formats[ad->ad_nformats++] = *format;
+
        return 0;
 }
 
@@ -2609,32 +2609,37 @@
        int tag, chn, maxchan, c;
        int i, j;
 
-       fmt = HDAUDIO_FMT_BASE_48 | HDAUDIO_FMT_MULT(1) |
-           HDAUDIO_FMT_DIV(1) | HDAUDIO_FMT_BITS_16_16;
+       KASSERT(mode == AUMODE_PLAY || mode == AUMODE_RECORD);
+
        dfmt = COP_DIGITAL_CONVCTRL1_DIGEN;     /* TODO: AC3 */
 
+       if (mode == AUMODE_PLAY)
+               fmt = hdaudio_stream_param(sc->sc_audiodev.ad_playback,
+                   &sc->sc_pparam);
+       else
+               fmt = hdaudio_stream_param(sc->sc_audiodev.ad_capture,
+                   &sc->sc_rparam);
+
        for (i = 0; i < sc->sc_nassocs; i++) {
                if (as[i].as_enable == false)
                        continue;
 
-               if ((mode & (AUMODE_PLAY|AUMODE_RECORD)) == AUMODE_PLAY &&
-                   as[i].as_dir != HDAUDIO_PINDIR_OUT)
+               if (mode == AUMODE_PLAY && as[i].as_dir != HDAUDIO_PINDIR_OUT)
                        continue;
-               if ((mode & (AUMODE_PLAY|AUMODE_RECORD)) == AUMODE_RECORD &&
-                   as[i].as_dir != HDAUDIO_PINDIR_IN)
+               if (mode == AUMODE_RECORD && as[i].as_dir != HDAUDIO_PINDIR_IN)
                        continue;
 
                fmt &= ~HDAUDIO_FMT_CHAN_MASK;
                if (as[i].as_dir == HDAUDIO_PINDIR_OUT &&
                    sc->sc_audiodev.ad_playback != NULL) {
                        tag = hdaudio_stream_tag(sc->sc_audiodev.ad_playback);
-                       fmt |= HDAUDIO_FMT_CHAN(sc->sc_curpchan);
-                       maxchan = sc->sc_curpchan;
+                       fmt |= HDAUDIO_FMT_CHAN(sc->sc_pparam.channels);
+                       maxchan = sc->sc_pparam.channels;
                } else if (as[i].as_dir == HDAUDIO_PINDIR_IN &&
                    sc->sc_audiodev.ad_capture != NULL) {
                        tag = hdaudio_stream_tag(sc->sc_audiodev.ad_capture);
-                       fmt |= HDAUDIO_FMT_CHAN(sc->sc_currchan);
-                       maxchan = sc->sc_currchan;
+                       fmt |= HDAUDIO_FMT_CHAN(sc->sc_rparam.channels);
+                       maxchan = sc->sc_rparam.channels;
                } else {
                        tag = 0;
                        if (as[i].as_dir == HDAUDIO_PINDIR_OUT) {
@@ -2732,40 +2737,85 @@
        return nchans;
 }
 
-static void
-hdaudio_afg_configure_encodings(struct hdaudio_afg_softc *sc)
+static bool
+hdaudio_afg_rate_supported(struct hdaudio_afg_softc *sc, u_int frequency)
 {
-       struct hdaudio_assoc *as = sc->sc_assocs;
+       uint32_t caps = sc->sc_p.pcm_size_rate;
+
+#define ISFREQOK(shift)        ((caps & (1 << (shift))) ? true : false)
+       switch (frequency) {
+       case 8000:
+               return ISFREQOK(0);
+       case 11025:
+               return ISFREQOK(1);
+       case 16000:
+               return ISFREQOK(2);
+       case 22050:
+               return ISFREQOK(3);
+       case 32000:
+               return ISFREQOK(4);
+       case 44100:
+               return ISFREQOK(5);
+       case 48000:
+               return true;    /* Must be supported by all codecs */
+       case 88200:
+               return ISFREQOK(7);
+       case 96000:
+               return ISFREQOK(8);
+       case 176400:
+               return ISFREQOK(9);
+       case 192000:
+               return ISFREQOK(10);
+       case 384000:
+               return ISFREQOK(11);
+       default:
+               return false;
+       }
+#undef ISFREQOK
+}
+
+static bool
+hdaudio_afg_bits_supported(struct hdaudio_afg_softc *sc, u_int bits)
+{
+       uint32_t caps = sc->sc_p.pcm_size_rate;
+#define ISBITSOK(shift)        ((caps & (1 << (shift))) ? true : false)
+       switch (bits) {
+       case 8:
+               return ISBITSOK(16);
+       case 16:
+               return ISBITSOK(17);
+       case 20:
+               return ISBITSOK(18);
+       case 24:
+               return ISBITSOK(19);
+       case 32:
+               return ISBITSOK(20);
+       default:
+               return false;
+       }
+#undef ISBITSOK
+}
+
+static bool
+hdaudio_afg_probe_encoding(struct hdaudio_afg_softc *sc,
+    u_int minrate, u_int maxrate, u_int validbits, u_int precision)
+{
        struct audio_format f;
-       int nchan, i;
-
-       sc->sc_pchan = sc->sc_rchan = 0;
-
-       for (nchan = 0, i = 0; i < sc->sc_nassocs; i++) {



Home | Main Index | Thread Index | Old Index