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