~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/ppc/beep.c

Version: ~ [ linux-5.12 ] ~ [ linux-5.11.16 ] ~ [ linux-5.10.32 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.114 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.188 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.231 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.267 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.267 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * Beep using pcm
  4  *
  5  * Copyright (c) by Takashi Iwai <tiwai@suse.de>
  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         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 
107         chip = input_get_drvdata(dev);
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 
161 static int snd_pmac_info_beep(struct snd_kcontrol *kcontrol,
162                               struct snd_ctl_elem_info *uinfo)
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 
171 static int snd_pmac_get_beep(struct snd_kcontrol *kcontrol,
172                              struct snd_ctl_elem_value *ucontrol)
173 {
174         struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
175         if (snd_BUG_ON(!chip->beep))
176                 return -ENXIO;
177         ucontrol->value.integer.value[0] = chip->beep->volume;
178         return 0;
179 }
180 
181 static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol,
182                              struct snd_ctl_elem_value *ucontrol)
183 {
184         struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
185         unsigned int oval, nval;
186         if (snd_BUG_ON(!chip->beep))
187                 return -ENXIO;
188         oval = chip->beep->volume;
189         nval = ucontrol->value.integer.value[0];
190         if (nval > 100)
191                 return -EINVAL;
192         chip->beep->volume = nval;
193         return oval != chip->beep->volume;
194 }
195 
196 static const struct snd_kcontrol_new snd_pmac_beep_mixer = {
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 */
205 int snd_pmac_attach_beep(struct snd_pmac *chip)
206 {
207         struct pmac_beep *beep;
208         struct input_dev *input_dev;
209         struct snd_kcontrol *beep_ctl;
210         void *dmabuf;
211         int err = -ENOMEM;
212 
213         beep = kzalloc(sizeof(*beep), GFP_KERNEL);
214         if (! beep)
215                 return -ENOMEM;
216         dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
217                                     &beep->addr, GFP_KERNEL);
218         input_dev = input_allocate_device();
219         if (! dmabuf || ! input_dev)
220                 goto fail1;
221 
222         /* FIXME: set more better values */
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 
230         input_dev->evbit[0] = BIT_MASK(EV_SND);
231         input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
232         input_dev->event = snd_pmac_beep_event;
233         input_dev->dev.parent = &chip->pdev->dev;
234         input_set_drvdata(input_dev, chip);
235 
236         beep->dev = input_dev;
237         beep->buf = dmabuf;
238         beep->volume = BEEP_VOLUME;
239         beep->running = 0;
240 
241         beep_ctl = snd_ctl_new1(&snd_pmac_beep_mixer, chip);
242         err = snd_ctl_add(chip->card, beep_ctl);
243         if (err < 0)
244                 goto fail1;
245 
246         chip->beep = beep;
247 
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);
259         kfree(beep);
260         return err;
261 }
262 
263 void snd_pmac_detach_beep(struct snd_pmac *chip)
264 {
265         if (chip->beep) {
266                 input_unregister_device(chip->beep->dev);
267                 dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4,
268                                   chip->beep->buf, chip->beep->addr);
269                 kfree(chip->beep);
270                 chip->beep = NULL;
271         }
272 }
273 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp