Merge tag 'input-for-v6.1-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor...
[linux-block.git] / sound / ppc / beep.c
CommitLineData
1a59d1b8 1// SPDX-License-Identifier: GPL-2.0-or-later
1da177e4
LT
2/*
3 * Beep using pcm
4 *
5 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
1da177e4
LT
6 */
7
6cbbfe1c 8#include <linux/io.h>
1da177e4
LT
9#include <asm/irq.h>
10#include <linux/init.h>
11#include <linux/slab.h>
12#include <linux/input.h>
7bbd8277
BH
13#include <linux/pci.h>
14#include <linux/dma-mapping.h>
1da177e4
LT
15#include <sound/core.h>
16#include <sound/control.h>
17#include "pmac.h"
18
65b29f50 19struct pmac_beep {
5ebdcbc2
DT
20 int running; /* boolean */
21 int volume; /* mixer volume: 0-100 */
1da177e4
LT
22 int volume_play; /* currently playing volume */
23 int hz;
24 int nsamples;
25 short *buf; /* allocated wave buffer */
7bbd8277 26 dma_addr_t addr; /* physical address of buffer */
5ebdcbc2 27 struct input_dev *dev;
1da177e4
LT
28};
29
30/*
31 * stop beep if running
32 */
65b29f50 33void snd_pmac_beep_stop(struct snd_pmac *chip)
1da177e4 34{
65b29f50 35 struct pmac_beep *beep = chip->beep;
1da177e4
LT
36 if (beep && beep->running) {
37 beep->running = 0;
38 snd_pmac_beep_dma_stop(chip);
39 }
40}
41
42/*
43 * Stuff for outputting a beep. The values range from -327 to +327
44 * so we can multiply by an amplitude in the range 0..100 to get a
45 * signed short value to put in the output buffer.
46 */
6e9ef32f 47static const short beep_wform[256] = {
1da177e4
LT
48 0, 40, 79, 117, 153, 187, 218, 245,
49 269, 288, 304, 316, 323, 327, 327, 324,
50 318, 310, 299, 288, 275, 262, 249, 236,
51 224, 213, 204, 196, 190, 186, 183, 182,
52 182, 183, 186, 189, 192, 196, 200, 203,
53 206, 208, 209, 209, 209, 207, 204, 201,
54 197, 193, 188, 183, 179, 174, 170, 166,
55 163, 161, 160, 159, 159, 160, 161, 162,
56 164, 166, 168, 169, 171, 171, 171, 170,
57 169, 167, 163, 159, 155, 150, 144, 139,
58 133, 128, 122, 117, 113, 110, 107, 105,
59 103, 103, 103, 103, 104, 104, 105, 105,
60 105, 103, 101, 97, 92, 86, 78, 68,
61 58, 45, 32, 18, 3, -11, -26, -41,
62 -55, -68, -79, -88, -95, -100, -102, -102,
63 -99, -93, -85, -75, -62, -48, -33, -16,
64 0, 16, 33, 48, 62, 75, 85, 93,
65 99, 102, 102, 100, 95, 88, 79, 68,
66 55, 41, 26, 11, -3, -18, -32, -45,
67 -58, -68, -78, -86, -92, -97, -101, -103,
68 -105, -105, -105, -104, -104, -103, -103, -103,
69 -103, -105, -107, -110, -113, -117, -122, -128,
70 -133, -139, -144, -150, -155, -159, -163, -167,
71 -169, -170, -171, -171, -171, -169, -168, -166,
72 -164, -162, -161, -160, -159, -159, -160, -161,
73 -163, -166, -170, -174, -179, -183, -188, -193,
74 -197, -201, -204, -207, -209, -209, -209, -208,
75 -206, -203, -200, -196, -192, -189, -186, -183,
76 -182, -182, -183, -186, -190, -196, -204, -213,
77 -224, -236, -249, -262, -275, -288, -299, -310,
78 -318, -324, -327, -327, -323, -316, -304, -288,
79 -269, -245, -218, -187, -153, -117, -79, -40,
80};
81
82#define BEEP_SRATE 22050 /* 22050 Hz sample rate */
83#define BEEP_BUFLEN 512
84#define BEEP_VOLUME 15 /* 0 - 100 */
85
65b29f50
TI
86static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type,
87 unsigned int code, int hz)
1da177e4 88{
65b29f50
TI
89 struct snd_pmac *chip;
90 struct pmac_beep *beep;
1da177e4
LT
91 unsigned long flags;
92 int beep_speed = 0;
93 int srate;
94 int period, ncycles, nsamples;
95 int i, j, f;
96 short *p;
97
98 if (type != EV_SND)
99 return -1;
100
101 switch (code) {
a98478f8 102 case SND_BELL: if (hz) hz = 1000; break;
1da177e4
LT
103 case SND_TONE: break;
104 default: return -1;
105 }
106
1e2831db 107 chip = input_get_drvdata(dev);
e73ad388
TI
108 if (!chip)
109 return -1;
110 beep = chip->beep;
111 if (!beep)
1da177e4
LT
112 return -1;
113
114 if (! hz) {
115 spin_lock_irqsave(&chip->reg_lock, flags);
116 if (beep->running)
117 snd_pmac_beep_stop(chip);
118 spin_unlock_irqrestore(&chip->reg_lock, flags);
119 return 0;
120 }
121
122 beep_speed = snd_pmac_rate_index(chip, &chip->playback, BEEP_SRATE);
123 srate = chip->freq_table[beep_speed];
124
125 if (hz <= srate / BEEP_BUFLEN || hz > srate / 2)
126 hz = 1000;
127
128 spin_lock_irqsave(&chip->reg_lock, flags);
129 if (chip->playback.running || chip->capture.running || beep->running) {
130 spin_unlock_irqrestore(&chip->reg_lock, flags);
131 return 0;
132 }
133 beep->running = 1;
134 spin_unlock_irqrestore(&chip->reg_lock, flags);
135
136 if (hz == beep->hz && beep->volume == beep->volume_play) {
137 nsamples = beep->nsamples;
138 } else {
139 period = srate * 256 / hz; /* fixed point */
140 ncycles = BEEP_BUFLEN * 256 / period;
141 nsamples = (period * ncycles) >> 8;
142 f = ncycles * 65536 / nsamples;
143 j = 0;
144 p = beep->buf;
145 for (i = 0; i < nsamples; ++i, p += 2) {
146 p[0] = p[1] = beep_wform[j >> 8] * beep->volume;
147 j = (j + f) & 0xffff;
148 }
149 beep->hz = hz;
150 beep->volume_play = beep->volume;
151 beep->nsamples = nsamples;
152 }
153
154 spin_lock_irqsave(&chip->reg_lock, flags);
155 snd_pmac_beep_dma_start(chip, beep->nsamples * 4, beep->addr, beep_speed);
156 spin_unlock_irqrestore(&chip->reg_lock, flags);
157 return 0;
158}
159
160/*
161 * beep volume mixer
162 */
163
65b29f50
TI
164static int snd_pmac_info_beep(struct snd_kcontrol *kcontrol,
165 struct snd_ctl_elem_info *uinfo)
1da177e4
LT
166{
167 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
168 uinfo->count = 1;
169 uinfo->value.integer.min = 0;
170 uinfo->value.integer.max = 100;
171 return 0;
172}
173
65b29f50
TI
174static int snd_pmac_get_beep(struct snd_kcontrol *kcontrol,
175 struct snd_ctl_elem_value *ucontrol)
1da177e4 176{
65b29f50 177 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
5e246b85
TI
178 if (snd_BUG_ON(!chip->beep))
179 return -ENXIO;
1da177e4
LT
180 ucontrol->value.integer.value[0] = chip->beep->volume;
181 return 0;
182}
183
65b29f50
TI
184static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol,
185 struct snd_ctl_elem_value *ucontrol)
1da177e4 186{
65b29f50 187 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
d4079ac4 188 unsigned int oval, nval;
5e246b85
TI
189 if (snd_BUG_ON(!chip->beep))
190 return -ENXIO;
1da177e4 191 oval = chip->beep->volume;
d4079ac4
TI
192 nval = ucontrol->value.integer.value[0];
193 if (nval > 100)
194 return -EINVAL;
195 chip->beep->volume = nval;
1da177e4
LT
196 return oval != chip->beep->volume;
197}
198
905e46ac 199static const struct snd_kcontrol_new snd_pmac_beep_mixer = {
1da177e4
LT
200 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
201 .name = "Beep Playback Volume",
202 .info = snd_pmac_info_beep,
203 .get = snd_pmac_get_beep,
204 .put = snd_pmac_put_beep,
205};
206
207/* Initialize beep stuff */
15afafc2 208int snd_pmac_attach_beep(struct snd_pmac *chip)
1da177e4 209{
65b29f50 210 struct pmac_beep *beep;
5ebdcbc2 211 struct input_dev *input_dev;
f03d68fe 212 struct snd_kcontrol *beep_ctl;
5ebdcbc2
DT
213 void *dmabuf;
214 int err = -ENOMEM;
1da177e4 215
5ebdcbc2 216 beep = kzalloc(sizeof(*beep), GFP_KERNEL);
f03d68fe
DT
217 if (! beep)
218 return -ENOMEM;
5ebdcbc2
DT
219 dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
220 &beep->addr, GFP_KERNEL);
221 input_dev = input_allocate_device();
f03d68fe
DT
222 if (! dmabuf || ! input_dev)
223 goto fail1;
1da177e4
LT
224
225 /* FIXME: set more better values */
5ebdcbc2
DT
226 input_dev->name = "PowerMac Beep";
227 input_dev->phys = "powermac/beep";
228 input_dev->id.bustype = BUS_ADB;
229 input_dev->id.vendor = 0x001f;
230 input_dev->id.product = 0x0001;
231 input_dev->id.version = 0x0100;
232
7b19ada2
JS
233 input_dev->evbit[0] = BIT_MASK(EV_SND);
234 input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
5ebdcbc2 235 input_dev->event = snd_pmac_beep_event;
1e2831db
DT
236 input_dev->dev.parent = &chip->pdev->dev;
237 input_set_drvdata(input_dev, chip);
1da177e4 238
5ebdcbc2
DT
239 beep->dev = input_dev;
240 beep->buf = dmabuf;
1da177e4
LT
241 beep->volume = BEEP_VOLUME;
242 beep->running = 0;
5ebdcbc2 243
f03d68fe
DT
244 beep_ctl = snd_ctl_new1(&snd_pmac_beep_mixer, chip);
245 err = snd_ctl_add(chip->card, beep_ctl);
5ebdcbc2 246 if (err < 0)
f03d68fe 247 goto fail1;
1e2831db
DT
248
249 chip->beep = beep;
1da177e4 250
f03d68fe
DT
251 err = input_register_device(beep->dev);
252 if (err)
253 goto fail2;
254
255 return 0;
256
257 fail2: snd_ctl_remove(chip->card, beep_ctl);
258 fail1: input_free_device(input_dev);
259 if (dmabuf)
260 dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
261 dmabuf, beep->addr);
5ebdcbc2
DT
262 kfree(beep);
263 return err;
1da177e4
LT
264}
265
65b29f50 266void snd_pmac_detach_beep(struct snd_pmac *chip)
1da177e4
LT
267{
268 if (chip->beep) {
5ebdcbc2 269 input_unregister_device(chip->beep->dev);
7bbd8277
BH
270 dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
271 chip->beep->buf, chip->beep->addr);
1da177e4
LT
272 kfree(chip->beep);
273 chip->beep = NULL;
274 }
275}