📄 ad1848.c
字号:
void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int share_dma){ int i, mixer, dev = 0; ad1848_info *devc = NULL; for (i = 0; devc == NULL && i < nr_ad1848_devs; i++) { if (adev_info[i].base == io_base) { devc = &adev_info[i]; dev = devc->dev_no; } } if (devc != NULL) { if(audio_devs[dev]->portc!=NULL) kfree(audio_devs[dev]->portc); release_region(devc->base, 4); if (!share_dma) { if (devc->irq > 0) /* There is no point in freeing irq, if it wasn't allocated */ free_irq(devc->irq, (void *)devc->dev_no); sound_free_dma(dma_playback); if (dma_playback != dma_capture) sound_free_dma(dma_capture); } mixer = audio_devs[devc->dev_no]->mixer_dev; if(mixer>=0) sound_unload_mixerdev(mixer); if (devc->pmdev) pm_unregister(devc->pmdev); nr_ad1848_devs--; for ( ; i < nr_ad1848_devs ; i++) adev_info[i] = adev_info[i+1]; } else printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base);}void adintr(int irq, void *dev_id, struct pt_regs *dummy){ unsigned char status; ad1848_info *devc; int dev; int alt_stat = 0xff; unsigned char c930_stat = 0; int cnt = 0; dev = (int)dev_id; devc = (ad1848_info *) audio_devs[dev]->devc;interrupt_again: /* Jump back here if int status doesn't reset */ status = inb(io_Status(devc)); if (status == 0x80) printk(KERN_DEBUG "adintr: Why?\n"); if (devc->model == MD_1848) outb((0), io_Status(devc)); /* Clear interrupt status */ if (status & 0x01) { if (devc->model == MD_C930) { /* 82C930 has interrupt status register in MAD16 register MC11 */ unsigned long flags; save_flags(flags); cli(); /* 0xe0e is C930 address port * 0xe0f is C930 data port */ outb(11, 0xe0e); c930_stat = inb(0xe0f); outb((~c930_stat), 0xe0f); restore_flags(flags); alt_stat = (c930_stat << 2) & 0x30; } else if (devc->model != MD_1848) { alt_stat = ad_read(devc, 24); ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat); /* Selective ack */ } if ((devc->open_mode & OPEN_READ) && (devc->audio_mode & PCM_ENABLE_INPUT) && (alt_stat & 0x20)) { DMAbuf_inputintr(devc->record_dev); } if ((devc->open_mode & OPEN_WRITE) && (devc->audio_mode & PCM_ENABLE_OUTPUT) && (alt_stat & 0x10)) { DMAbuf_outputintr(devc->playback_dev, 1); } if (devc->model != MD_1848 && (alt_stat & 0x40)) /* Timer interrupt */ { devc->timer_ticks++;#ifndef EXCLUDE_TIMERS if (timer_installed == dev && devc->timer_running) sound_timer_interrupt();#endif } }/* * Sometimes playback or capture interrupts occur while a timer interrupt * is being handled. The interrupt will not be retriggered if we don't * handle it now. Check if an interrupt is still pending and restart * the handler in this case. */ if (inb(io_Status(devc)) & 0x01 && cnt++ < 4) { goto interrupt_again; }}/* * Experimental initialization sequence for the integrated sound system * of the Compaq Deskpro M. */static int init_deskpro_m(struct address_info *hw_config){ unsigned char tmp; if ((tmp = inb(0xc44)) == 0xff) { DDB(printk("init_deskpro_m: Dead port 0xc44\n")); return 0; } outb(0x10, 0xc44); outb(0x40, 0xc45); 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -