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