Subject: port-i386/16523: make the sb driver support Avance Logic ALS007
To: None <gnats-bugs@gnats.netbsd.org>
From: None <chrisp@belgacom.net>
List: netbsd-bugs
Date: 04/27/2002 12:07:15
>Number:         16523
>Category:       port-i386
>Synopsis:       make the sb driver support Avance Logic ALS007
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    port-i386-maintainer
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sat Apr 27 12:08:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Chris Pockele
>Release:        NetBSD 1.5ZC 20020410
>Organization:
BSDaemon - http://www.bsdaemon.be/
>Environment:
NetBSD cabrio 1.5ZC NetBSD 1.5ZC (CABRIO) #1: Sun Apr 21 11:11:27 CEST 2002     root@cabrio:/usr/src/sys/arch/i386/compile/CABRIO i386

>Description:
The Avance Logic ALS007 is a sound chip mostly compatible with the SB16, except for the mixer.  It supports 48 kHz sampling rate.  It uses ISA Plug and Play.
I've created a patch to make it work with NetBSD (the patch is against the sources of the 20020410-1.5ZC-XFree86-4.2.0 snapshot).
>How-To-Repeat:

>Fix:
diff -ru sys_plain/dev/isa/sbdsp.c sys/dev/isa/sbdsp.c
--- sys_plain/dev/isa/sbdsp.c   Mon Jan  7 13:11:20 2002
+++ sys/dev/isa/sbdsp.c Sun Apr 21 06:19:58 2002
@@ -112,7 +112,6 @@
 #include <dev/isa/sbreg.h>
 #include <dev/isa/sbdspvar.h>
 
-
 #ifdef AUDIO_DEBUG
 #define DPRINTF(x)     if (sbdspdebug) printf x
 #define DPRINTFN(n,x)  if (sbdspdebug >= (n)) printf x
@@ -417,7 +416,8 @@
 
        printf(": dsp v%d.%02d%s\n",
               SBVER_MAJOR(sc->sc_version), SBVER_MINOR(sc->sc_version),
-              sc->sc_model == SB_JAZZ ? ": <Jazz16>" : "");
+              sc->sc_model == SB_JAZZ ? ": <Jazz16>" : 
+               (sc->sc_model == SB_ALS007 ? ": <ALS007>" : ""));
 
        sc->sc_fullduplex = ISSB16CLASS(sc) && 
            sc->sc_drq8 != -1 && sc->sc_drq16 != -1 &&
@@ -485,6 +485,7 @@
        val = bus_space_read_1(iot, ioh, SBP_MIXER_DATA);
        delay(30);
        splx(s);
+
        return val;
 }
 
@@ -840,6 +841,26 @@
                }
                sbdsp_mix_write(sc, SBP_RECORD_SOURCE, sbport | sc->in_filter);
                break;
+       case SBM_ALS007:
+               switch(mask) {
+               case 1 << SB_MIC_VOL:
+                       sbport = ALS007_FROM_MIC;
+                       break;
+               case 1 << SB_LINE_IN_VOL:
+                       sbport = ALS007_FROM_LINE;
+                       break;
+               case 1 << SB_CD_VOL:
+                       sbport = ALS007_FROM_CD;
+                       break;
+               case 1 << SB_MIDI_VOL:
+                       sbport = ALS007_FROM_MIDI;
+                       break; 
+               default:
+                       return (EINVAL);
+               }
+               sbdsp_mix_write(sc, ALS007_RECORD_SOURCE,
+                                                sbport | sc->in_filter);
+               break;
        case SBM_CT1XX5:
        case SBM_CT1745:
                if (mask & ~((1<<SB_MIDI_VOL) | (1<<SB_LINE_IN_VOL) |
@@ -1175,6 +1196,17 @@
                        sc->sc_model = SB_64;
                else
 #endif
+
+/* ALS007 returns dsp v4.02 and according to the Linux documentation it has
+two post-reset != 0 registers at 0x3c and 0x4c, while a standard SB16 has
+no register at 0x4c */
+               if ( (SBVER_MINOR(v) == 2) && 
+                               sbdsp_mix_read(sc, ALS007_OUTPUT_CTRL1) &&
+                               sbdsp_mix_read(sc, ALS007_OUTPUT_CTRL2) ) {
+                       sc->sc_model = SB_ALS007;
+                       sc->sc_mixer_model = SBM_ALS007;
+               }
+               else
                        sc->sc_model = SB_16;
                break;
        }
@@ -1676,6 +1708,43 @@
                sbdsp_mix_write(sc, src, sc->gain[port][SB_LEFT]);
                sbdsp_mix_write(sc, SB16P_L_TO_R(src), sc->gain[port][SB_RIGHT])
;
                break;
+       case SBM_ALS007:
+                switch (port) {
+                case SB_MIC_VOL:
+                        src = ALS007P_MIC;
+                       gain = SB_MIC_GAIN(sc->gain[port][SB_LEFT]);
+                       sbdsp_mix_write(sc, src, gain);
+                       return; 
+                case SB_MASTER_VOL:
+                        src = ALS007P_MASTER;
+                        break;
+                case SB_LINE_IN_VOL:
+                        src = ALS007P_LINE;
+                        break;
+                case SB_VOICE_VOL:
+                        src = ALS007P_VOICE;
+                        break;
+                case SB_MIDI_VOL:
+                        src = ALS007P_MIDI;
+                        break;
+                case SB_CD_VOL:
+                        src = ALS007P_CD;
+                        break;
+                case SB_PCSPEAKER:
+                        sbdsp_mix_write(sc, ALS007P_PCSPEAKER, 
+                                               sc->gain[port][SB_LEFT]);
+                        return;
+                default:
+                        return;
+                }
+
+               /* It seems that bits 0-3 are for the right channel
+                * and bits 4-7 for the left channel
+               */
+               gain=((sc->gain[port][SB_LEFT])&0xF0) 
+                       | ((sc->gain[port][SB_RIGHT]>>4));
+               sbdsp_mix_write(sc, src, gain); 
+               break;
        }
 }
 
@@ -1967,7 +2036,7 @@
        default:
                return EINVAL;
        }
-
+       
        return 0;
 }
 
@@ -2151,24 +2220,6 @@
                strcpy(dip->un.v.units.name, AudioNvolume);
                return 0;
 
-       case SB_INPUT_GAIN:
-               dip->type = AUDIO_MIXER_VALUE;
-               dip->mixer_class = SB_INPUT_CLASS;
-               dip->prev = dip->next = AUDIO_MIXER_LAST;
-               strcpy(dip->label.name, AudioNinput);
-               dip->un.v.num_channels = 2;
-               strcpy(dip->un.v.units.name, AudioNvolume);
-               return 0;
-
-       case SB_OUTPUT_GAIN:
-               dip->type = AUDIO_MIXER_VALUE;
-               dip->mixer_class = SB_OUTPUT_CLASS;
-               dip->prev = dip->next = AUDIO_MIXER_LAST;
-               strcpy(dip->label.name, AudioNoutput);
-               dip->un.v.num_channels = 2;
-               strcpy(dip->un.v.units.name, AudioNvolume);
-               return 0;
-
        case SB_AGC:
                dip->type = AUDIO_MIXER_ENUM;
                dip->mixer_class = SB_INPUT_CLASS;
@@ -2264,7 +2315,30 @@
 
        }
 
-       return ENXIO;
+        if (sc->sc_mixer_model == SBM_ALS007)
+                return ENXIO; /* No IGain, OGain */
+
+       switch(dip->index) {
+        case SB_INPUT_GAIN:
+                dip->type = AUDIO_MIXER_VALUE;
+                dip->mixer_class = SB_INPUT_CLASS;
+                dip->prev = dip->next = AUDIO_MIXER_LAST;
+                strcpy(dip->label.name, AudioNinput);
+                dip->un.v.num_channels = 2;
+                strcpy(dip->un.v.units.name, AudioNvolume);
+                return 0;
+
+        case SB_OUTPUT_GAIN:
+                dip->type = AUDIO_MIXER_VALUE;
+                dip->mixer_class = SB_OUTPUT_CLASS;
+                dip->prev = dip->next = AUDIO_MIXER_LAST;
+                strcpy(dip->label.name, AudioNoutput);
+                dip->un.v.num_channels = 2;
+                strcpy(dip->un.v.units.name, AudioNvolume);
+                return 0;
+       }
+
+       return ENXIO;  
 }
 
 void *
diff -ru sys_plain/dev/isa/sbdspvar.h sys/dev/isa/sbdspvar.h
--- sys_plain/dev/isa/sbdspvar.h        Tue Dec 19 02:09:15 2000
+++ sys/dev/isa/sbdspvar.h      Sun Apr 21 06:20:12 2002
@@ -158,6 +158,7 @@
 #define SBM_CT1345     2
 #define SBM_CT1XX5     3
 #define SBM_CT1745     4
+#define SBM_ALS007     5
 #define ISSBM1745(x) ((x)->sc_mixer_model >= SBM_CT1XX5)
 
        u_int   sc_model;               /* DSP model */
@@ -170,8 +171,9 @@
 #define SB_16  5                       /* SB 16 */
 #define SB_32  6                       /* SB AWE 32 */
 #define SB_64  7                       /* SB AWE 64 */
+#define SB_ALS007      8               /* Avance Logic ALS007 */
 
-#define SB_NAMES { "SB_1", "SB_2.0", "SB_2.x", "SB_Pro", "Jazz_16", "SB_16", "S
B_AWE_32", "SB_AWE_64" }
+#define SB_NAMES { "SB_1", "SB_2.0", "SB_2.x", "SB_Pro", "Jazz_16", "SB_16", "S
B_AWE_32", "SB_AWE_64", "ALS_007" }
 
        u_int   sc_version;             /* DSP version */
 #define SBVER_MAJOR(v) (((v)>>8) & 0xff)
diff -ru sys_plain/dev/isa/sbreg.h sys/dev/isa/sbreg.h
--- sys_plain/dev/isa/sbreg.h   Wed Nov  3 00:35:02 1999
+++ sys/dev/isa/sbreg.h Sun Apr 21 06:20:21 2002
@@ -85,6 +85,11 @@
 #define        SBP_LINE_VOL            0x2E
 
 #define        SBP_RECORD_SOURCE       0x0C
+
+#define ALS007_RECORD_SOURCE   0x6C
+#define ALS007_OUTPUT_CTRL1     0x3c
+#define ALS007_OUTPUT_CTRL2     0x4c
+
 #define        SBP_STEREO              0x0E
 #define                SBP_PLAYMODE_STEREO     0x2
 #define                SBP_PLAYMODE_MONO       0x0
@@ -103,6 +108,12 @@
 #define                SBP_FROM_CD             0x02
 #define                SBP_FROM_LINE           0x06
 
+#define                ALS007_FROM_MIC         4
+#define                ALS007_FROM_LINE        6
+#define                ALS007_FROM_CD          2
+#define                ALS007_FROM_MIDI        7
+
+
 #define SBP_SET_IRQ            0x80    /* Soft-configured irq (SB16-) */
 #define SBP_SET_DRQ            0x81    /* Soft-configured drq (SB16-) */
 #define        SBP_IRQ_STATUS          0x82    /* Pending IRQ status (SB16-) */
@@ -138,6 +149,28 @@
 #define SB16P_L_TO_R(l) ((l)+1)
 
 #define SB16P_AGC              0x43
+
+#define ALS007P_MASTER          0x62
+#define ALS007P_VOICE           0x64
+#define ALS007P_MIDI            0x66
+#define ALS007P_CD              0x68
+#define ALS007P_LINE            0x6e
+#define ALS007P_MIC             0x6a
+#define ALS007P_PCSPEAKER         0x00
+#define ALS007P_OSWITCH           0x00
+#define ALS007P_ISWITCH_L         0x00
+#define ALS007P_ISWITCH_R         0x00
+#define         ALS007P_SW_MIC    0x01
+#define         ALS007P_SW_CD_R   0x02
+#define         ALS007P_SW_CD_L   0x04
+#define         ALS007P_SW_CD     (ALS007P_SW_CD_L|ALS007P_SW_CD_R)
+#define         ALS007P_SW_LINE_R 0x08
+#define         ALS007P_SW_LINE_L 0x10
+#define         ALS007P_SW_LINE   (ALS007P_SW_LINE_L|ALS007P_SW_LINE_R)
+#define         ALS007P_SW_MIDI_R 0x20
+#define         ALS007P_SW_MIDI_L 0x40
+#define         ALS007P_SW_MIDI   (ALS007P_SW_MIDI_L|ALS007P_SW_MIDI_R)
+
 
 #define SBP_RECORD_SOURCE_L    0x3d
 #define SBP_RECORD_SOURCE_R    0x3e
diff -ru sys_plain/dev/isapnp/isapnpdevs sys/dev/isapnp/isapnpdevs
--- sys_plain/dev/isapnp/isapnpdevs     Sun Feb 24 14:51:29 2002
+++ sys/dev/isapnp/isapnpdevs   Sat Apr 27 18:07:39 2002
@@ -137,6 +137,7 @@
 devlogic       joy     OPT0001         0       OPTi Audio 16
 devlogic       joy     PNPB02F         0       XXX broken GUS PnP
 devlogic       joy     ASB16FD         0       AdLib NSC 16 PNP
+devlogic       joy     @P@0001         0       ALS007 joy port
 devcompat      joy     PNPB02F         0       generic
 
 /*
@@ -187,6 +188,7 @@
 devlogic       sb      @X@0001         0       CMI8330. Audio Adapter
 devlogic       sb      @@@1001         0       Avance Logic ALS100+
 devlogic       sb      @@@2001         0       Avance Logic ALS120
+devlogic       sb      @@@0001         0       Avance Logic ALS007
 devcompat      sb      PNPB000         0       Generic SB 1.5
 devcompat      sb      PNPB001         0       Generic SB 2.0
 devcompat      sb      PNPB002         0       Generic SB Pro
diff -ru sys_plain/dev/isapnp/sb_isapnp.c sys/dev/isapnp/sb_isapnp.c
--- sys_plain/dev/isapnp/sb_isapnp.c    Wed Nov 14 13:17:32 2001
+++ sys/dev/isapnp/sb_isapnp.c  Sun Apr 21 10:21:20 2002
@@ -109,7 +109,8 @@
 
        /* Avance logic ALS100+ does not like being frobbed 
           trying to set irq/drq so set that quirk skip over it */
-       if(!strcmp(ipa->ipa_devlogic, "@@@1001"))
+       if(!strcmp(ipa->ipa_devlogic, "@@@1001") ||
+                       !strcmp(ipa->ipa_devlogic, "@@@0001"))
                sc->sc_quirks = SB_QUIRK_NO_INIT_DRQ;
 
        if (isapnp_config(ipa->ipa_iot, ipa->ipa_memt, ipa)) {

>Release-Note:
>Audit-Trail:
>Unformatted: