|
|
|
Back to Index
|
The interface between the pcm core and the sound drivers
is defined in terms of kernel objects.
There are two main interfaces that a sound driver will usually provide: CHANNEL and either MIXER or AC97.
The AC97 interface is a very
small hardware access (register read/write) interface, implemented by drivers for
hardware with an AC97 codec. In this case, the actual MIXER interface is provided by the
shared AC97 code in pcm.
Sound drivers usually have a private data structure to describe their device, and one
structure for each play and record data channel that it supports.
For all CHANNEL interface functions, the first parameter is an opaque pointer.
The second parameter is a pointer to the private channel data structure, except for
channel_init() which has a pointer to the private device
structure (and returns the channel pointer for further use by pcm).
For sound data transfers, the pcm core and the sound
drivers communicate through a shared memory area, described by a struct snd_dbuf.
struct snd_dbuf is private to pcm, and sound drivers obtain values of interest by calls to
accessor functions (sndbuf_getxxx()).
The shared memory area has a size of sndbuf_getsize()
and is divided into fixed size blocks of sndbuf_getblksz()
bytes.
When playing, the general transfer mechanism is as follows (reverse the idea for
recording):
-
pcm initially fills up the buffer, then calls the sound
driver's xxxchannel_trigger() function with a parameter of
PCMTRIG_START.
-
The sound driver then arranges to repeatedly transfer the whole memory area (sndbuf_getbuf(), sndbuf_getsize())
to the device, in blocks of sndbuf_getblksz() bytes. It
calls back the chn_intr() pcm
function for each transferred block (this will typically happen at interrupt time).
-
chn_intr() arranges to copy new data to the area that
was transferred to the device (now free), and make appropriate updates to the snd_dbuf structure.
xxxchannel_init() is called to initialize each of the
play or record channels. The calls are initiated from the sound driver attach routine.
(See the probe and attach section).
static void *
xxxchannel_init(kobj_t obj, void *data,
struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct xxx_info *sc = data;
struct xxx_chinfo *ch;
...
return ch;
}
-

- b is the address for the channel
struct snd_dbuf. It should be initialized in the function by
calling sndbuf_alloc(). The buffer size to use is normally
a small multiple of the 'typical' unit transfer size for your device.
-
c is the pcm channel control
structure pointer. This is an opaque object. The function should store it in the local
channel structure, to be used in later calls to pcm (ie:
chn_intr(c)).
-
dir indicates the channel direction (PCMDIR_PLAY or PCMDIR_REC).
-

- The function should return a pointer to the private area used to control this
channel. This will be passed as a parameter to other channel interface calls.
xxxchannel_setformat() should set up the hardware for
the specified channel for the specified sound format.
static int
xxxchannel_setformat(kobj_t obj, void *data, u_int32_t format)
{
struct xxx_chinfo *ch = data;
...
return 0;
}
-

- format is specified as an AFMT_XXX
value (soundcard.h).
xxxchannel_setspeed() sets up the channel hardware for
the specified sampling speed, and returns the possibly adjusted speed.
static int
xxxchannel_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
struct xxx_chinfo *ch = data;
...
return speed;
}
xxxchannel_setblocksize() sets the block size, which is
the size of unit transactions between pcm and the sound
driver, and between the sound driver and the device. Typically, this would be the number
of bytes transferred before an interrupt occurs. During a transfer, the sound driver
should call pcm's chn_intr()
every time this size has been transferred.
Most sound drivers only take note of the block size here, to be used when an actual
transfer will be started.
static int
xxxchannel_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
struct xxx_chinfo *ch = data;
...
return blocksize;
}
-

- The function returns the possibly adjusted block size. In case the block size is
indeed changed,
sndbuf_resize() should be called to adjust
the buffer.
xxxchannel_trigger() is called by pcm to control data transfer operations in the driver.
static int
xxxchannel_trigger(kobj_t obj, void *data, int go)
{
struct xxx_chinfo *ch = data;
...
return 0;
}
-

- go defines the action for the current call. The possible
values are:
-
-
PCMTRIG_START: the driver should start a data transfer from
or to the channel buffer. If needed, the buffer base and size can be retrieved through
sndbuf_getbuf() and sndbuf_getsize().
-
PCMTRIG_EMLDMAWR / PCMTRIG_EMLDMARD: this tells the driver that the input or output
buffer may have been updated. Most drivers just ignore these calls.
-
PCMTRIG_STOP / PCMTRIG_ABORT:
the driver should stop the current transfer.
Note: If the driver uses ISA DMA, sndbuf_isadma()
should be called before performing actions on the device, and will take care of the DMA
chip side of things.
xxxchannel_getptr() returns the current offset in the
transfer buffer. This will typically be called by chn_intr(), and this is how pcm knows
where it can transfer new data.
xxxchannel_free() is called to free up channel
resources, for example when the driver is unloaded, and should be implemented if the
channel data structures are dynamically allocated or if sndbuf_alloc() was not used for buffer allocation.
struct pcmchan_caps *
xxxchannel_getcaps(kobj_t obj, void *data)
{
return &xxx_caps;
}
-

- The routine returns a pointer to a (usually statically-defined)
pcmchan_caps structure (defined in sound/pcm/channel.h. The structure holds the minimum and maximum
sampling frequencies, and the accepted sound formats. Look at any sound driver for an
example.
channel_reset(), channel_resetdone(), and channel_notify() are for special purposes and should not be
implemented in a driver without discussing it with the authorities (Cameron Grant <cg@FreeBSD.org>).
channel_setdir() is deprecated.
xxxmixer_init() initializes the hardware and tells pcm what mixer devices are available for playing and
recording
static int
xxxmixer_init(struct snd_mixer *m)
{
struct xxx_info *sc = mix_getdevinfo(m);
u_int32_t v;
[Initialize hardware]
[Set appropriate bits in v for play mixers]
mix_setdevs(m, v);
[Set appropriate bits in v for record mixers]
mix_setrecdevs(m, v)
return 0;
}
-

- Set bits in an integer value and call
mix_setdevs() and
mix_setrecdevs() to tell pcm
what devices exist.
Mixer bits definitions can be found in soundcard.h (SOUND_MASK_XXX values and SOUND_MIXER_XXX bit shifts).
xxxmixer_uninit() should ensure that all sound is muted
and if possible mixer hardware should be powered down
xxxmixer_reinit() should ensure that the mixer hardware
is powered up and any settings not controlled by mixer_set() or mixer_setrecsrc()
are restored.
The AC97 interface is
implemented by drivers with an AC97 codec. It only has three methods:
The AC97 interface is used by
the AC97 code in pcm to perform higher level operations. Look
at sound/pci/maestro3.c or many others under sound/pci/ for an example.
|
|
|
|
© 2002-2004
Active-Venture.com
Website Hosting
Service
|
| |
|
Disclaimer: This
documentation is provided only for the benefits of our website hosting customers.
For authoritative source of the documentation, please refer to http://www.freebsd.org
|
|
|