Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/ppc/beep.c
29266 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Beep using pcm
4
*
5
* Copyright (c) by Takashi Iwai <[email protected]>
6
*/
7
8
#include <linux/io.h>
9
#include <asm/irq.h>
10
#include <linux/init.h>
11
#include <linux/slab.h>
12
#include <linux/input.h>
13
#include <linux/pci.h>
14
#include <linux/dma-mapping.h>
15
#include <sound/core.h>
16
#include <sound/control.h>
17
#include "pmac.h"
18
19
struct pmac_beep {
20
int running; /* boolean */
21
int volume; /* mixer volume: 0-100 */
22
int volume_play; /* currently playing volume */
23
int hz;
24
int nsamples;
25
short *buf; /* allocated wave buffer */
26
dma_addr_t addr; /* physical address of buffer */
27
struct input_dev *dev;
28
};
29
30
/*
31
* stop beep if running
32
*/
33
void snd_pmac_beep_stop(struct snd_pmac *chip)
34
{
35
struct pmac_beep *beep = chip->beep;
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
*/
47
static const short beep_wform[256] = {
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
86
static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type,
87
unsigned int code, int hz)
88
{
89
struct snd_pmac *chip;
90
struct pmac_beep *beep;
91
int beep_speed = 0;
92
int srate;
93
int period, ncycles, nsamples;
94
int i, j, f;
95
short *p;
96
97
if (type != EV_SND)
98
return -1;
99
100
switch (code) {
101
case SND_BELL: if (hz) hz = 1000; break;
102
case SND_TONE: break;
103
default: return -1;
104
}
105
106
chip = input_get_drvdata(dev);
107
if (!chip)
108
return -1;
109
beep = chip->beep;
110
if (!beep)
111
return -1;
112
113
if (! hz) {
114
guard(spinlock_irqsave)(&chip->reg_lock);
115
if (beep->running)
116
snd_pmac_beep_stop(chip);
117
return 0;
118
}
119
120
beep_speed = snd_pmac_rate_index(chip, &chip->playback, BEEP_SRATE);
121
srate = chip->freq_table[beep_speed];
122
123
if (hz <= srate / BEEP_BUFLEN || hz > srate / 2)
124
hz = 1000;
125
126
scoped_guard(spinlock_irqsave, &chip->reg_lock) {
127
if (chip->playback.running || chip->capture.running || beep->running)
128
return 0;
129
beep->running = 1;
130
}
131
132
if (hz == beep->hz && beep->volume == beep->volume_play) {
133
nsamples = beep->nsamples;
134
} else {
135
period = srate * 256 / hz; /* fixed point */
136
ncycles = BEEP_BUFLEN * 256 / period;
137
nsamples = (period * ncycles) >> 8;
138
f = ncycles * 65536 / nsamples;
139
j = 0;
140
p = beep->buf;
141
for (i = 0; i < nsamples; ++i, p += 2) {
142
p[0] = p[1] = beep_wform[j >> 8] * beep->volume;
143
j = (j + f) & 0xffff;
144
}
145
beep->hz = hz;
146
beep->volume_play = beep->volume;
147
beep->nsamples = nsamples;
148
}
149
150
guard(spinlock_irqsave)(&chip->reg_lock);
151
snd_pmac_beep_dma_start(chip, beep->nsamples * 4, beep->addr, beep_speed);
152
return 0;
153
}
154
155
/*
156
* beep volume mixer
157
*/
158
159
static int snd_pmac_info_beep(struct snd_kcontrol *kcontrol,
160
struct snd_ctl_elem_info *uinfo)
161
{
162
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
163
uinfo->count = 1;
164
uinfo->value.integer.min = 0;
165
uinfo->value.integer.max = 100;
166
return 0;
167
}
168
169
static int snd_pmac_get_beep(struct snd_kcontrol *kcontrol,
170
struct snd_ctl_elem_value *ucontrol)
171
{
172
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
173
if (snd_BUG_ON(!chip->beep))
174
return -ENXIO;
175
ucontrol->value.integer.value[0] = chip->beep->volume;
176
return 0;
177
}
178
179
static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol,
180
struct snd_ctl_elem_value *ucontrol)
181
{
182
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
183
unsigned int oval, nval;
184
if (snd_BUG_ON(!chip->beep))
185
return -ENXIO;
186
oval = chip->beep->volume;
187
nval = ucontrol->value.integer.value[0];
188
if (nval > 100)
189
return -EINVAL;
190
chip->beep->volume = nval;
191
return oval != chip->beep->volume;
192
}
193
194
static const struct snd_kcontrol_new snd_pmac_beep_mixer = {
195
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
196
.name = "Beep Playback Volume",
197
.info = snd_pmac_info_beep,
198
.get = snd_pmac_get_beep,
199
.put = snd_pmac_put_beep,
200
};
201
202
/* Initialize beep stuff */
203
int snd_pmac_attach_beep(struct snd_pmac *chip)
204
{
205
struct pmac_beep *beep;
206
struct input_dev *input_dev;
207
struct snd_kcontrol *beep_ctl;
208
void *dmabuf;
209
int err = -ENOMEM;
210
211
beep = kzalloc(sizeof(*beep), GFP_KERNEL);
212
if (! beep)
213
return -ENOMEM;
214
dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
215
&beep->addr, GFP_KERNEL);
216
input_dev = input_allocate_device();
217
if (! dmabuf || ! input_dev)
218
goto fail1;
219
220
/* FIXME: set more better values */
221
input_dev->name = "PowerMac Beep";
222
input_dev->phys = "powermac/beep";
223
input_dev->id.bustype = BUS_ADB;
224
input_dev->id.vendor = 0x001f;
225
input_dev->id.product = 0x0001;
226
input_dev->id.version = 0x0100;
227
228
input_dev->evbit[0] = BIT_MASK(EV_SND);
229
input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
230
input_dev->event = snd_pmac_beep_event;
231
input_dev->dev.parent = &chip->pdev->dev;
232
input_set_drvdata(input_dev, chip);
233
234
beep->dev = input_dev;
235
beep->buf = dmabuf;
236
beep->volume = BEEP_VOLUME;
237
beep->running = 0;
238
239
beep_ctl = snd_ctl_new1(&snd_pmac_beep_mixer, chip);
240
err = snd_ctl_add(chip->card, beep_ctl);
241
if (err < 0)
242
goto fail1;
243
244
chip->beep = beep;
245
246
err = input_register_device(beep->dev);
247
if (err)
248
goto fail2;
249
250
return 0;
251
252
fail2: snd_ctl_remove(chip->card, beep_ctl);
253
fail1: input_free_device(input_dev);
254
if (dmabuf)
255
dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
256
dmabuf, beep->addr);
257
kfree(beep);
258
return err;
259
}
260
261
void snd_pmac_detach_beep(struct snd_pmac *chip)
262
{
263
if (chip->beep) {
264
input_unregister_device(chip->beep->dev);
265
dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
266
chip->beep->buf, chip->beep->addr);
267
kfree(chip->beep);
268
chip->beep = NULL;
269
}
270
}
271
272