📄 msnd_pinnacle.c
字号:
spin_unlock_irqrestore(&dev.lock, flags); return n; } spin_unlock_irqrestore(&dev.lock, flags); buf += n; count -= n; if (!test_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) { dev.last_playbank = -1; if (pack_DAPF_to_DAPQ(1) > 0) set_bit(F_WRITING, &dev.flags); } if (dev.play_ndelay) return count == len ? -EAGAIN : len - count; if (count > 0) { set_bit(F_WRITEBLOCK, &dev.flags); interruptible_sleep_on_timeout( &dev.writeblock, get_play_delay_jiffies(DAP_BUFF_SIZE)); clear_bit(F_WRITEBLOCK, &dev.flags); if (signal_pending(current)) return -EINTR; } } return len - count;}static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off){ int minor = MINOR(file->f_dentry->d_inode->i_rdev); if (minor == dev.dsp_minor) return dsp_read(buf, count); else return -EINVAL;}static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_t *off){ int minor = MINOR(file->f_dentry->d_inode->i_rdev); if (minor == dev.dsp_minor) return dsp_write(buf, count); else return -EINVAL;}static __inline__ void eval_dsp_msg(register WORD wMessage){ switch (HIBYTE(wMessage)) { case HIMT_PLAY_DONE: if (dev.last_playbank == LOBYTE(wMessage) || !test_bit(F_WRITING, &dev.flags)) break; dev.last_playbank = LOBYTE(wMessage); if (pack_DAPF_to_DAPQ(0) <= 0) { if (!test_bit(F_WRITEBLOCK, &dev.flags)) { if (test_and_clear_bit(F_WRITEFLUSH, &dev.flags)) wake_up_interruptible(&dev.writeflush); } clear_bit(F_WRITING, &dev.flags); } if (test_bit(F_WRITEBLOCK, &dev.flags)) wake_up_interruptible(&dev.writeblock); break; case HIMT_RECORD_DONE: if (dev.last_recbank == LOBYTE(wMessage)) break; dev.last_recbank = LOBYTE(wMessage); pack_DARQ_to_DARF(dev.last_recbank); if (test_bit(F_READBLOCK, &dev.flags)) wake_up_interruptible(&dev.readblock); break; case HIMT_DSP: switch (LOBYTE(wMessage)) {#ifndef MSND_CLASSIC case HIDSP_PLAY_UNDER:#endif case HIDSP_INT_PLAY_UNDER:/* printk(KERN_DEBUG LOGNAME ": Play underflow\n"); */ clear_bit(F_WRITING, &dev.flags); break; case HIDSP_INT_RECORD_OVER:/* printk(KERN_DEBUG LOGNAME ": Record overflow\n"); */ clear_bit(F_READING, &dev.flags); break; default:/* printk(KERN_DEBUG LOGNAME ": DSP message %d 0x%02x\n", LOBYTE(wMessage), LOBYTE(wMessage)); */ break; } break; case HIMT_MIDI_IN_UCHAR: if (dev.midi_in_interrupt) (*dev.midi_in_interrupt)(&dev); break; default:/* printk(KERN_DEBUG LOGNAME ": HIMT message %d 0x%02x\n", HIBYTE(wMessage), HIBYTE(wMessage)); */ break; }}static void intr(int irq, void *dev_id, struct pt_regs *regs){ /* Send ack to DSP */ inb(dev.io + HP_RXL); /* Evaluate queued DSP messages */ while (isa_readw(dev.DSPQ + JQS_wTail) != isa_readw(dev.DSPQ + JQS_wHead)) { register WORD wTmp; eval_dsp_msg(isa_readw(dev.pwDSPQData + 2*isa_readw(dev.DSPQ + JQS_wHead))); if ((wTmp = isa_readw(dev.DSPQ + JQS_wHead) + 1) > isa_readw(dev.DSPQ + JQS_wSize)) isa_writew(0, dev.DSPQ + JQS_wHead); else isa_writew(wTmp, dev.DSPQ + JQS_wHead); }}static struct file_operations dev_fileops = { owner: THIS_MODULE, read: dev_read, write: dev_write, ioctl: dev_ioctl, open: dev_open, release: dev_release,};static int reset_dsp(void){ int timeout = 100; outb(HPDSPRESET_ON, dev.io + HP_DSPR); mdelay(1);#ifndef MSND_CLASSIC dev.info = inb(dev.io + HP_INFO);#endif outb(HPDSPRESET_OFF, dev.io + HP_DSPR); mdelay(1); while (timeout-- > 0) { if (inb(dev.io + HP_CVR) == HP_CVR_DEF) return 0; mdelay(1); } printk(KERN_ERR LOGNAME ": Cannot reset DSP\n"); return -EIO;}static int __init probe_multisound(void){#ifndef MSND_CLASSIC char *xv, *rev = NULL; char *pin = "Pinnacle", *fiji = "Fiji"; char *pinfiji = "Pinnacle/Fiji";#endif if (check_region(dev.io, dev.numio)) { printk(KERN_ERR LOGNAME ": I/O port conflict\n"); return -ENODEV; } request_region(dev.io, dev.numio, "probing"); if (reset_dsp() < 0) { release_region(dev.io, dev.numio); return -ENODEV; }#ifdef MSND_CLASSIC dev.name = "Classic/Tahiti/Monterey"; printk(KERN_INFO LOGNAME ": %s, "#else switch (dev.info >> 4) { case 0xf: xv = "<= 1.15"; break; case 0x1: xv = "1.18/1.2"; break; case 0x2: xv = "1.3"; break; case 0x3: xv = "1.4"; break; default: xv = "unknown"; break; } switch (dev.info & 0x7) { case 0x0: rev = "I"; dev.name = pin; break; case 0x1: rev = "F"; dev.name = pin; break; case 0x2: rev = "G"; dev.name = pin; break; case 0x3: rev = "H"; dev.name = pin; break; case 0x4: rev = "E"; dev.name = fiji; break; case 0x5: rev = "C"; dev.name = fiji; break; case 0x6: rev = "D"; dev.name = fiji; break; case 0x7: rev = "A-B (Fiji) or A-E (Pinnacle)"; dev.name = pinfiji; break; } printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, "#endif /* MSND_CLASSIC */ "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%lX-0x%lX\n", dev.name,#ifndef MSND_CLASSIC rev, xv,#endif dev.io, dev.io + dev.numio - 1, dev.irq, dev.base, dev.base + 0x7fff); release_region(dev.io, dev.numio); return 0;}static int init_sma(void){ static int initted; WORD mastVolLeft, mastVolRight; unsigned long flags;#ifdef MSND_CLASSIC outb(dev.memid, dev.io + HP_MEMM);#endif outb(HPBLKSEL_0, dev.io + HP_BLKS); if (initted) { mastVolLeft = isa_readw(dev.SMA + SMA_wCurrMastVolLeft); mastVolRight = isa_readw(dev.SMA + SMA_wCurrMastVolRight); } else mastVolLeft = mastVolRight = 0; isa_memset_io(dev.base, 0, 0x8000); /* Critical section: bank 1 access */ spin_lock_irqsave(&dev.lock, flags); outb(HPBLKSEL_1, dev.io + HP_BLKS); isa_memset_io(dev.base, 0, 0x8000); outb(HPBLKSEL_0, dev.io + HP_BLKS); spin_unlock_irqrestore(&dev.lock, flags); dev.pwDSPQData = (dev.base + DSPQ_DATA_BUFF); dev.pwMODQData = (dev.base + MODQ_DATA_BUFF); dev.pwMIDQData = (dev.base + MIDQ_DATA_BUFF); /* Motorola 56k shared memory base */ dev.SMA = dev.base + SMA_STRUCT_START; /* Digital audio play queue */ dev.DAPQ = dev.base + DAPQ_OFFSET; msnd_init_queue(dev.DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE); /* Digital audio record queue */ dev.DARQ = dev.base + DARQ_OFFSET; msnd_init_queue(dev.DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); /* MIDI out queue */ dev.MODQ = dev.base + MODQ_OFFSET; msnd_init_queue(dev.MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE); /* MIDI in queue */ dev.MIDQ = dev.base + MIDQ_OFFSET; msnd_init_queue(dev.MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE); /* DSP -> host message queue */ dev.DSPQ = dev.base + DSPQ_OFFSET; msnd_init_queue(dev.DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE); /* Setup some DSP values */#ifndef MSND_CLASSIC isa_writew(1, dev.SMA + SMA_wCurrPlayFormat); isa_writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize); isa_writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels); isa_writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate);#endif isa_writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD); isa_writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft); isa_writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight);#ifndef MSND_CLASSIC isa_writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch); isa_writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate);#endif isa_writew(0x303, dev.SMA + SMA_wCurrInputTagBits); initted = 1; return 0;}static int __init calibrate_adc(WORD srate){ isa_writew(srate, dev.SMA + SMA_wCalFreqAtoD); if (dev.calibrate_signal == 0) isa_writew(isa_readw(dev.SMA + SMA_wCurrHostStatusFlags) | 0x0001, dev.SMA + SMA_wCurrHostStatusFlags); else isa_writew(isa_readw(dev.SMA + SMA_wCurrHostStatusFlags) & ~0x0001, dev.SMA + SMA_wCurrHostStatusFlags); if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 && chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ / 3); return 0; } printk(KERN_WARNING LOGNAME ": ADC calibration failed\n"); return -EIO;}static int upload_dsp_code(void){ outb(HPBLKSEL_0, dev.io + HP_BLKS);#ifndef HAVE_DSPCODEH INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE); if (!INITCODE) { printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE); return -EBUSY; } PERMCODESIZE = mod_firmware_load(PERMCODEFILE, &PERMCODE); if (!PERMCODE) { printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE); vfree(INITCODE); return -EBUSY; }#endif isa_memcpy_toio(dev.base, PERMCODE, PERMCODESIZE); if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) { printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n"); return -ENODEV; }#ifdef HAVE_DSPCODEH printk(KERN_INFO LOGNAME ": DSP firmware uploaded (resident)\n");#else printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n");#endif#ifndef HAVE_DSPCODEH vfree(INITCODE); vfree(PERMCODE);#endif return 0;}#ifdef MSND_CLASSICstatic void reset_proteus(void){ outb(HPPRORESET_ON, dev.io + HP_PROR); mdelay(TIME_PRO_RESET); outb(HPPRORESET_OFF, dev.io + HP_PROR); mdelay(TIME_PRO_RESET_DONE);}#endifstatic int initialize(void){ int err, timeout;#ifdef MSND_CLASSIC outb(HPWAITSTATE_0, dev.io + HP_WAIT); outb(HPBITMODE_16, dev.io + HP_BITM); reset_proteus();#endif if ((err = init_sma()) < 0) { printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n"); return err; } if ((err = reset_dsp()) < 0) return err; if ((err = upload_dsp_code()) < 0) { printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n"); return err; } timeout = 200; while (isa_readw(dev.base)) { mdelay(1); if (!timeout--) { printk(KERN_DEBUG LOGNAME ": DSP reset timeout\n"); return -EIO; } } mixer_setup(); return 0;}static int dsp_full_reset(void){ int rv; if (test_bit(F_RESETTING, &dev.flags) || ++dev.nresets > 10) return 0; set_bit(F_RESETTING, &dev.flags); printk(KERN_INFO LOGNAME ": DSP reset\n"); dsp_halt(NULL); /* Unconditionally halt */ if ((rv = initialize())) printk(KERN_WARNING LOGNAME ": DSP reset failed\n"); force_recsrc(dev.recsrc); dsp_open(NULL); clear_bit(F_RESETTING, &dev.flags); return rv;}static int __init attach_multisound(void){ int err; if ((err = request_irq(dev.irq, intr, 0, dev.name, &dev)) < 0) { printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq); return err; } request_region(dev.io, dev.numio, dev.name); if ((err = dsp_full_reset()) < 0) { release_region(dev.io, dev.numio); free_irq(dev.irq, &dev); return err; } if ((err = msnd_register(&dev)) < 0) { printk(KERN_ERR LOGNAME ": Unable to register MultiSound\n"); release_region(dev.io, dev.numio); free_irq(dev.irq, &dev); return err; } if ((dev.dsp_minor = register_sound_dsp(&dev_fileops, -1)) < 0) { printk(KERN_ERR LOGNAME ": Unable to register DSP operations\n"); msnd_unregister(&dev); release_region(dev.io, dev.numio); free_irq(dev.irq, &dev); return dev.dsp_minor; } if ((dev.mixer_minor = register_sound_mixer(&dev_fileops, -1)) < 0) { printk(KERN_ERR LOGNAME ": Unable to register mixer operations\n"); unregister_sound_mixer(dev.mixer_minor); msnd_unregister(&dev); release_region(dev.io, dev.numio); free_irq(dev.irq, &dev); return dev.mixer_minor; } dev.ext_midi_dev = dev.hdr_midi_dev = -1; disable_irq(dev.irq); calibrate_adc(dev.play_sample_rate);#ifndef MSND_CLASSIC force_recsrc(SOUND_MASK_IMIX);#endif return 0;}static void __exit unload_multisound(void){ release_region(dev.io, dev.numio); free_irq(dev.irq, &dev); unregister_sound_mixer(dev.mixer_minor); unregister_sound_dsp(dev.dsp_minor); msnd_unregister(&dev);}#ifndef MSND_CLASSIC
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -