Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 29 Jul 1997 00:21:10 -0700
From:      Amancio Hasty <hasty@rah.star-gate.com>
To:        Johan Larsson <gozer@ludd.luth.se>
Cc:        freebsd-multimedia@freebsd.org
Subject:   Re: guspnp12b 
Message-ID:  <199707290721.AAA02594@rah.star-gate.com>
In-Reply-To: Your message of "Tue, 29 Jul 1997 08:34:33 %2B0200." <Pine.SUN.3.95.970729081424.21521C-100000@brother.ludd.luth.se> 

next in thread | previous in thread | raw e-mail | index | archive | help
Tnks,

I will try to fix the last dma bug . It has to deal with 
changing the size of the last dma request. Typically, with 
auto dma the sound card cycles thru the dma buffer at fixed
step sizes and when the last output block of a sound stream
is sent out it is usually not the same step size;hence, 
the driver gets into trouble well at least with the sb16 cards.

Will try to fix it however if it looks too hard that is just the 
way that is going to be given that Luigi is revamping the dma
algorithm , I rather fix for good on his version.

Here is specifically whats going on:

sb16_dsp.c:sb16_dsp_output_block(int dev, u_long buf, int count, int intrflag, int dma_restart)
{
    u_long   flags, cnt;

    cnt = count;
    if (dsp_16bit)
	cnt >>= 1;
    cnt--;
    if (audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && cnt==dsp_count) {
	irq_mode = IMODE_OUTPUT;
	intr_active = 1;
	return;		/* Auto mode on. No need to react */
    }
    flags = splhigh();

    if (dma_restart) {

	sb16_dsp_halt(dev);
	DMAbuf_start_dma(dev, buf, count, 1);
    }


    sb_dsp_command(0x41);
    sb_dsp_command((u_char) ((dsp_current_speed >> 8) & 0xff));
    sb_dsp_command((u_char) (dsp_current_speed & 0xff));
    sb_dsp_command((u_char) (dsp_16bit ? 0xb6 : 0xc6));
    dsp_count = cnt;
    sb_dsp_command((u_char) ((dsp_stereo ? 0x20 : 0) +
				(dsp_16bit ? 0x10 : 0)));

/* here on the last output block we write a block which is usually
 * less than dsp_count 
*/
    sb_dsp_command((u_char) (cnt & 0xff));
    sb_dsp_command((u_char) (cnt >> 8));

    irq_mode = IMODE_OUTPUT;
    intr_active = 1;
    splx(flags);
}

Here is an interesting reading, in case someone wants to try to fix the
problem.



³ DSP commands ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

 D0 - Pause 8-bit DMA mode digitized sound I/O initiated by command Cxh.
      Applicable to both single-cycle and auto-initialized DMA I/O.
 D4 - Continue 8-bit DMA mode digitized sound I/O paused using command D0.
      Applicable to both single-cycle and auto-initialzied DMA I/O.

 D5 - Pause 16-bit DMA mode digitized sound I/O initiated by command Bxh.
      Applicable to both single-cycle and auto-initialized DMA I/O.
 D6 - Continue 16-bit DMA mode digitized sound I/O paused using command D5
      Applicable to both single-cycle and auto-initialized DMA I/O.

 D9 - Exit 16-bit auto-initialized DMA mode digitized sound I/O after the
      end of the current block.
 DA - Exit 8-bit auto-initialized DMA mode digitized sound I/O after the
      end of the current block.

When single-cycle DMA is used, sound output stops at the end of each block.
The interrupt handler can start another transfer, but there will be a break
in output.  This causes a click between each block, reducing sound quality.
When auto-initialized DMA is used, sound output loops around at the end of
the buffer.  The DMA controller keeps transfering the same block of memory
that the DMA transfer was initiated with.  When the end of the buffer is
reached, it will start sending the buffer again by auto-initializing the
current offset and count registers with the values stored in the base offset
and count registers.  The usual method for achieving click-less output is to
allocate a buffer and divide it into two blocks.  Program the DMA controller
with the length of the whole buffer, but program the SB16 with the length of
a block. (Half of the buffer)  An interrupt occurs for each sound card block,
so two interrupts will occur each time the buffer is played, once at the
midpoint (Start of the second block) and once at the end (In effect, the
start of the first block)  The interrupt handler should copy data into the
block that was just finished so that the data is ready when it is needed for
output.  The programming procedure for an auto-initialized DMA transfer is
identical to the procedure for a single-cycle DMA transfer, except that bit
4 of the DMA mode register and bit 3 of the DSP command are set.

Upon interrupt when using auto-initialized DMA:
  1)  Copy next chunk into output buffer block that just finished
  2)  Acknowledge the interrupt with the SB by reading from port 2xE for
      8-bit sound or port 2xF for 16-bit sound.
  3)  Acknowledge the end of interrupt with the PIC by writing 20h to port
      20h. If the sound card is on IRQ8-15, you must also write 20h to A0h.

To stop sound immediately:
  8-bit  - Write DSP command D0h (Pause 8-bit DMA mode digitized sound I/O)
  16-bit - Write DSP command D5h (Pause 16-bit DMA mode digitized sound I/O)
  (Stops sound immediately, without an interrupt)

To stop the sound at the end of the currently block:
  8-bit  - Write DSP command DAh (Stop 8-bit auto-init DMA sound I/O)
  16-bit - Write DSP command D9h (Stop 16-bit auto-init DMA sound I/O)
  (These two commands will stop the sound at the end of the current
  block.  If your program is not prepared for an interrupt after output
  is finished, it may cause problems)

You can also end auto-initialized mode by reprogramming the DSP for
single-cycle mode.  The card then switches from A/I mode to S/C mode after
the next interrupt.  It will then contiue to play or record for the length
specified, generate an interrupt and stop.  This will allow you to stop
output exactly at the end of the data, without requiring the remainder of
the DMA buffer to be filled with silence.  This technique may or may not
be useful to you.  I would recommend using the pause commands documented
in in the immediate stop section unless another method is more suited to
your purpose.


	Best Regards,
	Amancio


>From The Desk Of Johan Larsson :
> I have tried this one now, but very quickly, because i had to rebuild my
> system last night and it toook 11.5 hours(ugh, should it take this
> long?, i have a 486 dx4/100 with 32meg ram).
> 
> Back to guspnp12b. I noticed just one major thing, and that was that it
> repeated itself the last half of a second during playback. Otherwise the
> driver seems very stable.
> 
> Another thing(but i guess that has to do with the fact that i rebuilt my
> system last night) is that suddenly the playback speed got slower and
> slower after each playback (it starts about with a quarter of normal
> speed). I ran a 0718 kernel on my last night -current system.
> 
> Amancio, you said that i should rebuild my mixer, but now it doesn't work
> at all.. I'll rebuild my kernel today and get back to you of how it
> worked then.
> 
> But i really think now this driver is ready to replace the current one,
> it is just these flaws that needs to be fixed. :-)
> 
> Great work Amancio!
> 
> 	./johan
> 
> -- 
>     * mailto:gozer@ludd.luth.se * http://www.ludd.luth.se/users/gozer/ *
>     * finger gozer@mother.ludd.luth.se for more information... +-+-+-+ *
>     * Powered by FreeBSD. http://www.se.freebsd.org/ +-+-+-+-+-+-+-+-+ *
> 
> 





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199707290721.AAA02594>