[PATCH - ca0106] add mixer controls to ca0106

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

 



This patch adds a master volume/mute and routing controls for ca0106
cards without the ac97.  This gives the advantage of being able to
control the volume of all speakers from an application like MPlayer,
and to be able to play stereo audio on a surround sound setup.

Signed-off by: Nickolas Lloyd <ultrageek.lloyd@xxxxxxxxx>

I'm new to this whole thing so I'd be very receptive to feedback/criticism :)
----


diff -uprN alsa-driver-1.0.11-vanilla/alsa-kernel/pci/ca0106/ca0106.h
alsa-driver-1.0.11/alsa-kernel/pci/ca0106/ca0106.h
--- alsa-driver-1.0.11-vanilla/alsa-kernel/pci/ca0106/ca0106.h
2006-04-09 07:46:52.000000000 -0400
+++ alsa-driver-1.0.11/alsa-kernel/pci/ca0106/ca0106.h    2006-06-16
18:03:01.000000000 -0400
@@ -586,6 +586,7 @@ struct snd_ca0106 {
     struct snd_ca0106_details *details;
     struct pci_dev *pci;

+    long master_volume[2];
     unsigned long port;
     struct resource *res_port;
     int irq;
diff -uprN alsa-driver-1.0.11-vanilla/alsa-kernel/pci/ca0106/ca0106_main.c
alsa-driver-1.0.11/alsa-kernel/pci/ca0106/ca0106_main.c
--- alsa-driver-1.0.11-vanilla/alsa-kernel/pci/ca0106/ca0106_main.c
2006-04-09 15:46:09.000000000 -0400
+++ alsa-driver-1.0.11/alsa-kernel/pci/ca0106/ca0106_main.c
2006-06-16 18:03:01.000000000 -0400
@@ -1435,6 +1435,8 @@ static int __devinit snd_ca0106_create(s
         snd_ca0106_free(chip);
         return err;
     }
+
+    memset(&chip->master_volume, 0, sizeof(chip->master_volume));
     *rchip = chip;
     return 0;
 }
diff -uprN alsa-driver-1.0.11-vanilla/alsa-kernel/pci/ca0106/ca0106_mixer.c
alsa-driver-1.0.11/alsa-kernel/pci/ca0106/ca0106_mixer.c
--- alsa-driver-1.0.11-vanilla/alsa-kernel/pci/ca0106/ca0106_mixer.c
 2006-04-09 15:46:09.000000000 -0400
+++ alsa-driver-1.0.11/alsa-kernel/pci/ca0106/ca0106_mixer.c
2006-06-16 18:03:01.000000000 -0400
@@ -409,6 +409,174 @@ static int snd_ca0106_volume_put(struct
     return 1;
 }

+static int snd_ca0106_mute_analog_master_info(struct snd_kcontrol * kcontrol,
+                    struct snd_ctl_elem_info * uinfo)
+{
+    uinfo->count = 1;
+    uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+    uinfo->value.integer.min = 0;
+    uinfo->value.integer.max = 1;
+    return 0;
+}
+
+static int snd_ca0106_mute_analog_master_get(struct snd_kcontrol * kcontrol,
+                    struct snd_ctl_elem_value * ucontrol)
+{
+    struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+    unsigned long flags;
+    unsigned int muted;
+
+    spin_lock_irqsave(&emu->emu_lock, flags);
+    muted = inl(emu->port + GPIO) & 0x00004200;
+    spin_unlock_irqrestore(&emu->emu_lock, flags);
+    if(muted == 0x4200) ucontrol->value.integer.value[0] = 1;
+    else ucontrol->value.integer.value[0] = 0;
+    return 0;
+}
+
+static int snd_ca0106_mute_analog_master_put(struct snd_kcontrol * kcontrol,
+                    struct snd_ctl_elem_value * ucontrol)
+{
+    struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+    unsigned long flags;
+    unsigned int muted;
+
+    spin_lock_irqsave(&emu->emu_lock, flags);
+    muted = inl(emu->port + GPIO) & 0x00004200;
+    if(muted == 0x000 && ucontrol->value.integer.value[0] == 1)
+        outl((inl(emu->port + GPIO) | 0x00004200), emu->port + GPIO);
+    else if(muted == 0x4200 && ucontrol->value.integer.value[0] == 0)
+        outl((inl(emu->port + GPIO) & 0xffffbdff), emu->port + GPIO);
+    spin_unlock_irqrestore(&emu->emu_lock, flags);
+    return 0;
+}
+
+static int snd_ca0106_volume_get_analog_master(struct snd_kcontrol * kcontrol,
+                    struct snd_ctl_elem_value * ucontrol)
+{
+    struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+    ucontrol->value.integer.value[0] = emu->master_volume[0];
+    ucontrol->value.integer.value[1] = emu->master_volume[1];
+    return 0;
+}
+
+static int snd_ca0106_volume_put_analog_master(struct snd_kcontrol * kcontrol,
+                    struct snd_ctl_elem_value * ucontrol)
+{
+    struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+    unsigned int value;
+    long volume[2];
+    int channel_id;
+    unsigned int reg;
+    struct snd_ctl_elem_value ucontrol_channel_id;
+
+    memset(&ucontrol_channel_id, 0, sizeof(ucontrol_channel_id));
+    reg = (emu->spdif_enable) ? PLAYBACK_VOLUME1 : PLAYBACK_VOLUME2;
+    for (channel_id = 0; channel_id < 4; channel_id++) {
+        kcontrol->private_value = ((channel_id) << 8) | (reg);
+        snd_ca0106_volume_get(kcontrol, &ucontrol_channel_id);
+        volume[0] = (ucontrol->value.integer.value[0] -
+            emu->master_volume[0]) +
+            ucontrol_channel_id.value.integer.value[0];
+        volume[1] = (ucontrol->value.integer.value[1] -
+        emu->master_volume[1]) +
+        ucontrol_channel_id.value.integer.value[1];
+        if(volume[0] < 0) volume[0] = 0;
+        if(volume[1] < 0) volume[1] = 0;
+        value = ((0xff - volume[0]) << 24) | ((0xff - volume[1]) << 16);
+        value = value | ((0xff - volume[0]) << 8) | ((0xff - volume[1]));
+        snd_ca0106_ptr_write(emu, reg, channel_id, value);
+    }
+    emu->master_volume[0] = ucontrol->value.integer.value[0];
+    emu->master_volume[1] = ucontrol->value.integer.value[1];
+    return 1;
+}
+
+static int snd_ca0106_routing_analog_info(struct snd_kcontrol * kcontrol,
+                    struct snd_ctl_elem_info * uinfo)
+{
+    static char *texts[4] = { "Front Output", "Center/LFE Output",
+                    "Side Output", "Rear Output" };
+
+    uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+    uinfo->count = 1;
+    uinfo->value.enumerated.items = 4;
+    if(uinfo->value.enumerated.item > 3)
+        uinfo->value.enumerated.item = 3;
+    strcpy(uinfo->value.enumerated.name,
+        texts[uinfo->value.enumerated.item]);
+    return 0;
+}
+
+static int snd_ca0106_routing_analog_get(struct snd_kcontrol * kcontrol,
+                    struct snd_ctl_elem_value * ucontrol)
+{
+    struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+
+    unsigned int route = snd_ca0106_ptr_read(emu, CAPTURE_ROUTING1, 0);
+    unsigned int route_mask;
+    unsigned int shift;
+    if(kcontrol->private_value == CONTROL_FRONT_CHANNEL) {
+        route_mask = 0xff;
+        shift = 0;
+    }
+    else if(kcontrol->private_value == CONTROL_CENTER_LFE_CHANNEL) {
+        route_mask = 0xff00;
+        shift = 8;
+    }
+    else if(kcontrol->private_value == CONTROL_UNKNOWN_CHANNEL) {
+        route_mask = 0xff0000;
+        shift = 16;
+    }
+    else if(kcontrol->private_value == CONTROL_REAR_CHANNEL) {
+        route_mask = 0xff000000;
+        shift = 24;
+    }
+    else return 0;
+    route = (route & route_mask) >> shift;
+    if(route == 0x10) ucontrol->value.enumerated.item[0] = 0;
+    else if(route == 0x54) ucontrol->value.enumerated.item[0] = 1;
+    else if(route == 0x76) ucontrol->value.enumerated.item[0] = 2;
+    else if(route == 0x32) ucontrol->value.enumerated.item[0] = 3;
+    return 0;
+}
+
+static int snd_ca0106_routing_analog_put(struct snd_kcontrol * kcontrol,
+                    struct snd_ctl_elem_value * ucontrol)
+{
+    struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+
+    unsigned int route = snd_ca0106_ptr_read(emu, CAPTURE_ROUTING1, 0);
+    unsigned int route_mask;
+    unsigned int shift;
+    if(kcontrol->private_value == CONTROL_FRONT_CHANNEL) {
+        route_mask = 0xffffff00;
+        shift = 0;
+    }
+    else if(kcontrol->private_value == CONTROL_CENTER_LFE_CHANNEL) {
+        route_mask = 0xffff00ff;
+        shift = 8;
+    }
+    else if(kcontrol->private_value == CONTROL_UNKNOWN_CHANNEL) {
+        route_mask = 0xff00ffff;
+        shift = 8;
+    }
+    else if(kcontrol->private_value == CONTROL_REAR_CHANNEL) {
+        route_mask = 0x00ffffff;
+        shift = 24;
+    }
+    else return 0;
+    if(ucontrol->value.enumerated.item[0] == 0) route = (route &
route_mask) | (0x10 << shift);
+    else if(ucontrol->value.enumerated.item[0] == 1) route = (route &
route_mask) | (0x54 << shift);
+    else if(ucontrol->value.enumerated.item[0] == 2) route = (route &
route_mask) | (0x76 << shift);
+    else if(ucontrol->value.enumerated.item[0] == 3) route = (route &
route_mask) | (0x32 << shift);
+    else route = (route & route_mask) | (0x10 << shift);
+    snd_ca0106_ptr_write(emu, CAPTURE_ROUTING1, 0, route);
+    return 0;
+}
+
+
+
 static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol,
                   struct snd_ctl_elem_info *uinfo)
 {
@@ -475,6 +643,15 @@ static int snd_ca0106_i2c_volume_put(str
     .private_value = ((chid) << 8) | (reg)            \
 }

+#define CA_ROUTING(xname,chid) \
+{                                \
+    .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,    \
+    .info =  snd_ca0106_routing_analog_info,        \
+    .get =   snd_ca0106_routing_analog_get,            \
+    .put =   snd_ca0106_routing_analog_put,            \
+    .private_value = chid                    \
+}
+
 #define I2C_VOLUME(xname,chid) \
 {                                \
     .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,    \
@@ -484,6 +661,26 @@ static int snd_ca0106_i2c_volume_put(str
     .private_value = chid                    \
 }

+static struct snd_kcontrol_new snd_ca0106_routing_ctls[] __devinitdata = {
+    {
+        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name = "Master Playback Volume",
+        .info = snd_ca0106_volume_info,
+        .get = snd_ca0106_volume_get_analog_master,
+        .put = snd_ca0106_volume_put_analog_master
+    },
+    {
+        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name = "Master Playback Switch",
+        .info = snd_ca0106_mute_analog_master_info,
+        .get = snd_ca0106_mute_analog_master_get,
+        .put = snd_ca0106_mute_analog_master_put
+    },
+    CA_ROUTING("Front Jack Playback Route", CONTROL_FRONT_CHANNEL),
+    CA_ROUTING("Center/LFE Jack Playback Route", CONTROL_CENTER_LFE_CHANNEL),
+    CA_ROUTING("Side Jack Playback Route", CONTROL_UNKNOWN_CHANNEL),
+    CA_ROUTING("Rear Jack Playback Route", CONTROL_REAR_CHANNEL)
+};

 static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
     CA_VOLUME("Analog Front Playback Volume",
@@ -629,6 +826,13 @@ int __devinit snd_ca0106_mixer(struct sn
         rename_ctl(card, c[0], c[1]);
 #endif

+    if(emu->details->ac97 != 1) {
+        for(i = 0; i < ARRAY_SIZE(snd_ca0106_routing_ctls); i++) {
+            err = snd_ctl_add(card,
snd_ctl_new1(&snd_ca0106_routing_ctls[i], emu));
+            if (err < 0)
+                return err;
+        }
+    }
     for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_ctls); i++) {
         err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_ctls[i], emu));
         if (err < 0)


_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux