summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authorasami <asami@FreeBSD.org>1996-11-02 10:41:28 +0000
committerasami <asami@FreeBSD.org>1996-11-02 10:41:28 +0000
commit223875ec7d51de4b686f9069a84494af29734cf6 (patch)
tree9675654af532c3965b39dbb0dd6f132eab3714d7 /sys/i386
parent2ccb731676c10d2eff50861371a9cb4cdb505e81 (diff)
downloadFreeBSD-src-223875ec7d51de4b686f9069a84494af29734cf6.zip
FreeBSD-src-223875ec7d51de4b686f9069a84494af29734cf6.tar.gz
The last update/merge of PC98 stuff before 2.2. The whole
pc98/pc98/sound directory has vanished now! Submitted by: FreeBSD(98) Development Team
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/isa/lptreg.h26
-rw-r--r--sys/i386/isa/sound/ad1848.c56
-rw-r--r--sys/i386/isa/sound/opl3.c8
-rw-r--r--sys/i386/isa/sound/pas2_pcm.c4
-rw-r--r--sys/i386/isa/sound/pcm86.c2189
-rw-r--r--sys/i386/isa/sound/sb16_dsp.c24
-rw-r--r--sys/i386/isa/sound/sb16_midi.c6
-rw-r--r--sys/i386/isa/sound/sb_dsp.c29
-rw-r--r--sys/i386/isa/sound/sound_switch.c6
-rw-r--r--sys/i386/isa/sound/soundcard.c26
-rw-r--r--sys/i386/isa/wdreg.h33
11 files changed, 2404 insertions, 3 deletions
diff --git a/sys/i386/isa/lptreg.h b/sys/i386/isa/lptreg.h
index 9e10ba9..583e96f 100644
--- a/sys/i386/isa/lptreg.h
+++ b/sys/i386/isa/lptreg.h
@@ -6,7 +6,7 @@
* William Jolitz.
*
* form: @(#)lptreg.h 1.1 (Berkeley) 12/19/90
- * $Id$
+ * $Id: lptreg.h,v 1.2 1993/10/16 13:46:12 rgrimes Exp $
*/
/*
@@ -16,6 +16,29 @@
* Copyright (C) William Jolitz 1990
*/
+/*
+ * modified for PC9801 by A.Kojima
+ * Kyoto University Microcomputer Club (KMC)
+ */
+
+#ifdef PC98
+#define lpt_pstb_ctrl (-9) /* PSTB enable control */
+#define LPC_EN_PSTB 0xc /* PSTB enable */
+#define LPC_DIS_PSTB 0xd /* PSTB disable */
+
+#define lpt_data 0 /* Data to/from printer (R/W) */
+
+#define lpt_status 2 /* Status of printer (R) */
+#define LPS_NBSY 0x4 /* printer no ack of data */
+
+#define lpt_control 6 /* Control printer (W) */
+#define LPC_MODE8255 0x82 /* 8255 mode */
+#define LPC_IRQ8 0x6 /* IRQ8 active */
+#define LPC_NIRQ8 0x7 /* IRQ8 inactive */
+#define LPC_PSTB 0xe /* PSTB active */
+#define LPC_NPSTB 0xf /* PSTB inactive */
+
+#else /* IBM-PC */
#define lpt_data 0 /* Data to/from printer (R/W) */
#define lpt_status 1 /* Status of printer (R) */
@@ -30,4 +53,5 @@
#define LPC_AUTOL 0x02 /* automatic linefeed */
#define LPC_NINIT 0x04 /* initialize printer */
#define LPC_SEL 0x08 /* printer selected */
+#endif
#define LPC_ENA 0x10 /* printer out of paper */
diff --git a/sys/i386/isa/sound/ad1848.c b/sys/i386/isa/sound/ad1848.c
index 8c385bd..0dc5464 100644
--- a/sys/i386/isa/sound/ad1848.c
+++ b/sys/i386/isa/sound/ad1848.c
@@ -157,9 +157,15 @@ wait_for_calibration (ad1848_info * devc)
*/
timeout = 100000;
+#ifdef PC98
+ while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)
+ timeout--;
+ if ((INB (devc->base) & 0x80) == 0x80)
+#else
while (timeout > 0 && INB (devc->base) & 0x80)
timeout--;
if (INB (devc->base) & 0x80)
+#endif
printk ("ad1848: Auto calibration timed out(1).\n");
timeout = 100;
@@ -474,7 +480,11 @@ static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] =
{
{
"Generic AD1848 codec",
+#ifdef PC98
+ NEEDS_RESTART,
+#else
DMA_AUTOMODE,
+#endif
AFMT_U8, /* Will be set later */
NULL,
ad1848_open,
@@ -910,8 +920,22 @@ ad1848_prepare_for_IO (int dev, int bsize, int bcount)
* Write to I8 starts resyncronization. Wait until it completes.
*/
timeout = 10000;
+#ifdef PC98
+ while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)
+#else
while (timeout > 0 && INB (devc->base) == 0x80)
+#endif
+ timeout--;
+
+#ifdef PC98
+ ad_write (devc, 8, fs);
+ /*
+ * Write to I8 starts resyncronization. Wait until it completes.
+ */
+ timeout = 10000;
+ while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)
timeout--;
+#endif
/*
* If mode == 2 (CS4231), set I28 also. It's the capture format register.
@@ -924,11 +948,26 @@ ad1848_prepare_for_IO (int dev, int bsize, int bcount)
* Write to I28 starts resyncronization. Wait until it completes.
*/
timeout = 10000;
+#ifdef PC98
+ while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)
+#else
while (timeout > 0 && INB (devc->base) == 0x80)
+#endif
timeout--;
}
+#ifdef PC98
+ ad_write (devc, 28, fs);
+
+ /*
+ * Write to I28 starts resyncronization. Wait until it completes.
+ */
+ timeout = 10000;
+ while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)
+ timeout--;
+#endif
+
ad_leave_MCE (devc); /*
* Starts the calibration process and
* enters playback mode after it.
@@ -950,7 +989,13 @@ ad1848_halt (int dev)
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
ad_mute (devc);
+#ifdef PC98
+ ad_enter_MCE (devc);
+#endif
ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */
+#ifdef PC98
+ ad_leave_MCE (devc);
+#endif
OUTB (0, io_Status (devc)); /* Clear interrupt status */
ad_enter_MCE (devc);
@@ -1399,7 +1444,11 @@ probe_ms_sound (struct address_info *hw_config)
return 0;
}
+#ifdef PC98
+ if (hw_config->irq > 12)
+#else
if (hw_config->irq > 11)
+#endif
{
printk ("MSS: Bad IRQ %d\n", hw_config->irq);
return 0;
@@ -1433,10 +1482,17 @@ probe_ms_sound (struct address_info *hw_config)
long
attach_ms_sound (long mem_start, struct address_info *hw_config)
{
+#ifdef PC98
+ static char interrupt_bits[13] =
+ {
+ -1, -1, -1, 0x08, -1, 0x10, -1, -1, -1, -1, 0x18, -1, 0x20
+ };
+#else
static char interrupt_bits[12] =
{
-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
};
+#endif
char bits;
static char dma_bits[4] =
diff --git a/sys/i386/isa/sound/opl3.c b/sys/i386/isa/sound/opl3.c
index b3660b7..42379cd 100644
--- a/sys/i386/isa/sound/opl3.c
+++ b/sys/i386/isa/sound/opl3.c
@@ -47,7 +47,11 @@
static int opl3_enabled = 0;
static int opl4_enabled = 0;
+#ifdef PC98
+static int left_address = 0x28d2, right_address = 0x28d2, both_address = 0;
+#else
static int left_address = 0x388, right_address = 0x388, both_address = 0;
+#endif
static int nr_voices = 9;
static int logical_voices[MAX_VOICE] =
@@ -812,10 +816,14 @@ opl3_command (int io_addr, unsigned int addr, unsigned int val)
for (i = 0; i < 2; i++)
INB (io_addr);
+#ifdef PC98
+ OUTB ((unsigned char) (val & 0xff), io_addr + 0x100);
+#else
OUTB ((unsigned char) (val & 0xff), io_addr + 1); /*
* Write to register
*
*/
+#endif
if (!opl3_enabled)
{
diff --git a/sys/i386/isa/sound/pas2_pcm.c b/sys/i386/isa/sound/pas2_pcm.c
index 97ae76c..db91165 100644
--- a/sys/i386/isa/sound/pas2_pcm.c
+++ b/sys/i386/isa/sound/pas2_pcm.c
@@ -377,7 +377,11 @@ pas_pcm_prepare_for_output (int dev, int bsize, int bcount)
static struct audio_operations pas_pcm_operations =
{
"Pro Audio Spectrum",
+#ifdef PC98
+ NEEDS_RESTART,
+#else
DMA_AUTOMODE,
+#endif
AFMT_U8 | AFMT_S16_LE,
NULL,
pas_pcm_open,
diff --git a/sys/i386/isa/sound/pcm86.c b/sys/i386/isa/sound/pcm86.c
new file mode 100644
index 0000000..aa7e3d7
--- /dev/null
+++ b/sys/i386/isa/sound/pcm86.c
@@ -0,0 +1,2189 @@
+/*
+ * 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.
+ *
+ * $Id: pcm86.c,v 2.4 1996/01/24 19:53:34 abtk 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 void
+dsp73_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 void
+dsp73_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 void
+dsp73_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 int
+set_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 int
+set_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 int
+set_stereo(int stereo)
+{
+ pcm_s.stereo = stereo ? YES : NO;
+
+ return pcm_s.stereo;
+}
+
+
+static void
+set_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 void
+fifo_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 void
+fifo_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 void
+fifo_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 void
+fifo_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 int
+fifo_send(pcm_data *buf, int count)
+{
+ int i, length, r, cnt, rslt;
+ pcm_data *p;
+
+ /* Calculate the length of PCM frames. */
+ cnt = count + tmpbuf.size;
+ length = pcm_s.bytes << pcm_s.stereo;
+ r = cnt % length;
+ cnt -= r;
+
+ if (cnt > 0) {
+ if (pcm_s.stereo)
+ fifo_send_stereo(buf, cnt);
+ else
+ fifo_send_monoral(buf, cnt);
+ /* Carry over extra data which doesn't seem to be a full PCM frame. */
+ p = (pcm_data *)buf + count - r;
+ for (i = 0; i < r; i++)
+ tmpbuf.buff[i] = *p++;
+ } else {
+ /* Carry over extra data which doesn't seem to be a full PCM frame. */
+ p = (pcm_data *)buf;
+ for (i = tmpbuf.size; i < r; i++)
+ tmpbuf.buff[i] = *p++;
+ }
+ tmpbuf.size = r;
+
+ rslt = ((cnt / length) * pcm_s.chipspeed / pcm_s.speed) * pcm_s.bytes * 2;
+#ifdef PCM86_DEBUG
+ printk("fifo_send(): %d bytes sent\n", rslt);
+#endif
+ return rslt;
+}
+
+
+static void
+fifo_sendtrailer(int count)
+{
+ /* Send trailing zeros to the FIFO buffer. */
+ int i;
+
+ for (i = 0; i < count; i++)
+ outb(pcm_s.iobase + 12, 0);
+ pcm_s.intr_trailer = YES;
+
+#ifdef PCM86_DEBUG
+ printk("fifo_sendtrailer(): %d bytes sent\n", count);
+#endif
+}
+
+
+static void
+fifo_send_stereo(pcm_data *buf, int count)
+{
+ /* Convert format and sampling speed. */
+ switch (pcm_s.format) {
+ case AFMT_MU_LAW:
+ fifo_send_stereo_ulaw(buf, count);
+ break;
+ case AFMT_S8:
+ fifo_send_stereo_8(buf, count, NO);
+ break;
+ case AFMT_U8:
+ fifo_send_stereo_8(buf, count, YES);
+ break;
+ case AFMT_S16_LE:
+ fifo_send_stereo_16le(buf, count, NO);
+ break;
+ case AFMT_U16_LE:
+ fifo_send_stereo_16le(buf, count, YES);
+ break;
+ case AFMT_S16_BE:
+ fifo_send_stereo_16be(buf, count, NO);
+ break;
+ case AFMT_U16_BE:
+ fifo_send_stereo_16be(buf, count, YES);
+ break;
+ }
+}
+
+
+static void
+fifo_send_monoral(pcm_data *buf, int count)
+{
+ /* Convert format and sampling speed. */
+ switch (pcm_s.format) {
+ case AFMT_MU_LAW:
+ fifo_send_mono_ulaw(buf, count);
+ break;
+ case AFMT_S8:
+ fifo_send_mono_8(buf, count, NO);
+ break;
+ case AFMT_U8:
+ fifo_send_mono_8(buf, count, YES);
+ break;
+ case AFMT_S16_LE:
+ fifo_send_mono_16le(buf, count, NO);
+ break;
+ case AFMT_U16_LE:
+ fifo_send_mono_16le(buf, count, YES);
+ break;
+ case AFMT_S16_BE:
+ fifo_send_mono_16be(buf, count, NO);
+ break;
+ case AFMT_U16_BE:
+ fifo_send_mono_16be(buf, count, YES);
+ break;
+ }
+}
+
+
+static void
+fifo_send_stereo_ulaw(pcm_data *buf, int count)
+{
+ int i;
+ signed char dl, dl0, dl1, dr, dr0, dr1;
+ pcm_data t[2];
+
+ if (tmpbuf.size > 0)
+ t[0] = ulaw2linear[tmpbuf.buff[0]];
+ else
+ t[0] = ulaw2linear[*buf++];
+ t[1] = ulaw2linear[*buf++];
+
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ outb(pcm_s.iobase + 12, t[0]);
+ outb(pcm_s.iobase + 12, t[1]);
+ count -= 2;
+ for (i = 0; i < count; i++)
+ outb(pcm_s.iobase + 12, ulaw2linear[*buf++]);
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ dl0 = pcm_s.last_l;
+ dr0 = pcm_s.last_r;
+ dl1 = t[0];
+ dr1 = t[1];
+ i = 0;
+ count /= 2;
+ while (i < count) {
+ while (pcm_s.acc >= pcm_s.chipspeed) {
+ pcm_s.acc -= pcm_s.chipspeed;
+ i++;
+ dl0 = dl1;
+ dr0 = dr1;
+ if (i < count) {
+ dl1 = ulaw2linear[*buf++];
+ dr1 = ulaw2linear[*buf++];
+ } else
+ dl1 = dr1 = 0;
+ }
+ dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
+ / pcm_s.chipspeed;
+ dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
+ / pcm_s.chipspeed;
+ outb(pcm_s.iobase + 12, dl);
+ outb(pcm_s.iobase + 12, dr);
+ pcm_s.acc += pcm_s.speed;
+ }
+
+ pcm_s.last_l = dl0;
+ pcm_s.last_r = dr0;
+ }
+}
+
+
+static void
+fifo_send_stereo_8(pcm_data *buf, int count, int uflag)
+{
+ int i;
+ signed char dl, dl0, dl1, dr, dr0, dr1, zlev;
+ pcm_data t[2];
+
+ zlev = uflag ? -128 : 0;
+
+ if (tmpbuf.size > 0)
+ t[0] = tmpbuf.buff[0] + zlev;
+ else
+ t[0] = *buf++ + zlev;
+ t[1] = *buf++ + zlev;
+
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ outb(pcm_s.iobase + 12, t[0]);
+ outb(pcm_s.iobase + 12, t[1]);
+ count -= 2;
+ for (i = 0; i < count; i++)
+ outb(pcm_s.iobase + 12, *buf++ + zlev);
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ dl0 = pcm_s.last_l;
+ dr0 = pcm_s.last_r;
+ dl1 = t[0];
+ dr1 = t[1];
+ i = 0;
+ count /= 2;
+ while (i < count) {
+ while (pcm_s.acc >= pcm_s.chipspeed) {
+ pcm_s.acc -= pcm_s.chipspeed;
+ i++;
+ dl0 = dl1;
+ dr0 = dr1;
+ if (i < count) {
+ dl1 = *buf++ + zlev;
+ dr1 = *buf++ + zlev;
+ } else
+ dl1 = dr1 = 0;
+ }
+ dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
+ / pcm_s.chipspeed;
+ dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
+ / pcm_s.chipspeed;
+ outb(pcm_s.iobase + 12, dl);
+ outb(pcm_s.iobase + 12, dr);
+ pcm_s.acc += pcm_s.speed;
+ }
+
+ pcm_s.last_l = dl0;
+ pcm_s.last_r = dr0;
+ }
+}
+
+
+static void
+fifo_send_stereo_16le(pcm_data *buf, int count, int uflag)
+{
+ int i;
+ short dl, dl0, dl1, dr, dr0, dr1, zlev;
+ pcm_data t[4];
+
+ zlev = uflag ? -128 : 0;
+
+ for (i = 0; i < 4; i++)
+ t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
+
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ outb(pcm_s.iobase + 12, t[1] + zlev);
+ outb(pcm_s.iobase + 12, t[0]);
+ outb(pcm_s.iobase + 12, t[3] + zlev);
+ outb(pcm_s.iobase + 12, t[2]);
+ count = count / 2 - 2;
+ for (i = 0; i < count; i++) {
+ outb(pcm_s.iobase + 12, *(buf + 1) + zlev);
+ outb(pcm_s.iobase + 12, *buf);
+ buf += 2;
+ }
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ dl0 = pcm_s.last_l;
+ dr0 = pcm_s.last_r;
+ dl1 = t[0] + ((t[1] + zlev) << 8);
+ dr1 = t[2] + ((t[3] + zlev) << 8);
+ i = 0;
+ count /= 4;
+ while (i < count) {
+ while (pcm_s.acc >= pcm_s.chipspeed) {
+ pcm_s.acc -= pcm_s.chipspeed;
+ i++;
+ dl0 = dl1;
+ dr0 = dr1;
+ if (i < count) {
+ dl1 = *buf + ((*(buf + 1) + zlev) << 8);
+ buf += 2;
+ dr1 = *buf + ((*(buf + 1) + zlev) << 8);
+ buf += 2;
+ } else
+ dl1 = dr1 = 0;
+ }
+ dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
+ / pcm_s.chipspeed;
+ dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
+ / pcm_s.chipspeed;
+ outb(pcm_s.iobase + 12, (dl >> 8) & 0xff);
+ outb(pcm_s.iobase + 12, dl & 0xff);
+ outb(pcm_s.iobase + 12, (dr >> 8) & 0xff);
+ outb(pcm_s.iobase + 12, dr & 0xff);
+ pcm_s.acc += pcm_s.speed;
+ }
+
+ pcm_s.last_l = dl0;
+ pcm_s.last_r = dr0;
+ }
+}
+
+
+static void
+fifo_send_stereo_16be(pcm_data *buf, int count, int uflag)
+{
+ int i;
+ short dl, dl0, dl1, dr, dr0, dr1, zlev;
+ pcm_data t[4];
+
+ zlev = uflag ? -128 : 0;
+
+ for (i = 0; i < 4; i++)
+ t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
+
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ outb(pcm_s.iobase + 12, t[0] + zlev);
+ outb(pcm_s.iobase + 12, t[1]);
+ outb(pcm_s.iobase + 12, t[2] + zlev);
+ outb(pcm_s.iobase + 12, t[3]);
+ count = count / 2 - 2;
+ for (i = 0; i < count; i++) {
+ outb(pcm_s.iobase + 12, *buf + zlev);
+ outb(pcm_s.iobase + 12, *(buf + 1));
+ buf += 2;
+ }
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ dl0 = pcm_s.last_l;
+ dr0 = pcm_s.last_r;
+ dl1 = ((t[0] + zlev) << 8) + t[1];
+ dr1 = ((t[2] + zlev) << 8) + t[3];
+ i = 0;
+ count /= 4;
+ while (i < count) {
+ while (pcm_s.acc >= pcm_s.chipspeed) {
+ pcm_s.acc -= pcm_s.chipspeed;
+ i++;
+ dl0 = dl1;
+ dr0 = dr1;
+ if (i < count) {
+ dl1 = ((*buf + zlev) << 8) + *(buf + 1);
+ buf += 2;
+ dr1 = ((*buf + zlev) << 8) + *(buf + 1);
+ buf += 2;
+ } else
+ dl1 = dr1 = 0;
+ }
+ dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
+ / pcm_s.chipspeed;
+ dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
+ / pcm_s.chipspeed;
+ outb(pcm_s.iobase + 12, (dl >> 8) & 0xff);
+ outb(pcm_s.iobase + 12, dl & 0xff);
+ outb(pcm_s.iobase + 12, (dr >> 8) & 0xff);
+ outb(pcm_s.iobase + 12, dr & 0xff);
+ pcm_s.acc += pcm_s.speed;
+ }
+
+ pcm_s.last_l = dl0;
+ pcm_s.last_r = dr0;
+ }
+}
+
+
+static void
+fifo_send_mono_ulaw(pcm_data *buf, int count)
+{
+ int i;
+ signed char d, d0, d1;
+
+ if (pcm_s.speed == pcm_s.chipspeed)
+ /* No reason to convert the pcm speed. */
+ for (i = 0; i < count; i++) {
+ d = ulaw2linear[*buf++];
+ outb(pcm_s.iobase + 12, d);
+ outb(pcm_s.iobase + 12, d);
+ }
+ else {
+ /* Speed conversion with linear interpolation method. */
+ d0 = pcm_s.last_l;
+ d1 = ulaw2linear[*buf++];
+ i = 0;
+ while (i < count) {
+ while (pcm_s.acc >= pcm_s.chipspeed) {
+ pcm_s.acc -= pcm_s.chipspeed;
+ i++;
+ d0 = d1;
+ d1 = (i < count) ? ulaw2linear[*buf++] : 0;
+ }
+ d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
+ / pcm_s.chipspeed;
+ outb(pcm_s.iobase + 12, d);
+ outb(pcm_s.iobase + 12, d);
+ pcm_s.acc += pcm_s.speed;
+ }
+
+ pcm_s.last_l = d0;
+ }
+}
+
+
+static void
+fifo_send_mono_8(pcm_data *buf, int count, int uflag)
+{
+ int i;
+ signed char d, d0, d1, zlev;
+
+ zlev = uflag ? -128 : 0;
+
+ if (pcm_s.speed == pcm_s.chipspeed)
+ /* No reason to convert the pcm speed. */
+ for (i = 0; i < count; i++) {
+ d = *buf++ + zlev;
+ outb(pcm_s.iobase + 12, d);
+ outb(pcm_s.iobase + 12, d);
+ }
+ else {
+ /* Speed conversion with linear interpolation method. */
+ d0 = pcm_s.last_l;
+ d1 = *buf++ + zlev;
+ i = 0;
+ while (i < count) {
+ while (pcm_s.acc >= pcm_s.chipspeed) {
+ pcm_s.acc -= pcm_s.chipspeed;
+ i++;
+ d0 = d1;
+ d1 = (i < count) ? *buf++ + zlev : 0;
+ }
+ d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
+ / pcm_s.chipspeed;
+ outb(pcm_s.iobase + 12, d);
+ outb(pcm_s.iobase + 12, d);
+ pcm_s.acc += pcm_s.speed;
+ }
+
+ pcm_s.last_l = d0;
+ }
+}
+
+
+static void
+fifo_send_mono_16le(pcm_data *buf, int count, int uflag)
+{
+ int i;
+ short d, d0, d1, zlev;
+ pcm_data t[2];
+
+ zlev = uflag ? -128 : 0;
+
+ for (i = 0; i < 2; i++)
+ t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
+
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ outb(pcm_s.iobase + 12, t[1] + zlev);
+ outb(pcm_s.iobase + 12, t[0]);
+ outb(pcm_s.iobase + 12, t[1] + zlev);
+ outb(pcm_s.iobase + 12, t[0]);
+ count = count / 2 - 1;
+ for (i = 0; i < count; i++) {
+ outb(pcm_s.iobase + 12, *(buf + 1) + zlev);
+ outb(pcm_s.iobase + 12, *buf);
+ outb(pcm_s.iobase + 12, *(buf + 1) + zlev);
+ outb(pcm_s.iobase + 12, *buf);
+ buf += 2;
+ }
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ d0 = pcm_s.last_l;
+ d1 = t[0] + ((t[1] + zlev) << 8);
+ i = 0;
+ count /= 2;
+ while (i < count) {
+ while (pcm_s.acc >= pcm_s.chipspeed) {
+ pcm_s.acc -= pcm_s.chipspeed;
+ i++;
+ d0 = d1;
+ if (i < count) {
+ d1 = *buf + ((*(buf + 1) + zlev) << 8);
+ buf += 2;
+ } else
+ d1 = 0;
+ }
+ d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
+ / pcm_s.chipspeed;
+ outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
+ outb(pcm_s.iobase + 12, d & 0xff);
+ outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
+ outb(pcm_s.iobase + 12, d & 0xff);
+ pcm_s.acc += pcm_s.speed;
+ }
+
+ pcm_s.last_l = d0;
+ }
+}
+
+
+static void
+fifo_send_mono_16be(pcm_data *buf, int count, int uflag)
+{
+ int i;
+ short d, d0, d1, zlev;
+ pcm_data t[2];
+
+ zlev = uflag ? -128 : 0;
+
+ for (i = 0; i < 2; i++)
+ t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
+
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ outb(pcm_s.iobase + 12, t[0] + zlev);
+ outb(pcm_s.iobase + 12, t[1]);
+ outb(pcm_s.iobase + 12, t[0] + zlev);
+ outb(pcm_s.iobase + 12, t[1]);
+ count = count / 2 - 1;
+ for (i = 0; i < count; i++) {
+ outb(pcm_s.iobase + 12, *buf + zlev);
+ outb(pcm_s.iobase + 12, *(buf + 1));
+ outb(pcm_s.iobase + 12, *buf + zlev);
+ outb(pcm_s.iobase + 12, *(buf + 1));
+ buf += 2;
+ }
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ d0 = pcm_s.last_l;
+ d1 = ((t[0] + zlev) << 8) + t[1];
+ i = 0;
+ count /= 2;
+ while (i < count) {
+ while (pcm_s.acc >= pcm_s.chipspeed) {
+ pcm_s.acc -= pcm_s.chipspeed;
+ i++;
+ d0 = d1;
+ if (i < count) {
+ d1 = ((*buf + zlev) << 8) + *(buf + 1);
+ buf += 2;
+ } else
+ d1 = 0;
+ }
+ d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
+ / pcm_s.chipspeed;
+ outb(pcm_s.iobase + 12, d & 0xff);
+ outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
+ outb(pcm_s.iobase + 12, d & 0xff);
+ outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
+ pcm_s.acc += pcm_s.speed;
+ }
+
+ pcm_s.last_l = d0;
+ }
+}
+
+
+static void
+fifo_input_block(void)
+{
+ int chunksize;
+
+ if (pcm_s.pdma_chunkcount) {
+ /* Update chunksize and then receive the next chunk from FIFO. */
+ chunksize = pcm_s.pdma_count / pcm_s.pdma_chunkcount--;
+ fifo_recv(pcm_s.pdma_buf, chunksize);
+ pcm_s.pdma_buf += chunksize;
+ pcm_s.pdma_count -= chunksize;
+ } else
+ /* ??? something wrong... */
+ printk("pcm0: chunkcount overrun\n");
+}
+
+
+static void
+fifo_recv(pcm_data *buf, int count)
+{
+ int i;
+
+ if (count > tmpbuf.size) {
+ for (i = 0; i < tmpbuf.size; i++)
+ *buf++ = tmpbuf.buff[i];
+ count -= tmpbuf.size;
+ tmpbuf.size = 0;
+ if (pcm_s.stereo)
+ fifo_recv_stereo(buf, count);
+ else
+ fifo_recv_monoral(buf, count);
+ } else {
+ for (i = 0; i < count; i++)
+ *buf++ = tmpbuf.buff[i];
+ for (i = 0; i < tmpbuf.size - count; i++)
+ tmpbuf.buff[i] = tmpbuf.buff[i + count];
+ tmpbuf.size -= count;
+ }
+
+#ifdef PCM86_DEBUG
+ printk("fifo_recv(): %d bytes received\n",
+ ((count / (pcm_s.bytes << pcm_s.stereo)) * pcm_s.chipspeed
+ / pcm_s.speed) * pcm_s.bytes * 2);
+#endif
+}
+
+
+static void
+fifo_recv_stereo(pcm_data *buf, int count)
+{
+ /* Convert format and sampling speed. */
+ switch (pcm_s.format) {
+ case AFMT_MU_LAW:
+ fifo_recv_stereo_ulaw(buf, count);
+ break;
+ case AFMT_S8:
+ fifo_recv_stereo_8(buf, count, NO);
+ break;
+ case AFMT_U8:
+ fifo_recv_stereo_8(buf, count, YES);
+ break;
+ case AFMT_S16_LE:
+ fifo_recv_stereo_16le(buf, count, NO);
+ break;
+ case AFMT_U16_LE:
+ fifo_recv_stereo_16le(buf, count, YES);
+ break;
+ case AFMT_S16_BE:
+ fifo_recv_stereo_16be(buf, count, NO);
+ break;
+ case AFMT_U16_BE:
+ fifo_recv_stereo_16be(buf, count, YES);
+ break;
+ }
+}
+
+
+static void
+fifo_recv_monoral(pcm_data *buf, int count)
+{
+ /* Convert format and sampling speed. */
+ switch (pcm_s.format) {
+ case AFMT_MU_LAW:
+ fifo_recv_mono_ulaw(buf, count);
+ break;
+ case AFMT_S8:
+ fifo_recv_mono_8(buf, count, NO);
+ break;
+ case AFMT_U8:
+ fifo_recv_mono_8(buf, count, YES);
+ break;
+ case AFMT_S16_LE:
+ fifo_recv_mono_16le(buf, count, NO);
+ break;
+ case AFMT_U16_LE:
+ fifo_recv_mono_16le(buf, count, YES);
+ break;
+ case AFMT_S16_BE:
+ fifo_recv_mono_16be(buf, count, NO);
+ break;
+ case AFMT_U16_BE:
+ fifo_recv_mono_16be(buf, count, YES);
+ break;
+ }
+}
+
+
+static void
+fifo_recv_stereo_ulaw(pcm_data *buf, int count)
+{
+ int i, cnt;
+ signed char dl, dl0, dl1, dr, dr0, dr1;
+
+ cnt = count / 2;
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ for (i = 0; i < cnt; i++) {
+ *buf++ = linear2ulaw[inb(pcm_s.iobase + 12)];
+ *buf++ = linear2ulaw[inb(pcm_s.iobase + 12)];
+ }
+ if (count % 2) {
+ *buf++ = linear2ulaw[inb(pcm_s.iobase + 12)];
+ tmpbuf.buff[0] = linear2ulaw[inb(pcm_s.iobase + 12)];
+ tmpbuf.size = 1;
+ }
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ dl0 = pcm_s.last_l;
+ dr0 = pcm_s.last_r;
+ dl1 = inb(pcm_s.iobase + 12);
+ dr1 = inb(pcm_s.iobase + 12);
+ for (i = 0; i < cnt; i++) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ dl0 = dl1;
+ dr0 = dr1;
+ dl1 = inb(pcm_s.iobase + 12);
+ dr1 = inb(pcm_s.iobase + 12);
+ }
+ dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
+ / pcm_s.speed;
+ dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
+ / pcm_s.speed;
+ *buf++ = linear2ulaw[dl & 0xff];
+ *buf++ = linear2ulaw[dr & 0xff];
+ pcm_s.acc += pcm_s.chipspeed;
+ }
+ if (count % 2) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ dl0 = dl1;
+ dr0 = dr1;
+ dl1 = inb(pcm_s.iobase + 12);
+ dr1 = inb(pcm_s.iobase + 12);
+ }
+ dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
+ / pcm_s.speed;
+ dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
+ / pcm_s.speed;
+ *buf++ = linear2ulaw[dl & 0xff];
+ tmpbuf.buff[0] = linear2ulaw[dr & 0xff];
+ tmpbuf.size = 1;
+ }
+
+ pcm_s.last_l = dl0;
+ pcm_s.last_r = dr0;
+ }
+}
+
+
+static void
+fifo_recv_stereo_8(pcm_data *buf, int count, int uflag)
+{
+ int i, cnt;
+ signed char dl, dl0, dl1, dr, dr0, dr1, zlev;
+
+ zlev = uflag ? -128 : 0;
+
+ cnt = count / 2;
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ for (i = 0; i < cnt; i++) {
+ *buf++ = inb(pcm_s.iobase + 12) + zlev;
+ *buf++ = inb(pcm_s.iobase + 12) + zlev;
+ }
+ if (count % 2) {
+ *buf++ = inb(pcm_s.iobase + 12) + zlev;
+ tmpbuf.buff[0] = inb(pcm_s.iobase + 12) + zlev;
+ tmpbuf.size = 1;
+ }
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ dl0 = pcm_s.last_l;
+ dr0 = pcm_s.last_r;
+ dl1 = inb(pcm_s.iobase + 12);
+ dr1 = inb(pcm_s.iobase + 12);
+ for (i = 0; i < cnt; i++) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ dl0 = dl1;
+ dr0 = dr1;
+ dl1 = inb(pcm_s.iobase + 12);
+ dr1 = inb(pcm_s.iobase + 12);
+ }
+ dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
+ / pcm_s.speed;
+ dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
+ / pcm_s.speed;
+ *buf++ = dl + zlev;
+ *buf++ = dr + zlev;
+ pcm_s.acc += pcm_s.chipspeed;
+ }
+ if (count % 2) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ dl0 = dl1;
+ dr0 = dr1;
+ dl1 = inb(pcm_s.iobase + 12);
+ dr1 = inb(pcm_s.iobase + 12);
+ }
+ dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
+ / pcm_s.speed;
+ dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
+ / pcm_s.speed;
+ *buf++ = dl + zlev;
+ tmpbuf.buff[0] = dr + zlev;
+ tmpbuf.size = 1;
+ }
+
+ pcm_s.last_l = dl0;
+ pcm_s.last_r = dr0;
+ }
+}
+
+
+static void
+fifo_recv_stereo_16le(pcm_data *buf, int count, int uflag)
+{
+ int i, cnt;
+ short dl, dl0, dl1, dr, dr0, dr1, zlev;
+ pcm_data t[4];
+
+ zlev = uflag ? -128 : 0;
+
+ cnt = count / 4;
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ for (i = 0; i < cnt; i++) {
+ *(buf + 1) = inb(pcm_s.iobase + 12) + zlev;
+ *buf = inb(pcm_s.iobase + 12);
+ *(buf + 3) = inb(pcm_s.iobase + 12) + zlev;
+ *(buf + 2) = inb(pcm_s.iobase + 12);
+ buf += 4;
+ }
+ if (count % 4) {
+ t[1] = inb(pcm_s.iobase + 12) + zlev;
+ t[0] = inb(pcm_s.iobase + 12);
+ t[3] = inb(pcm_s.iobase + 12) + zlev;
+ t[2] = inb(pcm_s.iobase + 12);
+ tmpbuf.size = 0;
+ for (i = 0; i < count % 4; i++)
+ *buf++ = t[i];
+ for (i = count % 4; i < 4; i++)
+ tmpbuf.buff[tmpbuf.size++] = t[i];
+ }
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ dl0 = pcm_s.last_l;
+ dr0 = pcm_s.last_r;
+ dl1 = inb(pcm_s.iobase + 12) << 8;
+ dl1 |= inb(pcm_s.iobase + 12);
+ dr1 = inb(pcm_s.iobase + 12) << 8;
+ dr1 |= inb(pcm_s.iobase + 12);
+ for (i = 0; i < cnt; i++) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ dl0 = dl1;
+ dr0 = dr1;
+ dl1 = inb(pcm_s.iobase + 12) << 8;
+ dl1 |= inb(pcm_s.iobase + 12);
+ dr1 = inb(pcm_s.iobase + 12) << 8;
+ dr1 |= inb(pcm_s.iobase + 12);
+ }
+ dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
+ / pcm_s.speed;
+ dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
+ / pcm_s.speed;
+ *buf++ = dl & 0xff;
+ *buf++ = ((dl >> 8) & 0xff) + zlev;
+ *buf++ = dr & 0xff;
+ *buf++ = ((dr >> 8) & 0xff) + zlev;
+ pcm_s.acc += pcm_s.chipspeed;
+ }
+ if (count % 4) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ dl0 = dl1;
+ dr0 = dr1;
+ dl1 = inb(pcm_s.iobase + 12) << 8;
+ dl1 |= inb(pcm_s.iobase + 12);
+ dr1 = inb(pcm_s.iobase + 12) << 8;
+ dr1 |= inb(pcm_s.iobase + 12);
+ }
+ dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
+ / pcm_s.speed;
+ dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
+ / pcm_s.speed;
+ t[0] = dl & 0xff;
+ t[1] = ((dl >> 8) & 0xff) + zlev;
+ t[2] = dr & 0xff;
+ t[3] = ((dr >> 8) & 0xff) + zlev;
+ tmpbuf.size = 0;
+ for (i = 0; i < count % 4; i++)
+ *buf++ = t[i];
+ for (i = count % 4; i < 4; i++)
+ tmpbuf.buff[tmpbuf.size++] = t[i];
+ }
+
+ pcm_s.last_l = dl0;
+ pcm_s.last_r = dr0;
+ }
+}
+
+
+static void
+fifo_recv_stereo_16be(pcm_data *buf, int count, int uflag)
+{
+ int i, cnt;
+ short dl, dl0, dl1, dr, dr0, dr1, zlev;
+ pcm_data t[4];
+
+ zlev = uflag ? -128 : 0;
+
+ cnt = count / 4;
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ for (i = 0; i < cnt; i++) {
+ *buf++ = inb(pcm_s.iobase + 12) + zlev;
+ *buf++ = inb(pcm_s.iobase + 12);
+ *buf++ = inb(pcm_s.iobase + 12) + zlev;
+ *buf++ = inb(pcm_s.iobase + 12);
+ }
+ if (count % 4) {
+ t[0] = inb(pcm_s.iobase + 12) + zlev;
+ t[1] = inb(pcm_s.iobase + 12);
+ t[2] = inb(pcm_s.iobase + 12) + zlev;
+ t[3] = inb(pcm_s.iobase + 12);
+ tmpbuf.size = 0;
+ for (i = 0; i < count % 4; i++)
+ *buf++ = t[i];
+ for (i = count % 4; i < 4; i++)
+ tmpbuf.buff[tmpbuf.size++] = t[i];
+ }
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ dl0 = pcm_s.last_l;
+ dr0 = pcm_s.last_r;
+ dl1 = inb(pcm_s.iobase + 12) << 8;
+ dl1 |= inb(pcm_s.iobase + 12);
+ dr1 = inb(pcm_s.iobase + 12) << 8;
+ dr1 |= inb(pcm_s.iobase + 12);
+ for (i = 0; i < cnt; i++) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ dl0 = dl1;
+ dr0 = dr1;
+ dl1 = inb(pcm_s.iobase + 12) << 8;
+ dl1 |= inb(pcm_s.iobase + 12);
+ dr1 = inb(pcm_s.iobase + 12) << 8;
+ dr1 |= inb(pcm_s.iobase + 12);
+ }
+ dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
+ / pcm_s.speed;
+ dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
+ / pcm_s.speed;
+ *buf++ = ((dl >> 8) & 0xff) + zlev;
+ *buf++ = dl & 0xff;
+ *buf++ = ((dr >> 8) & 0xff) + zlev;
+ *buf++ = dr & 0xff;
+ pcm_s.acc += pcm_s.chipspeed;
+ }
+ if (count % 4) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ dl0 = dl1;
+ dr0 = dr1;
+ dl1 = inb(pcm_s.iobase + 12) << 8;
+ dl1 |= inb(pcm_s.iobase + 12);
+ dr1 = inb(pcm_s.iobase + 12) << 8;
+ dr1 |= inb(pcm_s.iobase + 12);
+ }
+ dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
+ / pcm_s.speed;
+ dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
+ / pcm_s.speed;
+ t[0] = ((dl >> 8) & 0xff) + zlev;
+ t[1] = dl & 0xff;
+ t[2] = ((dr >> 8) & 0xff) + zlev;
+ t[3] = dr & 0xff;
+ tmpbuf.size = 0;
+ for (i = 0; i < count % 4; i++)
+ *buf++ = t[i];
+ for (i = count % 4; i < 4; i++)
+ tmpbuf.buff[tmpbuf.size++] = t[i];
+ }
+
+ pcm_s.last_l = dl0;
+ pcm_s.last_r = dr0;
+ }
+}
+
+
+static void
+fifo_recv_mono_ulaw(pcm_data *buf, int count)
+{
+ int i;
+ signed char d, d0, d1;
+
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ for (i = 0; i < count; i++) {
+ d = ((signed char)inb(pcm_s.iobase + 12)
+ + (signed char)inb(pcm_s.iobase + 12)) >> 1;
+ *buf++ = linear2ulaw[d & 0xff];
+ }
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ d0 = pcm_s.last_l;
+ d1 = ((signed char)inb(pcm_s.iobase + 12)
+ + (signed char)inb(pcm_s.iobase + 12)) >> 1;
+ for (i = 0; i < count; i++) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ d0 = d1;
+ d1 = ((signed char)inb(pcm_s.iobase + 12)
+ + (signed char)inb(pcm_s.iobase + 12)) >> 1;
+ }
+ d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
+ / pcm_s.speed;
+ *buf++ = linear2ulaw[d & 0xff];
+ pcm_s.acc += pcm_s.chipspeed;
+ }
+
+ pcm_s.last_l = d0;
+ }
+}
+
+
+static void
+fifo_recv_mono_8(pcm_data *buf, int count, int uflag)
+{
+ int i;
+ signed char d, d0, d1, zlev;
+
+ zlev = uflag ? -128 : 0;
+
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ for (i = 0; i < count; i++) {
+ d = ((signed char)inb(pcm_s.iobase + 12)
+ + (signed char)inb(pcm_s.iobase + 12)) >> 1;
+ *buf++ = d + zlev;
+ }
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ d0 = pcm_s.last_l;
+ d1 = ((signed char)inb(pcm_s.iobase + 12)
+ + (signed char)inb(pcm_s.iobase + 12)) >> 1;
+ for (i = 0; i < count; i++) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ d0 = d1;
+ d1 = ((signed char)inb(pcm_s.iobase + 12)
+ + (signed char)inb(pcm_s.iobase + 12)) >> 1;
+ }
+ d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
+ / pcm_s.speed;
+ *buf++ = d + zlev;
+ pcm_s.acc += pcm_s.chipspeed;
+ }
+
+ pcm_s.last_l = d0;
+ }
+}
+
+
+static void
+fifo_recv_mono_16le(pcm_data *buf, int count, int uflag)
+{
+ int i, cnt;
+ short d, d0, d1, el, er, zlev;
+
+ zlev = uflag ? -128 : 0;
+
+ cnt = count / 2;
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ for (i = 0; i < cnt; i++) {
+ el = inb(pcm_s.iobase + 12) << 8;
+ el |= inb(pcm_s.iobase + 12);
+ er = inb(pcm_s.iobase + 12) << 8;
+ er |= inb(pcm_s.iobase + 12);
+ d = (el + er) >> 1;
+ *buf++ = d & 0xff;
+ *buf++ = ((d >> 8) & 0xff) + zlev;
+ }
+ if (count % 2) {
+ el = inb(pcm_s.iobase + 12) << 8;
+ el |= inb(pcm_s.iobase + 12);
+ er = inb(pcm_s.iobase + 12) << 8;
+ er |= inb(pcm_s.iobase + 12);
+ d = (el + er) >> 1;
+ *buf++ = d & 0xff;
+ tmpbuf.buff[0] = ((d >> 8) & 0xff) + zlev;
+ tmpbuf.size = 1;
+ }
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ d0 = pcm_s.last_l;
+ el = inb(pcm_s.iobase + 12) << 8;
+ el |= inb(pcm_s.iobase + 12);
+ er = inb(pcm_s.iobase + 12) << 8;
+ er |= inb(pcm_s.iobase + 12);
+ d1 = (el + er) >> 1;
+ for (i = 0; i < cnt; i++) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ d0 = d1;
+ el = inb(pcm_s.iobase + 12) << 8;
+ el |= inb(pcm_s.iobase + 12);
+ er = inb(pcm_s.iobase + 12) << 8;
+ er |= inb(pcm_s.iobase + 12);
+ d1 = (el + er) >> 1;
+ }
+ d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
+ / pcm_s.speed;
+ *buf++ = d & 0xff;
+ *buf++ = ((d >> 8) & 0xff) + zlev;
+ pcm_s.acc += pcm_s.chipspeed;
+ }
+ if (count % 2) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ d0 = d1;
+ el = inb(pcm_s.iobase + 12) << 8;
+ el |= inb(pcm_s.iobase + 12);
+ er = inb(pcm_s.iobase + 12) << 8;
+ er |= inb(pcm_s.iobase + 12);
+ d1 = (el + er) >> 1;
+ }
+ d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
+ / pcm_s.speed;
+ *buf++ = d & 0xff;
+ tmpbuf.buff[0] = ((d >> 8) & 0xff) + zlev;
+ tmpbuf.size = 1;
+ }
+
+ pcm_s.last_l = d0;
+ }
+}
+
+
+static void
+fifo_recv_mono_16be(pcm_data *buf, int count, int uflag)
+{
+ int i, cnt;
+ short d, d0, d1, el, er, zlev;
+
+ zlev = uflag ? -128 : 0;
+
+ cnt = count / 2;
+ if (pcm_s.speed == pcm_s.chipspeed) {
+ /* No reason to convert the pcm speed. */
+ for (i = 0; i < cnt; i++) {
+ el = inb(pcm_s.iobase + 12) << 8;
+ el |= inb(pcm_s.iobase + 12);
+ er = inb(pcm_s.iobase + 12) << 8;
+ er |= inb(pcm_s.iobase + 12);
+ d = (el + er) >> 1;
+ *buf++ = ((d >> 8) & 0xff) + zlev;
+ *buf++ = d & 0xff;
+ }
+ if (count % 2) {
+ el = inb(pcm_s.iobase + 12) << 8;
+ el |= inb(pcm_s.iobase + 12);
+ er = inb(pcm_s.iobase + 12) << 8;
+ er |= inb(pcm_s.iobase + 12);
+ d = (el + er) >> 1;
+ *buf++ = ((d >> 8) & 0xff) + zlev;
+ tmpbuf.buff[0] = d & 0xff;
+ tmpbuf.size = 1;
+ }
+ } else {
+ /* Speed conversion with linear interpolation method. */
+ d0 = pcm_s.last_l;
+ el = inb(pcm_s.iobase + 12) << 8;
+ el |= inb(pcm_s.iobase + 12);
+ er = inb(pcm_s.iobase + 12) << 8;
+ er |= inb(pcm_s.iobase + 12);
+ d1 = (el + er) >> 1;
+ for (i = 0; i < cnt; i++) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ d0 = d1;
+ el = inb(pcm_s.iobase + 12) << 8;
+ el |= inb(pcm_s.iobase + 12);
+ er = inb(pcm_s.iobase + 12) << 8;
+ er |= inb(pcm_s.iobase + 12);
+ d1 = (el + er) >> 1;
+ }
+ d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
+ / pcm_s.speed;
+ *buf++ = ((d >> 8) & 0xff) + zlev;
+ *buf++ = d & 0xff;
+ pcm_s.acc += pcm_s.chipspeed;
+ }
+ if (count % 2) {
+ while (pcm_s.acc >= pcm_s.speed) {
+ pcm_s.acc -= pcm_s.speed;
+ d0 = d1;
+ el = inb(pcm_s.iobase + 12) << 8;
+ el |= inb(pcm_s.iobase + 12);
+ er = inb(pcm_s.iobase + 12) << 8;
+ er |= inb(pcm_s.iobase + 12);
+ d1 = (el + er) >> 1;
+ }
+ d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
+ / pcm_s.speed;
+ *buf++ = ((d >> 8) & 0xff) + zlev;
+ tmpbuf.buff[0] = d & 0xff;
+ tmpbuf.size = 1;
+ }
+
+ pcm_s.last_l = d0;
+ }
+}
+
+
+static void
+pcm_stop(void)
+{
+ fifo_stop(); /* stop FIFO */
+ fifo_reset(); /* reset FIFO buffer */
+
+ /* Reset driver's status. */
+ pcm_s.intr_busy = NO;
+ pcm_s.intr_last = NO;
+ pcm_s.intr_trailer = NO;
+ pcm_s.acc = 0;
+ pcm_s.last_l = 0;
+ pcm_s.last_r = 0;
+
+ DEB(printk("pcm_stop\n"));
+}
+
+
+static void
+pcm_init(void)
+{
+ /* Initialize registers on the board. */
+ pcm_stop();
+ if (pcm_s.board_type == PC980173_FAMILY)
+ dsp73_init();
+
+ /* Set default volume. */
+ set_volume(DEFAULT_VOLUME);
+
+ /* Initialize driver's status. */
+ pcm_s.opened = NO;
+ pcm_initialized = YES;
+}
+
+
+/*
+ * Codes for global use
+ */
+
+int
+probe_pcm86(struct address_info *hw_config)
+{
+ return pcm86_detect(hw_config);
+}
+
+
+long
+attach_pcm86(long mem_start, struct address_info *hw_config)
+{
+ if (pcm_s.board_type == NO_SUPPORTED_BOARD)
+ return mem_start;
+
+ /* Initialize the board. */
+ pcm_init();
+
+ printk("pcm0: <%s>", pcm86_operations.name);
+
+ if (num_audiodevs < MAX_AUDIO_DEV) {
+ my_dev = num_audiodevs++;
+ audio_devs[my_dev] = &pcm86_operations;
+ audio_devs[my_dev]->buffcount = DSP_BUFFCOUNT;
+ audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
+#ifdef PCM86_DEBUG
+ printk("\nbuffsize = %d", DSP_BUFFSIZE);
+#endif
+ } else
+ printk("pcm0: Too many PCM devices available");
+
+ return mem_start;
+}
+
+
+static int
+pcm86_detect(struct address_info *hw_config)
+{
+ int opna_iobase = 0x188, irq = 12, i;
+ unsigned char tmp;
+
+ if (hw_config->io_base == -1) {
+ printf("pcm0: iobase not specified. Assume default port(0x%x)\n",
+ PCM86_IOBASE);
+ hw_config->io_base = PCM86_IOBASE;
+ }
+ pcm_s.iobase = hw_config->io_base;
+
+ /* auto configuration */
+ tmp = inb(pcm_s.iobase) & 0xfc;
+ switch ((tmp & 0xf0) >> 4) {
+ case 2:
+ opna_iobase = 0x188;
+ pcm_s.board_type = PC980173_FAMILY;
+ break;
+ case 3:
+ opna_iobase = 0x288;
+ pcm_s.board_type = PC980173_FAMILY;
+ break;
+ case 4:
+ opna_iobase = 0x188;
+ pcm_s.board_type = PC980186_FAMILY;
+ break;
+ case 5:
+ opna_iobase = 0x288;
+ pcm_s.board_type = PC980186_FAMILY;
+ break;
+ default:
+ pcm_s.board_type = NO_SUPPORTED_BOARD;
+ return NO;
+ }
+
+ /* Enable OPNA(YM2608) facilities. */
+ outb(pcm_s.iobase, tmp | 0x01);
+
+ /* Wait for OPNA to be ready. */
+ i = 100000; /* Some large value */
+ while((inb(opna_iobase) & 0x80) && (i-- > 0));
+
+ /* Make IOA/IOB port ready (IOA:input, IOB:output) */
+ outb(opna_iobase, 0x07);
+ outb(0x5f, 0); /* Because OPNA ports are comparatively slow(?), */
+ outb(0x5f, 0); /* we'd better wait a moment. */
+ outb(0x5f, 0);
+ outb(0x5f, 0);
+ tmp = inb(opna_iobase + 2) & 0x3f;
+ outb(opna_iobase + 2, tmp | 0x80);
+
+ /* Wait for OPNA to be ready. */
+ i = 100000; /* Some large value */
+ while((inb(opna_iobase) & 0x80) && (i-- > 0));
+
+ /* Get irq number from IOA port. */
+ outb(opna_iobase, 0x0e);
+ outb(0x5f, 0);
+ outb(0x5f, 0);
+ outb(0x5f, 0);
+ outb(0x5f, 0);
+ tmp = inb(opna_iobase + 2) & 0xc0;
+ switch (tmp >> 6) {
+ case 0: /* INT0 (IRQ3)*/
+ irq = 3;
+ break;
+ case 1: /* INT6 (IRQ13)*/
+ irq = 13;
+ break;
+ case 2: /* INT4 (IRQ10)*/
+ irq = 10;
+ break;
+ case 3: /* INT5 (IRQ12)*/
+ irq = 12;
+ break;
+ default: /* error */
+ return NO;
+ }
+
+ /* Wait for OPNA to be ready. */
+ i = 100000; /* Some large value */
+ while((inb(opna_iobase) & 0x80) && (i-- > 0));
+
+ /* Reset OPNA timer register. */
+ outb(opna_iobase, 0x27);
+ outb(0x5f, 0);
+ outb(0x5f, 0);
+ outb(0x5f, 0);
+ outb(0x5f, 0);
+ outb(opna_iobase + 2, 0x30);
+
+ /* Ok. Detection finished. */
+ sprintf(pcm86_operations.name, board_name[pcm_s.board_type]);
+ pcm_initialized = NO;
+ pcm_s.irq = irq;
+
+ if ((hw_config->irq > 0) && (hw_config->irq != irq))
+ printf("pcm0: change irq %d -> %d\n", hw_config->irq, irq);
+ hw_config->irq = irq;
+
+ return YES;
+}
+
+
+static int
+pcm86_open(int dev, int mode)
+{
+ int err;
+
+ if (!pcm_initialized)
+ return RET_ERROR(ENXIO);
+
+ if (pcm_s.intr_busy || pcm_s.opened)
+ return RET_ERROR(EBUSY);
+
+ if ((err = snd_set_irq_handler(pcm_s.irq, pcmintr, "PC-9801-73/86")) < 0)
+ return err;
+
+ pcm_stop();
+
+ tmpbuf.size = 0;
+ pcm_s.intr_mode = IMODE_NONE;
+ pcm_s.opened = YES;
+
+ return 0;
+}
+
+
+static void
+pcm86_close(int dev)
+{
+ snd_release_irq(pcm_s.irq);
+
+ pcm_s.opened = NO;
+}
+
+
+static void
+pcm86_output_block(int dev, unsigned long buf, int count, int intrflag,
+ int dma_restart)
+{
+ unsigned long flags, cnt;
+ int maxchunksize;
+
+#ifdef PCM86_DEBUG
+ printk("pcm86_output_block():");
+ if (audio_devs[dev]->dmap->flags & DMA_BUSY)
+ printk(" DMA_BUSY");
+ if (audio_devs[dev]->dmap->flags & DMA_RESTART)
+ printk(" DMA_RESTART");
+ if (audio_devs[dev]->dmap->flags & DMA_ACTIVE)
+ printk(" DMA_ACTIVE");
+ if (audio_devs[dev]->dmap->flags & DMA_STARTED)
+ printk(" DMA_STARTED");
+ if (audio_devs[dev]->dmap->flags & DMA_ALLOC_DONE)
+ printk(" DMA_ALLOC_DONE");
+ printk("\n");
+#endif
+
+#if 0
+ DISABLE_INTR(flags);
+#endif
+
+#ifdef PCM86_DEBUG
+ printk("pcm86_output_block(): count = %d, intrsize= %d\n",
+ count, pcm_s.intr_size);
+#endif
+
+ pcm_s.pdma_buf = (pcm_data *)buf;
+ pcm_s.pdma_count = count;
+ pcm_s.pdma_chunkcount = 1;
+ maxchunksize = (((PCM86_FIFOSIZE - pcm_s.intr_size * 2)
+ / (pcm_s.bytes * 2)) * pcm_s.speed
+ / pcm_s.chipspeed) * (pcm_s.bytes << pcm_s.stereo);
+ if (count > maxchunksize)
+ pcm_s.pdma_chunkcount = 2 * count / maxchunksize;
+ /*
+ * Let chunksize = (float)count / (float)pcm_s.pdma_chunkcount.
+ * Data of size chunksize is sent to the FIFO buffer on the 86-board
+ * on every occuring of interrupt.
+ * By assuming that pcm_s.intr_size < PCM86_FIFOSIZE / 2, we can conclude
+ * that the FIFO buffer never overflows from the following lemma.
+ *
+ * Lemma:
+ * maxchunksize / 2 <= chunksize <= maxchunksize.
+ * (Though pcm_s.pdma_chunkcount is obtained through the flooring
+ * function, this inequality holds.)
+ * Proof) Omitted.
+ */
+
+ fifo_output_block();
+
+ pcm_s.intr_last = NO;
+ pcm_s.intr_mode = IMODE_OUTPUT;
+ if (!pcm_s.intr_busy)
+ fifo_start(IMODE_OUTPUT);
+ pcm_s.intr_busy = YES;
+
+#if 0
+ RESTORE_INTR(flags);
+#endif
+}
+
+
+static void
+pcm86_start_input(int dev, unsigned long buf, int count, int intrflag,
+ int dma_restart)
+{
+ unsigned long flags, cnt;
+ int maxchunksize;
+
+#ifdef PCM86_DEBUG
+ printk("pcm86_start_input():");
+ if (audio_devs[dev]->dmap->flags & DMA_BUSY)
+ printk(" DMA_BUSY");
+ if (audio_devs[dev]->dmap->flags & DMA_RESTART)
+ printk(" DMA_RESTART");
+ if (audio_devs[dev]->dmap->flags & DMA_ACTIVE)
+ printk(" DMA_ACTIVE");
+ if (audio_devs[dev]->dmap->flags & DMA_STARTED)
+ printk(" DMA_STARTED");
+ if (audio_devs[dev]->dmap->flags & DMA_ALLOC_DONE)
+ printk(" DMA_ALLOC_DONE");
+ printk("\n");
+#endif
+
+#if 0
+ DISABLE_INTR(flags);
+#endif
+
+ pcm_s.intr_size = PCM86_INTRSIZE_IN;
+
+#ifdef PCM86_DEBUG
+ printk("pcm86_start_input(): count = %d, intrsize= %d\n",
+ count, pcm_s.intr_size);
+#endif
+
+ pcm_s.pdma_buf = (pcm_data *)buf;
+ pcm_s.pdma_count = count;
+ pcm_s.pdma_chunkcount = 1;
+ maxchunksize = ((pcm_s.intr_size / (pcm_s.bytes * 2)) * pcm_s.speed
+ / pcm_s.chipspeed) * (pcm_s.bytes << pcm_s.stereo);
+ if (count > maxchunksize)
+ pcm_s.pdma_chunkcount = 2 * count / maxchunksize;
+
+ pcm_s.intr_mode = IMODE_INPUT;
+ if (!pcm_s.intr_busy)
+ fifo_start(IMODE_INPUT);
+ pcm_s.intr_busy = YES;
+
+#if 0
+ RESTORE_INTR(flags);
+#endif
+}
+
+
+static int
+pcm86_ioctl(int dev, unsigned int cmd, unsigned int arg, int local)
+{
+ switch (cmd) {
+ case SOUND_PCM_WRITE_RATE:
+ if (local)
+ return set_speed(arg);
+ return IOCTL_OUT(arg, set_speed(IOCTL_IN(arg)));
+
+ case SOUND_PCM_READ_RATE:
+ if (local)
+ return pcm_s.speed;
+ return IOCTL_OUT(arg, pcm_s.speed);
+
+ case SNDCTL_DSP_STEREO:
+ if (local)
+ return set_stereo(arg);
+ return IOCTL_OUT(arg, set_stereo(IOCTL_IN(arg)));
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return set_stereo(arg - 1) + 1;
+ return IOCTL_OUT(arg, set_stereo(IOCTL_IN(arg) - 1) + 1);
+
+ case SOUND_PCM_READ_CHANNELS:
+ if (local)
+ return pcm_s.stereo + 1;
+ return IOCTL_OUT(arg, pcm_s.stereo + 1);
+
+ case SNDCTL_DSP_SETFMT:
+ if (local)
+ return set_format(arg);
+ return IOCTL_OUT(arg, set_format(IOCTL_IN(arg)));
+
+ case SOUND_PCM_READ_BITS:
+ if (local)
+ return pcm_s.bytes * 8;
+ return IOCTL_OUT(arg, pcm_s.bytes * 8);
+ }
+
+ /* Invalid ioctl request */
+ return RET_ERROR(EINVAL);
+}
+
+
+static int
+pcm86_prepare_for_input(int dev, int bufsize, int nbufs)
+{
+ pcm_s.intr_size = PCM86_INTRSIZE_IN;
+ pcm_s.intr_mode = IMODE_NONE;
+ pcm_s.acc = 0;
+ pcm_s.last_l = 0;
+ pcm_s.last_r = 0;
+
+ DEB(printk("pcm86_prepare_for_input\n"));
+
+ return 0;
+}
+
+
+static int
+pcm86_prepare_for_output(int dev, int bufsize, int nbufs)
+{
+ pcm_s.intr_size = PCM86_INTRSIZE_OUT;
+ pcm_s.intr_mode = IMODE_NONE;
+ pcm_s.acc = 0;
+ pcm_s.last_l = 0;
+ pcm_s.last_r = 0;
+
+ DEB(printk("pcm86_prepare_for_output\n"));
+
+ return 0;
+}
+
+
+static void
+pcm86_reset(int dev)
+{
+ pcm_stop();
+}
+
+
+static void
+pcm86_halt_xfer(int dev)
+{
+ pcm_stop();
+
+ DEB(printk("pcm86_halt_xfer\n"));
+}
+
+
+void
+pcmintr(int unit)
+{
+ unsigned char tmp;
+
+ if ((inb(pcm_s.iobase + 8) & 0x10) == 0)
+ return; /* not FIFO intr. */
+
+ switch(pcm_s.intr_mode) {
+ case IMODE_OUTPUT:
+ if (pcm_s.intr_trailer) {
+ DEB(printk("pcmintr(): fifo_reset\n"));
+ fifo_reset();
+ pcm_s.intr_trailer = NO;
+ pcm_s.intr_busy = NO;
+ }
+ if (pcm_s.pdma_count > 0)
+ fifo_output_block();
+ else
+ DMAbuf_outputintr(my_dev, 1);
+ /* Reset intr. flag. */
+ tmp = inb(pcm_s.iobase + 8);
+ outb(pcm_s.iobase + 8, tmp & ~0x10);
+ outb(pcm_s.iobase + 8, tmp | 0x10);
+ break;
+
+ case IMODE_INPUT:
+ fifo_input_block();
+ if (pcm_s.pdma_count == 0)
+ DMAbuf_inputintr(my_dev);
+ /* Reset intr. flag. */
+ tmp = inb(pcm_s.iobase + 8);
+ outb(pcm_s.iobase + 8, tmp & ~0x10);
+ outb(pcm_s.iobase + 8, tmp | 0x10);
+ break;
+
+ default:
+ pcm_stop();
+ printk("pcm0: unexpected interrupt\n");
+ }
+}
+
+
+#endif /* EXCLUDE_PCM86, EXCLUDE_AUDIO */
+
+#endif /* CONFIGURE_SOUNDCARD */
diff --git a/sys/i386/isa/sound/sb16_dsp.c b/sys/i386/isa/sound/sb16_dsp.c
index d5af2c1..5e84e67 100644
--- a/sys/i386/isa/sound/sb16_dsp.c
+++ b/sys/i386/isa/sound/sb16_dsp.c
@@ -84,7 +84,11 @@ static void dsp_cleanup (void);
static struct audio_operations sb16_dsp_operations =
{
"SoundBlaster 16",
+#ifdef PC98
+ NEEDS_RESTART,
+#else
DMA_AUTOMODE,
+#endif
AFMT_U8 | AFMT_S16_LE,
NULL,
sb16_dsp_open,
@@ -447,6 +451,17 @@ set_irq_hw (int level)
switch (level)
{
+#ifdef PC98
+ case 5:
+ ival = 8;
+ break;
+ case 3:
+ ival = 1;
+ break;
+ case 10:
+ ival = 2;
+ break;
+#else
case 5:
ival = 2;
break;
@@ -459,6 +474,7 @@ set_irq_hw (int level)
case 10:
ival = 8;
break;
+#endif
default:
printk ("SB16_IRQ_LEVEL %d does not exist\n", level);
return;
@@ -517,6 +533,9 @@ sb16_dsp_detect (struct address_info *hw_config)
if (sbc_major < 4) /* Set by the plain SB driver */
return 0; /* Not a SB16 */
+#ifdef PC98
+ hw_config->dma = sb_config->dma;
+#else
if (hw_config->dma < 4)
if (hw_config->dma != sb_config->dma)
{
@@ -524,11 +543,16 @@ sb16_dsp_detect (struct address_info *hw_config)
sb_config->dma, hw_config->dma);
return 0;
}
+#endif
dma16 = hw_config->dma;
dma8 = sb_config->dma;
set_irq_hw (sb_config->irq);
+#ifdef PC98
+ sb_setmixer (DMA_NR, hw_config->dma == 0 ? 1 : 2);
+#else
sb_setmixer (DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma));
+#endif
DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
diff --git a/sys/i386/isa/sound/sb16_midi.c b/sys/i386/isa/sound/sb16_midi.c
index 4e45e2e..7dae750 100644
--- a/sys/i386/isa/sound/sb16_midi.c
+++ b/sys/i386/isa/sound/sb16_midi.c
@@ -35,9 +35,15 @@
#include <i386/isa/sound/sb.h>
+#ifdef PC98
+#define DATAPORT (sb16midi_base)
+#define COMDPORT (sb16midi_base+0x100)
+#define STATPORT (sb16midi_base+0x100)
+#else
#define DATAPORT (sb16midi_base)
#define COMDPORT (sb16midi_base+1)
#define STATPORT (sb16midi_base+1)
+#endif
#define sb16midi_status() INB(STATPORT)
#define input_avail() (!(sb16midi_status()&INPUT_AVAIL))
diff --git a/sys/i386/isa/sound/sb_dsp.c b/sys/i386/isa/sound/sb_dsp.c
index 560fc79..82a2178 100644
--- a/sys/i386/isa/sound/sb_dsp.c
+++ b/sys/i386/isa/sound/sb_dsp.c
@@ -1067,6 +1067,30 @@ sb_dsp_detect (struct address_info *hw_config)
return 0;
#endif
+#ifdef PC98
+ switch (sbc_irq)
+ {
+ case 3:
+ sb_setmixer (IRQ_NR, 1);
+ break;
+ case 5:
+ sb_setmixer (IRQ_NR, 8);
+ break;
+ case 10:
+ sb_setmixer (IRQ_NR, 2);
+ break;
+ }
+ switch (hw_config->dma)
+ {
+ case 0:
+ sb_setmixer (DMA_NR, 1);
+ break;
+ case 3:
+ sb_setmixer (DMA_NR, 2);
+ break;
+ }
+#endif
+
return 1; /*
* Detected
*/
@@ -1137,8 +1161,13 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
#ifndef EXCLUDE_YM3812
+#ifdef PC98
+ if (sbc_major > 3 ||
+ (sbc_major == 3 && INB (0x28d2) == 0x00))
+#else
if (sbc_major > 3 ||
(sbc_major == 3 && INB (0x388) == 0x00)) /* Should be 0x06 if not OPL-3 */
+#endif
enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
#endif
diff --git a/sys/i386/isa/sound/sound_switch.c b/sys/i386/isa/sound/sound_switch.c
index 21bcd69..83994e0 100644
--- a/sys/i386/isa/sound/sound_switch.c
+++ b/sys/i386/isa/sound/sound_switch.c
@@ -171,10 +171,16 @@ init_status (void)
return;
if (!put_status_int (snd_installed_cards[i].config.irq, 10))
return;
+#ifdef PC98
+ if (snd_installed_cards[i].config.dma >= 0) {
+#endif
if (!put_status (" drq "))
return;
if (!put_status_int (snd_installed_cards[i].config.dma, 10))
return;
+#ifdef PC98
+ }
+#endif
if (!snd_installed_cards[i].enabled)
if (!put_status (")"))
diff --git a/sys/i386/isa/sound/soundcard.c b/sys/i386/isa/sound/soundcard.c
index c7af8ab..3a06b6c 100644
--- a/sys/i386/isa/sound/soundcard.c
+++ b/sys/i386/isa/sound/soundcard.c
@@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: soundcard.c,v 1.42 1996/03/28 14:31:13 scrappy Exp $
+ * $Id: soundcard.c,v 1.43 1996/09/10 08:26:06 bde Exp $
*/
#include <i386/isa/sound/sound_config.h>
@@ -91,6 +91,9 @@ struct isa_driver gusxvidriver = {sndprobe, sndattach, "gusxvi"};
struct isa_driver gusmaxdriver = {sndprobe, sndattach, "gusmax"};
struct isa_driver uartdriver = {sndprobe, sndattach, "uart"};
struct isa_driver mssdriver = {sndprobe, sndattach, "mss"};
+#ifdef PC98
+struct isa_driver pcmdriver = {sndprobe, sndattach, "pcm"};
+#endif
static unsigned short
ipri_to_irq (unsigned short ipri);
@@ -274,6 +277,10 @@ driver_to_voxunit(struct isa_driver *driver)
return(SNDCARD_GUS16);
else if(driver == &mssdriver)
return(SNDCARD_MSS);
+#ifdef PC98
+ else if(driver == &pcmdriver)
+ return(SNDCARD_PCM86);
+#endif
else
return(0);
}
@@ -291,6 +298,19 @@ sndprobe (struct isa_device *dev)
hw_config.dma_read = dev->id_flags; /* misuse the flags field for read dma*/
if(unit)
+#ifdef PC98
+ if(unit == SNDCARD_PCM86) {
+ int result;
+
+ result = sndtable_probe (unit, &hw_config);
+ dev->id_iobase = hw_config.io_base;
+ dev->id_irq = (1 << hw_config.irq);
+ dev->id_drq = hw_config.dma;
+
+ return result;
+ }
+ else
+#endif
return sndtable_probe (unit, &hw_config);
else
return 0;
@@ -468,7 +488,11 @@ sound_mem_init (void)
for (dev = 0; dev < num_audiodevs; dev++) /* Enumerate devices */
if (!(dsp_init_mask & (1 << dev))) /* Not already done */
+#ifdef PC98
+ if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan >= 0)
+#else
if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan > 0)
+#endif
{
dsp_init_mask |= (1 << dev);
dmap = audio_devs[dev]->dmap;
diff --git a/sys/i386/isa/wdreg.h b/sys/i386/isa/wdreg.h
index 20d37da..2a0a32f 100644
--- a/sys/i386/isa/wdreg.h
+++ b/sys/i386/isa/wdreg.h
@@ -34,12 +34,42 @@
* SUCH DAMAGE.
*
* from: @(#)wdreg.h 7.1 (Berkeley) 5/9/91
- * $Id: wdreg.h,v 1.11 1996/01/28 22:16:20 wollman Exp $
+ * $Id: wdreg.h,v 1.12 1996/06/08 10:03:38 bde Exp $
+ */
+
+/*
+ * modified for PC9801 by F.Ukai
+ * Kyoto University Microcomputer Club (KMC)
*/
/*
* Disk Controller register definitions.
*/
+#ifdef PC98
+#define wd_data 0x0 /* data register (R/W - 16 bits) */
+#define wd_error 0x2 /* error register (R) */
+#define wd_precomp wd_error /* write precompensation (W) */
+#define wd_features wd_error /* features register (W) */
+#define wd_seccnt 0x4 /* sector count (R/W) */
+#define wd_sector 0x6 /* first sector number (R/W) */
+#define wd_cyl_lo 0x8 /* cylinder address, low byte (R/W) */
+#define wd_cyl_hi 0xa /* cylinder address, high byte (R/W)*/
+#define wd_sdh 0xc /* sector size/drive/head (R/W)*/
+#define wd_command 0xe /* command register (W) */
+#define wd_status wd_command /* immediate status (R) */
+
+#define wd_altsts_nec 0x10c /*alternate fixed disk status(via 1015) (R)*/
+#define wd_ctlr_nec 0x10c /*fixed disk controller control(via 1015) (W)*/
+#define wd_altsts_epson 0x3 /*alternate fixed disk status(via 1015) (R)*/
+#define wd_ctlr_epson 0x3 /*fixed disk controller control(via 1015) (W)*/
+#define wd_altsts wd_alsts_nec
+#define wd_ctlr wd_ctlr_nec
+
+#define WDCTL_4BIT 0x8 /* use four head bits (wd1003) */
+#define WDCTL_RST 0x4 /* reset the controller */
+#define WDCTL_IDS 0x2 /* disable controller interrupts */
+#define wd_digin 0x10e /* disk controller input(via 1015) (R)*/
+#else /* IBM-PC */
#define wd_data 0x0 /* data register (R/W - 16 bits) */
#define wd_error 0x1 /* error register (R) */
#define wd_precomp wd_error /* write precompensation (W) */
@@ -58,6 +88,7 @@
#define WDCTL_RST 0x4 /* reset the controller */
#define WDCTL_IDS 0x2 /* disable controller interrupts */
#define wd_digin 0x207 /* disk controller input(via 1015) (R)*/
+#endif /* PC98 */
/*
* Status Bits.
OpenPOWER on IntegriCloud