📄 sscape.c
字号:
done = 1; } } sscape_write(devc, GA_CDCFG_REG, codec_dma_bits); restore_flags(flags); if (!done) { printk(KERN_ERR "soundscape: The OBP didn't respond after code download\n"); return 0; } save_flags(flags); cli(); done = 0; timeout_val = 5 * HZ; while (!done && timeout_val-- > 0) { sleep(1); if (inb(PORT(HOST_DATA)) == 0xfe) /* Host startup acknowledge */ done = 1; } restore_flags(flags); if (!done) { printk(KERN_ERR "soundscape: OBP Initialization failed.\n"); return 0; } printk(KERN_INFO "SoundScape board initialized OK\n"); set_control(devc, CTL_MASTER_VOL, 100); set_control(devc, CTL_SYNTH_VOL, 100);#ifdef SSCAPE_DEBUG3 /* * Temporary debugging aid. Print contents of the registers after * downloading the code. */ { int i; for (i = 0; i < 13; i++) printk("I%d = %02x (new value)\n", i, sscape_read(devc, i)); }#endif } return 1;}static int download_boot_block(void *dev_info, copr_buffer * buf){ if (buf->len <= 0 || buf->len > sizeof(buf->data)) return -EINVAL; if (!sscape_download_boot(devc, buf->data, buf->len, buf->flags)) { printk(KERN_ERR "soundscape: Unable to load microcode block to the OBP.\n"); return -EIO; } return 0;}static int sscape_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int local){ copr_buffer *buf; int err; switch (cmd) { case SNDCTL_COPR_RESET: sscape_coproc_reset(dev_info); return 0; case SNDCTL_COPR_LOAD: buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); if (buf == NULL) return -ENOSPC; if (copy_from_user(buf, arg, sizeof(copr_buffer))) { vfree(buf); return -EFAULT; } err = download_boot_block(dev_info, buf); vfree(buf); return err; default: return -EINVAL; }}static coproc_operations sscape_coproc_operations ={ "SoundScape M68K", THIS_MODULE, sscape_coproc_open, sscape_coproc_close, sscape_coproc_ioctl, sscape_coproc_reset, &adev_info};static int sscape_detected = 0;static int sscape_is_pnp = 0;void __init attach_sscape(struct address_info *hw_config){#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, \/* I1 */ 0xf0, /* Note! Ignored. Set always to 0xf0 */ \/* I2 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \/* I3 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \/* I4 */ 0xf5, /* Ignored */ \/* I5 */ 0x10, \/* I6 */ 0x00, \/* I7 */ 0x2e, /* I7 MEM config A. Likely to vary between models */ \/* I8 */ 0x00, /* I8 MEM config B. 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 (sscape_detected != hw_config->io_base) return; request_region(devc->base + 2, 6, "SoundScape"); if (old_hardware) { valid_interrupts = valid_interrupts_old; conf_printf("Ensoniq SoundScape (old)", hw_config); } else conf_printf("Ensoniq SoundScape", hw_config); 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(KERN_ERR "Invalid IRQ%d\n", hw_config->irq); return; } if (!sscape_is_pnp) { save_flags(flags); cli(); 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) & 0xc0)); break; case 6: /* CD-ROM config (WSS codec actually) */ sscape_write(devc, i, regs[i]); break; case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ sscape_write(devc, i, (sscape_read(devc, i) & 0xf0) | 0x08); break; default: sscape_write(devc, i, regs[i]); } } restore_flags(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 (probe_mpu401(hw_config)) hw_config->always_detect = 1; hw_config->name = "SoundScape"; hw_config->irq *= -1; /* Negative value signals IRQ sharing */ attach_mpu401(hw_config, THIS_MODULE); hw_config->irq *= -1; /* Restore it */ if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ { sscape_mididev = hw_config->slots[1]; midi_devs[hw_config->slots[1]]->coproc = &sscape_coproc_operations; } sscape_write(devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ devc->ok = 1; devc->failed = 0;}static int detect_ga(sscape_info * devc){ unsigned char save; DDB(printk("Entered Soundscape detect_ga(%x)\n", devc->base)); if (check_region(devc->base, 8)) return 0; /* * First check that the address register of "ODIE" is * there and that it has exactly 4 writable bits. * First 4 bits */ if ((save = inb(PORT(ODIE_ADDR))) & 0xf0) { DDB(printk("soundscape: Detect error A\n")); return 0; } outb((0x00), PORT(ODIE_ADDR)); if (inb(PORT(ODIE_ADDR)) != 0x00) { DDB(printk("soundscape: Detect error B\n")); return 0; } outb((0xff), PORT(ODIE_ADDR)); if (inb(PORT(ODIE_ADDR)) != 0x0f) { DDB(printk("soundscape: Detect error C\n")); 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) { DDB(printk("soundscape: Detect error D (%x)\n", sscape_read(devc, 0))); return 0; } if (sscape_read(devc, 1) & 0x0f) { DDB(printk("soundscape: Detect error E\n")); return 0; } if (sscape_read(devc, 5) & 0x0f) { DDB(printk("soundscape: Detect error F\n")); return 0; } return 1;}static int sscape_read_host_ctrl(sscape_info* devc){ return host_read(devc);}static void sscape_write_host_ctrl2(sscape_info *devc, int a, int b){ host_command2(devc, a, b);}static int sscape_alloc_dma(sscape_info *devc){ char *start_addr, *end_addr; int dma_pagesize; int sz, size; struct page *page; if (devc->raw_buf != NULL) return 0; /* Already done */ dma_pagesize = (devc->dma < 4) ? (64 * 1024) : (128 * 1024); devc->raw_buf = NULL; devc->buffsize = 8192*4; if (devc->buffsize > dma_pagesize) devc->buffsize = dma_pagesize; start_addr = NULL; /* * Now loop until we get a free buffer. Try to get smaller buffer if * it fails. Don't accept smaller than 8k buffer for performance * reasons. */ while (start_addr == NULL && devc->buffsize > PAGE_SIZE) { for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1); devc->buffsize = PAGE_SIZE * (1 << sz); start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz); if (start_addr == NULL) devc->buffsize /= 2; } if (start_addr == NULL) { printk(KERN_ERR "sscape pnp init error: Couldn't allocate DMA buffer\n"); return 0; } else { /* make some checks */ end_addr = start_addr + devc->buffsize - 1; /* now check if it fits into the same dma-pagesize */ if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1)) || end_addr >= (char *) (MAX_DMA_ADDRESS)) { printk(KERN_ERR "sscape pnp: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, devc->buffsize); return 0; } } devc->raw_buf = start_addr; devc->raw_buf_phys = virt_to_bus(start_addr); for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) mem_map_reserve(page); return 1;}static void sscape_free_dma(sscape_info *devc){ int sz, size; unsigned long start_addr, end_addr; struct page *page; if (devc->raw_buf == NULL) return; for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1); start_addr = (unsigned long) devc->raw_buf; end_addr = start_addr + devc->buffsize; for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) mem_map_unreserve(page); free_pages((unsigned long) devc->raw_buf, sz); devc->raw_buf = NULL;}/* Intel version !!!!!!!!! */static int sscape_start_dma(int chan, unsigned long physaddr, int count, int dma_mode){ unsigned long flags; flags = claim_dma_lock(); disable_dma(chan); clear_dma_ff(chan); set_dma_mode(chan, dma_mode); set_dma_addr(chan, physaddr); set_dma_count(chan, count); enable_dma(chan); release_dma_lock(flags); return 0;}static void sscape_pnp_start_dma(sscape_info* devc, int arg ){ int reg; if (arg == 0) reg = 2; else reg = 3; sscape_write(devc, reg, sscape_read( devc, reg) | 0x01); sscape_write(devc, reg, sscape_read( devc, reg) & 0xFE);}static int sscape_pnp_wait_dma (sscape_info* devc, int arg ){ int reg; unsigned long i; unsigned char d; if (arg == 0) reg = 2; else reg = 3; sleep ( 1 ); i = 0; do { d = sscape_read(devc, reg) & 1; if ( d == 1) break; i++; } while (i < 500000); d = sscape_read(devc, reg) & 1; return d;}static int sscape_pnp_alloc_dma(sscape_info* devc){ /* printk(KERN_INFO "sscape: requesting dma\n"); */ if (request_dma(devc -> dma, "sscape")) return 0; /* printk(KERN_INFO "sscape: dma channel allocated\n"); */ if (!sscape_alloc_dma(devc)) { free_dma(devc -> dma); return 0; }; return 1;}static void sscape_pnp_free_dma(sscape_info* devc){ sscape_free_dma( devc); free_dma(devc -> dma ); /* printk(KERN_INFO "sscape: dma released\n"); */}static int sscape_pnp_upload_file(sscape_info* devc, char* fn){ int done = 0; int timeout_val; char* data,*dt; int len,l; unsigned long flags; sscape_write( devc, 9, sscape_read(devc, 9 ) & 0x3F ); sscape_write( devc, 2, (devc -> dma << 4) | 0x80 ); sscape_write( devc, 3, 0x20 ); sscape_write( devc, 9, sscape_read( devc, 9 ) | 0x80 ); len = mod_firmware_load(fn, &data); if (len == 0) { printk(KERN_ERR "sscape: file not found: %s\n", fn); return 0; } dt = data; save_flags(flags); cli(); while ( len > 0 ) { if (len > devc -> buffsize) l = devc->buffsize; else l = len; len -= l; memcpy(devc->raw_buf, dt, l); dt += l; sscape_start_dma(devc->dma, devc->raw_buf_phys, l, 0x48); sscape_pnp_start_dma ( devc, 0 ); if (sscape_pnp_wait_dma ( devc, 0 ) == 0) { restore_flags(flags); return 0; } } restore_flags(flags); vfree(data); outb(0, devc -> base + 2); outb(0, devc -> base); sscape_write ( devc, 9, sscape_read( devc, 9 ) | 0x40); timeout_val = 5 * HZ; while (!done && timeout_val-- > 0) { unsigned char x; sleep(1); x = inb( devc -> base + 3); if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ { //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x); done = 1; } } timeout_val = 5 * HZ; done = 0; while (!done && timeout_val-- > 0) { unsigned char x; sleep(1); x = inb( devc -> base + 3); if (x == 0xfe) /* OBP startup acknowledge */ { //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x); done = 1; } } if ( !done ) printk(KERN_ERR "soundscape: OBP Initialization failed.\n"); sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40); sscape_write( devc, 3, (devc -> dma << 4) + 0x80); return 1;}static void __init sscape_pnp_init_hw(sscape_info* devc){ unsigned char midi_irq = 0, sb_irq = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -