Loading sound/usb/6fire/control.c +124 −22 Original line number Diff line number Diff line Loading @@ -7,6 +7,10 @@ * Created: Jan 01, 2011 * Copyright: (C) Torsten Schenk * * Thanks to: * - Holger Ruckdeschel: he found out how to control individual channel * volumes and introduced mute switch * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or Loading Loading @@ -39,7 +43,7 @@ init_data[] = { { 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 }, { 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 }, { 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 }, { 0x12, 0x0d, 0x78 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, { 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, { 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 }, { 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 }, { 0 } /* TERMINATING ENTRY */ Loading @@ -56,14 +60,17 @@ enum { DIGITAL_THRU_ONLY_SAMPLERATE = 3 }; static void usb6fire_control_master_vol_update(struct control_runtime *rt) static void usb6fire_control_output_vol_update(struct control_runtime *rt) { struct comm_runtime *comm_rt = rt->chip->comm; if (comm_rt) { /* set volume */ comm_rt->write8(comm_rt, 0x12, 0x0f, 180 - rt->master_vol); /* unmute */ comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00); int i; if (comm_rt) for (i = 0; i < 6; i++) if (!(rt->ovol_updated & (1 << i))) { comm_rt->write8(comm_rt, 0x12, 0x0f + i, 180 - rt->output_vol[i]); rt->ovol_updated |= 1 << i; } } Loading Loading @@ -146,34 +153,58 @@ static int usb6fire_control_streaming_update(struct control_runtime *rt) return -EINVAL; } static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = 180; return 0; } static int usb6fire_control_master_vol_put(struct snd_kcontrol *kcontrol, static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct control_runtime *rt = snd_kcontrol_chip(kcontrol); unsigned int ch = kcontrol->private_value; int changed = 0; if (rt->master_vol != ucontrol->value.integer.value[0]) { rt->master_vol = ucontrol->value.integer.value[0]; usb6fire_control_master_vol_update(rt); if (ch > 4) { snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); return -EINVAL; } if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) { rt->output_vol[ch] = ucontrol->value.integer.value[0]; rt->ovol_updated &= ~(1 << ch); changed = 1; } if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) { rt->output_vol[ch + 1] = ucontrol->value.integer.value[1]; rt->ovol_updated &= ~(2 << ch); changed = 1; } if (changed) usb6fire_control_output_vol_update(rt); return changed; } static int usb6fire_control_master_vol_get(struct snd_kcontrol *kcontrol, static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct control_runtime *rt = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = rt->master_vol; unsigned int ch = kcontrol->private_value; if (ch > 4) { snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); return -EINVAL; } ucontrol->value.integer.value[0] = rt->output_vol[ch]; ucontrol->value.integer.value[1] = rt->output_vol[ch + 1]; return 0; } Loading Loading @@ -268,18 +299,47 @@ static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol, return 0; } static struct __devinitdata snd_kcontrol_new elements[] = { static struct __devinitdata snd_kcontrol_new vol_elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", .name = "Analog Playback Volume", .index = 0, .private_value = 0, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = usb6fire_control_output_vol_info, .get = usb6fire_control_output_vol_get, .put = usb6fire_control_output_vol_put, .tlv = { .p = tlv_output } }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog Playback Volume", .index = 1, .private_value = 2, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = usb6fire_control_output_vol_info, .get = usb6fire_control_output_vol_get, .put = usb6fire_control_output_vol_put, .tlv = { .p = tlv_output } }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog Playback Volume", .index = 2, .private_value = 4, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = usb6fire_control_master_vol_info, .get = usb6fire_control_master_vol_get, .put = usb6fire_control_master_vol_put, .info = usb6fire_control_output_vol_info, .get = usb6fire_control_output_vol_get, .put = usb6fire_control_output_vol_put, .tlv = { .p = tlv_output } }, {} }; static struct __devinitdata snd_kcontrol_new elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line/Phono Capture Route", Loading Loading @@ -310,6 +370,40 @@ static struct __devinitdata snd_kcontrol_new elements[] = { {} }; static int usb6fire_control_add_virtual( struct control_runtime *rt, struct snd_card *card, char *name, struct snd_kcontrol_new *elems) { int ret; int i; struct snd_kcontrol *vmaster = snd_ctl_make_virtual_master(name, tlv_output); struct snd_kcontrol *control; if (!vmaster) return -ENOMEM; ret = snd_ctl_add(card, vmaster); if (ret < 0) return ret; i = 0; while (elems[i].name) { control = snd_ctl_new1(&elems[i], rt); if (!control) return -ENOMEM; ret = snd_ctl_add(card, control); if (ret < 0) return ret; ret = snd_ctl_add_slave(vmaster, control); if (ret < 0) return ret; i++; } return 0; } int __devinit usb6fire_control_init(struct sfire_chip *chip) { int i; Loading @@ -335,9 +429,17 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) usb6fire_control_opt_coax_update(rt); usb6fire_control_line_phono_update(rt); usb6fire_control_master_vol_update(rt); usb6fire_control_output_vol_update(rt); usb6fire_control_streaming_update(rt); ret = usb6fire_control_add_virtual(rt, chip->card, "Master Playback Volume", vol_elements); if (ret) { kfree(rt); snd_printk(KERN_ERR PREFIX "cannot add control.\n"); return ret; } i = 0; while (elements[i].name) { ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt)); Loading sound/usb/6fire/control.h +2 −1 Original line number Diff line number Diff line Loading @@ -43,7 +43,8 @@ struct control_runtime { bool line_phono_switch; bool digital_thru_switch; bool usb_streaming; u8 master_vol; u8 output_vol[6]; u8 ovol_updated; }; int __devinit usb6fire_control_init(struct sfire_chip *chip); Loading Loading
sound/usb/6fire/control.c +124 −22 Original line number Diff line number Diff line Loading @@ -7,6 +7,10 @@ * Created: Jan 01, 2011 * Copyright: (C) Torsten Schenk * * Thanks to: * - Holger Ruckdeschel: he found out how to control individual channel * volumes and introduced mute switch * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or Loading Loading @@ -39,7 +43,7 @@ init_data[] = { { 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 }, { 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 }, { 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 }, { 0x12, 0x0d, 0x78 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, { 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, { 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 }, { 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 }, { 0 } /* TERMINATING ENTRY */ Loading @@ -56,14 +60,17 @@ enum { DIGITAL_THRU_ONLY_SAMPLERATE = 3 }; static void usb6fire_control_master_vol_update(struct control_runtime *rt) static void usb6fire_control_output_vol_update(struct control_runtime *rt) { struct comm_runtime *comm_rt = rt->chip->comm; if (comm_rt) { /* set volume */ comm_rt->write8(comm_rt, 0x12, 0x0f, 180 - rt->master_vol); /* unmute */ comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00); int i; if (comm_rt) for (i = 0; i < 6; i++) if (!(rt->ovol_updated & (1 << i))) { comm_rt->write8(comm_rt, 0x12, 0x0f + i, 180 - rt->output_vol[i]); rt->ovol_updated |= 1 << i; } } Loading Loading @@ -146,34 +153,58 @@ static int usb6fire_control_streaming_update(struct control_runtime *rt) return -EINVAL; } static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = 180; return 0; } static int usb6fire_control_master_vol_put(struct snd_kcontrol *kcontrol, static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct control_runtime *rt = snd_kcontrol_chip(kcontrol); unsigned int ch = kcontrol->private_value; int changed = 0; if (rt->master_vol != ucontrol->value.integer.value[0]) { rt->master_vol = ucontrol->value.integer.value[0]; usb6fire_control_master_vol_update(rt); if (ch > 4) { snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); return -EINVAL; } if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) { rt->output_vol[ch] = ucontrol->value.integer.value[0]; rt->ovol_updated &= ~(1 << ch); changed = 1; } if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) { rt->output_vol[ch + 1] = ucontrol->value.integer.value[1]; rt->ovol_updated &= ~(2 << ch); changed = 1; } if (changed) usb6fire_control_output_vol_update(rt); return changed; } static int usb6fire_control_master_vol_get(struct snd_kcontrol *kcontrol, static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct control_runtime *rt = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = rt->master_vol; unsigned int ch = kcontrol->private_value; if (ch > 4) { snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); return -EINVAL; } ucontrol->value.integer.value[0] = rt->output_vol[ch]; ucontrol->value.integer.value[1] = rt->output_vol[ch + 1]; return 0; } Loading Loading @@ -268,18 +299,47 @@ static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol, return 0; } static struct __devinitdata snd_kcontrol_new elements[] = { static struct __devinitdata snd_kcontrol_new vol_elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", .name = "Analog Playback Volume", .index = 0, .private_value = 0, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = usb6fire_control_output_vol_info, .get = usb6fire_control_output_vol_get, .put = usb6fire_control_output_vol_put, .tlv = { .p = tlv_output } }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog Playback Volume", .index = 1, .private_value = 2, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = usb6fire_control_output_vol_info, .get = usb6fire_control_output_vol_get, .put = usb6fire_control_output_vol_put, .tlv = { .p = tlv_output } }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog Playback Volume", .index = 2, .private_value = 4, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = usb6fire_control_master_vol_info, .get = usb6fire_control_master_vol_get, .put = usb6fire_control_master_vol_put, .info = usb6fire_control_output_vol_info, .get = usb6fire_control_output_vol_get, .put = usb6fire_control_output_vol_put, .tlv = { .p = tlv_output } }, {} }; static struct __devinitdata snd_kcontrol_new elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line/Phono Capture Route", Loading Loading @@ -310,6 +370,40 @@ static struct __devinitdata snd_kcontrol_new elements[] = { {} }; static int usb6fire_control_add_virtual( struct control_runtime *rt, struct snd_card *card, char *name, struct snd_kcontrol_new *elems) { int ret; int i; struct snd_kcontrol *vmaster = snd_ctl_make_virtual_master(name, tlv_output); struct snd_kcontrol *control; if (!vmaster) return -ENOMEM; ret = snd_ctl_add(card, vmaster); if (ret < 0) return ret; i = 0; while (elems[i].name) { control = snd_ctl_new1(&elems[i], rt); if (!control) return -ENOMEM; ret = snd_ctl_add(card, control); if (ret < 0) return ret; ret = snd_ctl_add_slave(vmaster, control); if (ret < 0) return ret; i++; } return 0; } int __devinit usb6fire_control_init(struct sfire_chip *chip) { int i; Loading @@ -335,9 +429,17 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) usb6fire_control_opt_coax_update(rt); usb6fire_control_line_phono_update(rt); usb6fire_control_master_vol_update(rt); usb6fire_control_output_vol_update(rt); usb6fire_control_streaming_update(rt); ret = usb6fire_control_add_virtual(rt, chip->card, "Master Playback Volume", vol_elements); if (ret) { kfree(rt); snd_printk(KERN_ERR PREFIX "cannot add control.\n"); return ret; } i = 0; while (elements[i].name) { ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt)); Loading
sound/usb/6fire/control.h +2 −1 Original line number Diff line number Diff line Loading @@ -43,7 +43,8 @@ struct control_runtime { bool line_phono_switch; bool digital_thru_switch; bool usb_streaming; u8 master_vol; u8 output_vol[6]; u8 ovol_updated; }; int __devinit usb6fire_control_init(struct sfire_chip *chip); Loading