No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / audiobell.c
blobd0a949e0f486fc7ed26b0debbb33a8ed26bfced9
1 /* $NetBSD: audiobell.c,v 1.7 2009/05/07 09:23:01 cegger Exp $ */
3 /*
4 * Copyright (c) 1999 Richard Earnshaw
5 * Copyright (c) 2004 Ben Harris
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the RiscBSD team.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/types.h>
34 __KERNEL_RCSID(0, "$NetBSD: audiobell.c,v 1.7 2009/05/07 09:23:01 cegger Exp $");
36 #include <sys/audioio.h>
37 #include <sys/conf.h>
38 #include <sys/device.h>
39 #include <sys/fcntl.h>
40 #include <sys/malloc.h>
41 #include <sys/null.h>
42 #include <sys/systm.h>
43 #include <sys/uio.h>
45 #include <dev/audio_if.h>
46 #include <dev/audiobellvar.h>
48 extern dev_type_open(audioopen);
49 extern dev_type_write(audiowrite);
50 extern dev_type_close(audioclose);
52 /* Convert a %age volume to an amount to add to u-law values */
53 /* XXX Probably highly inaccurate -- should be regenerated */
54 static const uint8_t volmap[] = {
55 0x7f, 0x67, 0x5b, 0x53, 0x49, 0x45, 0x41, 0x3e, 0x3a, 0x38,
56 0x36, 0x32, 0x30, 0x2f, 0x2e, 0x2c, 0x2b, 0x2a, 0x28, 0x27,
57 0x26, 0x25, 0x23, 0x22, 0x21, 0x1f, 0x1f, 0x1e, 0x1e, 0x1d,
58 0x1c, 0x1c, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18, 0x17, 0x17,
59 0x16, 0x15, 0x15, 0x14, 0x13, 0x13, 0x12, 0x11, 0x11, 0x10,
60 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d,
61 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09,
62 0x09, 0x09, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
63 0x06, 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03,
64 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
65 0x00
68 /* 1/4 cycle sine wave in u-law */
69 /* XXX Probably highly inaccurate -- should be regenerated */
70 static const uint8_t sinewave[] = {
71 0xff, 0xd3, 0xc5, 0xbc, 0xb6, 0xb0, 0xad, 0xaa,
72 0xa7, 0xa3, 0xa0, 0x9e, 0x9d, 0x9b, 0x9a, 0x98,
73 0x97, 0x96, 0x94, 0x93, 0x91, 0x90, 0x8f, 0x8e,
74 0x8e, 0x8d, 0x8c, 0x8c, 0x8b, 0x8b, 0x8a, 0x89,
75 0x89, 0x88, 0x88, 0x87, 0x87, 0x86, 0x86, 0x85,
76 0x85, 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x82,
77 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80,
78 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
79 0x80,
82 static inline uint8_t
83 audiobell_ulawscale(uint8_t val, uint8_t vol)
85 uint8_t result;
87 result = val + vol;
88 /* Spot underflow and just return silence */
89 if ((result ^ val) & 0x80)
90 return 0x7f;
91 return result;
94 static inline void
95 audiobell_expandwave(uint8_t *buf, int volume)
97 u_int i;
98 int uvol;
100 KASSERT(volume >= 0 && volume <= 100);
101 uvol = volmap[volume];
102 for (i = 0; i < 65; i++)
103 buf[i] = audiobell_ulawscale(sinewave[i], uvol);
104 for (i = 65; i < 128; i++)
105 buf[i] = buf[128 - i];
106 for (i = 128; i < 256; i++)
107 buf[i] = buf[i - 128] ^ 0x80;
111 * The algorithm here is based on that described in the RISC OS Programmer's
112 * Reference Manual (pp1624--1628).
114 static inline int
115 audiobell_synthesize(uint8_t *buf, u_int pitch, u_int period, u_int volume)
117 uint8_t *wave;
118 uint16_t phase;
120 wave = malloc(256, M_TEMP, M_WAITOK);
121 if (wave == NULL) return -1;
122 audiobell_expandwave(wave, volume);
123 pitch = pitch * 65536 / 8000;
124 period = period * 8; /* 8000 / 1000 */
125 phase = 0;
127 for (; period != 0; period--) {
128 *buf++ = wave[phase >> 8];
129 phase += pitch;
132 free(wave, M_TEMP);
133 return 0;
136 void
137 audiobell(void *arg, u_int pitch, u_int period, u_int volume, int poll)
139 device_t audio = arg;
140 uint8_t *buf;
141 struct uio auio;
142 struct iovec aiov;
144 /* The audio system isn't built for polling. */
145 if (poll) return;
147 /* If not configured, we can't beep. */
148 if (audioopen(AUDIO_DEVICE | device_unit(audio), FWRITE, 0, NULL) != 0)
149 return;
151 buf = malloc(period * 8, M_TEMP, M_WAITOK);
152 if (buf == NULL) goto out;
153 if (audiobell_synthesize(buf, pitch, period, volume) != 0) goto out;
155 aiov.iov_base = (void *)buf;
156 aiov.iov_len = period * 8;
157 auio.uio_iov = &aiov;
158 auio.uio_iovcnt = 1;
159 auio.uio_offset = 0;
160 auio.uio_resid = period * 8;
161 auio.uio_rw = UIO_WRITE;
162 UIO_SETUP_SYSSPACE(&auio);
164 audiowrite(AUDIO_DEVICE | device_unit(audio), &auio, 0);
166 out:
167 if (buf != NULL) free(buf, M_TEMP);
168 audioclose(AUDIO_DEVICE | device_unit(audio), FWRITE, 0, NULL);