Merge tag 'docs-5.6-2' of git://git.lwn.net/linux
[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) {
102 case SND_BELL: if (hz) hz = 1000;
103 case SND_TONE: break;
104 default: return -1;
105 }
106
1e2831db 107 chip = input_get_drvdata(dev);
1da177e4
LT
108 if (! chip || (beep = chip->beep) == NULL)
109 return -1;
110
111 if (! hz) {
112 spin_lock_irqsave(&chip->reg_lock, flags);
113 if (beep->running)
114 snd_pmac_beep_stop(chip);
115 spin_unlock_irqrestore(&chip->reg_lock, flags);
116 return 0;
117 }
118
119 beep_speed = snd_pmac_rate_index(chip, &chip->playback, BEEP_SRATE);
120 srate = chip->freq_table[beep_speed];
121
122 if (hz <= srate / BEEP_BUFLEN || hz > srate / 2)
123 hz = 1000;
124
125 spin_lock_irqsave(&chip->reg_lock, flags);
126 if (chip->playback.running || chip->capture.running || beep->running) {
127 spin_unlock_irqrestore(&chip->reg_lock, flags);
128 return 0;
129 }
130 beep->running = 1;
131 spin_unlock_irqrestore(&chip->reg_lock, flags);
132
133 if (hz == beep->hz && beep->volume == beep->volume_play) {
134 nsamples = beep->nsamples;
135 } else {
136 period = srate * 256 / hz; /* fixed point */
137 ncycles = BEEP_BUFLEN * 256 / period;
138 nsamples = (period * ncycles) >> 8;
139 f = ncycles * 65536 / nsamples;
140 j = 0;
141 p = beep->buf;
142 for (i = 0; i < nsamples; ++i, p += 2) {
143 p[0] = p[1] = beep_wform[j >> 8] * beep->volume;
144 j = (j + f) & 0xffff;
145 }
146 beep->hz = hz;
147 beep->volume_play = beep->volume;
148 beep->nsamples = nsamples;
149 }
150
151 spin_lock_irqsave(&chip->reg_lock, flags);
152 snd_pmac_beep_dma_start(chip, beep->nsamples * 4, beep->addr, beep_speed);
153 spin_unlock_irqrestore(&chip->reg_lock, flags);
154 return 0;
155}
156
157/*
158 * beep volume mixer
159 */
160
65b29f50
TI
161static int snd_pmac_info_beep(struct snd_kcontrol *kcontrol,
162 struct snd_ctl_elem_info *uinfo)
1da177e4
LT
163{
164 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
165 uinfo->count = 1;
166 uinfo->value.integer.min = 0;
167 uinfo->value.integer.max = 100;
168 return 0;
169}
170
65b29f50
TI
171static int snd_pmac_get_beep(struct snd_kcontrol *kcontrol,
172 struct snd_ctl_elem_value *ucontrol)
1da177e4 173{
65b29f50 174 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
5e246b85
TI
175 if (snd_BUG_ON(!chip->beep))
176 return -ENXIO;
1da177e4
LT
177 ucontrol->value.integer.value[0] = chip->beep->volume;
178 return 0;
179}
180
65b29f50
TI
181static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol,
182 struct snd_ctl_elem_value *ucontrol)
1da177e4 183{
65b29f50 184 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
d4079ac4 185 unsigned int oval, nval;
5e246b85
TI
186 if (snd_BUG_ON(!chip->beep))
187 return -ENXIO;
1da177e4 188 oval = chip->beep->volume;
d4079ac4
TI
189 nval = ucontrol->value.integer.value[0];
190 if (nval > 100)
191 return -EINVAL;
192 chip->beep->volume = nval;
1da177e4
LT
193 return oval != chip->beep->volume;
194}
195
905e46ac 196static const struct snd_kcontrol_new snd_pmac_beep_mixer = {
1da177e4
LT
197 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
198 .name = "Beep Playback Volume",
199 .info = snd_pmac_info_beep,
200 .get = snd_pmac_get_beep,
201 .put = snd_pmac_put_beep,
202};
203
204/* Initialize beep stuff */
15afafc2 205int snd_pmac_attach_beep(struct snd_pmac *chip)
1da177e4 206{
65b29f50 207 struct pmac_beep *beep;
5ebdcbc2 208 struct input_dev *input_dev;
f03d68fe 209 struct snd_kcontrol *beep_ctl;
5ebdcbc2
DT
210 void *dmabuf;
211 int err = -ENOMEM;
1da177e4 212
5ebdcbc2 213 beep = kzalloc(sizeof(*beep), GFP_KERNEL);
f03d68fe
DT
214 if (! beep)
215 return -ENOMEM;
5ebdcbc2
DT
216 dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
217 &beep->addr, GFP_KERNEL);
218 input_dev = input_allocate_device();
f03d68fe
DT
219 if (! dmabuf || ! input_dev)
220 goto fail1;
1da177e4
LT
221
222 /* FIXME: set more better values */
5ebdcbc2
DT
223 input_dev->name = "PowerMac Beep";
224 input_dev->phys = "powermac/beep";
225 input_dev->id.bustype = BUS_ADB;
226 input_dev->id.vendor = 0x001f;
227 input_dev->id.product = 0x0001;
228 input_dev->id.version = 0x0100;
229
7b19ada2
JS
230 input_dev->evbit[0] = BIT_MASK(EV_SND);
231 input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
5ebdcbc2 232 input_dev->event = snd_pmac_beep_event;
1e2831db
DT
233 input_dev->dev.parent = &chip->pdev->dev;
234 input_set_drvdata(input_dev, chip);
1da177e4 235
5ebdcbc2
DT
236 beep->dev = input_dev;
237 beep->buf = dmabuf;
1da177e4
LT
238 beep->volume = BEEP_VOLUME;
239 beep->running = 0;
5ebdcbc2 240
f03d68fe
DT
241 beep_ctl = snd_ctl_new1(&snd_pmac_beep_mixer, chip);
242 err = snd_ctl_add(chip->card, beep_ctl);
5ebdcbc2 243 if (err < 0)
f03d68fe 244 goto fail1;
1e2831db
DT
245
246 chip->beep = beep;
1da177e4 247
f03d68fe
DT
248 err = input_register_device(beep->dev);
249 if (err)
250 goto fail2;
251
252 return 0;
253
254 fail2: snd_ctl_remove(chip->card, beep_ctl);
255 fail1: input_free_device(input_dev);
256 if (dmabuf)
257 dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
258 dmabuf, beep->addr);
5ebdcbc2
DT
259 kfree(beep);
260 return err;
1da177e4
LT
261}
262
65b29f50 263void snd_pmac_detach_beep(struct snd_pmac *chip)
1da177e4
LT
264{
265 if (chip->beep) {
5ebdcbc2 266 input_unregister_device(chip->beep->dev);
7bbd8277
BH
267 dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
268 chip->beep->buf, chip->beep->addr);
1da177e4
LT
269 kfree(chip->beep);
270 chip->beep = NULL;
271 }
272}