1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * OPL4 mixer functions
4  * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de>
5  */
6 
7 #include "opl4_local.h"
8 #include <sound/control.h>
9 
snd_opl4_ctl_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)10 static int snd_opl4_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11 {
12 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13 	uinfo->count = 2;
14 	uinfo->value.integer.min = 0;
15 	uinfo->value.integer.max = 7;
16 	return 0;
17 }
18 
snd_opl4_ctl_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)19 static int snd_opl4_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
20 {
21 	struct snd_opl4 *opl4 = snd_kcontrol_chip(kcontrol);
22 	unsigned long flags;
23 	u8 reg = kcontrol->private_value;
24 	u8 value;
25 
26 	spin_lock_irqsave(&opl4->reg_lock, flags);
27 	value = snd_opl4_read(opl4, reg);
28 	spin_unlock_irqrestore(&opl4->reg_lock, flags);
29 	ucontrol->value.integer.value[0] = 7 - (value & 7);
30 	ucontrol->value.integer.value[1] = 7 - ((value >> 3) & 7);
31 	return 0;
32 }
33 
snd_opl4_ctl_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)34 static int snd_opl4_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
35 {
36 	struct snd_opl4 *opl4 = snd_kcontrol_chip(kcontrol);
37 	unsigned long flags;
38 	u8 reg = kcontrol->private_value;
39 	u8 value, old_value;
40 
41 	value = (7 - (ucontrol->value.integer.value[0] & 7)) |
42 		((7 - (ucontrol->value.integer.value[1] & 7)) << 3);
43 	spin_lock_irqsave(&opl4->reg_lock, flags);
44 	old_value = snd_opl4_read(opl4, reg);
45 	snd_opl4_write(opl4, reg, value);
46 	spin_unlock_irqrestore(&opl4->reg_lock, flags);
47 	return value != old_value;
48 }
49 
50 static const struct snd_kcontrol_new snd_opl4_controls[] = {
51 	{
52 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
53 		.name = "FM Playback Volume",
54 		.info = snd_opl4_ctl_info,
55 		.get = snd_opl4_ctl_get,
56 		.put = snd_opl4_ctl_put,
57 		.private_value = OPL4_REG_MIX_CONTROL_FM
58 	},
59 	{
60 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
61 		.name = "Wavetable Playback Volume",
62 		.info = snd_opl4_ctl_info,
63 		.get = snd_opl4_ctl_get,
64 		.put = snd_opl4_ctl_put,
65 		.private_value = OPL4_REG_MIX_CONTROL_PCM
66 	}
67 };
68 
snd_opl4_create_mixer(struct snd_opl4 * opl4)69 int snd_opl4_create_mixer(struct snd_opl4 *opl4)
70 {
71 	struct snd_card *card = opl4->card;
72 	int i, err;
73 
74 	strcat(card->mixername, ",OPL4");
75 
76 	for (i = 0; i < 2; ++i) {
77 		err = snd_ctl_add(card, snd_ctl_new1(&snd_opl4_controls[i], opl4));
78 		if (err < 0)
79 			return err;
80 	}
81 	return 0;
82 }
83