Blame view

sound/ppc/beep.c 7.08 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
  /*
   * Beep using pcm
   *
   * Copyright (c) by Takashi Iwai <tiwai@suse.de>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
   */
6cbbfe1c8   Takashi Iwai   ALSA: Include lin...
7
  #include <linux/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
  #include <asm/irq.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/input.h>
7bbd82775   Benjamin Herrenschmidt   [PATCH] ppc64: ve...
12
13
  #include <linux/pci.h>
  #include <linux/dma-mapping.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
  #include <sound/core.h>
  #include <sound/control.h>
  #include "pmac.h"
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
17
  struct pmac_beep {
5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
18
19
  	int running;		/* boolean */
  	int volume;		/* mixer volume: 0-100 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
  	int volume_play;	/* currently playing volume */
  	int hz;
  	int nsamples;
  	short *buf;		/* allocated wave buffer */
7bbd82775   Benjamin Herrenschmidt   [PATCH] ppc64: ve...
24
  	dma_addr_t addr;	/* physical address of buffer */
5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
25
  	struct input_dev *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
30
  };
  
  /*
   * stop beep if running
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
31
  void snd_pmac_beep_stop(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
33
  	struct pmac_beep *beep = chip->beep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
40
41
42
43
44
  	if (beep && beep->running) {
  		beep->running = 0;
  		snd_pmac_beep_dma_stop(chip);
  	}
  }
  
  /*
   * Stuff for outputting a beep.  The values range from -327 to +327
   * so we can multiply by an amplitude in the range 0..100 to get a
   * signed short value to put in the output buffer.
   */
6e9ef32fa   Takashi Iwai   ALSA: ppc: More c...
45
  static const short beep_wform[256] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  	0,	40,	79,	117,	153,	187,	218,	245,
  	269,	288,	304,	316,	323,	327,	327,	324,
  	318,	310,	299,	288,	275,	262,	249,	236,
  	224,	213,	204,	196,	190,	186,	183,	182,
  	182,	183,	186,	189,	192,	196,	200,	203,
  	206,	208,	209,	209,	209,	207,	204,	201,
  	197,	193,	188,	183,	179,	174,	170,	166,
  	163,	161,	160,	159,	159,	160,	161,	162,
  	164,	166,	168,	169,	171,	171,	171,	170,
  	169,	167,	163,	159,	155,	150,	144,	139,
  	133,	128,	122,	117,	113,	110,	107,	105,
  	103,	103,	103,	103,	104,	104,	105,	105,
  	105,	103,	101,	97,	92,	86,	78,	68,
  	58,	45,	32,	18,	3,	-11,	-26,	-41,
  	-55,	-68,	-79,	-88,	-95,	-100,	-102,	-102,
  	-99,	-93,	-85,	-75,	-62,	-48,	-33,	-16,
  	0,	16,	33,	48,	62,	75,	85,	93,
  	99,	102,	102,	100,	95,	88,	79,	68,
  	55,	41,	26,	11,	-3,	-18,	-32,	-45,
  	-58,	-68,	-78,	-86,	-92,	-97,	-101,	-103,
  	-105,	-105,	-105,	-104,	-104,	-103,	-103,	-103,
  	-103,	-105,	-107,	-110,	-113,	-117,	-122,	-128,
  	-133,	-139,	-144,	-150,	-155,	-159,	-163,	-167,
  	-169,	-170,	-171,	-171,	-171,	-169,	-168,	-166,
  	-164,	-162,	-161,	-160,	-159,	-159,	-160,	-161,
  	-163,	-166,	-170,	-174,	-179,	-183,	-188,	-193,
  	-197,	-201,	-204,	-207,	-209,	-209,	-209,	-208,
  	-206,	-203,	-200,	-196,	-192,	-189,	-186,	-183,
  	-182,	-182,	-183,	-186,	-190,	-196,	-204,	-213,
  	-224,	-236,	-249,	-262,	-275,	-288,	-299,	-310,
  	-318,	-324,	-327,	-327,	-323,	-316,	-304,	-288,
  	-269,	-245,	-218,	-187,	-153,	-117,	-79,	-40,
  };
  
  #define BEEP_SRATE	22050	/* 22050 Hz sample rate */
  #define BEEP_BUFLEN	512
  #define BEEP_VOLUME	15	/* 0 - 100 */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
83
84
  static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type,
  			       unsigned int code, int hz)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
86
87
  	struct snd_pmac *chip;
  	struct pmac_beep *beep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  	unsigned long flags;
  	int beep_speed = 0;
  	int srate;
  	int period, ncycles, nsamples;
  	int i, j, f;
  	short *p;
  
  	if (type != EV_SND)
  		return -1;
  
  	switch (code) {
  	case SND_BELL: if (hz) hz = 1000;
  	case SND_TONE: break;
  	default: return -1;
  	}
1e2831db0   Dmitry Torokhov   Input: ppc-beep -...
103
  	chip = input_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  	if (! chip || (beep = chip->beep) == NULL)
  		return -1;
  
  	if (! hz) {
  		spin_lock_irqsave(&chip->reg_lock, flags);
  		if (beep->running)
  			snd_pmac_beep_stop(chip);
  		spin_unlock_irqrestore(&chip->reg_lock, flags);
  		return 0;
  	}
  
  	beep_speed = snd_pmac_rate_index(chip, &chip->playback, BEEP_SRATE);
  	srate = chip->freq_table[beep_speed];
  
  	if (hz <= srate / BEEP_BUFLEN || hz > srate / 2)
  		hz = 1000;
  
  	spin_lock_irqsave(&chip->reg_lock, flags);
  	if (chip->playback.running || chip->capture.running || beep->running) {
  		spin_unlock_irqrestore(&chip->reg_lock, flags);
  		return 0;
  	}
  	beep->running = 1;
  	spin_unlock_irqrestore(&chip->reg_lock, flags);
  
  	if (hz == beep->hz && beep->volume == beep->volume_play) {
  		nsamples = beep->nsamples;
  	} else {
  		period = srate * 256 / hz;	/* fixed point */
  		ncycles = BEEP_BUFLEN * 256 / period;
  		nsamples = (period * ncycles) >> 8;
  		f = ncycles * 65536 / nsamples;
  		j = 0;
  		p = beep->buf;
  		for (i = 0; i < nsamples; ++i, p += 2) {
  			p[0] = p[1] = beep_wform[j >> 8] * beep->volume;
  			j = (j + f) & 0xffff;
  		}
  		beep->hz = hz;
  		beep->volume_play = beep->volume;
  		beep->nsamples = nsamples;
  	}
  
  	spin_lock_irqsave(&chip->reg_lock, flags);
  	snd_pmac_beep_dma_start(chip, beep->nsamples * 4, beep->addr, beep_speed);
  	spin_unlock_irqrestore(&chip->reg_lock, flags);
  	return 0;
  }
  
  /*
   * beep volume mixer
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
156
157
  static int snd_pmac_info_beep(struct snd_kcontrol *kcontrol,
  			      struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
160
161
162
163
164
  {
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 1;
  	uinfo->value.integer.min = 0;
  	uinfo->value.integer.max = 100;
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
165
166
  static int snd_pmac_get_beep(struct snd_kcontrol *kcontrol,
  			     struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
168
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
169
170
  	if (snd_BUG_ON(!chip->beep))
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
  	ucontrol->value.integer.value[0] = chip->beep->volume;
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
174
175
  static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol,
  			     struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
177
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
d4079ac49   Takashi Iwai   [ALSA] powermac -...
178
  	unsigned int oval, nval;
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
179
180
  	if (snd_BUG_ON(!chip->beep))
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  	oval = chip->beep->volume;
d4079ac49   Takashi Iwai   [ALSA] powermac -...
182
183
184
185
  	nval = ucontrol->value.integer.value[0];
  	if (nval > 100)
  		return -EINVAL;
  	chip->beep->volume = nval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
  	return oval != chip->beep->volume;
  }
905e46acd   Bhumika Goyal   ALSA: declare snd...
188
  static const struct snd_kcontrol_new snd_pmac_beep_mixer = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
194
195
196
  	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	.name = "Beep Playback Volume",
  	.info = snd_pmac_info_beep,
  	.get = snd_pmac_get_beep,
  	.put = snd_pmac_put_beep,
  };
  
  /* Initialize beep stuff */
15afafc25   Bill Pemberton   ALSA: ppc: remove...
197
  int snd_pmac_attach_beep(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
199
  	struct pmac_beep *beep;
5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
200
  	struct input_dev *input_dev;
f03d68fe3   Dmitry Torokhov   [ALSA] ppc-beep -...
201
  	struct snd_kcontrol *beep_ctl;
5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
202
203
  	void *dmabuf;
  	int err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204

5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
205
  	beep = kzalloc(sizeof(*beep), GFP_KERNEL);
f03d68fe3   Dmitry Torokhov   [ALSA] ppc-beep -...
206
207
  	if (! beep)
  		return -ENOMEM;
5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
208
209
210
  	dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
  				    &beep->addr, GFP_KERNEL);
  	input_dev = input_allocate_device();
f03d68fe3   Dmitry Torokhov   [ALSA] ppc-beep -...
211
212
  	if (! dmabuf || ! input_dev)
  		goto fail1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
  
  	/* FIXME: set more better values */
5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
215
216
217
218
219
220
  	input_dev->name = "PowerMac Beep";
  	input_dev->phys = "powermac/beep";
  	input_dev->id.bustype = BUS_ADB;
  	input_dev->id.vendor = 0x001f;
  	input_dev->id.product = 0x0001;
  	input_dev->id.version = 0x0100;
7b19ada2e   Jiri Slaby   get rid of input ...
221
222
  	input_dev->evbit[0] = BIT_MASK(EV_SND);
  	input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
223
  	input_dev->event = snd_pmac_beep_event;
1e2831db0   Dmitry Torokhov   Input: ppc-beep -...
224
225
  	input_dev->dev.parent = &chip->pdev->dev;
  	input_set_drvdata(input_dev, chip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226

5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
227
228
  	beep->dev = input_dev;
  	beep->buf = dmabuf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
  	beep->volume = BEEP_VOLUME;
  	beep->running = 0;
5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
231

f03d68fe3   Dmitry Torokhov   [ALSA] ppc-beep -...
232
233
  	beep_ctl = snd_ctl_new1(&snd_pmac_beep_mixer, chip);
  	err = snd_ctl_add(chip->card, beep_ctl);
5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
234
  	if (err < 0)
f03d68fe3   Dmitry Torokhov   [ALSA] ppc-beep -...
235
  		goto fail1;
1e2831db0   Dmitry Torokhov   Input: ppc-beep -...
236
237
  
  	chip->beep = beep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238

f03d68fe3   Dmitry Torokhov   [ALSA] ppc-beep -...
239
240
241
242
243
244
245
246
247
248
249
  	err = input_register_device(beep->dev);
  	if (err)
  		goto fail2;
   
   	return 0;
   
   fail2:	snd_ctl_remove(chip->card, beep_ctl);
   fail1:	input_free_device(input_dev);
  	if (dmabuf)
  		dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
  				  dmabuf, beep->addr);
5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
250
251
  	kfree(beep);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
253
  void snd_pmac_detach_beep(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
  {
  	if (chip->beep) {
5ebdcbc2f   Dmitry Torokhov   [PATCH] Input: co...
256
  		input_unregister_device(chip->beep->dev);
7bbd82775   Benjamin Herrenschmidt   [PATCH] ppc64: ve...
257
258
  		dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
  				  chip->beep->buf, chip->beep->addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
261
262
  		kfree(chip->beep);
  		chip->beep = NULL;
  	}
  }