From: Adrian M. <ad...@mc...> - 2002-01-18 00:10:25
|
Please find below replacement (and better) patch for the sound driver. (NB: This is a patch against the code in the linuxdc cvs). A copy of the patched file - but named aica.c is also available at http://www.mcmen.demon.co.uk/linuxdc/aica/aica.c This incorporates previous patch: * eliminates dead code * streamlines existing code And incorporates further small tuning changes as well as 'proper' SNDCTL_DSP_POST and SNDCTL_DSP_SYNC ioctls. A further note on testing - I just can't get madplay to play anything well - both mpg123 and mplayer will handle high demand sound files perfectly or near perfectly, but madplay plays sound in poor quality and with lots of crackles no matter what sort of MP3 it is playing. Adrian PS: Hope I've got the patch format right this time. --- main.c Thu Jan 17 23:56:43 2002 +++ aica.c Thu Jan 17 23:57:07 2002 @@ -177,6 +177,7 @@ { uint32_t regval = readl(0xa0702c00); regval &= ~1; + spu_write_wait(); writel(regval, 0xa0702c00); } @@ -219,10 +220,8 @@ /* Start the SPU again */ spu_enable(); - // Wait one second - int j = jiffies + HZ; - while (jiffies < j) - schedule(); + // Wait a little + schedule(); @@ -270,24 +269,6 @@ static aica_dev_t *aica_dev_list; -static int aica_lock_channel(int channel) -{ - //channels exist in blocks of 32 32-bit registers - //beginning at 0xa0700000 for the SH4 - //...but there are only 64 of them! - if ((channel > 63) || (channel < 0)) { - DEBGM - ("Attempted to open a sound channel which does not exist\n"); - return -EINVAL; - } - return 0; -} - -static int aica_unlock_channel(int channel) -{ - - return 0; -} static struct aica_dev *aica_walk_devlist(void) { @@ -327,13 +308,10 @@ if (down_interruptible(&dsp_mutex)) return -ERESTARTSYS; + //Lock channels 1 & 2 + request_mem_region(0xa0700000, 0x100, "AICA Channels"); + - int err = aica_lock_channel(devc->channel); - if (err != 0) { - MOD_DEC_USE_COUNT; - up(&dsp_mutex); - return err; //failed - } //sample type - based on which device has been opened chanh = kmalloc(sizeof(aica_channel), GFP_KERNEL); if (chanh == NULL) @@ -343,9 +321,6 @@ if ((minor & 0xF) == SND_DEV_DSP) { chanh->sfmt = SM_8BIT; //AICA format devc->sformat = AFMT_U8; //OSS default format for this device - } else if ((minor & 0xF) == SND_DEV_AUDIO) { - chanh->sfmt = SM_8BIT; - devc->sformat = AFMT_MU_LAW; } else if ((minor & 0xF) == SND_DEV_DSP16) { chanh->sfmt = SM_16BIT; devc->sformat = AFMT_S16_LE; @@ -353,7 +328,7 @@ //total failure! DEBGM("Attempting to open an unsupported device file\n"); //unlock channel - aica_unlock_channel(devc->channel); + release_mem_region(0xa0700000, 0x100); up(&dsp_mutex); MOD_DEC_USE_COUNT; return -EINVAL; @@ -408,11 +383,13 @@ for (i = 0; i < (HZ * 2); i++) { - - interruptible_sleep_on_timeout(&(devc->open_wait), - 1); if (chanh->freq < 11000) - spu_write_wait(); + interruptible_sleep_on_timeout(& + (devc-> + open_wait), + 1); + + spu_write_wait(); playpoint = readl(0xa0810004 + 4); if ((playpoint * samplelength) > currentpoint) break; @@ -434,8 +411,7 @@ BUFFERL = NULL; BUFFERR = NULL; kfree(chanh); - if (devc) - aica_unlock_channel(devc->channel); + release_mem_region(0xa0700000, 0x100); MOD_DEC_USE_COUNT; total_count = 0; @@ -447,27 +423,32 @@ { //second channel has largely the same attributes as first + int z, y, x, w; *count_out = *count / 2; - BUFFER2 = kmalloc(*count_out, GFP_KERNEL); + y = *count_out; //only need to read this once + BUFFER2 = kmalloc(y, GFP_KERNEL); if (BUFFER2 == NULL) return -1; - char *BUFFER3 = kmalloc(*count_out, GFP_KERNEL); + char *BUFFER3 = kmalloc(y, GFP_KERNEL); if (BUFFER3 == NULL) return -1; - int z; + if (samplelength == 1) { - for (z = 0; z < *count_out; z++) { - BUFFER3[z] = BUFFER[z * 2]; - BUFFER2[z] = BUFFER[z * 2 + 1]; + for (z = 0; z < y; z++) { + x = z * 2; + BUFFER3[z] = BUFFER[x]; + BUFFER2[z] = BUFFER[x + 1]; } } else { - - for (z = 0; z < *count_out / samplelength; z++) { - BUFFER3[z * 2] = BUFFER[z * 4]; - BUFFER3[z * 2 + 1] = BUFFER[z * 4 + 1]; - BUFFER2[z * 2] = BUFFER[z * 4 + 2]; - BUFFER2[z * 2 + 1] = BUFFER[z * 4 + 3]; + y = y / samplelength; + for (z = 0; z < y; z++) { + x = z * 2; + w = z * 4; + BUFFER3[x] = BUFFER[w]; + BUFFER3[x + 1] = BUFFER[w + 1]; + BUFFER2[x] = BUFFER[w + 2]; + BUFFER2[x + 1] = BUFFER[w + 3]; } } @@ -477,41 +458,34 @@ } -inline static int aica_audio_tidy_buffers(aica_dev_t * devc, - int *count_out, int *count) +inline static int aica_audio_tidy_buffers(aica_dev_t * devc) { - - //about to overwrite a playing buffer? int playpoint; - do { - if (chanh->freq < 15000) + if (chanh->freq < 23000) interruptible_sleep_on_timeout(&(devc->open_wait), - 5); + 1); spu_write_wait(); playpoint = readl(0xa0810004 + 4); - } while (((playpoint * samplelength) > currentpoint) && ((playpoint * samplelength) < (currentpoint + total_count))); - - //writing past end of the buffer? - if ((currentpoint + total_count) > 0x8000) { currentpoint = 0; - //check again do { + if (chanh->freq < 23000) + interruptible_sleep_on_timeout(& + (devc-> + open_wait), + 1); spu_write_wait(); playpoint = readl(0xa0810004 + 4); } while ((playpoint * samplelength) <= total_count); } - - - return 0; } @@ -524,53 +498,44 @@ aica_dev_t *devc = (aica_dev_t *) (file->private_data); stereo = chanh->flags & 1; - BUFFER = kmalloc(count, GFP_KERNEL); - copy_from_user(BUFFER, buffer, count); int count_out = count; //check for any format changes needed samplelength = 1; if (chanh->sfmt == SM_16BIT) samplelength = 2; - switch (devc->sformat) { - case AFMT_U8: + else if (devc->sformat == AFMT_U8) convert_u8tos8(BUFFER, count); - break; - } //process stereo if required if (stereo) { if (aica_audio_process_stereo(&count_out, &count) != 0) return -1; + BUFFERR = BUFFER2; } - total_count = count_out; BUFFERL = BUFFER; BUFFER = NULL; - if (stereo) - BUFFERR = BUFFER2; BUFFER2 = NULL; - if (devc->last_write_length > 0) { - aica_audio_tidy_buffers(devc, &count_out, &count); + aica_audio_tidy_buffers(devc); } - - spu_memload(0x11000 + currentpoint, BUFFERL, total_count); if (stereo) spu_memload(0x21000 + currentpoint, BUFFERR, total_count); + if (BUFFERR) + kfree(BUFFERR); + kfree(BUFFERL); + BUFFERL = NULL; + BUFFERR = NULL; + currentpoint += total_count; if (devc->last_write_length == 0) { chanh->pos = 0; spu_memload(0x10004, (uint8_t *) chanh, sizeof(aica_channel)); chn_start(); } - currentpoint += total_count; devc->last_write_length = total_count; //store the value - kfree(BUFFERL); - kfree(BUFFERR); - BUFFERL = NULL; - BUFFERR = NULL; total_count = 0; return count; } @@ -590,11 +555,6 @@ case SNDCTL_DSP_SETFMT: get_user(newdata, (int *) arg); switch (newdata) { - case AFMT_MU_LAW: - return -1; //for now - devc->sformat = AFMT_MU_LAW; - chanh->sfmt = SM_8BIT; - break; case AFMT_U8: devc->sformat = AFMT_U8; chanh->sfmt = SM_8BIT; @@ -616,7 +576,7 @@ chanh->sfmt = SM_8BIT; //have set a default format //but should return an error - return -1; + return -ENOTTY; } put_user(devc->sformat, (int *) arg); return 0; @@ -664,7 +624,6 @@ buffer_size = 1 << s; m = 0x7fff; arg = (m << 16) | s; - put_user(0x010f, (int *) arg); return 0; case SNDCTL_DSP_GETODELAY: @@ -697,11 +656,28 @@ copy_to_user((audio_buf_info *) arg, &info, sizeof(info)); return 0; case SNDCTL_DSP_SYNC: - //wait a tick - interruptible_sleep_on_timeout(&(devc->open_wait), 1); - return 0; case SNDCTL_DSP_POST: - //do nothing + //flushes sound buffer + spu_write_wait(); + s = readl(0xa0810004 + 4); + if ((s * samplelength) > currentpoint) { + newdata = + currentpoint + 0x8000 - (s * samplelength); + } else + newdata = currentpoint - (s * samplelength); + //work out delay + newdata = newdata / samplelength; + //in milliseconds + newdata = (newdata * 1000) / chanh->freq; + //sleep that time then kill sound + newdata = (newdata * HZ) / 1000; + interruptible_sleep_on_timeout(&(devc->open_wait), + newdata); + chn_halt(); + //clear memory + spu_memset(0x21000, 0, 0x8000); + spu_memset(0x11000, 0, 0x8000); + currentpoint = 0; return 0; case SNDCTL_DSP_STEREO: get_user(newdata, (int *) arg); @@ -744,11 +720,10 @@ return 0; default: - return -1; + return -ENOTTY; } - return -1; } @@ -808,7 +783,7 @@ return 0; default: - return -1; + return -ENOTTY; } } @@ -823,7 +798,7 @@ static int __init attach_aica(void) { printk - ("AICA audio device driver for Dreamcast Linux - ver 0.1-pre10\n"); + ("AICA audio device driver for Dreamcast Linux - ver 0.1-pre13\n"); //initialise data holder for device aica_dev_t *devc = NULL; sema_init(&dsp_mutex, 1); |
From: M. R. B. <mr...@0x...> - 2002-01-18 00:28:33
|
* Adrian McMenamin <ad...@mc...> on Fri, Jan 18, 2002: > Please find below replacement (and better) patch for the sound driver. (N= B:=20 > This is a patch against the code in the linuxdc cvs). A copy of the patch= ed=20 > file - but named aica.c is also available at=20 > http://www.mcmen.demon.co.uk/linuxdc/aica/aica.c =20 Curious - why aren't you committing these to CVS after posting them to the list? M. R. |