⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcm86.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * PC-9801-86 PCM driver for FreeBSD(98). * * Copyright (c) 1995  NAGAO Tadaaki (ABTK) * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AND CONTRIBUTORS 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. * * $FreeBSD: src/sys/i386/isa/sound/pcm86.c,v 1.1.2.2 1999/09/05 08:14:06 peter Exp $ *//* * !! NOTE !! : *   This file DOES NOT belong to the VoxWare distribution though it works *   as part of the VoxWare drivers.  It is FreeBSD(98) original. *   -- Nagao (nagao@cs.titech.ac.jp) */#include <i386/isa/sound/sound_config.h>#ifdef CONFIGURE_SOUNDCARD#if !defined(EXCLUDE_PCM86) && !defined(EXCLUDE_AUDIO)/* * Constants */#define YES		1#define NO		0#define IMODE_NONE	0#define IMODE_INPUT	1#define IMODE_OUTPUT	2/* PC-9801-86 specific constants */#define	PCM86_IOBASE	0xa460	/* PCM I/O ports */#define PCM86_FIFOSIZE	32768	/* There is a 32kB FIFO buffer on 86-board *//* XXX -- These values should be chosen appropriately. */#define PCM86_INTRSIZE_OUT	1024#define PCM86_INTRSIZE_IN	(PCM86_FIFOSIZE / 2 - 128)#define DEFAULT_VOLUME		15	/* 0(min) - 15(max) *//* * Switches for debugging and experiments *//* #define PCM86_DEBUG */#ifdef PCM86_DEBUG# ifdef DEB#  undef DEB# endif# define DEB(x) x#endif/* * Private variables and types */typedef unsigned char pcm_data;enum board_type {    NO_SUPPORTED_BOARD = 0,    PC980186_FAMILY = 1,    PC980173_FAMILY = 2};static char *board_name[] = {    /* Each must be of the length less than 32 bytes. */    "No supported board",    "PC-9801-86 soundboard",    "PC-9801-73 soundboard"};/* Current status of the driver */static struct {    int			iobase;    int			irq;    enum board_type	board_type;    int			opened;    int			format;    int			bytes;    int			chipspeedno;    int			chipspeed;    int			speed;    int			stereo;    int			volume;    int			intr_busy;    int			intr_size;    int			intr_mode;    int			intr_last;    int			intr_trailer;    pcm_data *		pdma_buf;    int			pdma_count;    int			pdma_chunkcount;    int			acc;    int			last_l;    int			last_r;} pcm_s;static struct {    pcm_data		buff[4];    int			size;} tmpbuf;static int my_dev = 0;static char pcm_initialized = NO;/* 86-board supports only the following rates. */static int rates_tbl[8] = {#ifndef WAVEMASTER_FREQ    44100, 33075, 22050, 16538, 11025, 8269, 5513, 4134#else    /*     * It is said that Q-Vision's WaveMaster of some earlier lot(s?) has     * sampling rates incompatible with PC-9801-86.     * But I'm not sure whether the following rates are correct, especially     * 4000Hz.     */    44100, 33075, 22050, 16000, 11025, 8000, 5510, 4000#endif};/* u-law to linear translation table */static pcm_data ulaw2linear[256] = {    130, 134, 138, 142, 146, 150, 154, 158,     162, 166, 170, 174, 178, 182, 186, 190,     193, 195, 197, 199, 201, 203, 205, 207,     209, 211, 213, 215, 217, 219, 221, 223,     225, 226, 227, 228, 229, 230, 231, 232,     233, 234, 235, 236, 237, 238, 239, 240,     240, 241, 241, 242, 242, 243, 243, 244,     244, 245, 245, 246, 246, 247, 247, 248,     248, 248, 249, 249, 249, 249, 250, 250,     250, 250, 251, 251, 251, 251, 252, 252,     252, 252, 252, 252, 253, 253, 253, 253,     253, 253, 253, 253, 254, 254, 254, 254,     254, 254, 254, 254, 254, 254, 254, 254,     255, 255, 255, 255, 255, 255, 255, 255,     255, 255, 255, 255, 255, 255, 255, 255,     255, 255, 255, 255, 255, 255, 255, 255,     125, 121, 117, 113, 109, 105, 101,  97,      93,  89,  85,  81,  77,  73,  69,  65,      62,  60,  58,  56,  54,  52,  50,  48,      46,  44,  42,  40,  38,  36,  34,  32,      30,  29,  28,  27,  26,  25,  24,  23,      22,  21,  20,  19,  18,  17,  16,  15,      15,  14,  14,  13,  13,  12,  12,  11,      11,  10,  10,   9,   9,   8,   8,   7,       7,   7,   6,   6,   6,   6,   5,   5,       5,   5,   4,   4,   4,   4,   3,   3,       3,   3,   3,   3,   2,   2,   2,   2,       2,   2,   2,   2,   1,   1,   1,   1,       1,   1,   1,   1,   1,   1,   1,   1,       0,   0,   0,   0,   0,   0,   0,   0,       0,   0,   0,   0,   0,   0,   0,   0,       0,   0,   0,   0,   0,   0,   0,   0};/* linear to u-law translation table */static pcm_data linear2ulaw[256] = {    255, 231, 219, 211, 205, 201, 197, 193,     190, 188, 186, 184, 182, 180, 178, 176,     175, 174, 173, 172, 171, 170, 169, 168,     167, 166, 165, 164, 163, 162, 161, 160,     159, 159, 158, 158, 157, 157, 156, 156,     155, 155, 154, 154, 153, 153, 152, 152,     151, 151, 150, 150, 149, 149, 148, 148,     147, 147, 146, 146, 145, 145, 144, 144,     143, 143, 143, 143, 142, 142, 142, 142,     141, 141, 141, 141, 140, 140, 140, 140,     139, 139, 139, 139, 138, 138, 138, 138,     137, 137, 137, 137, 136, 136, 136, 136,     135, 135, 135, 135, 134, 134, 134, 134,     133, 133, 133, 133, 132, 132, 132, 132,     131, 131, 131, 131, 130, 130, 130, 130,     129, 129, 129, 129, 128, 128, 128, 128,       0,   0,   0,   0,   0,   1,   1,   1,       1,   2,   2,   2,   2,   3,   3,   3,       3,   4,   4,   4,   4,   5,   5,   5,       5,   6,   6,   6,   6,   7,   7,   7,       7,   8,   8,   8,   8,   9,   9,   9,       9,  10,  10,  10,  10,  11,  11,  11,      11,  12,  12,  12,  12,  13,  13,  13,      13,  14,  14,  14,  14,  15,  15,  15,      15,  16,  16,  17,  17,  18,  18,  19,      19,  20,  20,  21,  21,  22,  22,  23,      23,  24,  24,  25,  25,  26,  26,  27,      27,  28,  28,  29,  29,  30,  30,  31,      31,  32,  33,  34,  35,  36,  37,  38,      39,  40,  41,  42,  43,  44,  45,  46,      47,  48,  50,  52,  54,  56,  58,  60,      62,  65,  69,  73,  77,  83,  91, 103};/* * Prototypes */static int pcm86_detect(struct address_info *);static int pcm86_open(int, int);static void pcm86_close(int);static void pcm86_output_block(int, unsigned long, int, int, int);static void pcm86_start_input(int, unsigned long, int, int, int);static int pcm86_ioctl(int, unsigned int, unsigned int, int);static int pcm86_prepare_for_input(int, int, int);static int pcm86_prepare_for_output(int, int, int);static void pcm86_reset(int);static void pcm86_halt_xfer(int);static void dsp73_send_command(unsigned char);static void dsp73_send_data(unsigned char);static void dsp73_init(void);static int set_format(int);static int set_speed(int);static int set_stereo(int);static void set_volume(int);static void fifo_start(int);static void fifo_stop(void);static void fifo_reset(void);static void fifo_output_block(void);static int fifo_send(pcm_data *, int);static void fifo_sendtrailer(int);static void fifo_send_stereo(pcm_data *, int);static void fifo_send_monoral(pcm_data *, int);static void fifo_send_stereo_ulaw(pcm_data *, int);static void fifo_send_stereo_8(pcm_data *, int, int);static void fifo_send_stereo_16le(pcm_data *, int, int);static void fifo_send_stereo_16be(pcm_data *, int, int);static void fifo_send_mono_ulaw(pcm_data *, int);static void fifo_send_mono_8(pcm_data *, int, int);static void fifo_send_mono_16le(pcm_data *, int, int);static void fifo_send_mono_16be(pcm_data *, int, int);static void fifo_input_block(void);static void fifo_recv(pcm_data *, int);static void fifo_recv_stereo(pcm_data *, int);static void fifo_recv_monoral(pcm_data *, int);static void fifo_recv_stereo_ulaw(pcm_data *, int);static void fifo_recv_stereo_8(pcm_data *, int, int);static void fifo_recv_stereo_16le(pcm_data *, int, int);static void fifo_recv_stereo_16be(pcm_data *, int, int);static void fifo_recv_mono_ulaw(pcm_data *, int);static void fifo_recv_mono_8(pcm_data *, int, int);static void fifo_recv_mono_16le(pcm_data *, int, int);static void fifo_recv_mono_16be(pcm_data *, int, int);static void pcm_stop(void);static void pcm_init(void);/* * Identity */static struct audio_operations pcm86_operations ={    "PC-9801-86 SoundBoard", /* filled in properly by auto configuration */    NOTHING_SPECIAL,    ( AFMT_MU_LAW |      AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE |      AFMT_S8 | AFMT_U16_LE | AFMT_U16_BE ),    NULL,    pcm86_open,    pcm86_close,    pcm86_output_block,    pcm86_start_input,    pcm86_ioctl,    pcm86_prepare_for_input,    pcm86_prepare_for_output,    pcm86_reset,    pcm86_halt_xfer,    NULL,    NULL};/* * Codes for internal use */static voiddsp73_send_command(unsigned char command){    /* wait for RDY */    while ((inb(pcm_s.iobase + 2) & 0x48) != 8);    /* command mode */    outb(pcm_s.iobase + 2, (inb(pcm_s.iobase + 2) & 0x20) | 3);    /* wait for RDY */    while ((inb(pcm_s.iobase + 2) & 0x48) != 8);    /* send command */    outb(pcm_s.iobase + 4, command);}static voiddsp73_send_data(unsigned char data){    /* wait for RDY */    while ((inb(pcm_s.iobase + 2) & 0x48) != 8);    /* data mode */    outb(pcm_s.iobase + 2, (inb(pcm_s.iobase + 2) & 0x20) | 0x83);    /* wait for RDY */    while ((inb(pcm_s.iobase + 2) & 0x48) != 8);    /* send command */    outb(pcm_s.iobase + 4, data);}static voiddsp73_init(void){    const unsigned char dspinst[15] = {	0x00, 0x00, 0x27,	0x3f, 0xe0, 0x01,	0x00, 0x00, 0x27,	0x36, 0x5a, 0x0d,	0x3e, 0x60, 0x04    };    unsigned char t;    int i;    /* reset DSP */    t = inb(pcm_s.iobase + 2);    outb(pcm_s.iobase + 2, (t & 0x80) | 0x23);    /* mute on */    dsp73_send_command(0x04);    dsp73_send_data(0x6f);    dsp73_send_data(0x3c);    /* write DSP instructions */    dsp73_send_command(0x01);    dsp73_send_data(0x00);    for (i = 0; i < 16; i++)	dsp73_send_data(dspinst[i]);    /* mute off */    dsp73_send_command(0x04);    dsp73_send_data(0x6f);    dsp73_send_data(0x30);    /* wait for RDY */    while ((inb(pcm_s.iobase + 2) & 0x48) != 8);    outb(pcm_s.iobase + 2, 3);}static intset_format(int format){    switch (format) {    case AFMT_MU_LAW:    case AFMT_S8:    case AFMT_U8:	pcm_s.format = format;	pcm_s.bytes = 1;	/* 8bit */	break;    case AFMT_S16_LE:    case AFMT_U16_LE:    case AFMT_S16_BE:    case AFMT_U16_BE:	pcm_s.format = format;	pcm_s.bytes = 2;	/* 16bit */	break;    case AFMT_QUERY:	break;    default:	return -1;    }    return pcm_s.format;}static intset_speed(int speed){    int i;    if (speed < 4000)	/* Minimum 4000Hz */	speed = 4000;    if (speed > 44100)	/* Maximum 44100Hz */	speed = 44100;    for (i = 7; i >= 0; i--) {	if (speed <= rates_tbl[i]) {	    pcm_s.chipspeedno = i;	    pcm_s.chipspeed = rates_tbl[i];	    break;	}    }    pcm_s.speed = speed;    return speed;}static intset_stereo(int stereo){    pcm_s.stereo = stereo ? YES : NO;    return pcm_s.stereo;}static voidset_volume(int volume){    if (volume < 0)	volume = 0;    if (volume > 15)	volume = 15;    pcm_s.volume = volume;    outb(pcm_s.iobase + 6, 0xaf - volume);	/* D/A -> LINE OUT */    outb(0x5f,0);    outb(0x5f,0);    outb(0x5f,0);    outb(0x5f,0);    outb(pcm_s.iobase + 6, 0x20);		/* FM -> A/D */    outb(0x5f,0);    outb(0x5f,0);    outb(0x5f,0);    outb(0x5f,0);    outb(pcm_s.iobase + 6, 0x60);		/* LINE IN -> A/D */    outb(0x5f,0);    outb(0x5f,0);    outb(0x5f,0);    outb(0x5f,0);}static voidfifo_start(int mode){    unsigned char tmp;    /* Set frame length & panpot(LR). */    tmp = inb(pcm_s.iobase + 10) & 0x88;    outb(pcm_s.iobase + 10, tmp | ((pcm_s.bytes == 1) ? 0x72 : 0x32));    tmp = pcm_s.chipspeedno;    if (mode == IMODE_INPUT)	tmp |= 0x40;    /* Reset intr. flag. */    outb(pcm_s.iobase + 8, tmp);    outb(pcm_s.iobase + 8, tmp | 0x10);    /* Enable FIFO intr. */    outb(pcm_s.iobase + 8, tmp | 0x30);    /* Set intr. interval. */    outb(pcm_s.iobase + 10, pcm_s.intr_size / 128 - 1);    /* Start intr. */    outb(pcm_s.iobase + 8, tmp | 0xb0);}static voidfifo_stop(void){    unsigned char tmp;    /* Reset intr. flag, and disable FIFO intr. */    tmp = inb(pcm_s.iobase + 8) & 0x0f;    outb(pcm_s.iobase + 8, tmp);}static voidfifo_reset(void){    unsigned char tmp;    /* Reset FIFO. */    tmp = inb(pcm_s.iobase + 8) & 0x77;    outb(pcm_s.iobase + 8, tmp | 0x8);    outb(pcm_s.iobase + 8, tmp);}static voidfifo_output_block(void){    int chunksize, count;    if (pcm_s.pdma_chunkcount) {	/* Update chunksize and then send the next chunk to FIFO. */	chunksize = pcm_s.pdma_count / pcm_s.pdma_chunkcount--;	count = fifo_send(pcm_s.pdma_buf, chunksize);    } else {	/* ??? something wrong... */	printk("pcm0: chunkcount overrun\n");	chunksize = count = 0;    }    if (((audio_devs[my_dev]->dmap->qlen < 2) && (pcm_s.pdma_chunkcount == 0))	|| (count < pcm_s.intr_size)) {	/* The sent chunk seems to be the last one. */	fifo_sendtrailer(pcm_s.intr_size);	pcm_s.intr_last = YES;    }    pcm_s.pdma_buf += chunksize;    pcm_s.pdma_count -= chunksize;}static intfifo_send(pcm_data *buf, int count){    int i, length, r, cnt, rslt;    pcm_data *p;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -