📄 wavefront_synth.c
字号:
Don't fetch unsupplied data from user space, just continue with whatever the final value was. */ } if (i < blocksize - 1) { outw (sample_short, dev->block_port); } else { outw (sample_short, dev->last_block_port); } } /* Get "DMA page acknowledge", even though its really nothing to do with DMA at all. */ if ((dma_ack = wavefront_read (dev)) != WF_DMA_ACK) { if (dma_ack == -1) { snd_printk ("upload sample " "DMA ack timeout\n"); return -(EIO); } else { snd_printk ("upload sample " "DMA ack error 0x%x\n", dma_ack); return -(EIO); } } } dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_SAMPLE); /* Note, label is here because sending the sample header shouldn't alter the sample_status info at all. */ sent: return (0);}static intwavefront_send_alias (snd_wavefront_t *dev, wavefront_patch_info *header){ unsigned char alias_hdr[WF_ALIAS_BYTES]; DPRINT (WF_DEBUG_LOAD_PATCH, "download alias, %d is " "alias for %d\n", header->number, header->hdr.a.OriginalSample); munge_int32 (header->number, &alias_hdr[0], 2); munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2); munge_int32 (*((unsigned int *)&header->hdr.a.sampleStartOffset), &alias_hdr[4], 4); munge_int32 (*((unsigned int *)&header->hdr.a.loopStartOffset), &alias_hdr[8], 4); munge_int32 (*((unsigned int *)&header->hdr.a.loopEndOffset), &alias_hdr[12], 4); munge_int32 (*((unsigned int *)&header->hdr.a.sampleEndOffset), &alias_hdr[16], 4); munge_int32 (header->hdr.a.FrequencyBias, &alias_hdr[20], 3); munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2); if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) { snd_printk ("download alias failed.\n"); return -(EIO); } dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS); return (0);}static intwavefront_send_multisample (snd_wavefront_t *dev, wavefront_patch_info *header){ int i; int num_samples; unsigned char *msample_hdr; msample_hdr = kmalloc(sizeof(WF_MSAMPLE_BYTES), GFP_KERNEL); if (! msample_hdr) return -ENOMEM; munge_int32 (header->number, &msample_hdr[0], 2); /* You'll recall at this point that the "number of samples" value in a wavefront_multisample struct is actually the log2 of the real number of samples. */ num_samples = (1<<(header->hdr.ms.NumberOfSamples&7)); msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples; DPRINT (WF_DEBUG_LOAD_PATCH, "multi %d with %d=%d samples\n", header->number, header->hdr.ms.NumberOfSamples, num_samples); for (i = 0; i < num_samples; i++) { DPRINT(WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA, "sample[%d] = %d\n", i, header->hdr.ms.SampleNumber[i]); munge_int32 (header->hdr.ms.SampleNumber[i], &msample_hdr[3+(i*2)], 2); } /* Need a hack here to pass in the number of bytes to be written to the synth. This is ugly, and perhaps one day, I'll fix it. */ if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_MULTISAMPLE, (unsigned char *) (long) ((num_samples*2)+3), msample_hdr)) { snd_printk ("download of multisample failed.\n"); kfree(msample_hdr); return -(EIO); } dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE); kfree(msample_hdr); return (0);}static intwavefront_fetch_multisample (snd_wavefront_t *dev, wavefront_patch_info *header){ int i; unsigned char log_ns[1]; unsigned char number[2]; int num_samples; munge_int32 (header->number, number, 2); if (snd_wavefront_cmd (dev, WFC_UPLOAD_MULTISAMPLE, log_ns, number)) { snd_printk ("upload multisample failed.\n"); return -(EIO); } DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n", header->number, log_ns[0]); header->hdr.ms.NumberOfSamples = log_ns[0]; /* get the number of samples ... */ num_samples = (1 << log_ns[0]); for (i = 0; i < num_samples; i++) { char d[2]; int val; if ((val = wavefront_read (dev)) == -1) { snd_printk ("upload multisample failed " "during sample loop.\n"); return -(EIO); } d[0] = val; if ((val = wavefront_read (dev)) == -1) { snd_printk ("upload multisample failed " "during sample loop.\n"); return -(EIO); } d[1] = val; header->hdr.ms.SampleNumber[i] = demunge_int32 ((unsigned char *) d, 2); DPRINT (WF_DEBUG_DATA, "msample sample[%d] = %d\n", i, header->hdr.ms.SampleNumber[i]); } return (0);}static intwavefront_send_drum (snd_wavefront_t *dev, wavefront_patch_info *header){ unsigned char drumbuf[WF_DRUM_BYTES]; wavefront_drum *drum = &header->hdr.d; int i; DPRINT (WF_DEBUG_LOAD_PATCH, "downloading edrum for MIDI " "note %d, patch = %d\n", header->number, drum->PatchNumber); drumbuf[0] = header->number & 0x7f; for (i = 0; i < 4; i++) { munge_int32 (((unsigned char *)drum)[i], &drumbuf[1+(i*2)], 2); } if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) { snd_printk ("download drum failed.\n"); return -(EIO); } return (0);}static int wavefront_find_free_sample (snd_wavefront_t *dev){ int i; for (i = 0; i < WF_MAX_SAMPLE; i++) { if (!(dev->sample_status[i] & WF_SLOT_FILLED)) { return i; } } snd_printk ("no free sample slots!\n"); return -1;}#if 0static int wavefront_find_free_patch (snd_wavefront_t *dev){ int i; for (i = 0; i < WF_MAX_PATCH; i++) { if (!(dev->patch_status[i] & WF_SLOT_FILLED)) { return i; } } snd_printk ("no free patch slots!\n"); return -1;}#endifstatic intwavefront_load_patch (snd_wavefront_t *dev, const char __user *addr){ wavefront_patch_info *header; int err; header = kmalloc(sizeof(*header), GFP_KERNEL); if (! header) return -ENOMEM; if (copy_from_user (header, addr, sizeof(wavefront_patch_info) - sizeof(wavefront_any))) { snd_printk ("bad address for load patch.\n"); err = -EFAULT; goto __error; } DPRINT (WF_DEBUG_LOAD_PATCH, "download " "Sample type: %d " "Sample number: %d " "Sample size: %d\n", header->subkey, header->number, header->size); switch (header->subkey) { case WF_ST_SAMPLE: /* sample or sample_header, based on patch->size */ if (copy_from_user (&header->hdr.s, header->hdrptr, sizeof (wavefront_sample))) { err = -EFAULT; break; } err = wavefront_send_sample (dev, header, header->dataptr, 0); break; case WF_ST_MULTISAMPLE: if (copy_from_user (&header->hdr.s, header->hdrptr, sizeof (wavefront_multisample))) { err = -EFAULT; break; } err = wavefront_send_multisample (dev, header); break; case WF_ST_ALIAS: if (copy_from_user (&header->hdr.a, header->hdrptr, sizeof (wavefront_alias))) { err = -EFAULT; break; } err = wavefront_send_alias (dev, header); break; case WF_ST_DRUM: if (copy_from_user (&header->hdr.d, header->hdrptr, sizeof (wavefront_drum))) { err = -EFAULT; break; } err = wavefront_send_drum (dev, header); break; case WF_ST_PATCH: if (copy_from_user (&header->hdr.p, header->hdrptr, sizeof (wavefront_patch))) { err = -EFAULT; break; } err = wavefront_send_patch (dev, header); break; case WF_ST_PROGRAM: if (copy_from_user (&header->hdr.pr, header->hdrptr, sizeof (wavefront_program))) { err = -EFAULT; break; } err = wavefront_send_program (dev, header); break; default: snd_printk ("unknown patch type %d.\n", header->subkey); err = -EINVAL; break; } __error: kfree(header); return err;}/***********************************************************************WaveFront: hardware-dependent interface***********************************************************************/static voidprocess_sample_hdr (u8 *buf){ wavefront_sample s; u8 *ptr; ptr = buf; /* The board doesn't send us an exact copy of a "wavefront_sample" in response to an Upload Sample Header command. Instead, we have to convert the data format back into our data structure, just as in the Download Sample command, where we have to do something very similar in the reverse direction. */ *((u32 *) &s.sampleStartOffset) = demunge_int32 (ptr, 4); ptr += 4; *((u32 *) &s.loopStartOffset) = demunge_int32 (ptr, 4); ptr += 4; *((u32 *) &s.loopEndOffset) = demunge_int32 (ptr, 4); ptr += 4; *((u32 *) &s.sampleEndOffset) = demunge_int32 (ptr, 4); ptr += 4; *((u32 *) &s.FrequencyBias) = demunge_int32 (ptr, 3); ptr += 3; s.SampleResolution = *ptr & 0x3; s.Loop = *ptr & 0x8; s.Bidirectional = *ptr & 0x10; s.Reverse = *ptr & 0x40; /* Now copy it back to where it came from */ memcpy (buf, (unsigned char *) &s, sizeof (wavefront_sample));}static intwavefront_synth_control (snd_wavefront_card_t *acard, wavefront_control *wc){ snd_wavefront_t *dev = &acard->wavefront; unsigned char patchnumbuf[2]; int i; DPRINT (WF_DEBUG_CMD, "synth control with " "cmd 0x%x\n", wc->cmd); /* Pre-handling of or for various commands */ switch (wc->cmd) { case WFC_DISABLE_INTERRUPTS: snd_printk ("interrupts disabled.\n"); outb (0x80|0x20, dev->control_port); dev->interrupts_are_midi = 1; return 0; case WFC_ENABLE_INTERRUPTS: snd_printk ("interrupts enabled.\n"); outb (0x80|0x40|0x20, dev->control_port); dev->interrupts_are_midi = 1; return 0; case WFC_INTERRUPT_STATUS: wc->rbuf[0] = dev->interrupts_are_midi; return 0; case WFC_ROMSAMPLES_RDONLY: dev->rom_samples_rdonly = wc->wbuf[0]; wc->status = 0; return 0; case WFC_IDENTIFY_SLOT_TYPE: i = wc->wbuf[0] | (wc->wbuf[1] << 7); if (i <0 || i >= WF_MAX_SAMPLE) { snd_printk ("invalid slot ID %d\n", i); wc->status = EINVAL; return -EINVAL; } wc->rbuf[0] = dev->sample_status[i]; wc->status = 0; return 0; case WFC_DEBUG_DRIVER: dev->debug = wc->wbuf[0]; snd_printk ("debug = 0x%x\n", dev->debug); return 0; case WFC_UPLOAD_PATCH: munge_int32 (*((u32 *) wc->wbuf), patchnumbuf, 2); memcpy (wc->wbuf, patchnumbuf, 2); break; case WFC_UPLOAD_MULTISAMPLE: /* multisamples have to be handled differently, and cannot be dealt with properly by snd_wavefront_cmd() alone. */ wc->status = wavefront_fetch_multisample (dev, (wavefront_patch_info *) wc->rbuf); return 0; case WFC_UPLOAD_SAMPLE_ALIAS: snd_printk ("support for sample alias upload " "being considered.\n"); wc->status = EINVAL; return -EINVAL; } wc->status = snd_wavefront_cmd (dev, wc->cmd, wc->rbuf, wc->wbuf); /* Post-handling of certain commands. In particular, if the command was an upload, demunge the data so that the user-level doesn't have to think about it. */ if (wc->status == 0) { switch (wc->cmd) { /* intercept any freemem requests so that we know we are always current with the user-level view of things. */ case WFC_REPORT_FREE_MEMORY: dev->freemem = demunge_int32 (wc->rbuf, 4); break; case WFC_UPLOAD_PATCH: demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES); break; case WFC_UPLOAD_PROGRAM: demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES); break; case WFC_UPLOAD_EDRUM_PROGRAM: demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1); break; case WFC_UPLOAD_SAMPLE_HEADER: process_sample_hdr (wc->rbuf); break; case WFC_UPLOAD_SAMPLE_ALIAS: snd_printk ("support for " "sample aliases still " "being considered.\n"); break; case WFC_VMIDI_OFF: snd_wavefront_midi_disable_virtual (acard); break; case WFC_VMIDI_ON: snd_wavefront_midi_enable_virtual (acard); break; } } return 0;}int snd_wavefront_synth_open (snd_hwdep_t *hw, struct file *file){ if (!try_module_get(hw->card->module)) return -EFAULT; file->private_data = hw; return 0;}int snd_wavefront_synth_release (snd_hwdep_t *hw, struct file *file){ module_put(hw->card->module); return 0;}intsnd_wavefront_synth_ioctl (snd_hwdep_t *hw, struct file *file, unsigned int cmd, unsigned long arg){ snd_card_t *card; snd_wavefront_t *dev; snd_wavefront_card_t *acard; wavefront_control *wc; void __user *argp = (void __user *)arg; int err; card = (snd_card_t *) hw->card; snd_assert(card != NULL, return -ENODEV); snd_assert(card->private_data != NULL, return -ENODEV); acard = card->private_data; dev = &acard->wavefront; switch (cmd) { case WFCTL_LOAD_SPP: if (wavefront_load_patch (dev, argp) != 0) { return -EIO; } break; case WFCTL_WFCMD: wc = kmalloc(sizeof(*wc), GFP_KERNEL); if (! wc) return -ENOMEM; if (copy_from_user (wc, argp, sizeof (*wc))) err = -EFAULT; else if (wavefront_synth_control (acard, wc) < 0) err = -EIO; else if (copy_to_user (argp, wc, sizeof (*wc))) err = -EFAULT; else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -