Summary:
 OSS sound driver related modules.
  - add hardware specific initialization.
  - IO port address and IRQ number change.
diffstat:
 sound/oss/Config.in      |   18 ++++
 sound/oss/Makefile       |    1 
 sound/oss/ad1848.c       |   45 +++++++++++
 sound/oss/dev_table.h    |    3 
 sound/oss/dmabuf.c       |    3 
 sound/oss/mpu401.c       |  178 +++++++++++++++++++++++++++++++++++++++++++++++
 sound/oss/opl3.c         |  132 +++++++++++++++++++++++++++++++++-
 sound/oss/sb.h           |   34 ++++++++
 sound/oss/sb_common.c    |  103 ++++++++++++++++++++++++++-
 sound/oss/sound_config.h |   12 +++
 sound/oss/uart401.c      |   17 ++++
 11 files changed, 540 insertions(+), 6 deletions(-)
patch:
diff -urN linux/sound/oss/Config.in linux98/sound/oss/Config.in
--- linux/sound/oss/Config.in	Tue Sep 10 02:35:13 2002
+++ linux98/sound/oss/Config.in	Thu Sep 12 10:58:42 2002
@@ -132,6 +132,9 @@
   
    dep_tristate '    Microsoft Sound System support' CONFIG_SOUND_MSS $CONFIG_SOUND_OSS
    dep_tristate '    MPU-401 support (NOT for SB16)' CONFIG_SOUND_MPU401 $CONFIG_SOUND_OSS
+     if [ "$CONFIG_SOUND_MPU401" != "n" -a "$CONFIG_PC9800" = "y" ]; then
+        dep_bool '      Roland MPU-PC98II support' CONFIG_MPU_PC98II y
+     fi
    dep_tristate '    NM256AV/NM256ZX audio support' CONFIG_SOUND_NM256 $CONFIG_SOUND_OSS
    dep_tristate '    OPTi MAD16 and/or Mozart based cards' CONFIG_SOUND_MAD16 $CONFIG_SOUND_OSS $CONFIG_SOUND_GAMEPORT
    if [ "$CONFIG_SOUND_MAD16" = "y" -o "$CONFIG_SOUND_MAD16" = "m" ]; then
@@ -151,6 +154,9 @@
 
    dep_tristate '    100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SOUND_SB $CONFIG_SOUND_OSS
    dep_tristate '    AWE32 synth' CONFIG_SOUND_AWE32_SYNTH $CONFIG_SOUND_OSS
+   if [ "$CONFIG_PC9800" = "y" -a "$CONFIG_SOUND_SB" != "n" ]; then
+ 	define_bool CONFIG_SB16_PC9800 y
+   fi
    dep_tristate '    Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/soundcards' CONFIG_SOUND_WAVEFRONT $CONFIG_SOUND_OSS m
    dep_tristate '    Limited support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_SOUND_MAUI $CONFIG_SOUND_OSS
    if [ "$CONFIG_SOUND_MAUI" = "y" ]; then
@@ -161,6 +167,9 @@
    fi
 
    dep_tristate '    Yamaha FM synthesizer (YM3812/OPL-3) support' CONFIG_SOUND_YM3812 $CONFIG_SOUND_OSS
+   if [ "$CONFIG_PC9800" = "y" -a "$CONFIG_SOUND_YM3812" != "n" ]; then
+       define_bool CONFIG_PC9801_118 y
+   fi
    dep_tristate '    Yamaha OPL3-SA1 audio controller' CONFIG_SOUND_OPL3SA1 $CONFIG_SOUND_OSS
    dep_tristate '    Yamaha OPL3-SA2 and SA3 based PnP cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS
    dep_tristate '    Yamaha YMF7xx PCI audio (native mode)' CONFIG_SOUND_YMFPCI $CONFIG_SOUND_OSS $CONFIG_PCI
@@ -197,6 +206,15 @@
       dep_tristate '    Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER
    fi
 
+   if [ "$CONFIG_PC9800" = "y" ]; then
+     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+       dep_tristate '    NEC PC-9801-86 PCM support' CONFIG_SOUND_PC9801_86 $CONFIG_SOUND_OSS
+       if [ "$CONFIG_SOUND_PC9801_86" != "n" ]; then
+         hex '      PC-9801-86 I/O base' CONFIG_PC9801_86_BASE a460
+       fi
+     fi
+   fi
+
 fi
 
 dep_tristate '  TV card (bt848) mixer support' CONFIG_SOUND_TVMIXER $CONFIG_SOUND $CONFIG_I2C
diff -urN linux/sound/oss/Makefile linux98/sound/oss/Makefile
--- linux/sound/oss/Makefile	Fri Aug  2 06:16:16 2002
+++ linux98/sound/oss/Makefile	Wed Aug  7 10:04:10 2002
@@ -42,6 +42,7 @@
 obj-$(CONFIG_SOUND_AD1816)	+= ad1816.o
 obj-$(CONFIG_SOUND_ACI_MIXER)	+= aci.o
 obj-$(CONFIG_SOUND_AWE32_SYNTH)	+= awe_wave.o
+obj-$(CONFIG_SOUND_PC9801_86)	+= pc9801_86_pcm.o
 
 obj-$(CONFIG_SOUND_VIA82CXXX)	+= via82cxxx_audio.o ac97_codec.o
 ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
diff -urN linux/sound/oss/ad1848.c linux98/sound/oss/ad1848.c
--- linux/sound/oss/ad1848.c	Sun Sep  1 07:05:28 2002
+++ linux98/sound/oss/ad1848.c	Tue Sep  3 00:03:35 2002
@@ -56,6 +56,10 @@
 #include "ad1848.h"
 #include "ad1848_mixer.h"
 
+#ifdef CONFIG_PC9800
+#include <sound/sound_pc9800.h>
+#endif
+
 typedef struct
 {
 	spinlock_t		lock;
@@ -2562,6 +2566,9 @@
 	}
 	DDB(printk("MSS signature = %x\n", tmp & 0x3f));
 	if ((tmp & 0x3f) != 0x04 &&
+#ifdef CONFIG_PC9800
+	    (tmp & 0x3f) != 0x05 &&
+#endif
 	    (tmp & 0x3f) != 0x0f &&
 	    (tmp & 0x3f) != 0x00)
 	{
@@ -2575,12 +2582,19 @@
 		hw_config->card_subtype = 1;
 		return 1;
 	}
+#ifndef CONFIG_PC9800
 	if ((hw_config->irq != 5)  &&
 	    (hw_config->irq != 7)  &&
 	    (hw_config->irq != 9)  &&
 	    (hw_config->irq != 10) &&
 	    (hw_config->irq != 11) &&
 	    (hw_config->irq != 12))
+#else /* CONFIG_PC9800 */
+	if ((hw_config->irq != 3)  &&
+	    (hw_config->irq != 5)  &&
+	    (hw_config->irq != 10) &&
+	    (hw_config->irq != 12))
+#endif /* CONFIG_PC9800 */
 	{
 		printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq);
 		return 0;
@@ -2609,10 +2623,24 @@
 
 void attach_ms_sound(struct address_info *hw_config, struct module *owner)
 {
+#ifndef CONFIG_PC9800
 	static signed char interrupt_bits[12] =
 	{
 		-1, -1, -1, -1, -1, 0x00, -1, 0x08, -1, 0x10, 0x18, 0x20
 	};
+#else /* CONFIG_PC9800 */
+	/* Valid IRQs are: 3 (INT0), 5 (INT1), 10 (INT41), 12 (INT5) */
+	static signed char interrupt_bits[13] =
+	{
+		-1, -1, -1, 0x08, -1, 0x10, -1, -1, -1, -1, 0x18, -1, 0x20 
+	};
+/* # ifdef CONFIG_PC9800_CANBE ??? */
+	static signed char interrupt_bits2[13] =
+	{
+		-1, -1, -1, 0x03, -1, 0x08, -1, -1, -1, -1, 0x02, -1, 0x00
+	};
+/* # endif */
+#endif /* CONFIG_PC9800 */
 	signed char     bits;
 	char            dma2_bit = 0;
 
@@ -2647,6 +2675,23 @@
 		printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq);
 		return;
 	}
+
+#ifdef CONFIG_PC9800
+	if (PC9800_SOUND_ID() == PC9800_SOUND_ID_118) {
+		/* Set up CanBe control registers. */
+		unsigned long flags;
+		static spinlock_t canbe_lock = SPIN_LOCK_UNLOCKED;
+
+		printk(KERN_DEBUG "MSS: "
+			"Setting up CanBe Sound System control register\n");
+		spin_lock_irqsave(&canbe_lock, flags);
+		outb(inb(PC9800_SOUND_IO_ID) | 0x3, PC9800_SOUND_IO_ID);
+		outb(0x01, 0x0f4a);
+		outb(interrupt_bits2[hw_config->irq], 0x0f4b);
+		spin_unlock_irqrestore(&canbe_lock, flags);
+	}
+#endif /* CONFIG_PC9800 */
+
 	outb((bits | 0x40), config_port);
 	if ((inb(version_port) & 0x40) == 0)
 		printk(KERN_ERR "[MSS: IRQ Conflict?]\n");
diff -urN linux/sound/oss/dev_table.h linux98/sound/oss/dev_table.h
--- linux/sound/oss/dev_table.h	Sun Sep  1 07:05:30 2002
+++ linux98/sound/oss/dev_table.h	Sun Sep  1 10:26:10 2002
@@ -34,6 +34,9 @@
 #define SNDCARD_OPL3SA2_MPU             43
 #define SNDCARD_WAVEARTIST              44	/* Waveartist */
 #define SNDCARD_OPL3SA2_MSS             45	/* Originally missed */
+#ifdef CONFIG_PC9800
+#define SNDCARD_PC9801_86               86	/* PC-9801-86 */
+#endif
 #define SNDCARD_AD1816                  88
 
 /*
diff -urN linux/sound/oss/dmabuf.c linux98/sound/oss/dmabuf.c
--- linux/sound/oss/dmabuf.c	Sun Aug 11 10:41:18 2002
+++ linux98/sound/oss/dmabuf.c	Fri Aug 23 20:36:52 2002
@@ -153,6 +157,9 @@
 	/* printk( "Start DMA%d %d, %d\n",  chan,  (int)(physaddr-dmap->raw_buf_phys),  count); */
 
 	flags = claim_dma_lock();
+#ifdef CONFIG_PC9800
+	outb(chan,0x29);
+#endif /* CONFIG_PC9800 */
 	disable_dma(chan);
 	clear_dma_ff(chan);
 	set_dma_mode(chan, dma_mode);
diff -urN linux/sound/oss/mpu401.c linux98/sound/oss/mpu401.c
--- linux/sound/oss/mpu401.c	Tue Sep 10 02:35:16 2002
+++ linux98/sound/oss/mpu401.c	Thu Sep 12 22:54:17 2002
@@ -71,9 +71,15 @@
 	  spinlock_t	lock;
   };
 
+#if !defined(CONFIG_SB16_PC9800) && !defined(CONFIG_MPU_PC98II)
 #define	DATAPORT(base)   (base)
 #define	COMDPORT(base)   (base+1)
 #define	STATPORT(base)   (base+1)
+#else
+#define	DATAPORT(base)   (base)
+#define	COMDPORT(base)   (base+2)
+#define	STATPORT(base)   (base+2)
+#endif
 
 
 static void mpu401_close(int dev);
@@ -1023,7 +1029,11 @@
 			mpu401_chk_version(m, devc);
 			spin_unlock_irqrestore(&devc->lock,flags);
 	}
+#if !defined(CONFIG_SB16_PC9800) && !defined(CONFIG_MPU_PC98II)
 	request_region(hw_config->io_base, 2, "mpu401");
+#else
+	request_region(hw_config->io_base, 4, "mpu401");
+#endif
 
 	if (devc->version != 0)
 		if (mpu_cmd(m, 0xC5, 0) >= 0)	/* Set timebase OK */
@@ -1152,7 +1162,12 @@
 		{
 			spin_lock_irqsave(&devc->lock,flags);
 			if (input_avail(devc))
+#ifdef CONFIG_PC9801_118
+				/* PC-9801-118 doesn't respond ACK for RESET Command */
+				read_data(devc);
+#else
 				if (read_data(devc) == MPU_ACK)
+#endif
 					ok = 1;
 			spin_unlock_irqrestore(&devc->lock,flags);
 		}
@@ -1194,7 +1209,11 @@
 	int ok = 0;
 	struct mpu_config tmp_devc;
 
+#if !defined(CONFIG_SB16_PC9800) && !defined(CONFIG_MPU_PC98II)
 	if (check_region(hw_config->io_base, 2))
+#else
+	if (check_region(hw_config->io_base, 4))
+#endif
 	{
 		printk(KERN_ERR "mpu401: I/O port %x already in use\n\n", hw_config->io_base);
 		return 0;
@@ -1208,7 +1227,162 @@
 	if (hw_config->always_detect)
 		return 1;
 
+#ifdef CONFIG_PC9801_118
+	{
+		#include <sound/pc9801_118_magic.h>
+		#define outp118(reg,data) outb((reg),0x148e);outb((data),0x148f)
+		#define WAIT118 outb(0x00,0x5f)
+		int	mpu_intr, count;
+#ifdef OOKUBO_ORIGINAL
+		int	err = 0;
+#endif /* OOKUBO_ORIGINAL */
+
+		switch (hw_config->irq)
+		{
+			case 3:
+				mpu_intr = 3;
+				break;
+			case 5:
+				mpu_intr = 2;
+				break;
+			case 6:
+				mpu_intr = 1;
+				break;
+			case 10:
+				mpu_intr = 0;
+				break;
+			default:
+				printk(KERN_ERR "mpu401: Bad irq %d\n\n", hw_config->irq);
+				return 0;
+		}
+
+		outp118(0x21, mpu_intr);
+		WAIT118;
+		outb(0x00, 0x148e);
+		if (inb(0x148f) & 0x08)
+		{
+			printk(KERN_DEBUG "mpu401: No MIDI daughter board found\n\n");
+			goto exit_mode_118;
+		}
+
+		outp118(0x20, 0x00);
+		outp118(0x05, 0x04);
+		for (count = 0; count < 35000; count ++)
+			WAIT118;
+		outb(0x05, 0x148e);
+		for (count = 0; count < 65000; count ++)
+			if (inb(0x148f) == 0x04)
+				goto set_mode_118;
+		printk(KERN_ERR "mpu401: MIDI daughter board initalize failed at stage1\n\n");
+		return 0;
+
+		set_mode_118:
+		outp118(0x05, 0x0c);
+		outb(0xaa, 0x485);
+		outb(0x99, 0x485);
+		outb(0x2a, 0x485);
+		for (count = 0; count < sizeof(Data0485_99); count ++)
+		{
+			outb(Data0485_99[count], 0x485);
+			WAIT118;
+		}
+
+		outb(0x00, 0x486);
+		outb(0xaa, 0x485);
+		outb(0x9e, 0x485);
+		outb(0x2a, 0x485);
+		for (count = 0; count < sizeof(Data0485_9E); count ++)
+			if (inb(0x485) != Data0485_9E[count])
+			{
+#ifdef OOKUBO_ORIGINAL
+				err = 1;
+#endif /* OOKUBO_ORIGINAL */
+				break;
+			}
+		outb(0x00, 0x486);
+		for (count = 0; count < 2000; count ++)
+			WAIT118;
+#ifdef OOKUBO_ORIGINAL
+		if (!err)
+		{
+			outb(0xaa, 0x485);
+			outb(0x36, 0x485);
+			outb(0x28, 0x485);
+			for (count = 0; count < sizeof(Data0485_36); count ++)
+				outb(Data0485_36[count], 0x485);
+			outb(0x00, 0x486);
+			for (count = 0; count < 1500; count ++)
+				WAIT118;
+			outp118(0x05, inb(0x148f) | 0x08);
+			outb(0xff, 0x148c);
+			outp118(0x05, inb(0x148f) & 0xf7);
+			for (count = 0; count < 1500; count ++)
+				WAIT118;
+		}
+#endif /* OOKUBO_ORIGINAL */
+
+		outb(0xaa, 0x485);
+		outb(0xa9, 0x485);
+		outb(0x21, 0x485);
+		for (count = 0; count < sizeof(Data0485_A9); count ++)
+		{
+			outb(Data0485_A9[count], 0x485);
+			WAIT118;
+		}
+
+		outb(0x00, 0x486);
+		outb(0xaa, 0x485);
+		outb(0x0c, 0x485);
+		outb(0x20, 0x485);
+		for (count = 0; count < sizeof(Data0485_0C); count ++)
+		{
+			outb(Data0485_0C[count], 0x485);
+			WAIT118;
+		}
+
+		outb(0x00, 0x486);
+		outb(0xaa, 0x485);
+		outb(0x66, 0x485);
+		outb(0x20, 0x485);
+		for (count = 0; count < sizeof(Data0485_66); count ++)
+		{
+			outb(Data0485_66[count], 0x485);
+			WAIT118;
+		}
+
+		outb(0x00, 0x486);
+		outb(0xaa, 0x485);
+		outb(0x60, 0x485);
+		outb(0x20, 0x485);
+		for (count = 0; count < sizeof(Data0485_60); count ++)
+		{
+			outb(Data0485_60[count], 0x485);
+			WAIT118;
+		}
+
+		outb(0x00, 0x486);
+		outp118(0x05, 0x04);
+		outp118(0x05, 0x00);
+		for (count = 0; count < 35000; count ++)
+			WAIT118;
+		outb(0x05, 0x148e);
+		for (count = 0; count < 65000; count ++)
+			if (inb(0x148f) == 0x00)
+				goto end_mode_118;
+		printk(KERN_ERR "mpu401: MIDI daughter board initalize failed at stage2\n\n");
+		return 0;
+
+		end_mode_118:
+		outb(0x3f, 0x148d);
+		exit_mode_118:
+	}
+#endif /* CONFIG_PC9801_118 */
+
+#if !defined(CONFIG_SB16_PC9800) && !defined(CONFIG_MPU_PC98II)
 	if (inb(hw_config->io_base + 1) == 0xff)
+#else
+	if (inb(hw_config->io_base + 2) == 0xff)
+#endif
 	{
 		DDB(printk("MPU401: Port %x looks dead.\n", hw_config->io_base));
 		return 0;	/* Just bus float? */
@@ -1227,7 +1401,11 @@
 	void *p;
 	int n=hw_config->slots[1];
 	
+#if !defined(CONFIG_SB16_PC9800) && !defined(CONFIG_MPU_PC98II)
 	release_region(hw_config->io_base, 2);
+#else
+	release_region(hw_config->io_base, 4);
+#endif
 	if (hw_config->always_detect == 0 && hw_config->irq > 0)
 		free_irq(hw_config->irq, (void *)n);
 	p=mpu401_synth_operations[n];
diff -urN linux/sound/oss/opl3.c linux98/sound/oss/opl3.c
--- linux/sound/oss/opl3.c	Tue Oct  8 03:24:38 2002
+++ linux98/sound/oss/opl3.c	Fri Oct 11 13:54:21 2002
@@ -37,6 +37,10 @@
 #include "opl3.h"
 #include "opl3_hw.h"
 
+#ifdef CONFIG_PC9800
+#include <sound/sound_pc9800.h>
+#endif
+
 #define MAX_VOICE	18
 #define OFFS_4OP	11
 
@@ -74,6 +78,9 @@
 
 	int             is_opl4;
 	int            *osp;
+#ifdef CONFIG_PC9800
+	int             is_sb16;
+#endif
 } opl_devinfo;
 
 static struct opl_devinfo *devc = NULL;
@@ -182,10 +189,43 @@
 		printk(KERN_WARNING "opl3: I/O port 0x%x already in use\n", ioaddr);
 		goto cleanup_devc;
 	}
+#ifdef CONFIG_PC9800
+	if (devc->is_sb16) {
+		if (!request_region(ioaddr + 0x200, 2, devc->fm_info.name)) {
+			printk(KERN_WARNING "opl3: I/O port 0x%x already in use\n", ioaddr + 0x200);
+			goto cleanup_region2;
+		}
+		if (!request_region(ioaddr + 0x800, 2, devc->fm_info.name)) {
+			printk(KERN_WARNING "opl3: I/O port 0x%x already in use\n", ioaddr + 0x800);
+			goto cleanup_region1;
+		}
+	}
+#endif
 
 	devc->osp = osp;
 	devc->base = ioaddr;
 
+#ifdef CONFIG_PC9800
+	switch (PC9800_SOUND_ID()) {
+	case PC9800_SOUND_ID_XMATE:
+	case PC9800_SOUND_ID_118:
+		outb(inb(PC9800_SOUND_IO_ID) | 0x3, PC9800_SOUND_IO_ID);
+		printk(KERN_INFO "opl3: PC-9801-118 (or compatible) found,"
+		       " and enabled OPL-3 functions.\n");
+		devc->is_sb16 = 0;
+		break;
+	case PC9800_SOUND_ID_UNKNOWN:
+		printk(KERN_INFO "opl3: Sound ID is UNKNOWN."
+		       " Try to detect SB16 for PC-9800.\n");
+		devc->is_sb16 = 1;
+		break;
+	default:
+		printk(KERN_ERR "opl3: "
+		       "This sound system doesn't support OPL-3.\n");
+		return 0;
+	}
+#endif
+
 	/* Reset timers 1 and 2 */
 	opl3_command(ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
 
@@ -216,10 +256,15 @@
 		 * only after a cold boot. In addition the OPL4 port
 		 * of the chip may not be connected to the PC bus at all.
 		 */
-
+#ifndef CONFIG_PC9800
 		opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0x00);
 		opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE);
-
+#else
+		opl3_command(ioaddr + (devc->is_sb16 ? 0x200 : 2),
+			     OPL3_MODE_REGISTER, 0x00);
+		opl3_command(ioaddr + (devc->is_sb16 ? 0x200 : 2),
+			     OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE);
+#endif
 		if ((tmp = inb(ioaddr)) == 0x02)	/* Have a OPL4 */
 		{
 			detected_model = 4;
@@ -248,7 +293,12 @@
 				detected_model = 3;
 			}
 		}
+#ifndef CONFIG_PC9800
 		opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0);
+#else
+		opl3_command(ioaddr + (devc->is_sb16 ? 0x200 : 2),
+			     OPL3_MODE_REGISTER, 0);
+#endif
 	}
 	for (i = 0; i < 9; i++)
 		opl3_command(ioaddr, KEYON_BLOCK + i, 0);	/*
@@ -261,6 +311,14 @@
 								 */
 	return 1;
 cleanup_region:
+#ifdef CONFIG_PC9800
+	if (devc->is_sb16) {
+		release_region(ioaddr + 0x800, 2);
+cleanup_region1:
+		release_region(ioaddr + 0x200, 2);
+cleanup_region2:
+	}
+#endif
 	release_region(ioaddr, 4);
 cleanup_devc:
 	kfree(devc);
@@ -735,9 +793,12 @@
 	else
 		for (i = 0; i < 2; i++)
 			inb(io_addr);
-
+#ifndef CONFIG_PC9800
 	outb(((unsigned char) (val & 0xff)), io_addr + 1);
-
+#else
+	outb(((unsigned char) (val & 0xff)),
+	     io_addr + (devc->is_sb16 ? 0x100 : 1));
+#endif
 	if (devc->model != 2)
 		udelay(30);
 	else
@@ -1102,6 +1163,33 @@
 	setup_voice:	opl3_setup_voice
 };
 
+#ifdef CONFIG_PC9801_118
+static inline void pc9801_118_opl3_init(unsigned long ioaddr)
+{
+	/* ??? */
+	outb(0x00, ioaddr + 6);
+	inb(ioaddr + 7);
+	/* Enable OPL-3 Function */
+	outb(inb(PC9800_SOUND_IO_ID)|0x03, PC9800_SOUND_IO_ID);
+
+	/* Initialize? */
+	opl3_command(ioaddr + 2, 0x05, 0x05);
+	opl3_command(ioaddr + 2, 0x08, 0x04);
+	opl3_command(ioaddr + 2, 0x08, 0x00);
+	opl3_command(ioaddr, 0xf7, 0x00);
+	opl3_command(ioaddr, 0x04, 0x60);
+	opl3_command(ioaddr, 0x04, 0x80);
+	inb(ioaddr);
+
+	opl3_command(ioaddr, 0x02, 0xff);
+	opl3_command(ioaddr, 0x04, 0x21);
+	inb(ioaddr);
+
+	opl3_command(ioaddr, 0x04, 0x60);
+	opl3_command(ioaddr, 0x04, 0x80);
+}
+#endif
+
 int opl3_init(int ioaddr, int *osp, struct module *owner)
 {
 	int i;
@@ -1119,6 +1207,27 @@
 		return -1;
 	}
 
+#ifdef CONFIG_PC9800
+	/* Inspect Sound Functions ID */
+	switch (PC9800_SOUND_ID()){
+#ifdef CONFIG_PC9801_118
+	case PC9800_SOUND_ID_XMATE:
+	case PC9800_SOUND_ID_118:
+		pc9801_118_opl3_init(ioaddr);
+		devc->is_sb16 = 0;
+		break;
+#endif
+#ifdef CONFIG_SB16_PC9800
+	case PC9800_SOUND_ID_UNKNOWN:
+		devc->is_sb16 = 1;
+		break;
+#endif
+	default:
+		printk(KERN_ERR "opl3: Sorry, this driver is not configured for your sound system.\n");
+		return -1;
+	}
+#endif
+
 	devc->nr_voice = 9;
 
 	devc->fm_info.device = 0;
@@ -1131,7 +1240,14 @@
 	devc->fm_info.capabilities = 0;
 	devc->left_io = ioaddr;
 	devc->right_io = ioaddr + 2;
-
+#ifdef CONFIG_PC9800
+#define OPL3_LEFT     0x20d2
+#define OPL3_RIGHT    0x22d2
+	if (devc->is_sb16) {
+		devc->left_io = OPL3_LEFT;
+		devc->right_io = OPL3_RIGHT;
+	}
+#endif
 	if (detected_model <= 2)
 		devc->model = 1;
 	else
@@ -1223,6 +1339,12 @@
 	{
 		if (devc->base) {
 			release_region(devc->base,4);
+#ifdef CONFIG_PC9800
+			if (devc->is_sb16) {
+				release_region(devc->base + 0x800, 2);
+				release_region(devc->base + 0x200, 2);
+			}
+#endif
 			if (devc->is_opl4)
 				release_region(devc->base - 8, 2);
 		}
diff -urN linux/sound/oss/sb.h linux98/drivers/sound/sb.h
--- linux/sound/oss/sb.h	Sat Feb 17 09:02:37 2001
+++ linux98/sound/oss/sb.h	Fri Aug 17 21:50:17 2001
@@ -1,3 +1,7 @@
+#include <linux/config.h>
+
+#ifndef CONFIG_SB16_PC9800
+
 #define DSP_RESET	(devc->base + 0x6)
 #define DSP_READ	(devc->base + 0xA)
 #define DSP_WRITE	(devc->base + 0xC)
@@ -10,6 +14,26 @@
 #define OPL3_LEFT	(devc->base + 0x0)
 #define OPL3_RIGHT	(devc->base + 0x2)
 #define OPL3_BOTH	(devc->base + 0x8)
+
+#else /* CONFIG_SB16_PC9800 */
+
+#define _SB_98_IOINCR	(devc->type == MDL_SB16_PC9800 ? 0x100 : 1)
+
+#define DSP_RESET	(devc->base + 0x6 * _SB_98_IOINCR)
+#define DSP_READ	(devc->base + 0xA * _SB_98_IOINCR)
+#define DSP_WRITE	(devc->base + 0xC * _SB_98_IOINCR)
+#define DSP_COMMAND	(devc->base + 0xC * _SB_98_IOINCR)
+#define DSP_STATUS	(devc->base + 0xC * _SB_98_IOINCR)
+#define DSP_DATA_AVAIL	(devc->base + 0xE * _SB_98_IOINCR)
+#define DSP_DATA_AVL16	(devc->base + 0xF * _SB_98_IOINCR)
+#define MIXER_ADDR	(devc->base + 0x4 * _SB_98_IOINCR)
+#define MIXER_DATA	(devc->base + 0x5 * _SB_98_IOINCR)
+#define OPL3_LEFT	(devc->base + 0x0 * _SB_98_IOINCR)
+#define OPL3_RIGHT	(devc->base + 0x2 * _SB_98_IOINCR)
+#define OPL3_BOTH	(devc->base + 0x8 * _SB_98_IOINCR)
+
+#endif /* CONFIG_SB16_PC9800 */
+
 /* DSP Commands */
 
 #define DSP_CMD_SPKON		0xD1
@@ -46,6 +70,10 @@
 #define MDL_ESSPCI	16	/* ESS PCI card */
 #define MDL_YMPCI	17	/* Yamaha PCI sb in emulation */
 
+#ifdef CONFIG_SB16_PC9800
+#define MDL_SB16_PC9800	9801 /* SB16 for PC-9800 */
+#endif
+
 #define SUBMDL_ALS007	42	/* ALS-007 differs from SB16 only in mixer */
 				/* register assignment */
 #define SUBMDL_ALS100	43	/* ALS-100 allows sampling rates of up */
@@ -175,6 +203,12 @@
 int sb_audio_open(int dev, int mode);
 void sb_audio_close(int dev);
 
+#ifdef CONFIG_SB16_PC9800
+int sb16_pc9800_check_region(int ioaddr);
+void sb16_pc9800_request_region(int ioaddr, const char *name);
+void sb16_pc9800_release_region(int ioaddr);
+#endif
+
 extern sb_devc *last_sb;
 
 /*	From sb_common.c */
diff -urN linux/sound/oss/sb_common.c linux98/sound/oss/sb_common.c
--- linux/sound/oss/sb_common.c	Sun Aug 11 10:41:18 2002
+++ linux98/sound/oss/sb_common.c	Fri Aug 23 20:39:27 2002
@@ -305,6 +305,9 @@
 	switch (hw_config->io_base)
 	{
 		case 0x300:
+#ifdef CONFIG_SB16_PC9800
+		case 0x80d2:
+#endif
 			sb_setmixer(devc, 0x84, bits | 0x04);
 			break;
 
@@ -322,6 +324,26 @@
 {
 	int ival;
 
+#ifdef CONFIG_SB16_PC9800
+	if (devc->type == MDL_SB16_PC9800)
+		switchh (level)
+		{
+		case 3:
+			ival = 1;
+			break;
+		case 5:
+			ival = 8;
+			break;
+		case 10:
+			ival = 2;
+			break;
+		default:
+			printk(KERN_ERR "SB16: Invalid IRQ%d\n", level);
+			return 0;
+		}
+	else
+#endif
+
 	switch (level)
 	{
 		case 5:
@@ -518,7 +541,13 @@
 	 */
 	
 	DDB(printk("sb_dsp_detect(%x) entered\n", hw_config->io_base));
+#ifndef CONFIG_SB16_PC9800
 	if (check_region(hw_config->io_base, 16))
+#else
+	if (hw_config->card_subtype == MDL_SB16_PC9800
+	    ? sb16_pc9800_check_region(hw_config->io_base, 16)
+	    : check_region(hw_config->io_base, 16))
+#endif
 	{
 #ifdef MODULE
 		printk(KERN_INFO "sb: I/O region in use.\n");
@@ -532,8 +561,11 @@
 	devc->base = hw_config->io_base;
 	devc->irq = hw_config->irq;
 	devc->dma8 = hw_config->dma;
-
+#ifdef CONFIG_SB16_PC9800
+	devc->dma16 = hw_config->dma;
+#else
 	devc->dma16 = -1;
+#endif
 	devc->pcibase = pciio;
 	
 	if(pci == SB_PCI_ESSMAESTRO)
@@ -733,6 +764,11 @@
 			}
 		}
 	}			/* IRQ setup */
+#ifdef CONFIG_SB16_PC9800
+	if (devc->type == MDL_SB16_PC9800)
+		sb16_pc9800_request_region(hw_config->io_base, "soundblaster");
+	else
+#endif
 	request_region(hw_config->io_base, 16, "soundblaster");
 
 	last_sb = devc;
@@ -796,6 +832,13 @@
 				}
 				sb_setmixer(devc,0x30,mixer30);
 			}
+#ifdef CONFIG_SB16_PC9800
+			else if (devc->type == MDL_SB16_PC9800){
+				/* devc->submodel = SUBMDL_SB16_PC9800; */
+				if(hw_config->name == NULL)
+					hw_config->name = "Sound Blaster 16 (for PC-9800)";
+			}
+#endif
 			else if (hw_config->name == NULL)
 				hw_config->name = "Sound Blaster 16";
 
@@ -803,7 +846,9 @@
 				devc->dma16 = devc->dma8;
 			else if (hw_config->dma2 < 5 || hw_config->dma2 > 7)
 			{
+#ifndef CONFIG_SB16_PC9800
 				printk(KERN_WARNING  "SB16: Bad or missing 16 bit DMA channel\n");
+#endif
 				devc->dma16 = devc->dma8;
 			}
 			else
@@ -811,7 +856,13 @@
 
 			if(!sb16_set_dma_hw(devc)) {
 				free_irq(devc->irq, devc);
+#ifdef CONFIG_SB16_PC9800
+				if(devc->type == MDL_SB16_PC9800)
+					sb16_pc9800_release_region(hw_config->io_base);
+				else
+#endif
 			        release_region(hw_config->io_base, 16);
+
 				return 0;
 			}
 
@@ -900,6 +951,11 @@
 	{
 		if ((devc->model & MDL_ESS) && devc->pcibase)
 			release_region(devc->pcibase, 8);
+#ifdef CONFIG_SB16_PC9800
+		if(devc->type == MDL_SB16_PC9800)
+			sb16_pc9800_release_region(devc->base);
+		else
+#endif
 
 		release_region(devc->base, 16);
 
@@ -1240,6 +1295,18 @@
 	switch (devc->model)
 	{
 		case MDL_SB16:
+#ifdef CONFIG_SB16_PC9800
+			if (devc->type == MDL_SB16_PC9800)
+			{
+				if (hw_config->io_base != 0x80d2
+				    || hw_config->io_base != 0xc8d2)
+				{
+					printk(KERN_ERR "SB16: Invalid MIDI port %x\n", hw_config->io_base);
+					return 0;
+				}
+			}
+			else
+#endif
 			if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330)
 			{
 				printk(KERN_ERR "SB16: Invalid MIDI port %x\n", hw_config->io_base);
@@ -1284,6 +1351,38 @@
 	unload_uart401(hw_config);
 }
 
+#ifdef CONFIG_SB16_PC9800
+int sb16_pc9800_check_region(int ioaddr)
+{
+	int n;
+	for (n = 4; n < 7; n++)
+		if(check_region(ioaddr + n*0x100, 1))
+			return 0;
+	for (n = 10; n < 16; n++)
+		if(check_region(ioaddr + n*0x100, 1))
+			return 0;
+	return 1;
+}
+
+void sb16_pc9800_request_region(int ioaddr, const char *name)
+{
+	int n;
+	for (n = 4; n < 7; n++)
+		request_region(ioaddr + n*0x100, 1, name);
+	for (n = 10; n < 16; n++)
+		request_region(ioaddr + n*0x100, 1, name);
+}
+
+void sb16_pc9800_release_region(int ioaddr)
+{
+	int n;
+	for (n = 4; n < 7; n++)
+		release_region(ioaddr + n*0x100, 1);
+	for (n = 10; n < 16; n++)
+		release_region(ioaddr + n*0x100, 1);
+}
+#endif /* CONFIG_SB16_PC9800 */
+
 EXPORT_SYMBOL(sb_dsp_init);
 EXPORT_SYMBOL(sb_dsp_detect);
 EXPORT_SYMBOL(sb_dsp_unload);
diff -urN linux/sound/oss/sound_config.h linux98/sound/oss/sound_config.h
--- linux/sound/oss/sound_config.h	Tue Dec 12 06:02:27 2000
+++ linux98/sound/oss/sound_config.h	Sun Aug 19 14:13:08 2001
@@ -34,13 +34,25 @@
  * Use always 64k buffer size. There is no reason to use shorter.
  */
 #undef DSP_BUFFSIZE
+#ifdef CONFIG_PC9800
+#define DSP_BUFFSIZE          61440
+#else
 #define DSP_BUFFSIZE		(64*1024)
+#endif
 
 #ifndef DSP_BUFFCOUNT
 #define DSP_BUFFCOUNT		1	/* 1 is recommended. */
 #endif
 
+#ifdef CONFIG_PC9800
+#define FM_MONO         0x28d2  /* This is the I/O address used by AdLib */
+#else
 #define FM_MONO		0x388	/* This is the I/O address used by AdLib */
+#endif
+
+#ifdef CONFIG_PC9801_118
+#define FM_MONO_118		0x1488	/* This is the I/O address used by AdLib */
+#endif
 
 #ifndef CONFIG_PAS_BASE
 #define CONFIG_PAS_BASE	0x388
diff -urN linux/sound/oss/uart401.c linux98/sound/oss/uart401.c
--- linux/sound/oss/uart401.c	Sun Sep  1 07:05:31 2002
+++ linux98/sound/oss/uart401.c	Sun Sep  1 10:26:11 2002
@@ -21,6 +21,7 @@
  *		Untested
  */
 
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
@@ -43,8 +44,13 @@
 uart401_devc;
 
 #define	DATAPORT   (devc->base)
+#ifndef CONFIG_SB16_PC9800
 #define	COMDPORT   (devc->base+1)
 #define	STATPORT   (devc->base+1)
+#else
+#define	COMDPORT   (devc->base+0x100)
+#define	STATPORT   (devc->base+0x100)
+#endif
 
 static int uart401_status(uart401_devc * devc)
 {
@@ -304,6 +310,14 @@
 		return 0;
 	}
 
+#ifdef CONFIG_SB16_PC9800
+	if (!request_region(hw_config->io_base + 0x100, 4, "MPU-401 UART SB16-PC98")) {
+		printk(KERN_INFO "uart401: could not request_region(%d, 4)\n", hw_config->io_base + 0x100);
+		release_region(hw_config->io_base, 4);
+		return 0;
+	}
+#endif
+
 	devc = kmalloc(sizeof(uart401_devc), GFP_KERNEL);
 	if (!devc) {
 		printk(KERN_WARNING "uart401: Can't allocate memory\n");
@@ -408,6 +422,9 @@
 
 	reset_uart401(devc);
 	release_region(hw_config->io_base, 4);
+#ifdef CONFIG_SB16_PC9800
+	release_region(hw_config->io_base + 0x100, 4);
+#endif
 
 	if (!devc->share_irq)
 		free_irq(devc->irq, devc);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/