Home | History | Annotate | Line # | Download | only in ic
msm6258.c revision 1.10
      1  1.10    isaki /*	$NetBSD: msm6258.c,v 1.10 2002/04/13 12:40:50 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.10    isaki __KERNEL_RCSID(0, "$NetBSD: msm6258.c,v 1.10 2002/04/13 12:40:50 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.9    isaki struct msm6258_codecvar {
     53   1.9    isaki 	/* ADPCM stream must be converted in order. */
     54   1.9    isaki 	u_char	mc_buf[AU_RING_SIZE]; /* XXX */
     55   1.1  minoura 
     56   1.9    isaki 	short	mc_amp;
     57   1.9    isaki 	char	mc_estim;
     58   1.9    isaki };
     59   1.1  minoura 
     60   1.9    isaki struct msm6258_softc {
     61   1.9    isaki 	struct device sc_dev;
     62   1.9    isaki 	struct msm6258_codecvar *sc_mc;
     63   1.9    isaki 	/* MD vars follow */
     64   1.9    isaki };
     65   1.9    isaki 
     66   1.9    isaki static inline u_char pcm2adpcm_step(struct msm6258_codecvar *, short);
     67   1.9    isaki static inline short  adpcm2pcm_step(struct msm6258_codecvar *, u_char);
     68   1.1  minoura 
     69   1.1  minoura static int adpcm_estimindex[16] = {
     70   1.9    isaki 	 2,  6,  10,  14,  18,  22,  26,  30,
     71   1.9    isaki 	-2, -6, -10, -14, -18, -22, -26, -30
     72   1.1  minoura };
     73   1.1  minoura 
     74   1.1  minoura static int adpcm_estim[49] = {
     75   1.1  minoura 	 16,  17,  19,  21,  23,  25,  28,  31,  34,  37,
     76   1.1  minoura 	 41,  45,  50,  55,  60,  66,  73,  80,  88,  97,
     77   1.1  minoura 	107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
     78   1.1  minoura 	279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
     79  1.10    isaki 	724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
     80   1.1  minoura };
     81   1.1  minoura 
     82   1.9    isaki static int adpcm_estimstep[16] = {
     83   1.1  minoura 	-1, -1, -1, -1, 2, 4, 6, 8,
     84   1.1  minoura 	-1, -1, -1, -1, 2, 4, 6, 8
     85   1.1  minoura };
     86   1.1  minoura 
     87   1.1  minoura void *
     88   1.1  minoura msm6258_codec_init (void)
     89   1.1  minoura {
     90   1.1  minoura 	struct msm6258_codecvar *r;
     91   1.1  minoura 
     92   1.1  minoura 	r = malloc (sizeof(*r), M_DEVBUF, M_NOWAIT);
     93   1.1  minoura 	if (r == 0)
     94   1.1  minoura 		return 0;
     95   1.1  minoura 	r->mc_amp = r->mc_estim = 0;
     96   1.1  minoura 
     97   1.1  minoura 	return r;
     98   1.8    isaki }
     99   1.8    isaki 
    100   1.8    isaki int
    101   1.8    isaki msm6258_codec_open(void *hdl)
    102   1.8    isaki {
    103   1.8    isaki 	struct msm6258_softc *sc = hdl;
    104   1.8    isaki 	struct msm6258_codecvar *mc = sc->sc_mc;
    105   1.8    isaki 
    106   1.8    isaki 	mc->mc_amp = 0;
    107   1.8    isaki 	mc->mc_estim = 0;
    108   1.8    isaki 
    109   1.8    isaki 	return 0;
    110   1.1  minoura }
    111   1.1  minoura 
    112   1.9    isaki /*
    113   1.9    isaki  * signed 16bit linear PCM -> OkiADPCM
    114   1.9    isaki  */
    115   1.1  minoura static inline u_char
    116   1.9    isaki pcm2adpcm_step(struct msm6258_codecvar *mc, short a)
    117   1.9    isaki {
    118   1.9    isaki 	int estim = (int)mc->mc_estim;
    119   1.9    isaki 	int df;
    120   1.9    isaki 	short dl, c;
    121   1.9    isaki 	unsigned char b;
    122   1.9    isaki 	unsigned char s;
    123   1.9    isaki 
    124   1.9    isaki 	df = a - mc->mc_amp;
    125   1.9    isaki 	dl = adpcm_estim[estim];
    126   1.9    isaki 	c = (df / 16) * 8 / dl;
    127   1.9    isaki 	if (df < 0) {
    128   1.9    isaki 		b = (unsigned char)(-c) / 2;
    129   1.9    isaki 		s = 0x08;
    130   1.9    isaki 	} else {
    131   1.9    isaki 		b = (unsigned char)(c) / 2;
    132   1.9    isaki 		s = 0;
    133   1.9    isaki 	}
    134   1.9    isaki 	if (b > 7)
    135   1.9    isaki 		b = 7;
    136   1.9    isaki 	s |= b;
    137   1.9    isaki 	mc->mc_amp += (short)(adpcm_estimindex[(int)s] * dl);
    138   1.9    isaki 	estim += adpcm_estimstep[b];
    139   1.9    isaki 	if (estim < 0)
    140   1.9    isaki 		estim = 0;
    141   1.9    isaki 	else if (estim > 48)
    142   1.9    isaki 		estim = 48;
    143   1.9    isaki 
    144   1.9    isaki 	mc->mc_estim = estim;
    145   1.9    isaki 	return s;
    146   1.9    isaki }
    147   1.9    isaki 
    148   1.9    isaki void
    149   1.9    isaki msm6258_slinear16_host_to_adpcm(void *hdl, u_char *p, int cc)
    150   1.1  minoura {
    151   1.9    isaki 	struct msm6258_softc *sc = hdl;
    152   1.9    isaki 	struct msm6258_codecvar *mc = sc->sc_mc;
    153   1.9    isaki 	short *s = (short *)p;
    154   1.9    isaki 	int i;
    155   1.9    isaki 	u_char f;
    156   1.1  minoura 
    157   1.9    isaki 	for (i = 0; i < cc; i += 4) {
    158   1.9    isaki 		f  = pcm2adpcm_step(mc, *s++);
    159   1.9    isaki 		f |= pcm2adpcm_step(mc, *s++) << 4;
    160   1.9    isaki 		*p++ = f;
    161   1.1  minoura 	}
    162   1.9    isaki }
    163   1.9    isaki 
    164   1.9    isaki void
    165   1.9    isaki msm6258_slinear16_le_to_adpcm(void *hdl, u_char *p, int cc)
    166   1.9    isaki {
    167   1.9    isaki #if BYTE_ORDER == BIG_ENDIAN
    168   1.9    isaki 	swap_bytes(hdl, p, cc);
    169   1.9    isaki #endif
    170   1.9    isaki 	msm6258_slinear16_host_to_adpcm(hdl, p, cc);
    171   1.9    isaki }
    172   1.1  minoura 
    173   1.9    isaki void
    174   1.9    isaki msm6258_slinear16_be_to_adpcm(void *hdl, u_char *p, int cc)
    175   1.9    isaki {
    176   1.9    isaki #if BYTE_ORDER == LITTLE_ENDIAN
    177   1.9    isaki 	swap_bytes(hdl, p, cc);
    178   1.9    isaki #endif
    179   1.9    isaki 	msm6258_slinear16_host_to_adpcm(hdl, p, cc);
    180   1.1  minoura }
    181   1.1  minoura 
    182   1.1  minoura void
    183   1.9    isaki msm6258_slinear8_to_adpcm(void *hdl, u_char *p, int cc)
    184   1.1  minoura {
    185   1.1  minoura 	struct msm6258_softc *sc = hdl;
    186   1.1  minoura 	struct msm6258_codecvar *mc = sc->sc_mc;
    187   1.9    isaki 	u_char *s = p;
    188   1.9    isaki 	int i;
    189   1.1  minoura 	u_char f;
    190   1.1  minoura 
    191   1.9    isaki 	for (i = 0; i < cc; i += 2) {
    192   1.9    isaki 		f  = pcm2adpcm_step(mc, (short)(*s++) * 256);
    193   1.9    isaki 		f |= pcm2adpcm_step(mc, (short)(*s++) * 256) << 4;
    194   1.9    isaki 		*p++ = f;
    195   1.1  minoura 	}
    196   1.1  minoura }
    197   1.1  minoura 
    198   1.1  minoura void
    199   1.9    isaki msm6258_ulinear8_to_adpcm(void *hdl, u_char *p, int cc)
    200   1.9    isaki {
    201   1.9    isaki 	change_sign8(hdl, p, cc);
    202   1.9    isaki 	msm6258_slinear8_to_adpcm(hdl, p, cc);
    203   1.9    isaki }
    204   1.9    isaki 
    205   1.9    isaki void
    206   1.1  minoura msm6258_mulaw_to_adpcm(void *hdl, u_char *p, int cc)
    207   1.1  minoura {
    208   1.9    isaki 	mulaw_to_slinear8(hdl, p, cc);
    209   1.9    isaki 	msm6258_slinear8_to_adpcm(hdl, p, cc);
    210   1.1  minoura }
    211   1.1  minoura 
    212   1.9    isaki 
    213   1.9    isaki /*
    214   1.9    isaki  * OkiADPCM -> signed 16bit linear PCM
    215   1.9    isaki  */
    216   1.9    isaki static inline short
    217   1.9    isaki adpcm2pcm_step(struct msm6258_codecvar *mc, u_char b)
    218   1.1  minoura {
    219   1.9    isaki 	int estim = (int)mc->mc_estim;
    220   1.7    isaki 
    221   1.9    isaki 	mc->mc_amp += adpcm_estim[estim] * adpcm_estimindex[b];
    222   1.9    isaki 	estim += adpcm_estimstep[b];
    223   1.7    isaki 
    224   1.7    isaki 	if (estim < 0)
    225   1.7    isaki 		estim = 0;
    226   1.9    isaki 	else if (estim > 48)
    227   1.7    isaki 		estim = 48;
    228   1.9    isaki 
    229   1.9    isaki 	mc->mc_estim = estim;
    230   1.9    isaki 
    231   1.9    isaki 	return mc->mc_amp;
    232   1.1  minoura }
    233   1.1  minoura 
    234   1.9    isaki void
    235   1.9    isaki msm6258_adpcm_to_slinear16_host(void *hdl, u_char *p, int cc)
    236   1.9    isaki {
    237   1.9    isaki 	struct msm6258_softc *sc = hdl;
    238   1.9    isaki 	struct msm6258_codecvar *mc = sc->sc_mc;
    239   1.9    isaki 	short *d = (short *)p;
    240   1.9    isaki 	int i;
    241   1.9    isaki 	u_char a;
    242   1.9    isaki 
    243   1.9    isaki 	/* XXX alignment ? */
    244   1.9    isaki 	memcpy(mc->mc_buf, p, cc / 4);
    245   1.9    isaki 	for (i = 0; i < cc / 4;) {
    246   1.9    isaki 		a = mc->mc_buf[i++];
    247   1.9    isaki 
    248   1.9    isaki 		*d++ = adpcm2pcm_step(mc, a & 0x0f);
    249   1.9    isaki 		*d++ = adpcm2pcm_step(mc, (a >> 4) & 0x0f);
    250   1.9    isaki 	}
    251   1.9    isaki }
    252   1.9    isaki 
    253   1.9    isaki void
    254   1.9    isaki msm6258_adpcm_to_slinear16_le(void *hdl, u_char *p, int cc)
    255   1.9    isaki {
    256   1.9    isaki 	msm6258_adpcm_to_slinear16_host(hdl, p, cc);
    257   1.9    isaki #if BYTE_ORDER == BIG_ENDIAN
    258   1.9    isaki 	swap_bytes(hdl, p, cc);
    259   1.9    isaki #endif
    260   1.9    isaki }
    261   1.9    isaki 
    262   1.9    isaki void
    263   1.9    isaki msm6258_adpcm_to_slinear16_be(void *hdl, u_char *p, int cc)
    264   1.9    isaki {
    265   1.9    isaki 	msm6258_adpcm_to_slinear16_host(hdl, p, cc);
    266   1.9    isaki #if BYTE_ORDER == LITTLE_ENDIAN
    267   1.9    isaki 	swap_bytes(hdl, p, cc);
    268   1.9    isaki #endif
    269   1.9    isaki }
    270   1.1  minoura 
    271   1.1  minoura void
    272   1.9    isaki msm6258_adpcm_to_slinear8(void *hdl, u_char *p, int cc)
    273   1.1  minoura {
    274   1.1  minoura 	struct msm6258_softc *sc = hdl;
    275   1.1  minoura 	struct msm6258_codecvar *mc = sc->sc_mc;
    276   1.9    isaki 	char *d = (char *)p;
    277   1.1  minoura 	int i;
    278   1.9    isaki 	u_char a;
    279   1.1  minoura 
    280   1.9    isaki 	/* cc may be even. XXX alignment ? */
    281   1.9    isaki 	memcpy(mc->mc_buf, p, cc / 2);
    282   1.9    isaki 	for (i = 0; i < cc / 2;) {
    283   1.9    isaki 		a = mc->mc_buf[i++];
    284   1.9    isaki 
    285   1.9    isaki 		*d++ = adpcm2pcm_step(mc, a & 0x0f) / 256;
    286   1.9    isaki 		*d++ = adpcm2pcm_step(mc, (a >> 4) & 0x0f) / 256;
    287   1.1  minoura 	}
    288   1.1  minoura }
    289   1.1  minoura 
    290   1.1  minoura void
    291   1.9    isaki msm6258_adpcm_to_ulinear8(void *hdl, u_char *p, int cc)
    292   1.9    isaki {
    293   1.9    isaki 	msm6258_adpcm_to_slinear8(hdl, p, cc);
    294   1.9    isaki 	change_sign8(hdl, p, cc);
    295   1.9    isaki }
    296   1.9    isaki 
    297   1.9    isaki void
    298   1.1  minoura msm6258_adpcm_to_mulaw(void *hdl, u_char *p, int cc)
    299   1.1  minoura {
    300   1.9    isaki 	msm6258_adpcm_to_slinear8(hdl, p, cc);
    301   1.9    isaki 	slinear8_to_mulaw(hdl, p, cc);
    302   1.1  minoura }
    303   1.9    isaki 
    304