📄 ad1848.c
字号:
outb(0x00, 0xc46); outb(0xe8, 0xc47); outb(0x14, 0xc44); outb(0x40, 0xc45); outb(0x00, 0xc46); outb(0xe8, 0xc47); outb(0x10, 0xc44); return 1;}/* * Experimental initialization sequence for the integrated sound system * of Compaq Deskpro XL. */static int init_deskpro(struct address_info *hw_config){ unsigned char tmp; if ((tmp = inb(0xc44)) == 0xff) { DDB(printk("init_deskpro: Dead port 0xc44\n")); return 0; } outb((tmp | 0x04), 0xc44); /* Select bank 1 */ if (inb(0xc44) != 0x04) { DDB(printk("init_deskpro: Invalid bank1 signature in port 0xc44\n")); return 0; } /* * OK. It looks like a Deskpro so let's proceed. */ /* * I/O port 0xc44 Audio configuration register. * * bits 0xc0: Audio revision bits * 0x00 = Compaq Business Audio * 0x40 = MS Sound System Compatible (reset default) * 0x80 = Reserved * 0xc0 = Reserved * bit 0x20: No Wait State Enable * 0x00 = Disabled (reset default, DMA mode) * 0x20 = Enabled (programmed I/O mode) * bit 0x10: MS Sound System Decode Enable * 0x00 = Decoding disabled (reset default) * 0x10 = Decoding enabled * bit 0x08: FM Synthesis Decode Enable * 0x00 = Decoding Disabled (reset default) * 0x08 = Decoding enabled * bit 0x04 Bank select * 0x00 = Bank 0 * 0x04 = Bank 1 * bits 0x03 MSS Base address * 0x00 = 0x530 (reset default) * 0x01 = 0x604 * 0x02 = 0xf40 * 0x03 = 0xe80 */#ifdef DEBUGXL /* Debug printing */ printk("Port 0xc44 (before): "); outb((tmp & ~0x04), 0xc44); printk("%02x ", inb(0xc44)); outb((tmp | 0x04), 0xc44); printk("%02x\n", inb(0xc44));#endif /* Set bank 1 of the register */ tmp = 0x58; /* MSS Mode, MSS&FM decode enabled */ switch (hw_config->io_base) { case 0x530: tmp |= 0x00; break; case 0x604: tmp |= 0x01; break; case 0xf40: tmp |= 0x02; break; case 0xe80: tmp |= 0x03; break; default: DDB(printk("init_deskpro: Invalid MSS port %x\n", hw_config->io_base)); return 0; } outb((tmp & ~0x04), 0xc44); /* Write to bank=0 */#ifdef DEBUGXL /* Debug printing */ printk("Port 0xc44 (after): "); outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ printk("%02x ", inb(0xc44)); outb((tmp | 0x04), 0xc44); /* Select bank=1 */ printk("%02x\n", inb(0xc44));#endif /* * I/O port 0xc45 FM Address Decode/MSS ID Register. * * bank=0, bits 0xfe: FM synthesis Decode Compare bits 7:1 (default=0x88) * bank=0, bit 0x01: SBIC Power Control Bit * 0x00 = Powered up * 0x01 = Powered down * bank=1, bits 0xfc: MSS ID (default=0x40) */#ifdef DEBUGXL /* Debug printing */ printk("Port 0xc45 (before): "); outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ printk("%02x ", inb(0xc45)); outb((tmp | 0x04), 0xc44); /* Select bank=1 */ printk("%02x\n", inb(0xc45));#endif outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ outb((0x88), 0xc45); /* FM base 7:0 = 0x88 */ outb((tmp | 0x04), 0xc44); /* Select bank=1 */ outb((0x10), 0xc45); /* MSS ID = 0x10 (MSS port returns 0x04) */#ifdef DEBUGXL /* Debug printing */ printk("Port 0xc45 (after): "); outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ printk("%02x ", inb(0xc45)); outb((tmp | 0x04), 0xc44); /* Select bank=1 */ printk("%02x\n", inb(0xc45));#endif /* * I/O port 0xc46 FM Address Decode/Address ASIC Revision Register. * * bank=0, bits 0xff: FM synthesis Decode Compare bits 15:8 (default=0x03) * bank=1, bits 0xff: Audio addressing ASIC id */#ifdef DEBUGXL /* Debug printing */ printk("Port 0xc46 (before): "); outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ printk("%02x ", inb(0xc46)); outb((tmp | 0x04), 0xc44); /* Select bank=1 */ printk("%02x\n", inb(0xc46));#endif outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ outb((0x03), 0xc46); /* FM base 15:8 = 0x03 */ outb((tmp | 0x04), 0xc44); /* Select bank=1 */ outb((0x11), 0xc46); /* ASIC ID = 0x11 */#ifdef DEBUGXL /* Debug printing */ printk("Port 0xc46 (after): "); outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ printk("%02x ", inb(0xc46)); outb((tmp | 0x04), 0xc44); /* Select bank=1 */ printk("%02x\n", inb(0xc46));#endif /* * I/O port 0xc47 FM Address Decode Register. * * bank=0, bits 0xff: Decode enable selection for various FM address bits * bank=1, bits 0xff: Reserved */#ifdef DEBUGXL /* Debug printing */ printk("Port 0xc47 (before): "); outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ printk("%02x ", inb(0xc47)); outb((tmp | 0x04), 0xc44); /* Select bank=1 */ printk("%02x\n", inb(0xc47));#endif outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ outb((0x7c), 0xc47); /* FM decode enable bits = 0x7c */ outb((tmp | 0x04), 0xc44); /* Select bank=1 */ outb((0x00), 0xc47); /* Reserved bank1 = 0x00 */#ifdef DEBUGXL /* Debug printing */ printk("Port 0xc47 (after): "); outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ printk("%02x ", inb(0xc47)); outb((tmp | 0x04), 0xc44); /* Select bank=1 */ printk("%02x\n", inb(0xc47));#endif /* * I/O port 0xc6f = Audio Disable Function Register */#ifdef DEBUGXL printk("Port 0xc6f (before) = %02x\n", inb(0xc6f));#endif outb((0x80), 0xc6f);#ifdef DEBUGXL printk("Port 0xc6f (after) = %02x\n", inb(0xc6f));#endif return 1;}int probe_ms_sound(struct address_info *hw_config){ unsigned char tmp; DDB(printk("Entered probe_ms_sound(%x, %d)\n", hw_config->io_base, hw_config->card_subtype)); if (check_region(hw_config->io_base, 8)) { printk(KERN_ERR "MSS: I/O port conflict\n"); return 0; } if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ { /* check_opl3(0x388, hw_config); */ return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); } if (deskpro_xl && hw_config->card_subtype == 2) /* Compaq Deskpro XL */ { if (!init_deskpro(hw_config)) return 0; } if (deskpro_m) /* Compaq Deskpro M */ { if (!init_deskpro_m(hw_config)) return 0; } /* * Check if the IO port returns valid signature. The original MS Sound * system returns 0x04 while some cards (AudioTrix Pro for example) * return 0x00 or 0x0f. */ if ((tmp = inb(hw_config->io_base + 3)) == 0xff) /* Bus float */ { int ret; DDB(printk("I/O address is inactive (%x)\n", tmp)); if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp))) return 0; return 1; } DDB(printk("MSS signature = %x\n", tmp & 0x3f)); if ((tmp & 0x3f) != 0x04 && (tmp & 0x3f) != 0x0f && (tmp & 0x3f) != 0x00) { int ret; MDB(printk(KERN_ERR "No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, (int) inb(hw_config->io_base + 3))); DDB(printk("Trying to detect codec anyway but IRQ/DMA may not work\n")); if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp))) return 0; hw_config->card_subtype = 1; return 1; } 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)) { printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq); return 0; } if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) { printk(KERN_ERR "MSS: Bad DMA %d\n", hw_config->dma); return 0; } /* * Check that DMA0 is not in use with a 8 bit board. */ if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) { printk(KERN_ERR "MSS: Can't use DMA0 with a 8 bit card/slot\n"); return 0; } if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) { printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); return 0; } return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp);}void attach_ms_sound(struct address_info *hw_config, struct module *owner){ static signed char interrupt_bits[12] = { -1, -1, -1, -1, -1, 0x00, -1, 0x08, -1, 0x10, 0x18, 0x20 }; signed char bits; char dma2_bit = 0; static char dma_bits[4] = { 1, 2, 0, 3 }; int config_port = hw_config->io_base + 0; int version_port = hw_config->io_base + 3; int dma = hw_config->dma; int dma2 = hw_config->dma2; if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ { hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4, hw_config->irq, hw_config->dma, hw_config->dma2, 0, hw_config->osp, owner); request_region(hw_config->io_base, 4, "WSS config"); return; } /* * Set the IRQ and DMA addresses. */ bits = interrupt_bits[hw_config->irq]; if (bits == -1) { printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq); return; } outb((bits | 0x40), config_port); if ((inb(version_port) & 0x40) == 0) printk(KERN_ERR "[MSS: IRQ Conflict?]\n");/* * Handle the capture DMA channel */ if (dma2 != -1 && dma2 != dma) { if (!((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) || (dma == 3 && dma2 == 0))) { /* Unsupported combination. Try to swap channels */ int tmp = dma; dma = dma2; dma2 = tmp; } if ((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) || (dma == 3 && dma2 == 0)) { dma2_bit = 0x04; /* Enable capture DMA */ } else { printk(KERN_WARNING "MSS: Invalid capture DMA\n"); dma2 = dma; } } else { dma2 = dma; } hw_config->dma = dma; hw_config->dma2 = dma2; outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4, hw_config->irq, dma, dma2, 0, hw_config->osp, THIS_MODULE); request_region(hw_config->io_base, 4, "WSS config");}void unload_ms_sound(struct address_info *hw_config){ ad1848_unload(hw_config->io_base + 4, hw_config->irq, hw_config->dma, hw_config->dma2, 0); sound_unload_audiodev(hw_config->slots[0]); release_region(hw_config->io_base, 4);}#ifndef EXCLUDE_TIMERS/* * Timer stuff (for /dev/music). */static unsigned int current_interval = 0;static unsigned int ad1848_tmr_start(int dev, unsigned int usecs){ unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; unsigned long xtal_nsecs; /* nanoseconds per xtal oscillator tick */ unsigned long divider; save_flags(flags); cli(); /* * Length of the timer interval (in nanoseconds) depends on the * selected crystal oscillator. Check this from bit 0x01 of I8. * * AD1845 has just one oscillator which has cycle time of 10.050 us * (when a 24.576 MHz xtal oscillator is used). * * Convert requested interval to nanoseconds before computing * the timer divider. */ if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE) xtal_nsecs = 10050; else if (ad_read(devc, 8) & 0x01) xtal_nsecs = 9920; else xtal_nsecs = 9969; divider = (usecs * 1000 + xtal_nsecs / 2) / xtal_nsecs; if (divider < 100) /* Don't allow shorter intervals than about 1ms */ divider = 100; if (divider > 65535) /* Overflow check */ divider = 65535; ad_write(devc, 21, (divider >> 8) & 0xff); /* Set upper bits */ ad_write(devc, 20, divider & 0xff); /* Set lower bits */ ad_write(devc, 16, ad_read(devc, 16) | 0x40); /* Start the timer */ devc->timer_running = 1; restore_flags(flags); return current_interval = (divider * xtal_nsecs + 500) / 1000;}static void ad1848_tmr_reprogram(int dev){ /* * Audio driver has changed sampling rate so that a different xtal * oscillator was selected. We have to reprogram the timer rate. */ ad1848_tmr_start(dev, current_interval); sound_timer_syncinterval(current_interval);}static void ad1848_tmr_disable(int dev){ unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; save_flags(flags); cli(); ad_write(devc, 16, ad_read(devc, 16) & ~0x40); devc->timer_running = 0; restore_flags(flags);}static void ad1848_tmr_restart(int dev){ unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; if (current_interval == 0) return; save_flags(flags); cli(); ad_write(devc, 16, ad_read(devc, 16) | 0x40); devc->timer_running = 1; restore_flags(flags);}static struct sound_lowlev_timer ad1848_tmr ={ 0, 2, ad1848_tmr_start, ad1848_tmr_disable, ad1848_tmr_restart};static int ad1848_tmr_install(int dev){ if (timer_installed != -1) return 0; /* Don't install another timer */ timer_installed = ad1848_tmr.dev = dev; sound_timer_init(&ad1848_tmr, audio_devs[dev]->name); return 1;}#endif /* EXCLUDE_TIMERS */static int ad1848_suspend(ad1848_info *devc){ unsigned long flags; save_flags(flags); cli(); ad_mute(devc); restore_flags(flags); return 0;}static int ad1848_resume(ad1848_info *devc){ unsigned long flags; int mixer_levels[32], i; save_flags(flags); cli(); /* store old mixer levels */ memcpy(mixer_levels, devc->levels, sizeof (mixer_levels)); ad1848_init_hw(devc); /* restore mixer levels */ for (i = 0; i < 32; i++) ad1848_mixer_set(devc, devc->dev_no, mixer_levels[i]); if (!devc->subtype) { static signed char interrupt_bits[12
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -