[PATCHSET 23/25] add support for PC-9800 architecture (sound oss #1)

From: Osamu Tomita (tomita@cinet.co.jp)
Date: Fri Oct 18 2002 - 11:56:54 EST


This is part 24/26 of patchset for add support NEC PC-9800 architecture,
against 2.5.43.

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/



This archive was generated by hypermail 2b29 : Wed Oct 23 2002 - 22:00:43 EST