?? wavfront.c
字號:
if ((x = wavefront_find_free_sample ()) < 0) { return -ENOMEM; } printk (KERN_DEBUG LOGNAME "unspecified sample => %d\n", x); header->number = x; } if (header->size) { /* XXX its a debatable point whether or not RDONLY semantics on the ROM samples should cover just the sample data or the sample header. For now, it only covers the sample data, so anyone is free at all times to rewrite sample headers. My reason for this is that we have the sample headers available in the WFB file for General MIDI, and so these can always be reset if needed. The sample data, however, cannot be recovered without a complete reset and firmware reload of the ICS2115, which is a very expensive operation. So, doing things this way allows us to honor the notion of "RESETSAMPLES" reasonably cheaply. Note however, that this is done purely at user level: there is no WFB parser in this driver, and so a complete reset (back to General MIDI, or theoretically some other configuration) is the responsibility of the user level library. To try to do this in the kernel would be a little crazy: we'd need 158K of kernel space just to hold a copy of the patch/program/sample header data. */ if (dev.rom_samples_rdonly) { if (dev.sample_status[header->number] & WF_SLOT_ROM) { printk (KERN_ERR LOGNAME "sample slot %d " "write protected\n", header->number); return -EACCES; } } wavefront_delete_sample (header->number); } if (header->size) { dev.freemem = wavefront_freemem (); if (dev.freemem < header->size) { printk (KERN_ERR LOGNAME "insufficient memory to " "load %d byte sample.\n", header->size); return -ENOMEM; } } skip = WF_GET_CHANNEL(&header->hdr.s); if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) { printk (KERN_ERR LOGNAME "channel selection only " "possible on 16-bit samples"); return -(EINVAL); } switch (skip) { case 0: initial_skip = 0; skip = 1; break; case 1: initial_skip = 0; skip = 2; break; case 2: initial_skip = 1; skip = 2; break; case 3: initial_skip = 2; skip = 3; break; case 4: initial_skip = 3; skip = 4; break; case 5: initial_skip = 4; skip = 5; break; case 6: initial_skip = 5; skip = 6; break; } DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => " "initial skip = %d, skip = %d\n", WF_GET_CHANNEL (&header->hdr.s), initial_skip, skip); /* Be safe, and zero the "Unused" bits ... */ WF_SET_CHANNEL(&header->hdr.s, 0); /* adjust size for 16 bit samples by dividing by two. We always send 16 bits per write, even for 8 bit samples, so the length is always half the size of the sample data in bytes. */ length = header->size / 2; /* the data we're sent has not been munged, and in fact, the header we have to send isn't just a munged copy either. so, build the sample header right here. */ shptr = &sample_hdr[0]; shptr = munge_int32 (header->number, shptr, 2); if (header->size) { shptr = munge_int32 (length, shptr, 4); } /* Yes, a 4 byte result doesn't contain all of the offset bits, but the offset only uses 24 bits. */ shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleStartOffset), shptr, 4); shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopStartOffset), shptr, 4); shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopEndOffset), shptr, 4); shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset), shptr, 4); /* This one is truly weird. What kind of weirdo decided that in a system dominated by 16 and 32 bit integers, they would use a just 12 bits ? */ shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3); /* Why is this nybblified, when the MSB is *always* zero ? Anyway, we can't take address of bitfield, so make a good-faith guess at where it starts. */ shptr = munge_int32 (*(&header->hdr.s.FrequencyBias+1), shptr, 2); if (wavefront_cmd (header->size ? WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER, 0, sample_hdr)) { printk (KERN_WARNING LOGNAME "sample %sdownload refused.\n", header->size ? "" : "header "); return -(EIO); } if (header->size == 0) { goto sent; /* Sorry. Just had to have one somewhere */ } data_end = dataptr + length; /* Do any initial skip over an unused channel's data */ dataptr += initial_skip; for (written = 0, blocknum = 0; written < length; written += max_blksize, blocknum++) { if ((length - written) > max_blksize) { blocksize = max_blksize; } else { /* round to nearest 16-byte value */ blocksize = ((length-written+7)&~0x7); } if (wavefront_cmd (WFC_DOWNLOAD_BLOCK, 0, 0)) { printk (KERN_WARNING LOGNAME "download block " "request refused.\n"); return -(EIO); } for (i = 0; i < blocksize; i++) { if (dataptr < data_end) { __get_user (sample_short, dataptr); dataptr += skip; if (data_is_unsigned) { /* GUS ? */ if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) { /* 8 bit sample resolution, sign extend both bytes. */ ((unsigned char*) &sample_short)[0] += 0x7f; ((unsigned char*) &sample_short)[1] += 0x7f; } else { /* 16 bit sample resolution, sign extend the MSB. */ sample_short += 0x7fff; } } } else { /* In padding section of final block: 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 ()) != WF_DMA_ACK) { if (dma_ack == -1) { printk (KERN_ERR LOGNAME "upload sample " "DMA ack timeout\n"); return -(EIO); } else { printk (KERN_ERR LOGNAME "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 (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 (wavefront_cmd (WFC_DOWNLOAD_SAMPLE_ALIAS, 0, alias_hdr)) { printk (KERN_ERR LOGNAME "download alias failed.\n"); return -(EIO); } dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS); return (0);}static intwavefront_send_multisample (wavefront_patch_info *header){ int i; int num_samples; unsigned char msample_hdr[WF_MSAMPLE_BYTES]; 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 (wavefront_cmd (WFC_DOWNLOAD_MULTISAMPLE, (unsigned char *) ((num_samples*2)+3), msample_hdr)) { printk (KERN_ERR LOGNAME "download of multisample failed.\n"); return -(EIO); } dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE); return (0);}static intwavefront_fetch_multisample (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 (wavefront_cmd (WFC_UPLOAD_MULTISAMPLE, log_ns, number)) { printk (KERN_ERR LOGNAME "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]; if ((d[0] = wavefront_read ()) == -1) { printk (KERN_ERR LOGNAME "upload multisample failed " "during sample loop.\n"); return -(EIO); } if ((d[1] = wavefront_read ()) == -1) { printk (KERN_ERR LOGNAME "upload multisample failed " "during sample loop.\n"); return -(EIO); } 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 (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 (wavefront_cmd (WFC_DOWNLOAD_EDRUM_PROGRAM, 0, drumbuf)) { printk (KERN_ERR LOGNAME "download drum failed.\n"); return -(EIO); } return (0);}static int wavefront_find_free_sample (void){ int i; for (i = 0; i < WF_MAX_SAMPLE; i++) { if (!(dev.sample_status[i] & WF_SLOT_FILLED)) { return i; } } printk (KERN_WARNING LOGNAME "no free sample slots!\n"); return -1;}static int wavefront_find_free_patch (void){ int i; for (i = 0; i < WF_MAX_PATCH; i++) { if (!(dev.patch_status[i] & WF_SLOT_FILLED)) { return i; } } printk (KERN_WARNING LOGNAME "no free patch slots!\n"); return -1;}static int log2_2048(int n){ int tbl[]={0, 0, 2048, 3246, 4096, 4755, 5294, 5749, 6143, 6492, 6803, 7084, 7342, 7578, 7797, 8001, 8192, 8371, 8540, 8699, 8851, 8995, 9132, 9264, 9390, 9510, 9626, 9738, 9845, 9949, 10049, 10146}; int i; /* Returns 2048*log2(n) */ /* FIXME: this is like doing integer math on quantum particles (RuN) */ i=0; while(n>=32*256) { n>>=8; i+=2048*8; } while(n>=32) { n>>=1; i+=2048; } i+=tbl[n]; return(i);}static intwavefront_load_gus_patch (int devno, int format, const char *addr, int offs, int count, int pmgr_flag){ struct patch_info guspatch; wavefront_patch_info samp, pat, prog; wavefront_patch *patp; wavefront_sample *sampp; wavefront_program *progp; int i,base_note; long sizeof_patch; /* Copy in the header of the GUS patch */ sizeof_patch = (long) &guspatch.data[0] - (long) &guspatch; copy_from_user (&((char *) &guspatch)[offs], &(addr)[offs], sizeof_patch - offs); if ((i = wavefront_find_free_patch ()) == -1) { return -EBUSY; } pat.number = i; pat.subkey = WF_ST_PATCH; patp = &pat.hdr.p; if ((i = wavefront_find_free_sample ()) == -1) { return -EBUSY; } samp.number = i; samp.subkey = WF_ST_SAMPLE; samp.size = guspatch.len; sampp = &samp.hdr.s; prog.number = guspatch.instr_no; progp = &prog.hdr.pr;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -