1280 lines
28 KiB
C
1280 lines
28 KiB
C
/* $NetBSD: aucc.c,v 1.32 2002/10/02 04:55:48 thorpej Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1999 Bernardo Innocenti
|
|
* All rights reserved.
|
|
*
|
|
* Copyright (c) 1997 Stephan Thesing
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Stephan Thesing.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/* TODO:
|
|
*
|
|
* - ulaw -> 14bit conversion
|
|
* - channel allocation is wrong for 14bit mono
|
|
* - convert the... err... conversion routines to 68k asm for best performance
|
|
* XXX: NO. aucc audio is limited by chipmem speed, anyway. You dont
|
|
* want to make life difficult for amigappc work.
|
|
* -is
|
|
*
|
|
* - rely on auconv.c routines for ulaw/alaw conversions
|
|
* - perhaps use a calibration table for better 14bit output
|
|
* - set 31KHz AGA video mode to allow 44.1KHz even if grfcc is missing
|
|
* in the kernel
|
|
* - 14bit output requires maximum volume
|
|
*/
|
|
|
|
#include "aucc.h"
|
|
#if NAUCC > 0
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: aucc.c,v 1.32 2002/10/02 04:55:48 thorpej Exp $");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/device.h>
|
|
#include <sys/proc.h>
|
|
#include <machine/cpu.h>
|
|
|
|
#include <sys/audioio.h>
|
|
#include <dev/audio_if.h>
|
|
#include <amiga/amiga/cc.h>
|
|
#include <amiga/amiga/custom.h>
|
|
#include <amiga/amiga/device.h>
|
|
#include <amiga/dev/auccvar.h>
|
|
|
|
#include "opt_lev6_defer.h"
|
|
|
|
|
|
#ifdef LEV6_DEFER
|
|
#define AUCC_MAXINT 3
|
|
#define AUCC_ALLINTF (INTF_AUD0|INTF_AUD1|INTF_AUD2)
|
|
#else
|
|
#define AUCC_MAXINT 4
|
|
#define AUCC_ALLINTF (INTF_AUD0|INTF_AUD1|INTF_AUD2|INTF_AUD3)
|
|
#endif
|
|
/* this unconditionally; we may use AUD3 as slave channel with LEV6_DEFER */
|
|
#define AUCC_ALLDMAF (DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3)
|
|
|
|
#ifdef AUDIO_DEBUG
|
|
/*extern printf(const char *,...);*/
|
|
int auccdebug = 1;
|
|
#define DPRINTF(x) if (auccdebug) printf x
|
|
#else
|
|
#define DPRINTF(x)
|
|
#endif
|
|
|
|
#ifdef splaudio
|
|
#undef splaudio
|
|
#endif
|
|
|
|
#define splaudio() spl4();
|
|
|
|
/* clock frequency.. */
|
|
extern int eclockfreq;
|
|
|
|
|
|
/* hw audio ch */
|
|
extern struct audio_channel channel[4];
|
|
|
|
|
|
/*
|
|
* Software state.
|
|
*/
|
|
struct aucc_softc {
|
|
struct device sc_dev; /* base device */
|
|
|
|
int sc_open; /* single use device */
|
|
aucc_data_t sc_channel[4]; /* per channel freq, ... */
|
|
u_int sc_encoding; /* encoding AUDIO_ENCODING_.*/
|
|
int sc_channels; /* # of channels used */
|
|
int sc_precision; /* 8 or 16 bits */
|
|
int sc_14bit; /* 14bit output enabled */
|
|
|
|
int sc_intrcnt; /* interrupt count */
|
|
int sc_channelmask; /* which channels are used ? */
|
|
void (*sc_decodefunc)(u_char **, u_char *, int);
|
|
/* pointer to format conversion routine */
|
|
};
|
|
|
|
/* interrupt interfaces */
|
|
void aucc_inthdl(int);
|
|
|
|
/* forward declarations */
|
|
static int init_aucc(struct aucc_softc *);
|
|
static u_int freqtoper(u_int);
|
|
static u_int pertofreq(u_int);
|
|
|
|
/* autoconfiguration driver */
|
|
void auccattach(struct device *, struct device *, void *);
|
|
int auccmatch(struct device *, struct cfdata *, void *);
|
|
|
|
CFATTACH_DECL(aucc, sizeof(struct aucc_softc),
|
|
auccmatch, auccattach, NULL, NULL);
|
|
|
|
struct audio_device aucc_device = {
|
|
"Amiga-audio",
|
|
"2.0",
|
|
"aucc"
|
|
};
|
|
|
|
|
|
struct aucc_softc *aucc=NULL;
|
|
|
|
|
|
unsigned char ulaw_to_lin[] = {
|
|
0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
|
|
0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
|
|
0xc1, 0xc3, 0xc5, 0xc7, 0xc9, 0xcb, 0xcd, 0xcf,
|
|
0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf,
|
|
0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
|
|
0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0,
|
|
0xf0, 0xf1, 0xf1, 0xf2, 0xf2, 0xf3, 0xf3, 0xf4,
|
|
0xf4, 0xf5, 0xf5, 0xf6, 0xf6, 0xf7, 0xf7, 0xf8,
|
|
0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa,
|
|
0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc,
|
|
0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd,
|
|
0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe,
|
|
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
|
|
0x7d, 0x79, 0x75, 0x71, 0x6d, 0x69, 0x65, 0x61,
|
|
0x5d, 0x59, 0x55, 0x51, 0x4d, 0x49, 0x45, 0x41,
|
|
0x3e, 0x3c, 0x3a, 0x38, 0x36, 0x34, 0x32, 0x30,
|
|
0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20,
|
|
0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17,
|
|
0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f,
|
|
0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b,
|
|
0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07,
|
|
0x07, 0x07, 0x06, 0x06, 0x06, 0x06, 0x05, 0x05,
|
|
0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
|
|
0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02,
|
|
0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
/*
|
|
* Define our interface to the higher level audio driver.
|
|
*/
|
|
int aucc_open(void *, int);
|
|
void aucc_close(void *);
|
|
int aucc_set_out_sr(void *, u_long);
|
|
int aucc_query_encoding(void *, struct audio_encoding *);
|
|
int aucc_round_blocksize(void *, int);
|
|
int aucc_commit_settings(void *);
|
|
int aucc_start_output(void *, void *, int, void (*)(void *), void *);
|
|
int aucc_start_input(void *, void *, int, void (*)(void *), void *);
|
|
int aucc_halt_output(void *);
|
|
int aucc_halt_input(void *);
|
|
int aucc_getdev(void *, struct audio_device *);
|
|
int aucc_set_port(void *, mixer_ctrl_t *);
|
|
int aucc_get_port(void *, mixer_ctrl_t *);
|
|
int aucc_query_devinfo(void *, mixer_devinfo_t *);
|
|
void aucc_encode(int, int, int, int, u_char *, u_short **);
|
|
int aucc_set_params(void *, int, int, struct audio_params *,
|
|
struct audio_params *);
|
|
int aucc_get_props(void *);
|
|
|
|
|
|
static void aucc_decode_slinear8_1ch(u_char **, u_char *, int);
|
|
static void aucc_decode_slinear8_2ch(u_char **, u_char *, int);
|
|
static void aucc_decode_slinear8_3ch(u_char **, u_char *, int);
|
|
static void aucc_decode_slinear8_4ch(u_char **, u_char *, int);
|
|
|
|
static void aucc_decode_ulinear8_1ch(u_char **, u_char *, int);
|
|
static void aucc_decode_ulinear8_2ch(u_char **, u_char *, int);
|
|
static void aucc_decode_ulinear8_3ch(u_char **, u_char *, int);
|
|
static void aucc_decode_ulinear8_4ch(u_char **, u_char *, int);
|
|
|
|
static void aucc_decode_ulaw_1ch(u_char **, u_char *, int);
|
|
static void aucc_decode_ulaw_2ch(u_char **, u_char *, int);
|
|
static void aucc_decode_ulaw_3ch(u_char **, u_char *, int);
|
|
static void aucc_decode_ulaw_4ch(u_char **, u_char *, int);
|
|
|
|
static void aucc_decode_slinear16_1ch(u_char **, u_char *, int);
|
|
static void aucc_decode_slinear16_2ch(u_char **, u_char *, int);
|
|
static void aucc_decode_slinear16_3ch(u_char **, u_char *, int);
|
|
static void aucc_decode_slinear16_4ch(u_char **, u_char *, int);
|
|
|
|
static void aucc_decode_slinear16sw_1ch(u_char **, u_char *, int);
|
|
static void aucc_decode_slinear16sw_2ch(u_char **, u_char *, int);
|
|
static void aucc_decode_slinear16sw_3ch(u_char **, u_char *, int);
|
|
static void aucc_decode_slinear16sw_4ch(u_char **, u_char *, int);
|
|
|
|
|
|
|
|
struct audio_hw_if sa_hw_if = {
|
|
aucc_open,
|
|
aucc_close,
|
|
NULL,
|
|
aucc_query_encoding,
|
|
aucc_set_params,
|
|
aucc_round_blocksize,
|
|
aucc_commit_settings,
|
|
NULL,
|
|
NULL,
|
|
aucc_start_output,
|
|
aucc_start_input,
|
|
aucc_halt_output,
|
|
aucc_halt_input,
|
|
NULL,
|
|
aucc_getdev,
|
|
NULL,
|
|
aucc_set_port,
|
|
aucc_get_port,
|
|
aucc_query_devinfo,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
aucc_get_props,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
};
|
|
|
|
/* autoconfig routines */
|
|
|
|
int
|
|
auccmatch(struct device *pdp, struct cfdata *cfp, void *aux)
|
|
{
|
|
static int aucc_matched = 0;
|
|
|
|
if (!matchname((char *)aux, "aucc") ||
|
|
#ifdef DRACO
|
|
is_draco() ||
|
|
#endif
|
|
aucc_matched)
|
|
return 0;
|
|
|
|
aucc_matched = 1;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Audio chip found.
|
|
*/
|
|
void
|
|
auccattach(struct device *parent, struct device *self, void *args)
|
|
{
|
|
register struct aucc_softc *sc = (struct aucc_softc *)self;
|
|
register int i;
|
|
|
|
printf("\n");
|
|
|
|
if((i=init_aucc(sc))) {
|
|
printf("audio: no chipmem\n");
|
|
return;
|
|
}
|
|
|
|
audio_attach_mi(&sa_hw_if, sc, &sc->sc_dev);
|
|
}
|
|
|
|
|
|
static int
|
|
init_aucc(struct aucc_softc *sc)
|
|
{
|
|
register int i, err=0;
|
|
|
|
/* init values per channel */
|
|
for (i=0;i<4;i++) {
|
|
sc->sc_channel[i].nd_freq=8000;
|
|
sc->sc_channel[i].nd_per=freqtoper(8000);
|
|
sc->sc_channel[i].nd_busy=0;
|
|
sc->sc_channel[i].nd_dma=alloc_chipmem(AUDIO_BUF_SIZE*2);
|
|
if (sc->sc_channel[i].nd_dma==NULL)
|
|
err=1;
|
|
sc->sc_channel[i].nd_dmalength=0;
|
|
sc->sc_channel[i].nd_volume=64;
|
|
sc->sc_channel[i].nd_intr=NULL;
|
|
sc->sc_channel[i].nd_intrdata=NULL;
|
|
sc->sc_channel[i].nd_doublebuf=0;
|
|
DPRINTF(("dma buffer for channel %d is %p\n", i,
|
|
sc->sc_channel[i].nd_dma));
|
|
}
|
|
|
|
if (err) {
|
|
for(i=0;i<4;i++)
|
|
if (sc->sc_channel[i].nd_dma)
|
|
free_chipmem(sc->sc_channel[i].nd_dma);
|
|
}
|
|
|
|
sc->sc_channels=1;
|
|
sc->sc_channelmask=0xf;
|
|
sc->sc_precision=8;
|
|
sc->sc_14bit = 0;
|
|
sc->sc_encoding=AUDIO_ENCODING_ULAW;
|
|
sc->sc_decodefunc = aucc_decode_ulaw_1ch;
|
|
|
|
/* clear interrupts and dma: */
|
|
custom.intena = AUCC_ALLINTF;
|
|
custom.dmacon = AUCC_ALLDMAF;
|
|
|
|
return err;
|
|
}
|
|
|
|
int
|
|
aucc_open(void *addr, int flags)
|
|
{
|
|
struct aucc_softc *sc = addr;
|
|
int i;
|
|
|
|
DPRINTF(("sa_open: unit %p\n",sc));
|
|
|
|
if (sc->sc_open)
|
|
return (EBUSY);
|
|
sc->sc_open = 1;
|
|
for (i=0;i<AUCC_MAXINT;i++) {
|
|
sc->sc_channel[i].nd_intr=NULL;
|
|
sc->sc_channel[i].nd_intrdata=NULL;
|
|
}
|
|
aucc=sc;
|
|
sc->sc_channelmask=0xf;
|
|
|
|
DPRINTF(("saopen: ok -> sc=0x%p\n",sc));
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
aucc_close(void *addr)
|
|
{
|
|
register struct aucc_softc *sc = addr;
|
|
|
|
DPRINTF(("sa_close: sc=0x%p\n", sc));
|
|
/*
|
|
* halt i/o, clear open flag, and done.
|
|
*/
|
|
aucc_halt_output(sc);
|
|
sc->sc_open = 0;
|
|
|
|
DPRINTF(("sa_close: closed.\n"));
|
|
}
|
|
|
|
int
|
|
aucc_set_out_sr(void *addr, u_long sr)
|
|
{
|
|
struct aucc_softc *sc=addr;
|
|
u_long per;
|
|
register int i;
|
|
|
|
per=freqtoper(sr);
|
|
if (per>0xffff)
|
|
return EINVAL;
|
|
sr=pertofreq(per);
|
|
|
|
for (i=0;i<4;i++) {
|
|
sc->sc_channel[i].nd_freq=sr;
|
|
sc->sc_channel[i].nd_per=per;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
aucc_query_encoding(void *addr, struct audio_encoding *fp)
|
|
{
|
|
switch (fp->index) {
|
|
case 0:
|
|
strcpy(fp->name, AudioEslinear);
|
|
fp->encoding = AUDIO_ENCODING_SLINEAR;
|
|
fp->precision = 8;
|
|
fp->flags = 0;
|
|
break;
|
|
case 1:
|
|
strcpy(fp->name, AudioEmulaw);
|
|
fp->encoding = AUDIO_ENCODING_ULAW;
|
|
fp->precision = 8;
|
|
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
|
|
break;
|
|
|
|
case 2:
|
|
strcpy(fp->name, AudioEulinear);
|
|
fp->encoding = AUDIO_ENCODING_ULINEAR;
|
|
fp->precision = 8;
|
|
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
|
|
break;
|
|
|
|
case 3:
|
|
strcpy(fp->name, AudioEslinear);
|
|
fp->encoding = AUDIO_ENCODING_SLINEAR;
|
|
fp->precision = 16;
|
|
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
|
|
break;
|
|
|
|
case 4:
|
|
strcpy(fp->name, AudioEslinear_be);
|
|
fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
|
|
fp->precision = 16;
|
|
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
|
|
break;
|
|
|
|
case 5:
|
|
strcpy(fp->name, AudioEslinear_le);
|
|
fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
|
|
fp->precision = 16;
|
|
fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
|
|
break;
|
|
|
|
default:
|
|
return(EINVAL);
|
|
/*NOTREACHED*/
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
aucc_set_params(void *addr, int setmode, int usemode, struct audio_params *p,
|
|
struct audio_params *r)
|
|
{
|
|
struct aucc_softc *sc = addr;
|
|
|
|
/* if (setmode & AUMODE_RECORD)
|
|
return 0 ENXIO*/;
|
|
|
|
#ifdef AUCCDEBUG
|
|
printf("aucc_set_params(setmode 0x%x, usemode 0x%x, "
|
|
"enc %d, bits %d, chn %d, sr %ld)\n", setmode, usemode,
|
|
p->encoding, p->precision, p->channels, p->sample_rate);
|
|
#endif
|
|
|
|
switch (p->precision) {
|
|
case 8:
|
|
switch (p->encoding) {
|
|
case AUDIO_ENCODING_ULAW:
|
|
switch (p->channels) {
|
|
case 1:
|
|
sc->sc_decodefunc = aucc_decode_ulaw_1ch;
|
|
break;
|
|
case 2:
|
|
sc->sc_decodefunc = aucc_decode_ulaw_2ch;
|
|
break;
|
|
case 3:
|
|
sc->sc_decodefunc = aucc_decode_ulaw_3ch;
|
|
break;
|
|
case 4:
|
|
sc->sc_decodefunc = aucc_decode_ulaw_4ch;
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
break;
|
|
|
|
case AUDIO_ENCODING_SLINEAR:
|
|
case AUDIO_ENCODING_SLINEAR_BE:
|
|
case AUDIO_ENCODING_SLINEAR_LE:
|
|
switch (p->channels) {
|
|
case 1:
|
|
sc->sc_decodefunc = aucc_decode_slinear8_1ch;
|
|
break;
|
|
case 2:
|
|
sc->sc_decodefunc = aucc_decode_slinear8_2ch;
|
|
break;
|
|
case 3:
|
|
sc->sc_decodefunc = aucc_decode_slinear8_3ch;
|
|
break;
|
|
case 4:
|
|
sc->sc_decodefunc = aucc_decode_slinear8_4ch;
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
break;
|
|
|
|
case AUDIO_ENCODING_ULINEAR:
|
|
case AUDIO_ENCODING_ULINEAR_BE:
|
|
case AUDIO_ENCODING_ULINEAR_LE:
|
|
switch (p->channels) {
|
|
case 1:
|
|
sc->sc_decodefunc = aucc_decode_ulinear8_1ch;
|
|
break;
|
|
case 2:
|
|
sc->sc_decodefunc = aucc_decode_ulinear8_2ch;
|
|
break;
|
|
case 3:
|
|
sc->sc_decodefunc = aucc_decode_ulinear8_3ch;
|
|
break;
|
|
case 4:
|
|
sc->sc_decodefunc = aucc_decode_ulinear8_4ch;
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
break;
|
|
|
|
case 16:
|
|
switch (p->encoding) {
|
|
#if BYTE_ORDER == BIG_ENDIAN
|
|
case AUDIO_ENCODING_SLINEAR:
|
|
#endif
|
|
case AUDIO_ENCODING_SLINEAR_BE:
|
|
switch (p->channels) {
|
|
case 1:
|
|
sc->sc_decodefunc = aucc_decode_slinear16_1ch;
|
|
break;
|
|
|
|
case 2:
|
|
sc->sc_decodefunc = aucc_decode_slinear16_2ch;
|
|
break;
|
|
case 3:
|
|
sc->sc_decodefunc = aucc_decode_slinear16_3ch;
|
|
break;
|
|
case 4:
|
|
sc->sc_decodefunc = aucc_decode_slinear16_4ch;
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
break;
|
|
|
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
case AUDIO_ENCODING_SLINEAR:
|
|
#endif
|
|
case AUDIO_ENCODING_SLINEAR_LE:
|
|
switch (p->channels) {
|
|
case 1:
|
|
sc->sc_decodefunc = aucc_decode_slinear16sw_1ch;
|
|
break;
|
|
case 2:
|
|
sc->sc_decodefunc = aucc_decode_slinear16sw_2ch;
|
|
break;
|
|
case 3:
|
|
sc->sc_decodefunc = aucc_decode_slinear16sw_3ch;
|
|
break;
|
|
case 4:
|
|
sc->sc_decodefunc = aucc_decode_slinear16sw_4ch;
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
|
|
sc->sc_encoding = p->encoding;
|
|
sc->sc_precision = p->precision;
|
|
sc->sc_14bit = ((p->precision == 16) && (p->channels <= 2));
|
|
sc->sc_channels = sc->sc_14bit ? (p->channels * 2) : p->channels;
|
|
|
|
return aucc_set_out_sr(addr, p->sample_rate);
|
|
}
|
|
|
|
int
|
|
aucc_round_blocksize(void *addr, int blk)
|
|
{
|
|
/* round up to even size */
|
|
return blk > AUDIO_BUF_SIZE ? AUDIO_BUF_SIZE : blk;
|
|
}
|
|
|
|
int
|
|
aucc_commit_settings(void *addr)
|
|
{
|
|
register struct aucc_softc *sc = addr;
|
|
register int i;
|
|
|
|
DPRINTF(("sa_commit.\n"));
|
|
|
|
for (i=0;i<4;i++) {
|
|
custom.aud[i].vol=sc->sc_channel[i].nd_volume;
|
|
custom.aud[i].per=sc->sc_channel[i].nd_per;
|
|
}
|
|
|
|
DPRINTF(("commit done\n"));
|
|
|
|
return(0);
|
|
}
|
|
|
|
static int masks[4] = {1,3,7,15}; /* masks for n first channels */
|
|
static int masks2[4] = {1,2,4,8};
|
|
|
|
int
|
|
aucc_start_output(void *addr, void *p, int cc, void (*intr)(void *), void *arg)
|
|
{
|
|
struct aucc_softc *sc;
|
|
int mask;
|
|
int i, j, k, len;
|
|
u_char *dmap[4];
|
|
|
|
|
|
sc = addr;
|
|
mask = sc->sc_channelmask;
|
|
|
|
dmap[0] = dmap[1] = dmap[2] = dmap[3] = NULL;
|
|
|
|
DPRINTF(("sa_start_output: cc=%d %p (%p)\n", cc, intr, arg));
|
|
|
|
if (sc->sc_channels > 1)
|
|
mask &= masks[sc->sc_channels - 1];
|
|
/* we use first sc_channels channels */
|
|
if (mask == 0) /* active and used channels are disjoint */
|
|
return EINVAL;
|
|
|
|
for (i=0;i<4;i++) {
|
|
/* channels available ? */
|
|
if ((masks2[i] & mask) && (sc->sc_channel[i].nd_busy))
|
|
return EBUSY; /* channel is busy */
|
|
if (channel[i].isaudio == -1)
|
|
return EBUSY; /* system uses them */
|
|
}
|
|
|
|
/* enable interrupt on 1st channel */
|
|
for (i = j = 0; i < AUCC_MAXINT; i++) {
|
|
if (masks2[i] & mask) {
|
|
DPRINTF(("first channel is %d\n",i));
|
|
j=i;
|
|
sc->sc_channel[i].nd_intr=intr;
|
|
sc->sc_channel[i].nd_intrdata=arg;
|
|
break;
|
|
}
|
|
}
|
|
|
|
DPRINTF(("dmap is %p %p %p %p, mask=0x%x\n", dmap[0], dmap[1],
|
|
dmap[2], dmap[3], mask));
|
|
|
|
/* disable ints, dma for channels, until all parameters set */
|
|
/* XXX dont disable DMA! custom.dmacon=mask;*/
|
|
custom.intreq = mask << INTB_AUD0;
|
|
custom.intena = mask << INTB_AUD0;
|
|
|
|
/* copy data to dma buffer */
|
|
|
|
if (sc->sc_channels == 1) {
|
|
dmap[0] =
|
|
dmap[1] =
|
|
dmap[2] =
|
|
dmap[3] = (u_char *)sc->sc_channel[j].nd_dma;
|
|
}
|
|
else {
|
|
for (k=0; k<4; k++) {
|
|
if (masks2[k+j] & mask)
|
|
dmap[k] = (u_char *)sc->sc_channel[k+j].nd_dma;
|
|
}
|
|
}
|
|
|
|
sc->sc_channel[j].nd_doublebuf ^= 1;
|
|
if (sc->sc_channel[j].nd_doublebuf) {
|
|
dmap[0] += AUDIO_BUF_SIZE;
|
|
dmap[1] += AUDIO_BUF_SIZE;
|
|
dmap[2] += AUDIO_BUF_SIZE;
|
|
dmap[3] += AUDIO_BUF_SIZE;
|
|
}
|
|
|
|
/* compute output length in bytes per channel.
|
|
* divide by two only for 16bit->8bit conversion.
|
|
*/
|
|
len = cc / sc->sc_channels;
|
|
if (!sc->sc_14bit && (sc->sc_precision == 16))
|
|
len /= 2;
|
|
|
|
/* call audio decoding routine */
|
|
sc->sc_decodefunc (dmap, (u_char *)p, len);
|
|
|
|
/* dma buffers: we use same buffer 4 all channels
|
|
* write dma location and length
|
|
*/
|
|
for (i = k = 0; i < 4; i++) {
|
|
if (masks2[i] & mask) {
|
|
DPRINTF(("turning channel %d on\n",i));
|
|
/* sc->sc_channel[i].nd_busy=1; */
|
|
channel[i].isaudio = 1;
|
|
channel[i].play_count = 1;
|
|
channel[i].handler = NULL;
|
|
custom.aud[i].per = sc->sc_channel[i].nd_per;
|
|
if (sc->sc_14bit && (i > 1))
|
|
custom.aud[i].vol = 1;
|
|
else
|
|
custom.aud[i].vol = sc->sc_channel[i].nd_volume;
|
|
custom.aud[i].lc = PREP_DMA_MEM(dmap[k++]);
|
|
custom.aud[i].len = len / 2;
|
|
sc->sc_channel[i].nd_mask = mask;
|
|
DPRINTF(("per is %d, vol is %d, len is %d\n",\
|
|
sc->sc_channel[i].nd_per,
|
|
sc->sc_channel[i].nd_volume, len));
|
|
}
|
|
}
|
|
|
|
channel[j].handler=aucc_inthdl;
|
|
|
|
/* enable ints */
|
|
custom.intena = INTF_SETCLR | INTF_INTEN | (masks2[j] << INTB_AUD0);
|
|
|
|
DPRINTF(("enabled ints: 0x%x\n", (masks2[j] << INTB_AUD0)));
|
|
|
|
/* enable dma */
|
|
custom.dmacon = DMAF_SETCLR | DMAF_MASTER | mask;
|
|
|
|
DPRINTF(("enabled dma, mask=0x%x\n",mask));
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
int
|
|
aucc_start_input(void *addr, void *p, int cc, void (*intr)(void *), void *arg)
|
|
{
|
|
|
|
return ENXIO; /* no input */
|
|
}
|
|
|
|
int
|
|
aucc_halt_output(void *addr)
|
|
{
|
|
register struct aucc_softc *sc = addr;
|
|
register int i;
|
|
|
|
/* XXX only halt, if input is also halted ?? */
|
|
/* stop dma, etc */
|
|
custom.intena = AUCC_ALLINTF;
|
|
custom.dmacon = AUCC_ALLDMAF;
|
|
/* mark every busy unit idle */
|
|
for (i=0;i<4;i++) {
|
|
sc->sc_channel[i].nd_busy=sc->sc_channel[i].nd_mask=0;
|
|
channel[i].isaudio=0;
|
|
channel[i].play_count=0;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
aucc_halt_input(void *addr)
|
|
{
|
|
/* no input */
|
|
|
|
return ENXIO;
|
|
}
|
|
|
|
int
|
|
aucc_getdev(void *addr, struct audio_device *retp)
|
|
{
|
|
*retp = aucc_device;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
aucc_set_port(void *addr, mixer_ctrl_t *cp)
|
|
{
|
|
register struct aucc_softc *sc = addr;
|
|
register int i,j;
|
|
|
|
DPRINTF(("aucc_set_port: port=%d", cp->dev));
|
|
|
|
switch (cp->type) {
|
|
case AUDIO_MIXER_SET:
|
|
if (cp->dev!=AUCC_CHANNELS)
|
|
return EINVAL;
|
|
i=cp->un.mask;
|
|
if ((i<1) || (i>15))
|
|
return EINVAL;
|
|
|
|
sc->sc_channelmask=i;
|
|
break;
|
|
|
|
case AUDIO_MIXER_VALUE:
|
|
i=cp->un.value.num_channels;
|
|
if ((i<1) || (i>4))
|
|
return EINVAL;
|
|
|
|
#ifdef __XXXwhatsthat
|
|
if (cp->dev!=AUCC_VOLUME)
|
|
return EINVAL;
|
|
#endif
|
|
|
|
/* set volume for channel 0..i-1 */
|
|
|
|
/* evil workaround for xanim bug, IMO */
|
|
if ((sc->sc_channels == 1) && (i == 2)) {
|
|
sc->sc_channel[0].nd_volume =
|
|
sc->sc_channel[3].nd_volume =
|
|
cp->un.value.level[0]>>2;
|
|
sc->sc_channel[1].nd_volume =
|
|
sc->sc_channel[2].nd_volume =
|
|
cp->un.value.level[1]>>2;
|
|
} else if (i>1) {
|
|
for (j=0;j<i;j++)
|
|
sc->sc_channel[j].nd_volume =
|
|
cp->un.value.level[j]>>2;
|
|
} else if (sc->sc_channels > 1)
|
|
for (j=0; j<sc->sc_channels; j++)
|
|
sc->sc_channel[j].nd_volume =
|
|
cp->un.value.level[0]>>2;
|
|
else
|
|
for (j=0; j<4; j++)
|
|
sc->sc_channel[j].nd_volume =
|
|
cp->un.value.level[0]>>2;
|
|
break;
|
|
|
|
default:
|
|
return EINVAL;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
aucc_get_port(void *addr, mixer_ctrl_t *cp)
|
|
{
|
|
register struct aucc_softc *sc = addr;
|
|
register int i,j;
|
|
|
|
DPRINTF(("aucc_get_port: port=%d", cp->dev));
|
|
|
|
switch (cp->type) {
|
|
case AUDIO_MIXER_SET:
|
|
if (cp->dev!=AUCC_CHANNELS)
|
|
return EINVAL;
|
|
cp->un.mask=sc->sc_channelmask;
|
|
break;
|
|
|
|
case AUDIO_MIXER_VALUE:
|
|
i = cp->un.value.num_channels;
|
|
if ((i<1)||(i>4))
|
|
return EINVAL;
|
|
|
|
for (j=0;j<i;j++)
|
|
cp->un.value.level[j] =
|
|
(sc->sc_channel[j].nd_volume<<2) +
|
|
(sc->sc_channel[j].nd_volume>>4);
|
|
break;
|
|
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
aucc_get_props(void *addr)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
aucc_query_devinfo(void *addr, register mixer_devinfo_t *dip)
|
|
{
|
|
register int i;
|
|
|
|
switch(dip->index) {
|
|
case AUCC_CHANNELS:
|
|
dip->type = AUDIO_MIXER_SET;
|
|
dip->mixer_class = AUCC_OUTPUT_CLASS;
|
|
dip->prev = dip->next = AUDIO_MIXER_LAST;
|
|
strcpy(dip->label.name, AudioNspeaker);
|
|
for (i=0;i<16;i++) {
|
|
sprintf(dip->un.s.member[i].label.name,
|
|
"channelmask%d", i);
|
|
dip->un.s.member[i].mask = i;
|
|
}
|
|
dip->un.s.num_mem = 16;
|
|
break;
|
|
|
|
case AUCC_VOLUME:
|
|
dip->type = AUDIO_MIXER_VALUE;
|
|
dip->mixer_class = AUCC_OUTPUT_CLASS;
|
|
dip->prev = dip->next = AUDIO_MIXER_LAST;
|
|
strcpy(dip->label.name, AudioNmaster);
|
|
dip->un.v.num_channels = 4;
|
|
strcpy(dip->un.v.units.name, AudioNvolume);
|
|
break;
|
|
|
|
case AUCC_OUTPUT_CLASS:
|
|
dip->type = AUDIO_MIXER_CLASS;
|
|
dip->mixer_class = AUCC_OUTPUT_CLASS;
|
|
dip->next = dip->prev = AUDIO_MIXER_LAST;
|
|
strcpy(dip->label.name, AudioCoutputs);
|
|
break;
|
|
|
|
default:
|
|
return ENXIO;
|
|
}
|
|
|
|
DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/* audio int handler */
|
|
void
|
|
aucc_inthdl(int ch)
|
|
{
|
|
register int i;
|
|
register int mask=aucc->sc_channel[ch].nd_mask;
|
|
|
|
/* for all channels in this maskgroup:
|
|
disable dma, int
|
|
mark idle */
|
|
DPRINTF(("inthandler called, channel %d, mask 0x%x\n",ch,mask));
|
|
|
|
custom.intreq=mask<<INTB_AUD0; /* clear request */
|
|
/*
|
|
* XXX: maybe we can leave ints and/or DMA on,
|
|
* if another sample has to be played?
|
|
*/
|
|
custom.intena=mask<<INTB_AUD0;
|
|
/*
|
|
* XXX custom.dmacon=mask; NO!!!
|
|
*/
|
|
for (i=0; i<4; i++) {
|
|
if (masks2[i]&&mask) {
|
|
DPRINTF(("marking channel %d idle\n",i));
|
|
aucc->sc_channel[i].nd_busy=0;
|
|
aucc->sc_channel[i].nd_mask=0;
|
|
channel[i].isaudio=channel[i].play_count=0;
|
|
}
|
|
}
|
|
|
|
/* call handler */
|
|
if (aucc->sc_channel[ch].nd_intr) {
|
|
DPRINTF(("calling %p\n",aucc->sc_channel[ch].nd_intr));
|
|
(*(aucc->sc_channel[ch].nd_intr))
|
|
(aucc->sc_channel[ch].nd_intrdata);
|
|
}
|
|
else
|
|
DPRINTF(("zero int handler\n"));
|
|
DPRINTF(("ints done\n"));
|
|
}
|
|
|
|
|
|
|
|
|
|
/* transform frequency to period, adjust bounds */
|
|
static u_int
|
|
freqtoper(u_int freq)
|
|
{
|
|
u_int per=eclockfreq*5/freq;
|
|
|
|
if (per<124)
|
|
per=124; /* must have at least 124 ticks between samples */
|
|
|
|
return per;
|
|
}
|
|
|
|
/* transform period to frequency */
|
|
static u_int
|
|
pertofreq(u_int per)
|
|
{
|
|
u_int freq=eclockfreq*5/per;
|
|
|
|
return freq;
|
|
}
|
|
|
|
static void
|
|
aucc_decode_slinear8_1ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
memcpy (dmap[0], p, i);
|
|
}
|
|
|
|
static void
|
|
aucc_decode_slinear8_2ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
|
|
while (i--) {
|
|
*ch0++ = *p++;
|
|
*ch1++ = *p++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
aucc_decode_slinear8_3ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
u_char *ch2 = dmap[2];
|
|
|
|
while (i--) {
|
|
*ch0++ = *p++;
|
|
*ch1++ = *p++;
|
|
*ch2++ = *p++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
aucc_decode_slinear8_4ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
u_char *ch2 = dmap[2];
|
|
u_char *ch3 = dmap[3];
|
|
|
|
while (i--) {
|
|
*ch0++ = *p++;
|
|
*ch1++ = *p++;
|
|
*ch2++ = *p++;
|
|
*ch3++ = *p++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
aucc_decode_ulinear8_1ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
|
|
while (i--)
|
|
*ch0++ = *p++ - 128;
|
|
}
|
|
|
|
static void
|
|
aucc_decode_ulinear8_2ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
|
|
while (i--) {
|
|
*ch0++ = *p++ - 128;
|
|
*ch1++ = *p++ - 128;
|
|
}
|
|
}
|
|
|
|
static void
|
|
aucc_decode_ulinear8_3ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
u_char *ch2 = dmap[2];
|
|
|
|
while (i--) {
|
|
*ch0++ = *p++ - 128;
|
|
*ch1++ = *p++ - 128;
|
|
*ch2++ = *p++ - 128;
|
|
}
|
|
}
|
|
|
|
static void
|
|
aucc_decode_ulinear8_4ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
u_char *ch2 = dmap[2];
|
|
u_char *ch3 = dmap[3];
|
|
|
|
while (i--) {
|
|
*ch0++ = *p++ - 128;
|
|
*ch1++ = *p++ - 128;
|
|
*ch2++ = *p++ - 128;
|
|
*ch3++ = *p++ - 128;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
aucc_decode_ulaw_1ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
|
|
while (i--)
|
|
*ch0++ = ulaw_to_lin[*p++];
|
|
}
|
|
|
|
static void
|
|
aucc_decode_ulaw_2ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
|
|
while (i--) {
|
|
*ch0++ = ulaw_to_lin[*p++];
|
|
*ch1++ = ulaw_to_lin[*p++];
|
|
}
|
|
}
|
|
|
|
static void
|
|
aucc_decode_ulaw_3ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
u_char *ch2 = dmap[2];
|
|
|
|
while (i--) {
|
|
*ch0++ = ulaw_to_lin[*p++];
|
|
*ch1++ = ulaw_to_lin[*p++];
|
|
*ch2++ = ulaw_to_lin[*p++];
|
|
}
|
|
}
|
|
|
|
static void
|
|
aucc_decode_ulaw_4ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
u_char *ch2 = dmap[2];
|
|
u_char *ch3 = dmap[3];
|
|
|
|
while (i--) {
|
|
*ch0++ = ulaw_to_lin[*p++];
|
|
*ch1++ = ulaw_to_lin[*p++];
|
|
*ch2++ = ulaw_to_lin[*p++];
|
|
*ch3++ = ulaw_to_lin[*p++];
|
|
}
|
|
}
|
|
|
|
|
|
/* 14bit output */
|
|
static void
|
|
aucc_decode_slinear16_1ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch3 = dmap[1]; /* XXX should be 3 */
|
|
|
|
while (i--) {
|
|
*ch0++ = *p++;
|
|
*ch3++ = *p++ >> 2;
|
|
}
|
|
}
|
|
|
|
/* 14bit stereo output */
|
|
static void
|
|
aucc_decode_slinear16_2ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
u_char *ch2 = dmap[2];
|
|
u_char *ch3 = dmap[3];
|
|
|
|
while (i--) {
|
|
*ch0++ = *p++;
|
|
*ch3++ = *p++ >> 2;
|
|
*ch1++ = *p++;
|
|
*ch2++ = *p++ >> 2;
|
|
}
|
|
}
|
|
|
|
static void
|
|
aucc_decode_slinear16_3ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
u_char *ch2 = dmap[2];
|
|
|
|
while (i--) {
|
|
*ch0++ = *p++; p++;
|
|
*ch1++ = *p++; p++;
|
|
*ch2++ = *p++; p++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
aucc_decode_slinear16_4ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
u_char *ch2 = dmap[2];
|
|
u_char *ch3 = dmap[3];
|
|
|
|
while (i--) {
|
|
*ch0++ = *p++; p++;
|
|
*ch1++ = *p++; p++;
|
|
*ch2++ = *p++; p++;
|
|
*ch3++ = *p++; p++;
|
|
}
|
|
}
|
|
|
|
/* 14bit output, swap bytes */
|
|
static void
|
|
aucc_decode_slinear16sw_1ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch3 = dmap[1]; /* XXX should be 3 */
|
|
|
|
while (i--) {
|
|
*ch3++ = *p++ >> 2;
|
|
*ch0++ = *p++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
aucc_decode_slinear16sw_2ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
u_char *ch2 = dmap[2];
|
|
u_char *ch3 = dmap[3];
|
|
|
|
while (i--) {
|
|
*ch3++ = *p++ >> 2;
|
|
*ch0++ = *p++;
|
|
*ch2++ = *p++ >> 2;
|
|
*ch1++ = *p++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
aucc_decode_slinear16sw_3ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
u_char *ch2 = dmap[2];
|
|
|
|
while (i--) {
|
|
p++; *ch0++ = *p++;
|
|
p++; *ch1++ = *p++;
|
|
p++; *ch2++ = *p++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
aucc_decode_slinear16sw_4ch(u_char **dmap, u_char *p, int i)
|
|
{
|
|
u_char *ch0 = dmap[0];
|
|
u_char *ch1 = dmap[1];
|
|
u_char *ch2 = dmap[2];
|
|
u_char *ch3 = dmap[3];
|
|
|
|
while (i--) {
|
|
p++; *ch0++ = *p++;
|
|
p++; *ch1++ = *p++;
|
|
p++; *ch2++ = *p++;
|
|
p++; *ch3++ = *p++;
|
|
}
|
|
}
|
|
|
|
|
|
#endif /* NAUCC > 0 */
|