[PATCH] proper prototype for tosh_smm()
[linux-2.6] / sound / ppc / beep.c
1 /*
2  * Beep using pcm
3  *
4  * Copyright (c) by Takashi Iwai <tiwai@suse.de>
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19  */
20
21 #include <sound/driver.h>
22 #include <asm/io.h>
23 #include <asm/irq.h>
24 #include <linux/init.h>
25 #include <linux/slab.h>
26 #include <linux/input.h>
27 #include <linux/pci.h>
28 #include <linux/dma-mapping.h>
29 #include <sound/core.h>
30 #include <sound/control.h>
31 #include "pmac.h"
32
33 struct pmac_beep {
34         int running;            /* boolean */
35         int volume;             /* mixer volume: 0-100 */
36         int volume_play;        /* currently playing volume */
37         int hz;
38         int nsamples;
39         short *buf;             /* allocated wave buffer */
40         dma_addr_t addr;        /* physical address of buffer */
41         struct input_dev *dev;
42 };
43
44 /*
45  * stop beep if running
46  */
47 void snd_pmac_beep_stop(struct snd_pmac *chip)
48 {
49         struct pmac_beep *beep = chip->beep;
50         if (beep && beep->running) {
51                 beep->running = 0;
52                 snd_pmac_beep_dma_stop(chip);
53         }
54 }
55
56 /*
57  * Stuff for outputting a beep.  The values range from -327 to +327
58  * so we can multiply by an amplitude in the range 0..100 to get a
59  * signed short value to put in the output buffer.
60  */
61 static short beep_wform[256] = {
62         0,      40,     79,     117,    153,    187,    218,    245,
63         269,    288,    304,    316,    323,    327,    327,    324,
64         318,    310,    299,    288,    275,    262,    249,    236,
65         224,    213,    204,    196,    190,    186,    183,    182,
66         182,    183,    186,    189,    192,    196,    200,    203,
67         206,    208,    209,    209,    209,    207,    204,    201,
68         197,    193,    188,    183,    179,    174,    170,    166,
69         163,    161,    160,    159,    159,    160,    161,    162,
70         164,    166,    168,    169,    171,    171,    171,    170,
71         169,    167,    163,    159,    155,    150,    144,    139,
72         133,    128,    122,    117,    113,    110,    107,    105,
73         103,    103,    103,    103,    104,    104,    105,    105,
74         105,    103,    101,    97,     92,     86,     78,     68,
75         58,     45,     32,     18,     3,      -11,    -26,    -41,
76         -55,    -68,    -79,    -88,    -95,    -100,   -102,   -102,
77         -99,    -93,    -85,    -75,    -62,    -48,    -33,    -16,
78         0,      16,     33,     48,     62,     75,     85,     93,
79         99,     102,    102,    100,    95,     88,     79,     68,
80         55,     41,     26,     11,     -3,     -18,    -32,    -45,
81         -58,    -68,    -78,    -86,    -92,    -97,    -101,   -103,
82         -105,   -105,   -105,   -104,   -104,   -103,   -103,   -103,
83         -103,   -105,   -107,   -110,   -113,   -117,   -122,   -128,
84         -133,   -139,   -144,   -150,   -155,   -159,   -163,   -167,
85         -169,   -170,   -171,   -171,   -171,   -169,   -168,   -166,
86         -164,   -162,   -161,   -160,   -159,   -159,   -160,   -161,
87         -163,   -166,   -170,   -174,   -179,   -183,   -188,   -193,
88         -197,   -201,   -204,   -207,   -209,   -209,   -209,   -208,
89         -206,   -203,   -200,   -196,   -192,   -189,   -186,   -183,
90         -182,   -182,   -183,   -186,   -190,   -196,   -204,   -213,
91         -224,   -236,   -249,   -262,   -275,   -288,   -299,   -310,
92         -318,   -324,   -327,   -327,   -323,   -316,   -304,   -288,
93         -269,   -245,   -218,   -187,   -153,   -117,   -79,    -40,
94 };
95
96 #define BEEP_SRATE      22050   /* 22050 Hz sample rate */
97 #define BEEP_BUFLEN     512
98 #define BEEP_VOLUME     15      /* 0 - 100 */
99
100 static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type,
101                                unsigned int code, int hz)
102 {
103         struct snd_pmac *chip;
104         struct pmac_beep *beep;
105         unsigned long flags;
106         int beep_speed = 0;
107         int srate;
108         int period, ncycles, nsamples;
109         int i, j, f;
110         short *p;
111
112         if (type != EV_SND)
113                 return -1;
114
115         switch (code) {
116         case SND_BELL: if (hz) hz = 1000;
117         case SND_TONE: break;
118         default: return -1;
119         }
120
121         chip = dev->private;
122         if (! chip || (beep = chip->beep) == NULL)
123                 return -1;
124
125         if (! hz) {
126                 spin_lock_irqsave(&chip->reg_lock, flags);
127                 if (beep->running)
128                         snd_pmac_beep_stop(chip);
129                 spin_unlock_irqrestore(&chip->reg_lock, flags);
130                 return 0;
131         }
132
133         beep_speed = snd_pmac_rate_index(chip, &chip->playback, BEEP_SRATE);
134         srate = chip->freq_table[beep_speed];
135
136         if (hz <= srate / BEEP_BUFLEN || hz > srate / 2)
137                 hz = 1000;
138
139         spin_lock_irqsave(&chip->reg_lock, flags);
140         if (chip->playback.running || chip->capture.running || beep->running) {
141                 spin_unlock_irqrestore(&chip->reg_lock, flags);
142                 return 0;
143         }
144         beep->running = 1;
145         spin_unlock_irqrestore(&chip->reg_lock, flags);
146
147         if (hz == beep->hz && beep->volume == beep->volume_play) {
148                 nsamples = beep->nsamples;
149         } else {
150                 period = srate * 256 / hz;      /* fixed point */
151                 ncycles = BEEP_BUFLEN * 256 / period;
152                 nsamples = (period * ncycles) >> 8;
153                 f = ncycles * 65536 / nsamples;
154                 j = 0;
155                 p = beep->buf;
156                 for (i = 0; i < nsamples; ++i, p += 2) {
157                         p[0] = p[1] = beep_wform[j >> 8] * beep->volume;
158                         j = (j + f) & 0xffff;
159                 }
160                 beep->hz = hz;
161                 beep->volume_play = beep->volume;
162                 beep->nsamples = nsamples;
163         }
164
165         spin_lock_irqsave(&chip->reg_lock, flags);
166         snd_pmac_beep_dma_start(chip, beep->nsamples * 4, beep->addr, beep_speed);
167         spin_unlock_irqrestore(&chip->reg_lock, flags);
168         return 0;
169 }
170
171 /*
172  * beep volume mixer
173  */
174
175 static int snd_pmac_info_beep(struct snd_kcontrol *kcontrol,
176                               struct snd_ctl_elem_info *uinfo)
177 {
178         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
179         uinfo->count = 1;
180         uinfo->value.integer.min = 0;
181         uinfo->value.integer.max = 100;
182         return 0;
183 }
184
185 static int snd_pmac_get_beep(struct snd_kcontrol *kcontrol,
186                              struct snd_ctl_elem_value *ucontrol)
187 {
188         struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
189         snd_assert(chip->beep, return -ENXIO);
190         ucontrol->value.integer.value[0] = chip->beep->volume;
191         return 0;
192 }
193
194 static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol,
195                              struct snd_ctl_elem_value *ucontrol)
196 {
197         struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
198         int oval;
199         snd_assert(chip->beep, return -ENXIO);
200         oval = chip->beep->volume;
201         chip->beep->volume = ucontrol->value.integer.value[0];
202         return oval != chip->beep->volume;
203 }
204
205 static struct snd_kcontrol_new snd_pmac_beep_mixer = {
206         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
207         .name = "Beep Playback Volume",
208         .info = snd_pmac_info_beep,
209         .get = snd_pmac_get_beep,
210         .put = snd_pmac_put_beep,
211 };
212
213 /* Initialize beep stuff */
214 int __init snd_pmac_attach_beep(struct snd_pmac *chip)
215 {
216         struct pmac_beep *beep;
217         struct input_dev *input_dev;
218         struct snd_kcontrol *beep_ctl;
219         void *dmabuf;
220         int err = -ENOMEM;
221
222         beep = kzalloc(sizeof(*beep), GFP_KERNEL);
223         if (! beep)
224                 return -ENOMEM;
225         dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
226                                     &beep->addr, GFP_KERNEL);
227         input_dev = input_allocate_device();
228         if (! dmabuf || ! input_dev)
229                 goto fail1;
230
231         /* FIXME: set more better values */
232         input_dev->name = "PowerMac Beep";
233         input_dev->phys = "powermac/beep";
234         input_dev->id.bustype = BUS_ADB;
235         input_dev->id.vendor = 0x001f;
236         input_dev->id.product = 0x0001;
237         input_dev->id.version = 0x0100;
238
239         input_dev->evbit[0] = BIT(EV_SND);
240         input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
241         input_dev->event = snd_pmac_beep_event;
242         input_dev->private = chip;
243         input_dev->cdev.dev = &chip->pdev->dev;
244
245         beep->dev = input_dev;
246         beep->buf = dmabuf;
247         beep->volume = BEEP_VOLUME;
248         beep->running = 0;
249
250         beep_ctl = snd_ctl_new1(&snd_pmac_beep_mixer, chip);
251         err = snd_ctl_add(chip->card, beep_ctl);
252         if (err < 0)
253                 goto fail1;
254  
255         chip->beep = beep;
256
257         err = input_register_device(beep->dev);
258         if (err)
259                 goto fail2;
260  
261         return 0;
262  
263  fail2: snd_ctl_remove(chip->card, beep_ctl);
264  fail1: input_free_device(input_dev);
265         if (dmabuf)
266                 dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
267                                   dmabuf, beep->addr);
268         kfree(beep);
269         return err;
270 }
271
272 void snd_pmac_detach_beep(struct snd_pmac *chip)
273 {
274         if (chip->beep) {
275                 input_unregister_device(chip->beep->dev);
276                 dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
277                                   chip->beep->buf, chip->beep->addr);
278                 kfree(chip->beep);
279                 chip->beep = NULL;
280         }
281 }