xref: /netbsd-src/sys/dev/ic/msm6258.c (revision 220b5c059a84c51ea44107ea8951a57ffaecdc8c)
1 /*	$NetBSD: msm6258.c,v 1.5 2001/11/13 13:14:42 lukem Exp $	*/
2 
3 /*
4  * Copyright (c) 2001 Tetsuya Isaki. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Tetsuya Isaki.
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * OKI MSM6258 ADPCM voice synthesizer codec.
35  */
36 
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: msm6258.c,v 1.5 2001/11/13 13:14:42 lukem Exp $");
39 
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/malloc.h>
43 #include <sys/select.h>
44 #include <sys/audioio.h>
45 
46 #include <dev/audio_if.h>
47 #include <dev/audiovar.h>
48 #include <dev/auconv.h>
49 #include <dev/mulaw.h>
50 #include <dev/ic/msm6258var.h>
51 
52 
53 static inline u_char pcm2adpcm_step(short, short *, char *);
54 static inline void adpcm2pcm_step(u_char, short *, char *);
55 
56 
57 static int adpcm_estimindex[16] = {
58 	 125,  375,  625,  875,  1125,  1375,  1625,  1875,
59 	-125, -375, -625, -875, -1125, -1375, -1625, -1875
60 };
61 
62 static int adpcm_estim[49] = {
63 	 16,  17,  19,  21,  23,  25,  28,  31,  34,  37,
64 	 41,  45,  50,  55,  60,  66,  73,  80,  88,  97,
65 	107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
66 	279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
67 	724, 796, 875, 963, 1060, 1166, 1282, 1411, 1552
68 };
69 
70 static u_char adpcm_estimindex_correct[16] = {
71 	-1, -1, -1, -1, 2, 4, 6, 8,
72 	-1, -1, -1, -1, 2, 4, 6, 8
73 };
74 
75 struct msm6258_codecvar {
76 	short	mc_amp;
77 	char	mc_estim;
78 };
79 
80 struct msm6258_softc {
81 	struct device sc_dev;
82 	struct msm6258_codecvar *sc_mc;
83 	/* MD vars follow */
84 };
85 
86 void *
87 msm6258_codec_init (void)
88 {
89 	struct msm6258_codecvar *r;
90 
91 	r = malloc (sizeof(*r), M_DEVBUF, M_NOWAIT);
92 	if (r == 0)
93 		return 0;
94 	r->mc_amp = r->mc_estim = 0;
95 
96 	return r;
97 }
98 
99 static inline u_char
100 pcm2adpcm_step(short a, short *y, char *x)
101 {
102 	int c, d;
103 	register unsigned char b;
104 
105 	a -= *y;
106 	d = adpcm_estim[(int) *x];
107 	c = a * 4 * 1000;
108 	c /= d;
109 
110 	if (c < 0) {
111 		b = (unsigned char)(-c/1000);
112 		if (b >= 8)
113 			b = 7;
114 		b |= 0x08;
115 	} else {
116 		b = (unsigned char)(c/1000);
117 		if (b >= 8)
118 			b = 7;
119 	}
120 
121 	*y += (short)(adpcm_estimindex[b] * d / 1000);
122 	*x += adpcm_estimindex_correct[b];
123 	if (*x < 0)
124 		*x = 0;
125 	else if (*x > 48)
126 		*x = 48;
127 	return b;
128 }
129 
130 void
131 msm6258_ulinear8_to_adpcm(void *hdl, u_char *p, int cc)
132 {
133 	struct msm6258_softc *sc = hdl;
134 	struct msm6258_codecvar *mc = sc->sc_mc;
135 	char *x = &(mc->mc_estim);
136 	short *y = &(mc->mc_amp);
137 	register int i;
138 	u_char f;
139 
140 	for (i = 0; i < cc; i++) {
141 		f = pcm2adpcm_step(p[i], y, x);
142 		p[i] = f + (pcm2adpcm_step(p[i], y, x) << 4);
143 	}
144 }
145 
146 void
147 msm6258_mulaw_to_adpcm(void *hdl, u_char *p, int cc)
148 {
149 	mulaw_to_ulinear8(hdl, p, cc);
150 	msm6258_ulinear8_to_adpcm(hdl, p, cc);
151 }
152 
153 static inline void
154 adpcm2pcm_step(u_char b, short *y, char *x)
155 {
156 	*y += (short)(adpcm_estimindex[b] * adpcm_estim[(int) *x]);
157 	*x += adpcm_estimindex_correct[b];
158 	if (*x < 0)
159 		*x = 0;
160 	else if (*x > 48)
161 		*x = 48;
162 }
163 
164 /* ADPCM stream must be converted in order. */
165 u_char tmpbuf[AU_RING_SIZE]; /* XXX */
166 
167 void
168 msm6258_adpcm_to_ulinear8(void *hdl, u_char *p, int cc)
169 {
170 	struct msm6258_softc *sc = hdl;
171 	struct msm6258_codecvar *mc = sc->sc_mc;
172 	char *x = &(mc->mc_estim);
173 	short *y = &(mc->mc_amp);
174 	u_char a, b;
175 	int i;
176 
177 	for (i = 0; i < cc;) {
178 		a = *p;
179 		p++;
180 		b = a & 0x0f;
181 		adpcm2pcm_step(b, y, x);
182 		tmpbuf[i++] = *y;
183 		b = a >> 4;
184 		adpcm2pcm_step(b, y, x);
185 		tmpbuf[i++] = *y;
186 	}
187 	memcpy(p, tmpbuf, cc*2);
188 }
189 
190 void
191 msm6258_adpcm_to_mulaw(void *hdl, u_char *p, int cc)
192 {
193 	msm6258_adpcm_to_ulinear8(hdl, p, cc);
194 	ulinear8_to_mulaw(hdl, p, cc*2);
195 }
196