/*
* Digital Audio (PCM) abstract layer
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Abramo Bagnara <abramo@alsa-project.org>
*
*
#include <sound/asound.h>
#include <sound/memalloc.h>
#include <linux/poll.h>
+#include <linux/mm.h>
#include <linux/bitops.h>
#define snd_pcm_substream_chip(substream) ((substream)->private_data)
size_t fifo_size; /* fifo size in bytes */
};
+struct snd_pcm_substream;
+
struct snd_pcm_ops {
int (*open)(struct snd_pcm_substream *substream);
int (*close)(struct snd_pcm_substream *substream);
struct snd_pcm_file {
struct snd_pcm_substream *substream;
- struct snd_pcm_file *next;
+ int no_compat_mmap;
};
struct snd_pcm_hw_rule;
snd_pcm_uframes_t period_size; /* period size */
unsigned int periods; /* periods */
snd_pcm_uframes_t buffer_size; /* buffer size */
- unsigned int tick_time; /* tick time */
snd_pcm_uframes_t min_align; /* Min alignment for the format */
size_t byte_align;
unsigned int frame_bits;
/* -- SW params -- */
int tstamp_mode; /* mmap timestamp is updated */
unsigned int period_step;
- unsigned int sleep_min; /* min ticks to sleep */
- snd_pcm_uframes_t xfer_align; /* xfer size need to be a multiple */
snd_pcm_uframes_t start_threshold;
snd_pcm_uframes_t stop_threshold;
snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
union snd_pcm_sync_id sync; /* hardware synchronization ID */
/* -- mmap -- */
- volatile struct snd_pcm_mmap_status *status;
- volatile struct snd_pcm_mmap_control *control;
- atomic_t mmap_count;
+ struct snd_pcm_mmap_status *status;
+ struct snd_pcm_mmap_control *control;
/* -- locking / scheduling -- */
wait_queue_head_t sleep;
- struct timer_list tick_timer;
struct fasync_struct *fasync;
/* -- private section -- */
/* -- timer -- */
unsigned int timer_resolution; /* timer resolution */
+ int tstamp_type; /* timestamp type */
/* -- DMA -- */
unsigned char *dma_area; /* DMA area */
int number;
char name[32]; /* substream name */
int stream; /* stream (direction) */
+ char latency_id[20]; /* latency identifier */
size_t buffer_bytes_max; /* limit ring buffer size */
struct snd_dma_buffer dma_buffer;
unsigned int dma_buf_id;
struct snd_pcm_group *group; /* pointer to current group */
/* -- assigned files -- */
void *file;
- struct file *ffile;
+ int ref_count;
+ atomic_t mmap_count;
+ unsigned int f_flags;
void (*pcm_release)(struct snd_pcm_substream *);
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
/* -- OSS things -- */
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;
#endif
/* misc flags */
- unsigned int no_mmap_ctrl: 1;
unsigned int hw_opened: 1;
};
-#define SUBSTREAM_BUSY(substream) ((substream)->file != NULL)
+#define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0)
struct snd_pcm_str {
/* -- OSS things -- */
struct snd_pcm_oss_stream oss;
#endif
- struct snd_pcm_file *files;
#ifdef CONFIG_SND_VERBOSE_PROCFS
struct snd_info_entry *proc_root;
struct snd_info_entry *proc_info_entry;
wait_queue_head_t open_wait;
void *private_data;
void (*private_free) (struct snd_pcm *pcm);
+ struct device *dev; /* actual hw device this belongs to */
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
struct snd_pcm_oss oss;
#endif
* Registering
*/
-extern struct file_operations snd_pcm_f_ops[2];
+extern const struct file_operations snd_pcm_f_ops[2];
int snd_pcm_new(struct snd_card *card, char *id, int device,
int playback_count, int capture_count,
read_unlock_irqrestore(&snd_pcm_link_rwlock, (flags)); \
} while (0)
-#define snd_pcm_group_for_each(pos, substream) \
- list_for_each(pos, &substream->group->substreams)
-
-#define snd_pcm_group_substream_entry(pos) \
- list_entry(pos, struct snd_pcm_substream, link_list)
+#define snd_pcm_group_for_each_entry(s, substream) \
+ list_for_each_entry(s, &substream->group->substreams, link_list)
static inline int snd_pcm_running(struct snd_pcm_substream *substream)
{
static inline const struct snd_mask *hw_param_mask_c(const struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var)
{
- return (const struct snd_mask *)hw_param_mask((struct snd_pcm_hw_params*) params, var);
+ return ¶ms->masks[var - SNDRV_PCM_HW_PARAM_FIRST_MASK];
}
static inline const struct snd_interval *hw_param_interval_c(const struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var)
{
- return (const struct snd_interval *)hw_param_interval((struct snd_pcm_hw_params*) params, var);
+ return ¶ms->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
}
#define params_access(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_ACCESS))
#define params_periods(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIODS)->min
#define params_buffer_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min
#define params_buffer_bytes(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min
-#define params_tick_time(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_TICK_TIME)->min
int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v);
void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params);
void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var);
-int snd_pcm_hw_param_near(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var,
- unsigned int val, int *dir);
-int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm,
- struct snd_pcm_hw_params *params,
- snd_pcm_hw_param_t var,
- unsigned int val, int dir);
int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params);
int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params);
int snd_pcm_playback_xrun_asap(struct snd_pcm_substream *substream);
int snd_pcm_capture_xrun_asap(struct snd_pcm_substream *substream);
void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr);
-void snd_pcm_tick_prepare(struct snd_pcm_substream *substream);
-void snd_pcm_tick_set(struct snd_pcm_substream *substream, unsigned long ticks);
-void snd_pcm_tick_elapsed(struct snd_pcm_substream *substream);
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream);
snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream,
const void __user *buf,
snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
void __user **bufs, snd_pcm_uframes_t frames);
+extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates;
+
int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime);
+unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate);
static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substream,
struct snd_dma_buffer *bufp)
void snd_pcm_timer_init(struct snd_pcm_substream *substream);
void snd_pcm_timer_done(struct snd_pcm_substream *substream);
+static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime,
+ struct timespec *tv)
+{
+ if (runtime->tstamp_type == SNDRV_PCM_TSTAMP_TYPE_MONOTONIC)
+ do_posix_clock_monotonic_gettime(tv);
+ else
+ getnstimeofday(tv);
+}
+
/*
* Memory
*/
static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
{
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
- atomic_inc(&substream->runtime->mmap_count);
+ atomic_inc(&substream->mmap_count);
}
static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area)
{
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
- atomic_dec(&substream->runtime->mmap_count);
+ atomic_dec(&substream->mmap_count);
}
/* mmap for io-memory area */