📄 sscape.c
字号:
}#endif } return 1;}static intdownload_boot_block (void *dev_info, copr_buffer * buf){ if (buf->len <= 0 || buf->len > sizeof (buf->data)) return RET_ERROR (EINVAL); if (!sscape_download_boot (devc, buf->data, buf->len, buf->flags)) { printk ("SSCAPE: Unable to load microcode block to the OBP.\n"); return RET_ERROR (EIO); } return 0;}static intsscape_coproc_ioctl (void *dev_info, unsigned int cmd, unsigned int arg, int local){ switch (cmd) { case SNDCTL_COPR_RESET: sscape_coproc_reset (dev_info); return 0; break; case SNDCTL_COPR_LOAD: { copr_buffer *buf; int err; buf = (copr_buffer *) KERNEL_MALLOC (sizeof (copr_buffer)); IOCTL_FROM_USER ((char *) buf, (char *) arg, 0, sizeof (*buf)); err = download_boot_block (dev_info, buf); KERNEL_FREE (buf); return err; } break; default: return RET_ERROR (EINVAL); } return RET_ERROR (EINVAL);}static coproc_operations sscape_coproc_operations ={ "SoundScape M68K", sscape_coproc_open, sscape_coproc_close, sscape_coproc_ioctl, sscape_coproc_reset, &dev_info};static intsscape_audio_open (int dev, int mode){ unsigned long flags; sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; DISABLE_INTR (flags); if (devc->opened) { RESTORE_INTR (flags); return RET_ERROR (EBUSY); } if (devc->dma_allocated == 0) { int err; if ((err = DMAbuf_open_dma (devc->my_audiodev)) < 0) { RESTORE_INTR (flags); return err; } devc->dma_allocated = 1; } devc->opened = 1; RESTORE_INTR (flags);#ifdef SSCAPE_DEBUG4 /* * Temporary debugging aid. Print contents of the registers * when the device is opened. */ { int i; for (i = 0; i < 13; i++) printk ("I%d = %02x\n", i, sscape_read (devc, i)); }#endif return 0;}static voidsscape_audio_close (int dev){ unsigned long flags; sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; DEB (printk ("sscape_audio_close(void)\n")); DISABLE_INTR (flags); if (devc->dma_allocated) { sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ DMAbuf_close_dma (dev); devc->dma_allocated = 0; } devc->opened = 0; RESTORE_INTR (flags);}static intset_speed (sscape_info * devc, int arg){ return 8000;}static intset_channels (sscape_info * devc, int arg){ return 1;}static intset_format (sscape_info * devc, int arg){ return AFMT_U8;}static intsscape_audio_ioctl (int dev, unsigned int cmd, unsigned int arg, int local){ sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; switch (cmd) { case SOUND_PCM_WRITE_RATE: if (local) return set_speed (devc, arg); return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg))); case SOUND_PCM_READ_RATE: if (local) return 8000; return IOCTL_OUT (arg, 8000); case SNDCTL_DSP_STEREO: if (local) return set_channels (devc, arg + 1) - 1; return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg) + 1) - 1); case SOUND_PCM_WRITE_CHANNELS: if (local) return set_channels (devc, arg); return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg))); case SOUND_PCM_READ_CHANNELS: if (local) return 1; return IOCTL_OUT (arg, 1); case SNDCTL_DSP_SAMPLESIZE: if (local) return set_format (devc, arg); return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg))); case SOUND_PCM_READ_BITS: if (local) return 8; return IOCTL_OUT (arg, 8); default:; } return RET_ERROR (EINVAL);}static voidsscape_audio_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart){}static voidsscape_audio_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart){}static intsscape_audio_prepare_for_input (int dev, int bsize, int bcount){ return 0;}static intsscape_audio_prepare_for_output (int dev, int bsize, int bcount){ return 0;}static voidsscape_audio_halt (int dev){}static voidsscape_audio_reset (int dev){ sscape_audio_halt (dev);}static struct audio_operations sscape_audio_operations ={ "Ensoniq SoundScape channel A", 0, AFMT_U8 | AFMT_S16_LE, NULL, sscape_audio_open, sscape_audio_close, sscape_audio_output_block, sscape_audio_start_input, sscape_audio_ioctl, sscape_audio_prepare_for_input, sscape_audio_prepare_for_output, sscape_audio_reset, sscape_audio_halt, NULL, NULL};longattach_sscape (long mem_start, struct address_info *hw_config){ int my_dev;#ifndef SSCAPE_REGS /* * Config register values for Spea/V7 Media FX and Ensoniq S-2000. * These values are card * dependent. If you have another SoundScape based card, you have to * find the correct values. Do the following: * - Compile this driver with SSCAPE_DEBUG1 defined. * - Shut down and power off your machine. * - Boot with DOS so that the SSINIT.EXE program is run. * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed * when detecting the SoundScape. * - Modify the following list to use the values printed during boot. * Undefine the SSCAPE_DEBUG1 */#define SSCAPE_REGS { \/* I0 */ 0x00, \ 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ 0x20, /* Note! Ignored. Set always to 0x20 */ \ 0x20, /* Note! Ignored. Set always to 0x20 */ \ 0xf5, /* Ignored */ \ 0x10, \ 0x00, \ 0x2e, /* I7 MEM config A. Likely to vary between models */ \ 0x00, /* I8 MEM config A. Likely to vary between models */ \/* I9 */ 0x40 /* Ignored */ \ }#endif unsigned long flags; static unsigned char regs[10] = SSCAPE_REGS; int i, irq_bits = 0xff; if (!probe_sscape (hw_config)) return mem_start; printk (" <Ensoniq Soundscape>"); for (i = 0; i < sizeof (valid_interrupts); i++) if (hw_config->irq == valid_interrupts[i]) { irq_bits = i; break; } if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) { printk ("Invalid IRQ%d\n", hw_config->irq); return mem_start; } DISABLE_INTR (flags); for (i = 1; i < 10; i++) switch (i) { case 1: /* Host interrupt enable */ sscape_write (devc, i, 0xf0); /* All interrupts enabled */ break; case 2: /* DMA A status/trigger register */ case 3: /* DMA B status/trigger register */ sscape_write (devc, i, 0x20); /* DMA channel disabled */ break; case 4: /* Host interrupt config reg */ sscape_write (devc, i, 0xf0 | (irq_bits << 2) | irq_bits); break; case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */ sscape_write (devc, i, (regs[i] & 0x3f) | (sscape_read (devc, i) & 0x0c)); break; case 6: /* CD-ROM config. Don't touch. */ break; case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ sscape_write (devc, i, (sscape_read (devc, i) & 0xf0) | 0x00); break; default: sscape_write (devc, i, regs[i]); } RESTORE_INTR (flags);#ifdef SSCAPE_DEBUG2 /* * Temporary debugging aid. Print contents of the registers after * changing them. */ { int i; for (i = 0; i < 13; i++) printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i)); }#endif#if !defined(EXCLUDE_MIDI) && !defined(EXCLUDE_MPU_EMU) hw_config->always_detect = 1; if (probe_mpu401 (hw_config)) { int prev_devs; prev_devs = num_midis; mem_start = attach_mpu401 (mem_start, hw_config); if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ midi_devs[prev_devs]->coproc = &sscape_coproc_operations; }#endif#ifndef EXCLUDE_NATIVE_PCM /* Not supported yet */#ifndef EXCLUDE_AUDIO if (num_audiodevs < MAX_AUDIO_DEV) { audio_devs[my_dev = num_audiodevs++] = &sscape_audio_operations; audio_devs[my_dev]->dmachan = hw_config->dma; audio_devs[my_dev]->buffcount = 1; audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; audio_devs[my_dev]->devc = devc; devc->my_audiodev = my_dev; devc->opened = 0; audio_devs[my_dev]->coproc = &sscape_coproc_operations; if (snd_set_irq_handler (hw_config->irq, sscapeintr, "SoundScape") < 0) printk ("Error: Can't allocate IRQ for SoundScape\n"); sscape_write (devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ } else printk ("SoundScape: More than enough audio devices detected\n");#endif#endif devc->ok = 1; return mem_start;}intprobe_sscape (struct address_info *hw_config){ unsigned char save; devc->base = hw_config->io_base; devc->irq = hw_config->irq; devc->dma = hw_config->dma; /* * First check that the address register of "ODIE" is * there and that it has exactly 4 writeable bits. * First 4 bits */ if ((save = INB (PORT (ODIE_ADDR))) & 0xf0) return 0; OUTB (0x00, PORT (ODIE_ADDR)); if (INB (PORT (ODIE_ADDR)) != 0x00) return 0; OUTB (0xff, PORT (ODIE_ADDR)); if (INB (PORT (ODIE_ADDR)) != 0x0f) return 0; OUTB (save, PORT (ODIE_ADDR)); /* * Now verify that some indirect registers return zero on some bits. * This may break the driver with some future revisions of "ODIE" but... */ if (sscape_read (devc, 0) & 0x0c) return 0; if (sscape_read (devc, 1) & 0x0f) return 0; if (sscape_read (devc, 5) & 0x0f) return 0;#ifdef SSCAPE_DEBUG1 /* * Temporary debugging aid. Print contents of the registers before * changing them. */ { int i; for (i = 0; i < 13; i++) printk ("I%d = %02x (old value)\n", i, sscape_read (devc, i)); }#endif return 1;}intprobe_ss_ms_sound (struct address_info *hw_config){ int i, irq_bits = 0xff; if (devc->ok == 0) { printk ("SoundScape: Invalid initialization order.\n"); return 0; } for (i = 0; i < sizeof (valid_interrupts); i++) if (hw_config->irq == valid_interrupts[i]) { irq_bits = i; break; }#ifdef REVEAL_SPEA { int tmp, status = 0; int cc; if (!((tmp = sscape_read (devc, GA_HMCTL_REG)) & 0xc0)) { sscape_write (devc, GA_HMCTL_REG, tmp | 0x80); for (cc = 0; cc < 200000; ++cc) INB (devc->base + ODIE_ADDR); } }#endif if (hw_config->irq > 15 || irq_bits == 0xff) { printk ("SoundScape: Invalid MSS IRQ%d\n", hw_config->irq); return 0; } return ad1848_detect (hw_config->io_base);}longattach_ss_ms_sound (long mem_start, struct address_info *hw_config){ /* * This routine configures the SoundScape card for use with the * Win Sound System driver. The AD1848 codec interface uses the CD-ROM * config registers of the "ODIE". */ int i, irq_bits = 0xff;#ifdef EXCLUDE_NATIVE_PCM int prev_devs = num_audiodevs;#endif /* * Setup the DMA polarity. */ sscape_write (devc, GA_DMACFG_REG, 0x50); /* * Take the gate-arry off of the DMA channel. */ sscape_write (devc, GA_DMAB_REG, 0x20); /* * Init the AD1848 (CD-ROM) config reg. */ for (i = 0; i < sizeof (valid_interrupts); i++) if (hw_config->irq == valid_interrupts[i]) { irq_bits = i; break; } sscape_write (devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1)); if (hw_config->irq == devc->irq) printk ("SoundScape: Warning! The WSS mode can't share IRQ with MIDI\n"); ad1848_init ("SoundScape", hw_config->io_base, hw_config->irq, hw_config->dma, hw_config->dma);#ifdef EXCLUDE_NATIVE_PCM if (num_audiodevs == (prev_devs + 1)) /* The AD1848 driver installed itself */ audio_devs[prev_devs]->coproc = &sscape_coproc_operations;#endif#ifdef SSCAPE_DEBUG5 /* * Temporary debugging aid. Print contents of the registers * after the AD1848 device has been initialized. */ { int i; for (i = 0; i < 13; i++) printk ("I%d = %02x\n", i, sscape_read (devc, i)); }#endif return mem_start;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -