1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * PC-Speaker driver for Linux
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Mixer implementation.
6*4882a593Smuzhiyun * Copyright (C) 2001-2008 Stas Sergeev
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <sound/core.h>
10*4882a593Smuzhiyun #include <sound/control.h>
11*4882a593Smuzhiyun #include "pcsp.h"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun
pcsp_enable_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)14*4882a593Smuzhiyun static int pcsp_enable_info(struct snd_kcontrol *kcontrol,
15*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
18*4882a593Smuzhiyun uinfo->count = 1;
19*4882a593Smuzhiyun uinfo->value.integer.min = 0;
20*4882a593Smuzhiyun uinfo->value.integer.max = 1;
21*4882a593Smuzhiyun return 0;
22*4882a593Smuzhiyun }
23*4882a593Smuzhiyun
pcsp_enable_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)24*4882a593Smuzhiyun static int pcsp_enable_get(struct snd_kcontrol *kcontrol,
25*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
28*4882a593Smuzhiyun ucontrol->value.integer.value[0] = chip->enable;
29*4882a593Smuzhiyun return 0;
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun
pcsp_enable_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)32*4882a593Smuzhiyun static int pcsp_enable_put(struct snd_kcontrol *kcontrol,
33*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
36*4882a593Smuzhiyun int changed = 0;
37*4882a593Smuzhiyun int enab = ucontrol->value.integer.value[0];
38*4882a593Smuzhiyun if (enab != chip->enable) {
39*4882a593Smuzhiyun chip->enable = enab;
40*4882a593Smuzhiyun changed = 1;
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun return changed;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun
pcsp_treble_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)45*4882a593Smuzhiyun static int pcsp_treble_info(struct snd_kcontrol *kcontrol,
46*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
49*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
50*4882a593Smuzhiyun uinfo->count = 1;
51*4882a593Smuzhiyun uinfo->value.enumerated.items = chip->max_treble + 1;
52*4882a593Smuzhiyun if (uinfo->value.enumerated.item > chip->max_treble)
53*4882a593Smuzhiyun uinfo->value.enumerated.item = chip->max_treble;
54*4882a593Smuzhiyun sprintf(uinfo->value.enumerated.name, "%lu",
55*4882a593Smuzhiyun (unsigned long)PCSP_CALC_RATE(uinfo->value.enumerated.item));
56*4882a593Smuzhiyun return 0;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
pcsp_treble_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)59*4882a593Smuzhiyun static int pcsp_treble_get(struct snd_kcontrol *kcontrol,
60*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
63*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] = chip->treble;
64*4882a593Smuzhiyun return 0;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
pcsp_treble_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)67*4882a593Smuzhiyun static int pcsp_treble_put(struct snd_kcontrol *kcontrol,
68*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
71*4882a593Smuzhiyun int changed = 0;
72*4882a593Smuzhiyun int treble = ucontrol->value.enumerated.item[0];
73*4882a593Smuzhiyun if (treble != chip->treble) {
74*4882a593Smuzhiyun chip->treble = treble;
75*4882a593Smuzhiyun #if PCSP_DEBUG
76*4882a593Smuzhiyun printk(KERN_INFO "PCSP: rate set to %li\n", PCSP_RATE());
77*4882a593Smuzhiyun #endif
78*4882a593Smuzhiyun changed = 1;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun return changed;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
pcsp_pcspkr_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)83*4882a593Smuzhiyun static int pcsp_pcspkr_info(struct snd_kcontrol *kcontrol,
84*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
87*4882a593Smuzhiyun uinfo->count = 1;
88*4882a593Smuzhiyun uinfo->value.integer.min = 0;
89*4882a593Smuzhiyun uinfo->value.integer.max = 1;
90*4882a593Smuzhiyun return 0;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
pcsp_pcspkr_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)93*4882a593Smuzhiyun static int pcsp_pcspkr_get(struct snd_kcontrol *kcontrol,
94*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
97*4882a593Smuzhiyun ucontrol->value.integer.value[0] = chip->pcspkr;
98*4882a593Smuzhiyun return 0;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
pcsp_pcspkr_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)101*4882a593Smuzhiyun static int pcsp_pcspkr_put(struct snd_kcontrol *kcontrol,
102*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
105*4882a593Smuzhiyun int changed = 0;
106*4882a593Smuzhiyun int spkr = ucontrol->value.integer.value[0];
107*4882a593Smuzhiyun if (spkr != chip->pcspkr) {
108*4882a593Smuzhiyun chip->pcspkr = spkr;
109*4882a593Smuzhiyun changed = 1;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun return changed;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun #define PCSP_MIXER_CONTROL(ctl_type, ctl_name) \
115*4882a593Smuzhiyun { \
116*4882a593Smuzhiyun .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
117*4882a593Smuzhiyun .name = ctl_name, \
118*4882a593Smuzhiyun .info = pcsp_##ctl_type##_info, \
119*4882a593Smuzhiyun .get = pcsp_##ctl_type##_get, \
120*4882a593Smuzhiyun .put = pcsp_##ctl_type##_put, \
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_pcsp_controls_pcm[] = {
124*4882a593Smuzhiyun PCSP_MIXER_CONTROL(enable, "Master Playback Switch"),
125*4882a593Smuzhiyun PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"),
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_pcsp_controls_spkr[] = {
129*4882a593Smuzhiyun PCSP_MIXER_CONTROL(pcspkr, "Beep Playback Switch"),
130*4882a593Smuzhiyun };
131*4882a593Smuzhiyun
snd_pcsp_ctls_add(struct snd_pcsp * chip,const struct snd_kcontrol_new * ctls,int num)132*4882a593Smuzhiyun static int snd_pcsp_ctls_add(struct snd_pcsp *chip,
133*4882a593Smuzhiyun const struct snd_kcontrol_new *ctls, int num)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun int i, err;
136*4882a593Smuzhiyun struct snd_card *card = chip->card;
137*4882a593Smuzhiyun for (i = 0; i < num; i++) {
138*4882a593Smuzhiyun err = snd_ctl_add(card, snd_ctl_new1(ctls + i, chip));
139*4882a593Smuzhiyun if (err < 0)
140*4882a593Smuzhiyun return err;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun return 0;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
snd_pcsp_new_mixer(struct snd_pcsp * chip,int nopcm)145*4882a593Smuzhiyun int snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun int err;
148*4882a593Smuzhiyun struct snd_card *card = chip->card;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun if (!nopcm) {
151*4882a593Smuzhiyun err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_pcm,
152*4882a593Smuzhiyun ARRAY_SIZE(snd_pcsp_controls_pcm));
153*4882a593Smuzhiyun if (err < 0)
154*4882a593Smuzhiyun return err;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_spkr,
157*4882a593Smuzhiyun ARRAY_SIZE(snd_pcsp_controls_spkr));
158*4882a593Smuzhiyun if (err < 0)
159*4882a593Smuzhiyun return err;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun strcpy(card->mixername, "PC-Speaker");
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun return 0;
164*4882a593Smuzhiyun }
165