Merge branch 'for-next' into for-linus

This commit is contained in:
Takashi Iwai
2015-04-13 10:23:18 +02:00
202 changed files with 7453 additions and 7055 deletions
@@ -18,6 +18,7 @@ Required properties:
* Headphones
* Speakers
* Mic Jack
* Int Mic
- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
connected to the CODEC.
+5 -1
View File
@@ -466,7 +466,11 @@ The generic parser supports the following hints:
- add_jack_modes (bool): add "xxx Jack Mode" enum controls to each
I/O jack for allowing to change the headphone amp and mic bias VREF
capabilities
- power_down_unused (bool): power down the unused widgets
- power_save_node (bool): advanced power management for each widget,
controlling the power sate (D0/D3) of each widget node depending on
the actual pin and stream states
- power_down_unused (bool): power down the unused widgets, a subset of
power_save_node, and will be dropped in future
- add_hp_mic (bool): add the headphone to capture source if possible
- hp_mic_detect (bool): enable/disable the hp/mic shared input for a
single built-in mic case; default true
+200
View File
@@ -0,0 +1,200 @@
The ALSA API can provide two different system timestamps:
- Trigger_tstamp is the system time snapshot taken when the .trigger
callback is invoked. This snapshot is taken by the ALSA core in the
general case, but specific hardware may have synchronization
capabilities or conversely may only be able to provide a correct
estimate with a delay. In the latter two cases, the low-level driver
is responsible for updating the trigger_tstamp at the most appropriate
and precise moment. Applications should not rely solely on the first
trigger_tstamp but update their internal calculations if the driver
provides a refined estimate with a delay.
- tstamp is the current system timestamp updated during the last
event or application query.
The difference (tstamp - trigger_tstamp) defines the elapsed time.
The ALSA API provides reports two basic pieces of information, avail
and delay, which combined with the trigger and current system
timestamps allow for applications to keep track of the 'fullness' of
the ring buffer and the amount of queued samples.
The use of these different pointers and time information depends on
the application needs:
- 'avail' reports how much can be written in the ring buffer
- 'delay' reports the time it will take to hear a new sample after all
queued samples have been played out.
When timestamps are enabled, the avail/delay information is reported
along with a snapshot of system time. Applications can select from
CLOCK_REALTIME (NTP corrections including going backwards),
CLOCK_MONOTONIC (NTP corrections but never going backwards),
CLOCK_MONOTIC_RAW (without NTP corrections) and change the mode
dynamically with sw_params
The ALSA API also provide an audio_tstamp which reflects the passage
of time as measured by different components of audio hardware. In
ascii-art, this could be represented as follows (for the playback
case):
--------------------------------------------------------------> time
^ ^ ^ ^ ^
| | | | |
analog link dma app FullBuffer
time time time time time
| | | | |
|< codec delay >|<--hw delay-->|<queued samples>|<---avail->|
|<----------------- delay---------------------->| |
|<----ring buffer length---->|
The analog time is taken at the last stage of the playback, as close
as possible to the actual transducer
The link time is taken at the output of the SOC/chipset as the samples
are pushed on a link. The link time can be directly measured if
supported in hardware by sample counters or wallclocks (e.g. with
HDAudio 24MHz or PTP clock for networked solutions) or indirectly
estimated (e.g. with the frame counter in USB).
The DMA time is measured using counters - typically the least reliable
of all measurements due to the bursty natured of DMA transfers.
The app time corresponds to the time tracked by an application after
writing in the ring buffer.
The application can query what the hardware supports, define which
audio time it wants reported by selecting the relevant settings in
audio_tstamp_config fields, get an estimate of the timestamp
accuracy. It can also request the delay-to-analog be included in the
measurement. Direct access to the link time is very interesting on
platforms that provide an embedded DSP; measuring directly the link
time with dedicated hardware, possibly synchronized with system time,
removes the need to keep track of internal DSP processing times and
latency.
In case the application requests an audio tstamp that is not supported
in hardware/low-level driver, the type is overridden as DEFAULT and the
timestamp will report the DMA time based on the hw_pointer value.
For backwards compatibility with previous implementations that did not
provide timestamp selection, with a zero-valued COMPAT timestamp type
the results will default to the HDAudio wall clock for playback
streams and to the DMA time (hw_ptr) in all other cases.
The audio timestamp accuracy can be returned to user-space, so that
appropriate decisions are made:
- for dma time (default), the granularity of the transfers can be
inferred from the steps between updates and in turn provide
information on how much the application pointer can be rewound
safely.
- the link time can be used to track long-term drifts between audio
and system time using the (tstamp-trigger_tstamp)/audio_tstamp
ratio, the precision helps define how much smoothing/low-pass
filtering is required. The link time can be either reset on startup
or reported as is (the latter being useful to compare progress of
different streams - but may require the wallclock to be always
running and not wrap-around during idle periods). If supported in
hardware, the absolute link time could also be used to define a
precise start time (patches WIP)
- including the delay in the audio timestamp may
counter-intuitively not increase the precision of timestamps, e.g. if a
codec includes variable-latency DSP processing or a chain of
hardware components the delay is typically not known with precision.
The accuracy is reported in nanosecond units (using an unsigned 32-bit
word), which gives a max precision of 4.29s, more than enough for
audio applications...
Due to the varied nature of timestamping needs, even for a single
application, the audio_tstamp_config can be changed dynamically. In
the STATUS ioctl, the parameters are read-only and do not allow for
any application selection. To work around this limitation without
impacting legacy applications, a new STATUS_EXT ioctl is introduced
with read/write parameters. ALSA-lib will be modified to make use of
STATUS_EXT and effectively deprecate STATUS.
The ALSA API only allows for a single audio timestamp to be reported
at a time. This is a conscious design decision, reading the audio
timestamps from hardware registers or from IPC takes time, the more
timestamps are read the more imprecise the combined measurements
are. To avoid any interpretation issues, a single (system, audio)
timestamp is reported. Applications that need different timestamps
will be required to issue multiple queries and perform an
interpolation of the results
In some hardware-specific configuration, the system timestamp is
latched by a low-level audio subsytem, and the information provided
back to the driver. Due to potential delays in the communication with
the hardware, there is a risk of misalignment with the avail and delay
information. To make sure applications are not confused, a
driver_timestamp field is added in the snd_pcm_status structure; this
timestamp shows when the information is put together by the driver
before returning from the STATUS and STATUS_EXT ioctl. in most cases
this driver_timestamp will be identical to the regular system tstamp.
Examples of typestamping with HDaudio:
1. DMA timestamp, no compensation for DMA+analog delay
$ ./audio_time -p --ts_type=1
playback: systime: 341121338 nsec, audio time 342000000 nsec, systime delta -878662
playback: systime: 426236663 nsec, audio time 427187500 nsec, systime delta -950837
playback: systime: 597080580 nsec, audio time 598000000 nsec, systime delta -919420
playback: systime: 682059782 nsec, audio time 683020833 nsec, systime delta -961051
playback: systime: 852896415 nsec, audio time 853854166 nsec, systime delta -957751
playback: systime: 937903344 nsec, audio time 938854166 nsec, systime delta -950822
2. DMA timestamp, compensation for DMA+analog delay
$ ./audio_time -p --ts_type=1 -d
playback: systime: 341053347 nsec, audio time 341062500 nsec, systime delta -9153
playback: systime: 426072447 nsec, audio time 426062500 nsec, systime delta 9947
playback: systime: 596899518 nsec, audio time 596895833 nsec, systime delta 3685
playback: systime: 681915317 nsec, audio time 681916666 nsec, systime delta -1349
playback: systime: 852741306 nsec, audio time 852750000 nsec, systime delta -8694
3. link timestamp, compensation for DMA+analog delay
$ ./audio_time -p --ts_type=2 -d
playback: systime: 341060004 nsec, audio time 341062791 nsec, systime delta -2787
playback: systime: 426242074 nsec, audio time 426244875 nsec, systime delta -2801
playback: systime: 597080992 nsec, audio time 597084583 nsec, systime delta -3591
playback: systime: 682084512 nsec, audio time 682088291 nsec, systime delta -3779
playback: systime: 852936229 nsec, audio time 852940916 nsec, systime delta -4687
playback: systime: 938107562 nsec, audio time 938112708 nsec, systime delta -5146
Example 1 shows that the timestamp at the DMA level is close to 1ms
ahead of the actual playback time (as a side time this sort of
measurement can help define rewind safeguards). Compensating for the
DMA-link delay in example 2 helps remove the hardware buffering abut
the information is still very jittery, with up to one sample of
error. In example 3 where the timestamps are measured with the link
wallclock, the timestamps show a monotonic behavior and a lower
dispersion.
Example 3 and 4 are with USB audio class. Example 3 shows a high
offset between audio time and system time due to buffering. Example 4
shows how compensating for the delay exposes a 1ms accuracy (due to
the use of the frame counter by the driver)
Example 3: DMA timestamp, no compensation for delay, delta of ~5ms
$ ./audio_time -p -Dhw:1 -t1
playback: systime: 120174019 nsec, audio time 125000000 nsec, systime delta -4825981
playback: systime: 245041136 nsec, audio time 250000000 nsec, systime delta -4958864
playback: systime: 370106088 nsec, audio time 375000000 nsec, systime delta -4893912
playback: systime: 495040065 nsec, audio time 500000000 nsec, systime delta -4959935
playback: systime: 620038179 nsec, audio time 625000000 nsec, systime delta -4961821
playback: systime: 745087741 nsec, audio time 750000000 nsec, systime delta -4912259
playback: systime: 870037336 nsec, audio time 875000000 nsec, systime delta -4962664
Example 4: DMA timestamp, compensation for delay, delay of ~1ms
$ ./audio_time -p -Dhw:1 -t1 -d
playback: systime: 120190520 nsec, audio time 120000000 nsec, systime delta 190520
playback: systime: 245036740 nsec, audio time 244000000 nsec, systime delta 1036740
playback: systime: 370034081 nsec, audio time 369000000 nsec, systime delta 1034081
playback: systime: 495159907 nsec, audio time 494000000 nsec, systime delta 1159907
playback: systime: 620098824 nsec, audio time 619000000 nsec, systime delta 1098824
playback: systime: 745031847 nsec, audio time 744000000 nsec, systime delta 1031847
+3 -1
View File
@@ -608,7 +608,9 @@ struct ac97_quirk {
int type; /* quirk type above */
};
int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, const char *override);
int snd_ac97_tune_hardware(struct snd_ac97 *ac97,
const struct ac97_quirk *quirk,
const char *override);
int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate);
/*
+2 -2
View File
@@ -70,7 +70,7 @@ struct snd_compr_runtime {
* @device: device pointer
* @direction: stream direction, playback/recording
* @metadata_set: metadata set flag, true when set
* @next_track: has userspace signall next track transistion, true when set
* @next_track: has userspace signal next track transition, true when set
* @private_data: pointer to DSP private data
*/
struct snd_compr_stream {
@@ -95,7 +95,7 @@ struct snd_compr_stream {
* and the stream properties
* @get_params: retrieve the codec parameters, mandatory
* @set_metadata: Set the metadata values for a stream
* @get_metadata: retreives the requested metadata values from stream
* @get_metadata: retrieves the requested metadata values from stream
* @trigger: Trigger operations like start, pause, resume, drain, stop.
* This callback is mandatory
* @pointer: Retrieve current h/w pointer information. Mandatory
+1 -1
View File
@@ -227,7 +227,7 @@ snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
* Add a virtual slave control to the given master.
* Unlike snd_ctl_add_slave(), the element added via this function
* is supposed to have volatile values, and get callback is called
* at each time quried from the master.
* at each time queried from the master.
*
* When the control peeks the hardware values directly and the value
* can be changed by other means than the put callback of the element,
+2 -1
View File
@@ -278,7 +278,8 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type,
void *device_data, struct snd_device_ops *ops);
int snd_device_register(struct snd_card *card, void *device_data);
int snd_device_register_all(struct snd_card *card);
int snd_device_disconnect_all(struct snd_card *card);
void snd_device_disconnect(struct snd_card *card, void *device_data);
void snd_device_disconnect_all(struct snd_card *card);
void snd_device_free(struct snd_card *card, void *device_data);
void snd_device_free_all(struct snd_card *card);
+217
View File
@@ -0,0 +1,217 @@
/*
* HD-audio regmap helpers
*/
#ifndef __SOUND_HDA_REGMAP_H
#define __SOUND_HDA_REGMAP_H
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/hdaudio.h>
int snd_hdac_regmap_init(struct hdac_device *codec);
void snd_hdac_regmap_exit(struct hdac_device *codec);
int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
unsigned int verb);
int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
unsigned int *val);
int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
unsigned int val);
int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
unsigned int mask, unsigned int val);
/**
* snd_hdac_regmap_encode_verb - encode the verb to a pseudo register
* @nid: widget NID
* @verb: codec verb
*
* Returns an encoded pseudo register.
*/
#define snd_hdac_regmap_encode_verb(nid, verb) \
(((verb) << 8) | 0x80000 | ((unsigned int)(nid) << 20))
/**
* snd_hdac_regmap_encode_amp - encode the AMP verb to a pseudo register
* @nid: widget NID
* @ch: channel (left = 0, right = 1)
* @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
* @idx: input index value
*
* Returns an encoded pseudo register.
*/
#define snd_hdac_regmap_encode_amp(nid, ch, dir, idx) \
(snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) | \
((ch) ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT) | \
((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
(idx))
/**
* snd_hdac_regmap_encode_amp_stereo - encode a pseudo register for stereo AMPs
* @nid: widget NID
* @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
* @idx: input index value
*
* Returns an encoded pseudo register.
*/
#define snd_hdac_regmap_encode_amp_stereo(nid, dir, idx) \
(snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) | \
AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT | /* both bits set! */ \
((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
(idx))
/**
* snd_hdac_regmap_write - Write a verb with caching
* @nid: codec NID
* @reg: verb to write
* @val: value to write
*
* For writing an amp value, use snd_hda_regmap_amp_update().
*/
static inline int
snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
unsigned int verb, unsigned int val)
{
unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
return snd_hdac_regmap_write_raw(codec, cmd, val);
}
/**
* snd_hda_regmap_update - Update a verb value with caching
* @nid: codec NID
* @verb: verb to update
* @mask: bit mask to update
* @val: value to update
*
* For updating an amp value, use snd_hda_regmap_amp_update().
*/
static inline int
snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
unsigned int verb, unsigned int mask,
unsigned int val)
{
unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
}
/**
* snd_hda_regmap_read - Read a verb with caching
* @nid: codec NID
* @verb: verb to read
* @val: pointer to store the value
*
* For reading an amp value, use snd_hda_regmap_get_amp().
*/
static inline int
snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
unsigned int verb, unsigned int *val)
{
unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
return snd_hdac_regmap_read_raw(codec, cmd, val);
}
/**
* snd_hdac_regmap_get_amp - Read AMP value
* @codec: HD-audio codec
* @nid: NID to read the AMP value
* @ch: channel (left=0 or right=1)
* @direction: #HDA_INPUT or #HDA_OUTPUT
* @index: the index value (only for input direction)
* @val: the pointer to store the value
*
* Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit.
* Returns the value or a negative error.
*/
static inline int
snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
int ch, int dir, int idx)
{
unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
int err, val;
err = snd_hdac_regmap_read_raw(codec, cmd, &val);
return err < 0 ? err : val;
}
/**
* snd_hdac_regmap_update_amp - update the AMP value
* @codec: HD-audio codec
* @nid: NID to read the AMP value
* @ch: channel (left=0 or right=1)
* @direction: #HDA_INPUT or #HDA_OUTPUT
* @idx: the index value (only for input direction)
* @mask: bit mask to set
* @val: the bits value to set
*
* Update the AMP value with a bit mask.
* Returns 0 if the value is unchanged, 1 if changed, or a negative error.
*/
static inline int
snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
int ch, int dir, int idx, int mask, int val)
{
unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
}
/**
* snd_hdac_regmap_get_amp_stereo - Read stereo AMP values
* @codec: HD-audio codec
* @nid: NID to read the AMP value
* @ch: channel (left=0 or right=1)
* @direction: #HDA_INPUT or #HDA_OUTPUT
* @index: the index value (only for input direction)
* @val: the pointer to store the value
*
* Read stereo AMP values. The lower byte is left, the upper byte is right.
* Returns the value or a negative error.
*/
static inline int
snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
int dir, int idx)
{
unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
int err, val;
err = snd_hdac_regmap_read_raw(codec, cmd, &val);
return err < 0 ? err : val;
}
/**
* snd_hdac_regmap_update_amp_stereo - update the stereo AMP value
* @codec: HD-audio codec
* @nid: NID to read the AMP value
* @direction: #HDA_INPUT or #HDA_OUTPUT
* @idx: the index value (only for input direction)
* @mask: bit mask to set
* @val: the bits value to set
*
* Update the stereo AMP value with a bit mask.
* The lower byte is left, the upper byte is right.
* Returns 0 if the value is unchanged, 1 if changed, or a negative error.
*/
static inline int
snd_hdac_regmap_update_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
int dir, int idx, int mask, int val)
{
unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
}
/**
* snd_hdac_regmap_sync_node - sync the widget node attributes
* @codec: HD-audio codec
* @nid: NID to sync
*/
static inline void
snd_hdac_regmap_sync_node(struct hdac_device *codec, hda_nid_t nid)
{
regcache_mark_dirty(codec->regmap);
regcache_sync_region(codec->regmap, nid << 20, ((nid + 1) << 20) - 1);
}
#endif /* __SOUND_HDA_REGMAP_H */
+271
View File
@@ -0,0 +1,271 @@
/*
* HD-audio core stuff
*/
#ifndef __SOUND_HDAUDIO_H
#define __SOUND_HDAUDIO_H
#include <linux/device.h>
#include <sound/hda_verbs.h>
/* codec node id */
typedef u16 hda_nid_t;
struct hdac_bus;
struct hdac_device;
struct hdac_driver;
struct hdac_widget_tree;
/*
* exported bus type
*/
extern struct bus_type snd_hda_bus_type;
/*
* generic arrays
*/
struct snd_array {
unsigned int used;
unsigned int alloced;
unsigned int elem_size;
unsigned int alloc_align;
void *list;
};
/*
* HD-audio codec base device
*/
struct hdac_device {
struct device dev;
int type;
struct hdac_bus *bus;
unsigned int addr; /* codec address */
struct list_head list; /* list point for bus codec_list */
hda_nid_t afg; /* AFG node id */
hda_nid_t mfg; /* MFG node id */
/* ids */
unsigned int vendor_id;
unsigned int subsystem_id;
unsigned int revision_id;
unsigned int afg_function_id;
unsigned int mfg_function_id;
unsigned int afg_unsol:1;
unsigned int mfg_unsol:1;
unsigned int power_caps; /* FG power caps */
const char *vendor_name; /* codec vendor name */
const char *chip_name; /* codec chip name */
/* verb exec op override */
int (*exec_verb)(struct hdac_device *dev, unsigned int cmd,
unsigned int flags, unsigned int *res);
/* widgets */
unsigned int num_nodes;
hda_nid_t start_nid, end_nid;
/* misc flags */
atomic_t in_pm; /* suspend/resume being performed */
/* sysfs */
struct hdac_widget_tree *widgets;
/* regmap */
struct regmap *regmap;
struct snd_array vendor_verbs;
bool lazy_cache:1; /* don't wake up for writes */
bool caps_overwriting:1; /* caps overwrite being in process */
bool cache_coef:1; /* cache COEF read/write too */
};
/* device/driver type used for matching */
enum {
HDA_DEV_CORE,
HDA_DEV_LEGACY,
};
/* direction */
enum {
HDA_INPUT, HDA_OUTPUT
};
#define dev_to_hdac_dev(_dev) container_of(_dev, struct hdac_device, dev)
int snd_hdac_device_init(struct hdac_device *dev, struct hdac_bus *bus,
const char *name, unsigned int addr);
void snd_hdac_device_exit(struct hdac_device *dev);
int snd_hdac_device_register(struct hdac_device *codec);
void snd_hdac_device_unregister(struct hdac_device *codec);
int snd_hdac_refresh_widgets(struct hdac_device *codec);
unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid,
unsigned int verb, unsigned int parm);
int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd,
unsigned int flags, unsigned int *res);
int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid,
unsigned int verb, unsigned int parm, unsigned int *res);
int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm,
unsigned int *res);
int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid,
int parm);
int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid,
unsigned int parm, unsigned int val);
int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid,
hda_nid_t *conn_list, int max_conns);
int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid,
hda_nid_t *start_id);
/**
* snd_hdac_read_parm - read a codec parameter
* @codec: the codec object
* @nid: NID to read a parameter
* @parm: parameter to read
*
* Returns -1 for error. If you need to distinguish the error more
* strictly, use _snd_hdac_read_parm() directly.
*/
static inline int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid,
int parm)
{
unsigned int val;
return _snd_hdac_read_parm(codec, nid, parm, &val) < 0 ? -1 : val;
}
#ifdef CONFIG_PM
void snd_hdac_power_up(struct hdac_device *codec);
void snd_hdac_power_down(struct hdac_device *codec);
#else
static inline void snd_hdac_power_up(struct hdac_device *codec) {}
static inline void snd_hdac_power_down(struct hdac_device *codec) {}
#endif
/**
* snd_hdac_power_up_pm - power up the codec
* @codec: the codec object
*
* This function can be called in a recursive code path like init code
* which may be called by PM suspend/resume again. OTOH, if a power-up
* call must wake up the sleeper (e.g. in a kctl callback), use
* snd_hdac_power_up() instead.
*/
static inline void snd_hdac_power_up_pm(struct hdac_device *codec)
{
if (!atomic_read(&codec->in_pm))
snd_hdac_power_up(codec);
}
/**
* snd_hdac_power_down_pm - power down the codec
* @codec: the codec object
*
* Like snd_hdac_power_up_pm(), this function is used in a recursive
* code path like init code which may be called by PM suspend/resume again.
*/
static inline void snd_hdac_power_down_pm(struct hdac_device *codec)
{
if (!atomic_read(&codec->in_pm))
snd_hdac_power_down(codec);
}
/*
* HD-audio codec base driver
*/
struct hdac_driver {
struct device_driver driver;
int type;
int (*match)(struct hdac_device *dev, struct hdac_driver *drv);
void (*unsol_event)(struct hdac_device *dev, unsigned int event);
};
#define drv_to_hdac_driver(_drv) container_of(_drv, struct hdac_driver, driver)
/*
* HD-audio bus base driver
*/
struct hdac_bus_ops {
/* send a single command */
int (*command)(struct hdac_bus *bus, unsigned int cmd);
/* get a response from the last command */
int (*get_response)(struct hdac_bus *bus, unsigned int addr,
unsigned int *res);
};
#define HDA_UNSOL_QUEUE_SIZE 64
struct hdac_bus {
struct device *dev;
const struct hdac_bus_ops *ops;
/* codec linked list */
struct list_head codec_list;
unsigned int num_codecs;
/* link caddr -> codec */
struct hdac_device *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1];
/* unsolicited event queue */
u32 unsol_queue[HDA_UNSOL_QUEUE_SIZE * 2]; /* ring buffer */
unsigned int unsol_rp, unsol_wp;
struct work_struct unsol_work;
/* bit flags of powered codecs */
unsigned long codec_powered;
/* flags */
bool sync_write:1; /* sync after verb write */
/* locks */
struct mutex cmd_mutex;
};
int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
const struct hdac_bus_ops *ops);
void snd_hdac_bus_exit(struct hdac_bus *bus);
int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr,
unsigned int cmd, unsigned int *res);
int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr,
unsigned int cmd, unsigned int *res);
void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex);
int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec);
void snd_hdac_bus_remove_device(struct hdac_bus *bus,
struct hdac_device *codec);
static inline void snd_hdac_codec_link_up(struct hdac_device *codec)
{
set_bit(codec->addr, &codec->bus->codec_powered);
}
static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
{
clear_bit(codec->addr, &codec->bus->codec_powered);
}
/*
* generic array helpers
*/
void *snd_array_new(struct snd_array *array);
void snd_array_free(struct snd_array *array);
static inline void snd_array_init(struct snd_array *array, unsigned int size,
unsigned int align)
{
array->elem_size = size;
array->alloc_align = align;
}
static inline void *snd_array_elem(struct snd_array *array, unsigned int idx)
{
return array->list + idx * array->elem_size;
}
static inline unsigned int snd_array_index(struct snd_array *array, void *ptr)
{
return (unsigned long)(ptr - array->list) / array->elem_size;
}
#endif /* __SOUND_HDAUDIO_H */
+64 -2
View File
@@ -60,6 +60,9 @@ struct snd_pcm_hardware {
struct snd_pcm_substream;
struct snd_pcm_audio_tstamp_config; /* definitions further down */
struct snd_pcm_audio_tstamp_report;
struct snd_pcm_ops {
int (*open)(struct snd_pcm_substream *substream);
int (*close)(struct snd_pcm_substream *substream);
@@ -71,8 +74,10 @@ struct snd_pcm_ops {
int (*prepare)(struct snd_pcm_substream *substream);
int (*trigger)(struct snd_pcm_substream *substream, int cmd);
snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
int (*wall_clock)(struct snd_pcm_substream *substream,
struct timespec *audio_ts);
int (*get_time_info)(struct snd_pcm_substream *substream,
struct timespec *system_ts, struct timespec *audio_ts,
struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
int (*copy)(struct snd_pcm_substream *substream, int channel,
snd_pcm_uframes_t pos,
void __user *buf, snd_pcm_uframes_t count);
@@ -281,6 +286,58 @@ struct snd_pcm_hw_constraint_ranges {
struct snd_pcm_hwptr_log;
/*
* userspace-provided audio timestamp config to kernel,
* structure is for internal use only and filled with dedicated unpack routine
*/
struct snd_pcm_audio_tstamp_config {
/* 5 of max 16 bits used */
u32 type_requested:4;
u32 report_delay:1; /* add total delay to A/D or D/A */
};
static inline void snd_pcm_unpack_audio_tstamp_config(__u32 data,
struct snd_pcm_audio_tstamp_config *config)
{
config->type_requested = data & 0xF;
config->report_delay = (data >> 4) & 1;
}
/*
* kernel-provided audio timestamp report to user-space
* structure is for internal use only and read by dedicated pack routine
*/
struct snd_pcm_audio_tstamp_report {
/* 6 of max 16 bits used for bit-fields */
/* for backwards compatibility */
u32 valid:1;
/* actual type if hardware could not support requested timestamp */
u32 actual_type:4;
/* accuracy represented in ns units */
u32 accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy field is valid */
u32 accuracy; /* up to 4.29s, will be packed in separate field */
};
static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy,
const struct snd_pcm_audio_tstamp_report *report)
{
u32 tmp;
tmp = report->accuracy_report;
tmp <<= 4;
tmp |= report->actual_type;
tmp <<= 1;
tmp |= report->valid;
*data &= 0xffff; /* zero-clear MSBs */
*data |= (tmp << 16);
*accuracy = report->accuracy;
}
struct snd_pcm_runtime {
/* -- Status -- */
struct snd_pcm_substream *trigger_master;
@@ -361,6 +418,11 @@ struct snd_pcm_runtime {
struct snd_dma_buffer *dma_buffer_p; /* allocated buffer */
/* -- audio timestamp config -- */
struct snd_pcm_audio_tstamp_config audio_tstamp_config;
struct snd_pcm_audio_tstamp_report audio_tstamp_report;
struct timespec driver_tstamp;
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
/* -- OSS things -- */
struct snd_pcm_oss_runtime oss;
+7
View File
@@ -366,4 +366,11 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p)
return snd_pcm_format_physical_width(params_format(p));
}
static inline void
params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt)
{
snd_mask_set(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT),
(__force int)fmt);
}
#endif /* __SOUND_PCM_PARAMS_H */
+29 -17
View File
@@ -25,29 +25,26 @@
* registered device information
*/
#define ID_LEN 32
/* status flag */
#define SNDRV_SEQ_DEVICE_FREE 0
#define SNDRV_SEQ_DEVICE_REGISTERED 1
struct snd_seq_device {
/* device info */
struct snd_card *card; /* sound card */
int device; /* device number */
char id[ID_LEN]; /* driver id */
const char *id; /* driver id */
char name[80]; /* device name */
int argsize; /* size of the argument */
void *driver_data; /* private data for driver */
int status; /* flag - read only */
void *private_data; /* private data for the caller */
void (*private_free)(struct snd_seq_device *device);
struct list_head list; /* link to next device */
struct device dev;
};
#define to_seq_dev(_dev) \
container_of(_dev, struct snd_seq_device, dev)
/* sequencer driver */
/* driver operators
* init_device:
* probe:
* Initialize the device with given parameters.
* Typically,
* 1. call snd_hwdep_new
@@ -55,25 +52,40 @@ struct snd_seq_device {
* 3. call snd_hwdep_register
* 4. store the instance to dev->driver_data pointer.
*
* free_device:
* remove:
* Release the private data.
* Typically, call snd_device_free(dev->card, dev->driver_data)
*/
struct snd_seq_dev_ops {
int (*init_device)(struct snd_seq_device *dev);
int (*free_device)(struct snd_seq_device *dev);
struct snd_seq_driver {
struct device_driver driver;
char *id;
int argsize;
};
#define to_seq_drv(_drv) \
container_of(_drv, struct snd_seq_driver, driver)
/*
* prototypes
*/
#ifdef CONFIG_MODULES
void snd_seq_device_load_drivers(void);
int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, struct snd_seq_device **result);
int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize);
int snd_seq_device_unregister_driver(char *id);
#else
#define snd_seq_device_load_drivers()
#endif
int snd_seq_device_new(struct snd_card *card, int device, const char *id,
int argsize, struct snd_seq_device **result);
#define SNDRV_SEQ_DEVICE_ARGPTR(dev) (void *)((char *)(dev) + sizeof(struct snd_seq_device))
int __must_check __snd_seq_driver_register(struct snd_seq_driver *drv,
struct module *mod);
#define snd_seq_driver_register(drv) \
__snd_seq_driver_register(drv, THIS_MODULE)
void snd_seq_driver_unregister(struct snd_seq_driver *drv);
#define module_snd_seq_driver(drv) \
module_driver(drv, snd_seq_driver_register, snd_seq_driver_unregister)
/*
* id strings for generic devices
+1 -5
View File
@@ -99,13 +99,9 @@ int snd_seq_event_port_attach(int client, struct snd_seq_port_callback *pcbp,
int snd_seq_event_port_detach(int client, int port);
#ifdef CONFIG_MODULES
void snd_seq_autoload_lock(void);
void snd_seq_autoload_unlock(void);
void snd_seq_autoload_init(void);
#define snd_seq_autoload_exit() snd_seq_autoload_lock()
void snd_seq_autoload_exit(void);
#else
#define snd_seq_autoload_lock()
#define snd_seq_autoload_unlock()
#define snd_seq_autoload_init()
#define snd_seq_autoload_exit()
#endif
+14 -4
View File
@@ -450,8 +450,10 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai);
/* Jack reporting */
int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
struct snd_soc_jack *jack);
int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins,
unsigned int num_pins);
void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_pin *pins);
@@ -659,7 +661,7 @@ struct snd_soc_jack_gpio {
struct snd_soc_jack {
struct mutex mutex;
struct snd_jack *jack;
struct snd_soc_codec *codec;
struct snd_soc_card *card;
struct list_head pins;
int status;
struct blocking_notifier_head notifier;
@@ -954,6 +956,9 @@ struct snd_soc_dai_link {
unsigned int symmetric_channels:1;
unsigned int symmetric_samplebits:1;
/* Mark this pcm with non atomic ops */
bool nonatomic;
/* Do not create a PCM for this DAI link (Backend link) */
unsigned int no_pcm:1;
@@ -1071,11 +1076,16 @@ struct snd_soc_card {
/*
* Card-specific routes and widgets.
* Note: of_dapm_xxx for Device Tree; Otherwise for driver build-in.
*/
const struct snd_soc_dapm_widget *dapm_widgets;
int num_dapm_widgets;
const struct snd_soc_dapm_route *dapm_routes;
int num_dapm_routes;
const struct snd_soc_dapm_widget *of_dapm_widgets;
int num_of_dapm_widgets;
const struct snd_soc_dapm_route *of_dapm_routes;
int num_of_dapm_routes;
bool fully_routed;
struct work_struct deferred_resume_work;
@@ -1469,7 +1479,7 @@ static inline struct snd_soc_codec *snd_soc_kcontrol_codec(
}
/**
* snd_soc_kcontrol_platform() - Returns the platform that registerd the control
* snd_soc_kcontrol_platform() - Returns the platform that registered the control
* @kcontrol: The control for which to get the platform
*
* Note: This function will only work correctly if the control has been
+1
View File
@@ -22,6 +22,7 @@
#ifndef _UAPI__SOUND_ASEQUENCER_H
#define _UAPI__SOUND_ASEQUENCER_H
#include <sound/asound.h>
/** version of the sequencer */
#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION (1, 0, 1)
+34 -5
View File
@@ -25,6 +25,9 @@
#include <linux/types.h>
#ifndef __KERNEL__
#include <stdlib.h>
#endif
/*
* protocol version
@@ -140,7 +143,7 @@ struct snd_hwdep_dsp_image {
* *
*****************************************************************************/
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 12)
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 13)
typedef unsigned long snd_pcm_uframes_t;
typedef signed long snd_pcm_sframes_t;
@@ -267,10 +270,17 @@ typedef int __bitwise snd_pcm_subformat_t;
#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */
#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */
#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */
#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* has audio wall clock for audio/system time sync */
#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* (Deprecated)has audio wall clock for audio/system time sync */
#define SNDRV_PCM_INFO_HAS_LINK_ATIME 0x01000000 /* report hardware link audio time, reset on startup */
#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME 0x02000000 /* report absolute hardware link audio time, not reset on startup */
#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME 0x04000000 /* report estimated link audio time */
#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000 /* report synchronized audio/system time */
#define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */
#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */
typedef int __bitwise snd_pcm_state_t;
#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */
#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) /* stream has a setup */
@@ -408,6 +418,22 @@ struct snd_pcm_channel_info {
unsigned int step; /* samples distance in bits */
};
enum {
/*
* first definition for backwards compatibility only,
* maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else
*/
SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0,
/* timestamp definitions */
SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1, /* DMA time, reported as per hw_ptr */
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2, /* link time reported by sample or wallclock counter, reset on startup */
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3, /* link time reported by sample or wallclock counter, not reset on startup */
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4, /* link time estimated indirectly */
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /* link time synchronized with system time */
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED
};
struct snd_pcm_status {
snd_pcm_state_t state; /* stream state */
struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */
@@ -419,9 +445,11 @@ struct snd_pcm_status {
snd_pcm_uframes_t avail_max; /* max frames available on hw since last status */
snd_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */
snd_pcm_state_t suspended_state; /* suspended stream state */
__u32 reserved_alignment; /* must be filled with zero */
struct timespec audio_tstamp; /* from sample counter or wall clock */
unsigned char reserved[56-sizeof(struct timespec)]; /* must be filled with zero */
__u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */
struct timespec audio_tstamp; /* sample counter, wall clock, PHC or on-demand sync'ed */
struct timespec driver_tstamp; /* useful in case reference system tstamp is reported with delay */
__u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */
unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */
};
struct snd_pcm_mmap_status {
@@ -534,6 +562,7 @@ enum {
#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t)
#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22)
#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr)
#define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status)
#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info)
#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40)
#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41)
+1 -1
View File
@@ -75,7 +75,7 @@ struct snd_compr_tstamp {
/**
* struct snd_compr_avail - avail descriptor
* @avail: Number of bytes available in ring buffer for writing/reading
* @tstamp: timestamp infomation
* @tstamp: timestamp information
*/
struct snd_compr_avail {
__u64 avail;
+1 -2
View File
@@ -23,8 +23,7 @@
#define _UAPI__SOUND_EMU10K1_H
#include <linux/types.h>
#include <sound/asound.h>
/*
* ---- FX8010 ----
+6
View File
@@ -20,6 +20,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
#endif
/* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */
#define HDSPM_MAX_CHANNELS 64
+2
View File
@@ -76,6 +76,8 @@ source "sound/isa/Kconfig"
source "sound/pci/Kconfig"
source "sound/hda/Kconfig"
source "sound/ppc/Kconfig"
source "sound/aoa/Kconfig"

Some files were not shown because too many files have changed in this diff Show More