ALSA driver--PCM Device creation process

Source: Internet
Author: User

The creation framework for PCM device has been written before, so let's look at how PCM device is created.

A SND_PCM type of PCM device is created when the snd_pcm_new is called.

struct SND_PCM {
struct Snd_card *card;//pcm device says the sound card is mounted
struct List_head list;//A card may have multiple PCM DEVICE,PCM device lists
int device; /* Index of device number *///PCM device
unsigned int info_flags;
unsigned short dev_class;
unsigned short dev_subclass;
Char id[64];
Char name[80];
struct SND_PCM_STR STREAMS[2];//PCM playback and capture stream
struct Mutex Open_mutex;
wait_queue_head_t open_wait;
void *private_data;//private_data generally for chip-specific information
void (*private_free) (struct SND_PCM *pcm);//used to release Private_data
BOOL internal; /* PCM is for internal use only */
BOOL Nonatomic; /* Whole PCM operations is in non-atomic context */
#if defined (config_snd_pcm_oss) | | Defined (config_snd_pcm_oss_module)
struct Snd_pcm_oss oss;
#endif
};

Let's take a look at some of the actions in Snd_pcm_new:

static int _snd_pcm_new (struct snd_card *card, const char *id, int device,
int playback_count, int capture_count, BOOL internal,
struct SND_PCM **rpcm)
{
struct SND_PCM *pcm;
int err;
static struct Snd_device_ops Ops = {//PCM device operation function
. Dev_free = Snd_pcm_dev_free,
. dev_register =snd_pcm_dev_register,//in PCM device Rigister call
. Dev_disconnect = Snd_pcm_dev_disconnect,
};

if (snd_bug_on (!card))
Return-enxio;
if (RPCM)
*RPCM = NULL;
PCM = Kzalloc (sizeof (*PCM), gfp_kernel);//Create space for PCM device
if (!PCM)
Return-enomem;
Pcm->card = card;//to save the sound card in PCM device
Pcm->device = device;
Pcm->internal = internal;
Mutex_init (&pcm->open_mutex);
Init_waitqueue_head (&pcm->open_wait);
Init_list_head (&pcm->list);
if (ID)
strlcpy (pcm->id, id, sizeof (pcm->id));
if (err = Snd_pcm_new_stream (PCM, Sndrv_pcm_stream_playback, Playback_count)) < 0) {//Create PLAYBACK stream for PCM device
Snd_pcm_free (PCM);
return err;
}
if (err = Snd_pcm_new_stream (PCM, Sndrv_pcm_stream_capture, Capture_count)) < 0) {//Create CAPTURE stream for PCM device
Snd_pcm_free (PCM);
return err;
}
if (err = snd_device_new (Card, SNDRV_DEV_PCM, PCM, &ops)) < 0) {//Attach the PCM device to the card.
Snd_pcm_free (PCM);
return err;
}
if (RPCM)
*RPCM = PCM;
return 0;
}

A PCM device has a playback, capture stream, created by Snd_pcm_new_stream.

Playback and capture stream are a SND_PCM_STR structure,

struct SND_PCM_STR {
int stream;/* stream (direction) *///is playback stream or capture stream
struct SND_PCM * pcm;//the current PCM device
/*-substreams--*/
unsigned the number of int substream_count;//substream.
Unsigned int substream_opened;//The number of substream already open. Each open +1,close-1.
struct Snd_pcm_substream *substream;//playback stream or capture stream's substream linked list
#if defined (CONFIG_SND_PCM _oss) | | Defined (config_snd_pcm_oss_module)
/*--oss things--*/
struct snd_pcm_oss_stream oss;
  #endif
#ifdef config_snd_verbose_procfs
struct snd_info_entry *proc_root;
struct Snd_info_entry *proc_info_entry;
#ifdef config_snd_pcm_xrun_debug
unsigned int xrun_debug;/* 0 = disabled, 1 = verbose, 2 = stacktrace */
Str UCT Snd_info_entry *proc_xrun_debug_entry;
#endif
#endif
struct Snd_kcontrol *chmap_kctl;/* channel-mapping controls */
struct device Dev;//stream Device Structure
};

Substream Structural body Snd_pcm_substream:

struct Snd_pcm_substream {
struct SND_PCM *PCM;//PCM Device
struct SND_PCM_STR *pstr;//playback stream or Substream
void *private_data;/* copied from pcm->private_data *///private_data are usually the same as the private data of PCM device.
int number;//Index of the current Substream
Char name[32];/* substream name */
int stream;/* Stream (direction) *///is playback or capture Substream
struct Pm_qos_request latency_pm_qos_req; /* Pm_qos Request */
size_t buffer_bytes_max;/* limit Ring buffer size *///the largest buffer size
struct Snd_dma_buffer DMA_BUFFER;//DMA Buffer
size_t Dma_max;
/*--Hardware Operations--* *
const struct Snd_pcm_ops *ops;//substream operation function
/*-Runtime information--* *
struct Snd_pcm_runtime *runtime;//runtime Information
/*--Timer section--*/
struct Snd_timer *timer;/* Timer */
Unsigned timer_running:1;/* time is running */
/*-Next Substream--* *
struct Snd_pcm_substream *next;
/*--linked Substreams--* *
struct List_head link_list;/* Linked list member */
struct Snd_pcm_group self_group;/* fake group for non linked Substream (with Substream lock inside) */
struct Snd_pcm_group *group;/* pointer to current group */
/*--Assigned files--* *
void *file;
int ref_count;
atomic_t Mmap_count;
unsigned int f_flags;
void (*pcm_release) (struct snd_pcm_substream *);
struct PID *pid;
#if defined (config_snd_pcm_oss) | | Defined (config_snd_pcm_oss_module)
/*--OSS things--* *
struct Snd_pcm_oss_substream oss;
#endif
#ifdef CONFIG_SND_VERBOSE_PROCFS
struct Snd_info_entry *proc_root;
struct Snd_info_entry *proc_info_entry;
struct Snd_info_entry *proc_hw_params_entry;
struct Snd_info_entry *proc_sw_params_entry;
struct Snd_info_entry *proc_status_entry;
struct Snd_info_entry *proc_prealloc_entry;
struct Snd_info_entry *proc_prealloc_max_entry;
#ifdef Config_snd_pcm_xrun_debug
struct Snd_info_entry *proc_xrun_injection_entry;
#endif
#endif/* CONFIG_SND_VERBOSE_PROCFS */
/* Misc Flags */
unsigned int hw_opened:1;
};

/**
* Snd_pcm_new_stream-create a new PCM stream
* @pcm: The PCM instance
* @stream: The stream direction, sndrv_pcm_stream_xxx
* @substream_count: The number of Substreams
*/

int Snd_pcm_new_stream (struct SND_PCM *pcm, int stream, int substream_count)
{
int idx, err;
struct SND_PCM_STR *pstr = &pcm->streams[stream];//Current playback stream or capture stream
struct Snd_pcm_substream *substream, *prev;

#if is_enabled (Config_snd_pcm_oss)
Mutex_init (&pstr->oss.setup_mutex);
#endif
Pstr->stream = stream;
PSTR->PCM = PCM;
Pstr->substream_count = Substream_count;
if (!substream_count)
return 0;

Snd_device_initialize (&pstr->dev, Pcm->card);
Pstr->dev.groups = pcm_dev_attr_groups;
Dev_set_name (&pstr->dev, "pcmc%id%i%c", Pcm->card->number, pcm->device, stream = = SNDRV_PCM_STREAM_ PLAYBACK? ' P ': ' C ');//playback Stream's name

if (!pcm->internal) {
Err = Snd_pcm_stream_proc_init (PSTR);//The playback stream is hung to the/proc directory, which we can view through cat.      
if (Err < 0) {
Pcm_err (PCM, "Error in snd_pcm_stream_proc_init\n");
return err;  
}
}
prev = NULL;
for (idx = 0, prev = NULL; idx < substream_count; idx++) {//A playback stream can have multiple substream, create Substream
Substrea m = Kzalloc (sizeof (*substream), Gfp_kernel);    
if (!substream)
Return-enomem;
SUBSTREAM->PCM = PCM;
Substream->pstr = pstr;
Substream->number = idx;
Substream->stream = stream;
sprintf (Substream->name, "Subdevice #%i", IDX);
Substream->buffer_bytes_max = Uint_max; The
if (prev = = NULL)//links Substream to the Substream member of the playback stream.
Pstr->substream = Substream;
Else
Prev->next = substream;

if (!pcm->internal) {
Err = Snd_pcm_substream_proc_init (substream);//The Substream is hung under/proc.
if (Err < 0) {
Pcm_err (PCM, "Error in snd_pcm_stream_proc_init\n");
if (prev = = NULL)
Pstr->substream = NULL;
Else
Prev->next = NULL;
Kfree (Substream);
return err;
}
}
Substream->group = &substream->self_group;
Spin_lock_init (&substream->self_group.lock);
Mutex_init (&substream->self_group.mutex);
Init_list_head (&substream->self_group.substreams);
List_add_tail (&substream->link_list, &substream->self_group.substreams);
Atomic_set (&substream->mmap_count, 0);
prev = Substream;
}
return 0;
}

ALSA driver--PCM Device creation process

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.