162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PC-Speaker driver for Linux
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Mixer implementation.
662306a36Sopenharmony_ci * Copyright (C) 2001-2008  Stas Sergeev
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <sound/core.h>
1062306a36Sopenharmony_ci#include <sound/control.h>
1162306a36Sopenharmony_ci#include "pcsp.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic int pcsp_enable_info(struct snd_kcontrol *kcontrol,
1562306a36Sopenharmony_ci			    struct snd_ctl_elem_info *uinfo)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1862306a36Sopenharmony_ci	uinfo->count = 1;
1962306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
2062306a36Sopenharmony_ci	uinfo->value.integer.max = 1;
2162306a36Sopenharmony_ci	return 0;
2262306a36Sopenharmony_ci}
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic int pcsp_enable_get(struct snd_kcontrol *kcontrol,
2562306a36Sopenharmony_ci			   struct snd_ctl_elem_value *ucontrol)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
2862306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = chip->enable;
2962306a36Sopenharmony_ci	return 0;
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic int pcsp_enable_put(struct snd_kcontrol *kcontrol,
3362306a36Sopenharmony_ci			   struct snd_ctl_elem_value *ucontrol)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
3662306a36Sopenharmony_ci	int changed = 0;
3762306a36Sopenharmony_ci	int enab = ucontrol->value.integer.value[0];
3862306a36Sopenharmony_ci	if (enab != chip->enable) {
3962306a36Sopenharmony_ci		chip->enable = enab;
4062306a36Sopenharmony_ci		changed = 1;
4162306a36Sopenharmony_ci	}
4262306a36Sopenharmony_ci	return changed;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic int pcsp_treble_info(struct snd_kcontrol *kcontrol,
4662306a36Sopenharmony_ci			    struct snd_ctl_elem_info *uinfo)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
4962306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
5062306a36Sopenharmony_ci	uinfo->count = 1;
5162306a36Sopenharmony_ci	uinfo->value.enumerated.items = chip->max_treble + 1;
5262306a36Sopenharmony_ci	if (uinfo->value.enumerated.item > chip->max_treble)
5362306a36Sopenharmony_ci		uinfo->value.enumerated.item = chip->max_treble;
5462306a36Sopenharmony_ci	sprintf(uinfo->value.enumerated.name, "%lu",
5562306a36Sopenharmony_ci		(unsigned long)PCSP_CALC_RATE(uinfo->value.enumerated.item));
5662306a36Sopenharmony_ci	return 0;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int pcsp_treble_get(struct snd_kcontrol *kcontrol,
6062306a36Sopenharmony_ci			   struct snd_ctl_elem_value *ucontrol)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
6362306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = chip->treble;
6462306a36Sopenharmony_ci	return 0;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int pcsp_treble_put(struct snd_kcontrol *kcontrol,
6862306a36Sopenharmony_ci			   struct snd_ctl_elem_value *ucontrol)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
7162306a36Sopenharmony_ci	int changed = 0;
7262306a36Sopenharmony_ci	int treble = ucontrol->value.enumerated.item[0];
7362306a36Sopenharmony_ci	if (treble != chip->treble) {
7462306a36Sopenharmony_ci		chip->treble = treble;
7562306a36Sopenharmony_ci#if PCSP_DEBUG
7662306a36Sopenharmony_ci		printk(KERN_INFO "PCSP: rate set to %li\n", PCSP_RATE());
7762306a36Sopenharmony_ci#endif
7862306a36Sopenharmony_ci		changed = 1;
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci	return changed;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic int pcsp_pcspkr_info(struct snd_kcontrol *kcontrol,
8462306a36Sopenharmony_ci			    struct snd_ctl_elem_info *uinfo)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
8762306a36Sopenharmony_ci	uinfo->count = 1;
8862306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
8962306a36Sopenharmony_ci	uinfo->value.integer.max = 1;
9062306a36Sopenharmony_ci	return 0;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int pcsp_pcspkr_get(struct snd_kcontrol *kcontrol,
9462306a36Sopenharmony_ci			   struct snd_ctl_elem_value *ucontrol)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
9762306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = chip->pcspkr;
9862306a36Sopenharmony_ci	return 0;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic int pcsp_pcspkr_put(struct snd_kcontrol *kcontrol,
10262306a36Sopenharmony_ci			   struct snd_ctl_elem_value *ucontrol)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
10562306a36Sopenharmony_ci	int changed = 0;
10662306a36Sopenharmony_ci	int spkr = ucontrol->value.integer.value[0];
10762306a36Sopenharmony_ci	if (spkr != chip->pcspkr) {
10862306a36Sopenharmony_ci		chip->pcspkr = spkr;
10962306a36Sopenharmony_ci		changed = 1;
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci	return changed;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define PCSP_MIXER_CONTROL(ctl_type, ctl_name) \
11562306a36Sopenharmony_ci{ \
11662306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER, \
11762306a36Sopenharmony_ci	.name =		ctl_name, \
11862306a36Sopenharmony_ci	.info =		pcsp_##ctl_type##_info, \
11962306a36Sopenharmony_ci	.get =		pcsp_##ctl_type##_get, \
12062306a36Sopenharmony_ci	.put =		pcsp_##ctl_type##_put, \
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_pcsp_controls_pcm[] = {
12462306a36Sopenharmony_ci	PCSP_MIXER_CONTROL(enable, "Master Playback Switch"),
12562306a36Sopenharmony_ci	PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"),
12662306a36Sopenharmony_ci};
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_pcsp_controls_spkr[] = {
12962306a36Sopenharmony_ci	PCSP_MIXER_CONTROL(pcspkr, "Beep Playback Switch"),
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic int snd_pcsp_ctls_add(struct snd_pcsp *chip,
13362306a36Sopenharmony_ci			     const struct snd_kcontrol_new *ctls, int num)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	int i, err;
13662306a36Sopenharmony_ci	struct snd_card *card = chip->card;
13762306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
13862306a36Sopenharmony_ci		err = snd_ctl_add(card, snd_ctl_new1(ctls + i, chip));
13962306a36Sopenharmony_ci		if (err < 0)
14062306a36Sopenharmony_ci			return err;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci	return 0;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ciint snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	int err;
14862306a36Sopenharmony_ci	struct snd_card *card = chip->card;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (!nopcm) {
15162306a36Sopenharmony_ci		err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_pcm,
15262306a36Sopenharmony_ci			ARRAY_SIZE(snd_pcsp_controls_pcm));
15362306a36Sopenharmony_ci		if (err < 0)
15462306a36Sopenharmony_ci			return err;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci	err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_spkr,
15762306a36Sopenharmony_ci		ARRAY_SIZE(snd_pcsp_controls_spkr));
15862306a36Sopenharmony_ci	if (err < 0)
15962306a36Sopenharmony_ci		return err;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	strcpy(card->mixername, "PC-Speaker");
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	return 0;
16462306a36Sopenharmony_ci}
165