[alsa-devel] Questions about writing a new ALSA driver for a very limitted device

Tim Harvey tim_harvey at yahoo.com
Mon Apr 16 03:56:56 CEST 2007

Thanks for the help!  I've got a few more questions below:

--- Takashi Iwai <tiwai at suse.de> wrote:

> At Wed, 11 Apr 2007 18:18:54 -0700 (PDT),
> Tim Harvey wrote:
> > 
> > Greetings,
> > 
> > I'm setting out to write an ALSA driver for a very limited device thats
> behind
> > a PLD.  The actual codec is a uda1380 and does 16bit MSB stereo
> encode/decode. 
> > The way the device is driven the sampling rate is limited to 8KHz and data
> > transfer to/from the device I have to handle manually.
> > 
> > I've read over the 'writing an ALSA driver' tutorial and have started the
> > driver but have run into a few questions:
> > 
> >  - for the specs I've given above: 8000Hz sampling rate, 16bit stereo MSB
> > samples does the following snd_pcm_hardware_t look right?:
> > 
> > static snd_pcm_hardware_t my_playback_hw = {
> >         .info = (SNDRV_PCM_INFO_MMAP |
> >                  SNDRV_PCM_INFO_INTERLEAVED |
> >                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
> >                  SNDRV_PCM_INFO_MMAP_VALID),
> >         .formats =          SNDRV_PCM_FMTBIT_U16_BE,  // is this 16bit MSB?

So, just to confirm, SNDRV_PCM_FMTBIT_U16_BE is appropriate for a 2byte sample
where the first byte's msb is the msb of the sample and the 2nd bytes lsb is
the lsb of the sample correct?  And this will be the case regarding to the
endianess of my system?  (its an arm-be system).

> >         .rates =            SNDRV_PCM_RATE_8000,      // seems redundant?
> >         .rate_min =         8000,
> >         .rate_max =         8000,
> >         .channels_min =     2,
> >         .channels_max =     2,
> >         .buffer_bytes_max = 32768,
> >         .period_bytes_min = 4096,
> >         .period_bytes_max = 32768,
> >         .periods_min =      1,
> >         .periods_max =      1024,
> > };
> Looks fine to me.  rates field shouldn't be empty, so it's not
> redundant (although it might work without it).
> >  - I'm a little confused at how to deal with copying data from/to the
> device. 
> > It looks like I would implement the copy callback and copy the passed
> buffer to
> > the device in the device specific manner I need to (playback), but I'm not
> > clear where to put data that I receive from the device (capture).  I notice
> > that when the hw_params callback is called a dma buffer has been created by
> > ALSA in the substream->runtime struct.  I assume this is created based on
> hte
> > buffer_bytes_max field above and I'm to copy data to this buffer?  How do I
> > know where to copy it within the buffer and what data ALSA has already
> consumed
> > from the buffer?
> It's a little bit complicated right now.  If you don't need mmap mode
> transfer, the thing gets easier, but it restricts application usage.

to know if I need mmap mode that would depend on what userland apps I wish to
support and if they use this or not correct?  Are there many out there with
this requirement?

> Without mmap mode, you can implement copy and silence callbacks to
> copy the user-space data directly to the hardware buffer.  In this
> case, the period and buffer sizes in snd_pcm_hardware have to be
> identical with what the hardware can accept.  ISA GUS and emu8000_pcm
> are examples.

If my hardware buffer is somewhat small (ie ~1k) could I simply set
snd_pcm_hardware to reflect this?  Is there a minimum size for
buffer_bytes_max/min before you would want to use an intermediate buffer? 

> Otherwise, you'd need an intermediate buffer.  In this case, the
> transfer to the hardware is done either in the irq handler (via ack
> callback) or through a dedicated workqueue in background.
> >  - I might need to create an intermediate buffer between ALSA's rather
> large
> > buffers and my hardware buffer.  Is there any driver that I could look at
> that
> > does this?  The tutorial talks about the vxpocket driver but that code
> looks
> > very foriegn from the rest of the ALSA drivers.
> The vx driver implementation is complex and not well suitable as a
> reference.   If the manual copy can be done relatively fast, you can
> use helper functions in  pcm_indirect.h, as in emu10k1/emupcm.c,
> rme32 and cs46xx.  They transfer the data via ack callback, which is
> invoked from snd_pcm_period_elapsed().
> Actually, this is a missing piece in the current ALSA design, and now
> becoming a frequently asked thing.  Maybe it's good to think of a
> standard framework for non-DMA type driver implementation.
> >  - I'm not sure I understand what the 'period' is about.  Its clear to me
> that
> > I need to call snd_pcm_period_elapsed() periodically from either an IRQ or
> > other timed callback, but I'm not clear what the hardware pointer is or how
> > that converts to 'frames' and 'periods'.
> The hardware pointer (hw_ptr) is the current position of the
> transfer.  Note that this is in frames unit.
> Meanwhile, the application pointer (appl_ptr) is the current position
> of the filled data by the app.  Thus, appl_ptr - hw_ptr gives you the
> number of the rest data to be processed.
> Both pointers are linear and _not_ the offset in a ring-buffer.  It
> can be between 0 and runtime->boundary-1 (ca. LONG_MAX, aligned to
> period_size).
> However, the pointer callback returns the offset in a ring-buffer,
> i.e. between 0 and (buffer_size-1).  Then the pcm core layer
> recomputes the linear position.
> The "frame" represents the unit, 1 frame = # channels x sample_bytes.
> In your case, 1 frame corresponds to 2 channels x 16 bits = 4 bytes.
> The periods is the number of periods in a ring-buffer.  In OSS, called
> as "fragments".
> So,
>  - buffer_size = period_size * periods
>  - period_bytes = period_size * bytes_per_frame
>  - bytes_per_frame = channels * bytes_per_sample 

I still don't understand what 'period_size' and a 'period' is?

I've also noticed that I seem to 'have' to call
snd_pcm_lib_preallocate_pages_for_all or I get an error when ALSA tries to use
the drive.  I assume that I need to 'preallocate' or allocate manually upon
each 'open' (or another callback?).  Is this 'preallocate' going to allocate 1
buffer or 1 buffer per playback/capture?

For capture would I grab this buffer pointer and copy data to it inside of a
timer/irq event and adjust the hw_ptr manually?


> >  - in general, if my hardware device only allows 16bit MSB 8KHz, does ALSA
> > provides a mechanism for converting data from other formats?
> Yes, it's done in alsa-lib on user-space.
> Takashi

More information about the Alsa-devel mailing list