Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
72f770c6
Commit
72f770c6
authored
Feb 23, 2015
by
Takashi Iwai
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/timestamp' into for-next
parents
0eee62e0
c72638bd
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
444 additions
and
55 deletions
+444
-55
Documentation/sound/alsa/timestamping.txt
Documentation/sound/alsa/timestamping.txt
+200
-0
include/sound/pcm.h
include/sound/pcm.h
+64
-2
include/uapi/sound/asound.h
include/uapi/sound/asound.h
+31
-5
sound/core/pcm_compat.c
sound/core/pcm_compat.c
+23
-5
sound/core/pcm_lib.c
sound/core/pcm_lib.c
+59
-29
sound/core/pcm_native.c
sound/core/pcm_native.c
+38
-3
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_controller.c
+29
-11
No files found.
Documentation/sound/alsa/timestamping.txt
0 → 100644
View file @
72f770c6
This diff is collapsed.
Click to expand it.
include/sound/pcm.h
View file @
72f770c6
...
...
@@ -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
;
...
...
include/uapi/sound/asound.h
View file @
72f770c6
...
...
@@ -143,7 +143,7 @@ struct snd_hwdep_dsp_image {
* *
*****************************************************************************/
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 1
2
)
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 1
3
)
typedef
unsigned
long
snd_pcm_uframes_t
;
typedef
signed
long
snd_pcm_sframes_t
;
...
...
@@ -270,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 */
...
...
@@ -411,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 */
...
...
@@ -422,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
{
...
...
@@ -537,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)
...
...
sound/core/pcm_compat.c
View file @
72f770c6
...
...
@@ -194,18 +194,30 @@ struct snd_pcm_status32 {
u32
avail_max
;
u32
overrange
;
s32
suspended_state
;
u32
reserved_alignment
;
u32
audio_tstamp_data
;
struct
compat_timespec
audio_tstamp
;
unsigned
char
reserved
[
56
-
sizeof
(
struct
compat_timespec
)];
struct
compat_timespec
driver_tstamp
;
u32
audio_tstamp_accuracy
;
unsigned
char
reserved
[
52
-
2
*
sizeof
(
struct
compat_timespec
)];
}
__attribute__
((
packed
));
static
int
snd_pcm_status_user_compat
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_status32
__user
*
src
)
struct
snd_pcm_status32
__user
*
src
,
bool
ext
)
{
struct
snd_pcm_status
status
;
int
err
;
memset
(
&
status
,
0
,
sizeof
(
status
));
/*
* with extension, parameters are read/write,
* get audio_tstamp_data from user,
* ignore rest of status structure
*/
if
(
ext
&&
get_user
(
status
.
audio_tstamp_data
,
(
u32
__user
*
)(
&
src
->
audio_tstamp_data
)))
return
-
EFAULT
;
err
=
snd_pcm_status
(
substream
,
&
status
);
if
(
err
<
0
)
return
err
;
...
...
@@ -222,7 +234,10 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
put_user
(
status
.
avail_max
,
&
src
->
avail_max
)
||
put_user
(
status
.
overrange
,
&
src
->
overrange
)
||
put_user
(
status
.
suspended_state
,
&
src
->
suspended_state
)
||
compat_put_timespec
(
&
status
.
audio_tstamp
,
&
src
->
audio_tstamp
))
put_user
(
status
.
audio_tstamp_data
,
&
src
->
audio_tstamp_data
)
||
compat_put_timespec
(
&
status
.
audio_tstamp
,
&
src
->
audio_tstamp
)
||
compat_put_timespec
(
&
status
.
driver_tstamp
,
&
src
->
driver_tstamp
)
||
put_user
(
status
.
audio_tstamp_accuracy
,
&
src
->
audio_tstamp_accuracy
))
return
-
EFAULT
;
return
err
;
...
...
@@ -457,6 +472,7 @@ enum {
SNDRV_PCM_IOCTL_HW_PARAMS32
=
_IOWR
(
'A'
,
0x11
,
struct
snd_pcm_hw_params32
),
SNDRV_PCM_IOCTL_SW_PARAMS32
=
_IOWR
(
'A'
,
0x13
,
struct
snd_pcm_sw_params32
),
SNDRV_PCM_IOCTL_STATUS32
=
_IOR
(
'A'
,
0x20
,
struct
snd_pcm_status32
),
SNDRV_PCM_IOCTL_STATUS_EXT32
=
_IOWR
(
'A'
,
0x24
,
struct
snd_pcm_status32
),
SNDRV_PCM_IOCTL_DELAY32
=
_IOR
(
'A'
,
0x21
,
s32
),
SNDRV_PCM_IOCTL_CHANNEL_INFO32
=
_IOR
(
'A'
,
0x32
,
struct
snd_pcm_channel_info32
),
SNDRV_PCM_IOCTL_REWIND32
=
_IOW
(
'A'
,
0x46
,
u32
),
...
...
@@ -517,7 +533,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
case
SNDRV_PCM_IOCTL_SW_PARAMS32
:
return
snd_pcm_ioctl_sw_params_compat
(
substream
,
argp
);
case
SNDRV_PCM_IOCTL_STATUS32
:
return
snd_pcm_status_user_compat
(
substream
,
argp
);
return
snd_pcm_status_user_compat
(
substream
,
argp
,
false
);
case
SNDRV_PCM_IOCTL_STATUS_EXT32
:
return
snd_pcm_status_user_compat
(
substream
,
argp
,
true
);
case
SNDRV_PCM_IOCTL_SYNC_PTR32
:
return
snd_pcm_ioctl_sync_ptr_compat
(
substream
,
argp
);
case
SNDRV_PCM_IOCTL_CHANNEL_INFO32
:
...
...
sound/core/pcm_lib.c
View file @
72f770c6
...
...
@@ -232,6 +232,49 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream,
return
0
;
}
static
void
update_audio_tstamp
(
struct
snd_pcm_substream
*
substream
,
struct
timespec
*
curr_tstamp
,
struct
timespec
*
audio_tstamp
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
u64
audio_frames
,
audio_nsecs
;
struct
timespec
driver_tstamp
;
if
(
runtime
->
tstamp_mode
!=
SNDRV_PCM_TSTAMP_ENABLE
)
return
;
if
(
!
(
substream
->
ops
->
get_time_info
)
||
(
runtime
->
audio_tstamp_report
.
actual_type
==
SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT
))
{
/*
* provide audio timestamp derived from pointer position
* add delay only if requested
*/
audio_frames
=
runtime
->
hw_ptr_wrap
+
runtime
->
status
->
hw_ptr
;
if
(
runtime
->
audio_tstamp_config
.
report_delay
)
{
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
audio_frames
-=
runtime
->
delay
;
else
audio_frames
+=
runtime
->
delay
;
}
audio_nsecs
=
div_u64
(
audio_frames
*
1000000000LL
,
runtime
->
rate
);
*
audio_tstamp
=
ns_to_timespec
(
audio_nsecs
);
}
runtime
->
status
->
audio_tstamp
=
*
audio_tstamp
;
runtime
->
status
->
tstamp
=
*
curr_tstamp
;
/*
* re-take a driver timestamp to let apps detect if the reference tstamp
* read by low-level hardware was provided with a delay
*/
snd_pcm_gettime
(
substream
->
runtime
,
(
struct
timespec
*
)
&
driver_tstamp
);
runtime
->
driver_tstamp
=
driver_tstamp
;
}
static
int
snd_pcm_update_hw_ptr0
(
struct
snd_pcm_substream
*
substream
,
unsigned
int
in_interrupt
)
{
...
...
@@ -256,11 +299,18 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
pos
=
substream
->
ops
->
pointer
(
substream
);
curr_jiffies
=
jiffies
;
if
(
runtime
->
tstamp_mode
==
SNDRV_PCM_TSTAMP_ENABLE
)
{
snd_pcm_gettime
(
runtime
,
(
struct
timespec
*
)
&
curr_tstamp
);
if
((
runtime
->
hw
.
info
&
SNDRV_PCM_INFO_HAS_WALL_CLOCK
)
&&
(
substream
->
ops
->
wall_clock
))
substream
->
ops
->
wall_clock
(
substream
,
&
audio_tstamp
);
if
((
substream
->
ops
->
get_time_info
)
&&
(
runtime
->
audio_tstamp_config
.
type_requested
!=
SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT
))
{
substream
->
ops
->
get_time_info
(
substream
,
&
curr_tstamp
,
&
audio_tstamp
,
&
runtime
->
audio_tstamp_config
,
&
runtime
->
audio_tstamp_report
);
/* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */
if
(
runtime
->
audio_tstamp_report
.
actual_type
==
SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT
)
snd_pcm_gettime
(
runtime
,
(
struct
timespec
*
)
&
curr_tstamp
);
}
else
snd_pcm_gettime
(
runtime
,
(
struct
timespec
*
)
&
curr_tstamp
);
}
if
(
pos
==
SNDRV_PCM_POS_XRUN
)
{
...
...
@@ -403,8 +453,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
}
no_delta_check:
if
(
runtime
->
status
->
hw_ptr
==
new_hw_ptr
)
if
(
runtime
->
status
->
hw_ptr
==
new_hw_ptr
)
{
update_audio_tstamp
(
substream
,
&
curr_tstamp
,
&
audio_tstamp
);
return
0
;
}
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
&&
runtime
->
silence_size
>
0
)
...
...
@@ -426,30 +478,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
snd_BUG_ON
(
crossed_boundary
!=
1
);
runtime
->
hw_ptr_wrap
+=
runtime
->
boundary
;
}
if
(
runtime
->
tstamp_mode
==
SNDRV_PCM_TSTAMP_ENABLE
)
{
runtime
->
status
->
tstamp
=
curr_tstamp
;
if
(
!
(
runtime
->
hw
.
info
&
SNDRV_PCM_INFO_HAS_WALL_CLOCK
))
{
/*
* no wall clock available, provide audio timestamp
* derived from pointer position+delay
*/
u64
audio_frames
,
audio_nsecs
;
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
audio_frames
=
runtime
->
hw_ptr_wrap
+
runtime
->
status
->
hw_ptr
-
runtime
->
delay
;
else
audio_frames
=
runtime
->
hw_ptr_wrap
+
runtime
->
status
->
hw_ptr
+
runtime
->
delay
;
audio_nsecs
=
div_u64
(
audio_frames
*
1000000000LL
,
runtime
->
rate
);
audio_tstamp
=
ns_to_timespec
(
audio_nsecs
);
}
runtime
->
status
->
audio_tstamp
=
audio_tstamp
;
}
update_audio_tstamp
(
substream
,
&
curr_tstamp
,
&
audio_tstamp
);
return
snd_pcm_update_state
(
substream
,
runtime
);
}
...
...
sound/core/pcm_native.c
View file @
72f770c6
...
...
@@ -707,6 +707,23 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
snd_pcm_stream_lock_irq
(
substream
);
snd_pcm_unpack_audio_tstamp_config
(
status
->
audio_tstamp_data
,
&
runtime
->
audio_tstamp_config
);
/* backwards compatible behavior */
if
(
runtime
->
audio_tstamp_config
.
type_requested
==
SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT
)
{
if
(
runtime
->
hw
.
info
&
SNDRV_PCM_INFO_HAS_WALL_CLOCK
)
runtime
->
audio_tstamp_config
.
type_requested
=
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK
;
else
runtime
->
audio_tstamp_config
.
type_requested
=
SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT
;
runtime
->
audio_tstamp_report
.
valid
=
0
;
}
else
runtime
->
audio_tstamp_report
.
valid
=
1
;
status
->
state
=
runtime
->
status
->
state
;
status
->
suspended_state
=
runtime
->
status
->
suspended_state
;
if
(
status
->
state
==
SNDRV_PCM_STATE_OPEN
)
...
...
@@ -716,8 +733,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
snd_pcm_update_hw_ptr
(
substream
);
if
(
runtime
->
tstamp_mode
==
SNDRV_PCM_TSTAMP_ENABLE
)
{
status
->
tstamp
=
runtime
->
status
->
tstamp
;
status
->
driver_tstamp
=
runtime
->
driver_tstamp
;
status
->
audio_tstamp
=
runtime
->
status
->
audio_tstamp
;
if
(
runtime
->
audio_tstamp_report
.
valid
==
1
)
/* backwards compatibility, no report provided in COMPAT mode */
snd_pcm_pack_audio_tstamp_report
(
&
status
->
audio_tstamp_data
,
&
status
->
audio_tstamp_accuracy
,
&
runtime
->
audio_tstamp_report
);
goto
_tstamp_end
;
}
}
else
{
...
...
@@ -753,12 +777,21 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
}
static
int
snd_pcm_status_user
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_status
__user
*
_status
)
struct
snd_pcm_status
__user
*
_status
,
bool
ext
)
{
struct
snd_pcm_status
status
;
int
res
;
memset
(
&
status
,
0
,
sizeof
(
status
));
/*
* with extension, parameters are read/write,
* get audio_tstamp_data from user,
* ignore rest of status structure
*/
if
(
ext
&&
get_user
(
status
.
audio_tstamp_data
,
(
u32
__user
*
)(
&
_status
->
audio_tstamp_data
)))
return
-
EFAULT
;
res
=
snd_pcm_status
(
substream
,
&
status
);
if
(
res
<
0
)
return
res
;
...
...
@@ -2723,7 +2756,9 @@ static int snd_pcm_common_ioctl1(struct file *file,
case
SNDRV_PCM_IOCTL_SW_PARAMS
:
return
snd_pcm_sw_params_user
(
substream
,
arg
);
case
SNDRV_PCM_IOCTL_STATUS
:
return
snd_pcm_status_user
(
substream
,
arg
);
return
snd_pcm_status_user
(
substream
,
arg
,
false
);
case
SNDRV_PCM_IOCTL_STATUS_EXT
:
return
snd_pcm_status_user
(
substream
,
arg
,
true
);
case
SNDRV_PCM_IOCTL_CHANNEL_INFO
:
return
snd_pcm_channel_info_user
(
substream
,
arg
);
case
SNDRV_PCM_IOCTL_PREPARE
:
...
...
sound/pci/hda/hda_controller.c
View file @
72f770c6
...
...
@@ -731,17 +731,32 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
azx_get_position
(
chip
,
azx_dev
));
}
static
int
azx_get_wallclock_tstamp
(
struct
snd_pcm_substream
*
substream
,
struct
timespec
*
ts
)
static
int
azx_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
)
{
struct
azx_dev
*
azx_dev
=
get_azx_dev
(
substream
);
u64
nsec
;
nsec
=
timecounter_read
(
&
azx_dev
->
azx_tc
);
nsec
=
div_u64
(
nsec
,
3
);
/* can be optimized */
nsec
=
azx_adjust_codec_delay
(
substream
,
nsec
);
if
((
substream
->
runtime
->
hw
.
info
&
SNDRV_PCM_INFO_HAS_LINK_ATIME
)
&&
(
audio_tstamp_config
->
type_requested
==
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK
))
{
*
ts
=
ns_to_timespec
(
nsec
);
snd_pcm_gettime
(
substream
->
runtime
,
system_ts
);
nsec
=
timecounter_read
(
&
azx_dev
->
azx_tc
);
nsec
=
div_u64
(
nsec
,
3
);
/* can be optimized */
if
(
audio_tstamp_config
->
report_delay
)
nsec
=
azx_adjust_codec_delay
(
substream
,
nsec
);
*
audio_ts
=
ns_to_timespec
(
nsec
);
audio_tstamp_report
->
actual_type
=
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK
;
audio_tstamp_report
->
accuracy_report
=
1
;
/* rest of structure is valid */
audio_tstamp_report
->
accuracy
=
42
;
/* 24 MHz WallClock == 42ns resolution */
}
else
audio_tstamp_report
->
actual_type
=
SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT
;
return
0
;
}
...
...
@@ -755,7 +770,8 @@ static struct snd_pcm_hardware azx_pcm_hw = {
/* SNDRV_PCM_INFO_RESUME |*/
SNDRV_PCM_INFO_PAUSE
|
SNDRV_PCM_INFO_SYNC_START
|
SNDRV_PCM_INFO_HAS_WALL_CLOCK
|
SNDRV_PCM_INFO_HAS_WALL_CLOCK
|
/* legacy */
SNDRV_PCM_INFO_HAS_LINK_ATIME
|
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP
),
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
,
.
rates
=
SNDRV_PCM_RATE_48000
,
...
...
@@ -841,10 +857,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
return
-
EINVAL
;
}
/* disable
WALLCLOCK
timestamps for capture streams
/* disable
LINK_ATIME
timestamps for capture streams
until we figure out how to handle digital inputs */
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_CAPTURE
)
runtime
->
hw
.
info
&=
~
SNDRV_PCM_INFO_HAS_WALL_CLOCK
;
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_CAPTURE
)
{
runtime
->
hw
.
info
&=
~
SNDRV_PCM_INFO_HAS_WALL_CLOCK
;
/* legacy */
runtime
->
hw
.
info
&=
~
SNDRV_PCM_INFO_HAS_LINK_ATIME
;
}
spin_lock_irqsave
(
&
chip
->
reg_lock
,
flags
);
azx_dev
->
substream
=
substream
;
...
...
@@ -876,7 +894,7 @@ static struct snd_pcm_ops azx_pcm_ops = {
.
prepare
=
azx_pcm_prepare
,
.
trigger
=
azx_pcm_trigger
,
.
pointer
=
azx_pcm_pointer
,
.
wall_clock
=
azx_get_wallclock_tstamp
,
.
get_time_info
=
azx_get_time_info
,
.
mmap
=
azx_pcm_mmap
,
.
page
=
snd_pcm_sgbuf_ops_page
,
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment