Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
56599bb0
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
56599bb0
编写于
4月 18, 2012
作者:
T
Takashi Iwai
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'topic/usb-endpoint' into topic/misc
上级
7536c301
22026c1a
变更
8
展开全部
隐藏空白更改
内联
并排
Showing
8 changed file
with
1401 addition
and
825 deletion
+1401
-825
sound/usb/card.c
sound/usb/card.c
+9
-1
sound/usb/card.h
sound/usb/card.h
+62
-15
sound/usb/endpoint.c
sound/usb/endpoint.c
+894
-707
sound/usb/endpoint.h
sound/usb/endpoint.h
+20
-12
sound/usb/pcm.c
sound/usb/pcm.c
+365
-76
sound/usb/proc.c
sound/usb/proc.c
+21
-11
sound/usb/stream.c
sound/usb/stream.c
+28
-3
sound/usb/usbaudio.h
sound/usb/usbaudio.h
+2
-0
未找到文件。
sound/usb/card.c
浏览文件 @
56599bb0
...
...
@@ -131,8 +131,9 @@ static void snd_usb_stream_disconnect(struct list_head *head)
subs
=
&
as
->
substream
[
idx
];
if
(
!
subs
->
num_formats
)
continue
;
snd_usb_release_substream_urbs
(
subs
,
1
);
subs
->
interface
=
-
1
;
subs
->
data_endpoint
=
NULL
;
subs
->
sync_endpoint
=
NULL
;
}
}
...
...
@@ -276,6 +277,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
static
int
snd_usb_audio_free
(
struct
snd_usb_audio
*
chip
)
{
mutex_destroy
(
&
chip
->
mutex
);
kfree
(
chip
);
return
0
;
}
...
...
@@ -336,6 +338,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
return
-
ENOMEM
;
}
mutex_init
(
&
chip
->
mutex
);
mutex_init
(
&
chip
->
shutdown_mutex
);
chip
->
index
=
idx
;
chip
->
dev
=
dev
;
...
...
@@ -348,6 +351,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
chip
->
usb_id
=
USB_ID
(
le16_to_cpu
(
dev
->
descriptor
.
idVendor
),
le16_to_cpu
(
dev
->
descriptor
.
idProduct
));
INIT_LIST_HEAD
(
&
chip
->
pcm_list
);
INIT_LIST_HEAD
(
&
chip
->
ep_list
);
INIT_LIST_HEAD
(
&
chip
->
midi_list
);
INIT_LIST_HEAD
(
&
chip
->
mixer_list
);
...
...
@@ -565,6 +569,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
list_for_each
(
p
,
&
chip
->
pcm_list
)
{
snd_usb_stream_disconnect
(
p
);
}
/* release the endpoint resources */
list_for_each
(
p
,
&
chip
->
ep_list
)
{
snd_usb_endpoint_free
(
p
);
}
/* release the midi resources */
list_for_each
(
p
,
&
chip
->
midi_list
)
{
snd_usbmidi_disconnect
(
p
);
...
...
sound/usb/card.h
浏览文件 @
56599bb0
...
...
@@ -30,13 +30,17 @@ struct audioformat {
};
struct
snd_usb_substream
;
struct
snd_usb_endpoint
;
struct
snd_urb_ctx
{
struct
urb
*
urb
;
unsigned
int
buffer_size
;
/* size of data buffer, if data URB */
struct
snd_usb_substream
*
subs
;
struct
snd_usb_endpoint
*
ep
;
int
index
;
/* index for urb array */
int
packets
;
/* number of packets per urb */
int
packet_size
[
MAX_PACKS_HS
];
/* size of packets for next submission */
struct
list_head
ready_list
;
};
struct
snd_urb_ops
{
...
...
@@ -46,6 +50,60 @@ struct snd_urb_ops {
int
(
*
retire_sync
)(
struct
snd_usb_substream
*
subs
,
struct
snd_pcm_runtime
*
runtime
,
struct
urb
*
u
);
};
struct
snd_usb_endpoint
{
struct
snd_usb_audio
*
chip
;
int
use_count
;
int
ep_num
;
/* the referenced endpoint number */
int
type
;
/* SND_USB_ENDPOINT_TYPE_* */
unsigned
long
flags
;
void
(
*
prepare_data_urb
)
(
struct
snd_usb_substream
*
subs
,
struct
urb
*
urb
);
void
(
*
retire_data_urb
)
(
struct
snd_usb_substream
*
subs
,
struct
urb
*
urb
);
struct
snd_usb_substream
*
data_subs
;
struct
snd_usb_endpoint
*
sync_master
;
struct
snd_usb_endpoint
*
sync_slave
;
struct
snd_urb_ctx
urb
[
MAX_URBS
];
struct
snd_usb_packet_info
{
uint32_t
packet_size
[
MAX_PACKS_HS
];
int
packets
;
}
next_packet
[
MAX_URBS
];
int
next_packet_read_pos
,
next_packet_write_pos
;
struct
list_head
ready_playback_urbs
;
unsigned
int
nurbs
;
/* # urbs */
unsigned
long
active_mask
;
/* bitmask of active urbs */
unsigned
long
unlink_mask
;
/* bitmask of unlinked urbs */
char
*
syncbuf
;
/* sync buffer for all sync URBs */
dma_addr_t
sync_dma
;
/* DMA address of syncbuf */
unsigned
int
pipe
;
/* the data i/o pipe */
unsigned
int
freqn
;
/* nominal sampling rate in fs/fps in Q16.16 format */
unsigned
int
freqm
;
/* momentary sampling rate in fs/fps in Q16.16 format */
int
freqshift
;
/* how much to shift the feedback value to get Q16.16 */
unsigned
int
freqmax
;
/* maximum sampling rate, used for buffer management */
unsigned
int
phase
;
/* phase accumulator */
unsigned
int
maxpacksize
;
/* max packet size in bytes */
unsigned
int
maxframesize
;
/* max packet size in frames */
unsigned
int
curpacksize
;
/* current packet size in bytes (for capture) */
unsigned
int
curframesize
;
/* current packet size in frames (for capture) */
unsigned
int
syncmaxsize
;
/* sync endpoint packet size */
unsigned
int
fill_max
:
1
;
/* fill max packet size always */
unsigned
int
datainterval
;
/* log_2 of data packet interval */
unsigned
int
syncinterval
;
/* P for adaptive mode, 0 otherwise */
unsigned
char
silence_value
;
unsigned
int
stride
;
int
iface
,
alt_idx
;
spinlock_t
lock
;
struct
list_head
list
;
};
struct
snd_usb_substream
{
struct
snd_usb_stream
*
stream
;
struct
usb_device
*
dev
;
...
...
@@ -57,21 +115,6 @@ struct snd_usb_substream {
unsigned
int
cur_rate
;
/* current rate (for hw_params callback) */
unsigned
int
period_bytes
;
/* current period bytes (for hw_params callback) */
unsigned
int
altset_idx
;
/* USB data format: index of alternate setting */
unsigned
int
datapipe
;
/* the data i/o pipe */
unsigned
int
syncpipe
;
/* 1 - async out or adaptive in */
unsigned
int
datainterval
;
/* log_2 of data packet interval */
unsigned
int
syncinterval
;
/* P for adaptive mode, 0 otherwise */
unsigned
int
freqn
;
/* nominal sampling rate in fs/fps in Q16.16 format */
unsigned
int
freqm
;
/* momentary sampling rate in fs/fps in Q16.16 format */
int
freqshift
;
/* how much to shift the feedback value to get Q16.16 */
unsigned
int
freqmax
;
/* maximum sampling rate, used for buffer management */
unsigned
int
phase
;
/* phase accumulator */
unsigned
int
maxpacksize
;
/* max packet size in bytes */
unsigned
int
maxframesize
;
/* max packet size in frames */
unsigned
int
curpacksize
;
/* current packet size in bytes (for capture) */
unsigned
int
curframesize
;
/* current packet size in frames (for capture) */
unsigned
int
syncmaxsize
;
/* sync endpoint packet size */
unsigned
int
fill_max
:
1
;
/* fill max packet size always */
unsigned
int
txfr_quirk
:
1
;
/* allow sub-frame alignment */
unsigned
int
fmt_type
;
/* USB audio format type (1-3) */
...
...
@@ -87,6 +130,10 @@ struct snd_usb_substream {
struct
snd_urb_ctx
syncurb
[
SYNC_URBS
];
/* sync urb table */
char
*
syncbuf
;
/* sync buffer for all sync URBs */
dma_addr_t
sync_dma
;
/* DMA address of syncbuf */
/* data and sync endpoints for this stream */
struct
snd_usb_endpoint
*
data_endpoint
;
struct
snd_usb_endpoint
*
sync_endpoint
;
unsigned
long
flags
;
u64
formats
;
/* format bitmasks (all or'ed) */
unsigned
int
num_formats
;
/* number of supported audio formats (list) */
...
...
sound/usb/endpoint.c
浏览文件 @
56599bb0
此差异已折叠。
点击以展开。
sound/usb/endpoint.h
浏览文件 @
56599bb0
#ifndef __USBAUDIO_ENDPOINT_H
#define __USBAUDIO_ENDPOINT_H
void
snd_usb_init_substream
(
struct
snd_usb_stream
*
as
,
int
stream
,
struct
audioformat
*
fp
);
#define SND_USB_ENDPOINT_TYPE_DATA 0
#define SND_USB_ENDPOINT_TYPE_SYNC 1
int
snd_usb_init_substream_urbs
(
struct
snd_usb_substream
*
subs
,
unsigned
int
period_bytes
,
unsigned
int
rate
,
unsigned
int
frame_bits
);
struct
snd_usb_endpoint
*
snd_usb_add_endpoint
(
struct
snd_usb_audio
*
chip
,
struct
usb_host_interface
*
alts
,
int
ep_num
,
int
direction
,
int
type
);
void
snd_usb_release_substream_urbs
(
struct
snd_usb_substream
*
subs
,
int
force
);
int
snd_usb_endpoint_set_params
(
struct
snd_usb_endpoint
*
ep
,
struct
snd_pcm_hw_params
*
hw_params
,
struct
audioformat
*
fmt
,
struct
snd_usb_endpoint
*
sync_ep
);
int
snd_usb_substream_prepare
(
struct
snd_usb_substream
*
subs
,
struct
snd_pcm_runtime
*
runtime
);
int
snd_usb_endpoint_start
(
struct
snd_usb_endpoint
*
ep
);
void
snd_usb_endpoint_stop
(
struct
snd_usb_endpoint
*
ep
,
int
force
,
int
can_sleep
,
int
wait
);
int
snd_usb_endpoint_activate
(
struct
snd_usb_endpoint
*
ep
);
int
snd_usb_endpoint_deactivate
(
struct
snd_usb_endpoint
*
ep
);
void
snd_usb_endpoint_free
(
struct
list_head
*
head
);
int
snd_usb_substream_playback_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
);
int
snd_usb_substream_capture_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
);
int
snd_usb_endpoint_implict_feedback_sink
(
struct
snd_usb_endpoint
*
ep
);
void
snd_usb_handle_sync_urb
(
struct
snd_usb_endpoint
*
ep
,
struct
snd_usb_endpoint
*
sender
,
const
struct
urb
*
urb
);
#endif
/* __USBAUDIO_ENDPOINT_H */
sound/usb/pcm.c
浏览文件 @
56599bb0
...
...
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/ratelimit.h>
#include <linux/usb.h>
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
...
...
@@ -34,6 +35,9 @@
#include "clock.h"
#include "power.h"
#define SUBSTREAM_FLAG_DATA_EP_STARTED 0
#define SUBSTREAM_FLAG_SYNC_EP_STARTED 1
/* return the estimated delay based on USB frame counters */
snd_pcm_uframes_t
snd_usb_pcm_delay
(
struct
snd_usb_substream
*
subs
,
unsigned
int
rate
)
...
...
@@ -208,6 +212,84 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
}
}
static
int
start_endpoints
(
struct
snd_usb_substream
*
subs
)
{
int
err
;
if
(
!
subs
->
data_endpoint
)
return
-
EINVAL
;
if
(
!
test_and_set_bit
(
SUBSTREAM_FLAG_DATA_EP_STARTED
,
&
subs
->
flags
))
{
struct
snd_usb_endpoint
*
ep
=
subs
->
data_endpoint
;
snd_printdd
(
KERN_DEBUG
"Starting data EP @%p
\n
"
,
ep
);
ep
->
data_subs
=
subs
;
err
=
snd_usb_endpoint_start
(
ep
);
if
(
err
<
0
)
{
clear_bit
(
SUBSTREAM_FLAG_DATA_EP_STARTED
,
&
subs
->
flags
);
return
err
;
}
}
if
(
subs
->
sync_endpoint
&&
!
test_and_set_bit
(
SUBSTREAM_FLAG_SYNC_EP_STARTED
,
&
subs
->
flags
))
{
struct
snd_usb_endpoint
*
ep
=
subs
->
sync_endpoint
;
snd_printdd
(
KERN_DEBUG
"Starting sync EP @%p
\n
"
,
ep
);
ep
->
sync_slave
=
subs
->
data_endpoint
;
err
=
snd_usb_endpoint_start
(
ep
);
if
(
err
<
0
)
{
clear_bit
(
SUBSTREAM_FLAG_SYNC_EP_STARTED
,
&
subs
->
flags
);
return
err
;
}
}
return
0
;
}
static
void
stop_endpoints
(
struct
snd_usb_substream
*
subs
,
int
force
,
int
can_sleep
,
int
wait
)
{
if
(
test_and_clear_bit
(
SUBSTREAM_FLAG_SYNC_EP_STARTED
,
&
subs
->
flags
))
snd_usb_endpoint_stop
(
subs
->
sync_endpoint
,
force
,
can_sleep
,
wait
);
if
(
test_and_clear_bit
(
SUBSTREAM_FLAG_DATA_EP_STARTED
,
&
subs
->
flags
))
snd_usb_endpoint_stop
(
subs
->
data_endpoint
,
force
,
can_sleep
,
wait
);
}
static
int
activate_endpoints
(
struct
snd_usb_substream
*
subs
)
{
if
(
subs
->
sync_endpoint
)
{
int
ret
;
ret
=
snd_usb_endpoint_activate
(
subs
->
sync_endpoint
);
if
(
ret
<
0
)
return
ret
;
}
return
snd_usb_endpoint_activate
(
subs
->
data_endpoint
);
}
static
int
deactivate_endpoints
(
struct
snd_usb_substream
*
subs
)
{
int
reta
,
retb
;
reta
=
snd_usb_endpoint_deactivate
(
subs
->
sync_endpoint
);
retb
=
snd_usb_endpoint_deactivate
(
subs
->
data_endpoint
);
if
(
reta
<
0
)
return
reta
;
if
(
retb
<
0
)
return
retb
;
return
0
;
}
/*
* find a matching format and set up the interface
*/
...
...
@@ -219,7 +301,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
struct
usb_interface
*
iface
;
unsigned
int
ep
,
attr
;
int
is_playback
=
subs
->
direction
==
SNDRV_PCM_STREAM_PLAYBACK
;
int
err
;
int
err
,
implicit_fb
=
0
;
iface
=
usb_ifnum_to_if
(
dev
,
fmt
->
iface
);
if
(
WARN_ON
(
!
iface
))
...
...
@@ -232,40 +314,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
if
(
fmt
==
subs
->
cur_audiofmt
)
return
0
;
/* close the old interface */
if
(
subs
->
interface
>=
0
&&
subs
->
interface
!=
fmt
->
iface
)
{
if
(
usb_set_interface
(
subs
->
dev
,
subs
->
interface
,
0
)
<
0
)
{
snd_printk
(
KERN_ERR
"%d:%d:%d: return to setting 0 failed
\n
"
,
dev
->
devnum
,
fmt
->
iface
,
fmt
->
altsetting
);
return
-
EIO
;
}
subs
->
interface
=
-
1
;
subs
->
altset_idx
=
0
;
}
/* set interface */
if
(
subs
->
interface
!=
fmt
->
iface
||
subs
->
altset_idx
!=
fmt
->
altset_idx
)
{
if
(
usb_set_interface
(
dev
,
fmt
->
iface
,
fmt
->
altsetting
)
<
0
)
{
snd_printk
(
KERN_ERR
"%d:%d:%d: usb_set_interface failed
\n
"
,
dev
->
devnum
,
fmt
->
iface
,
fmt
->
altsetting
);
return
-
EIO
;
}
snd_printdd
(
KERN_INFO
"setting usb interface %d:%d
\n
"
,
fmt
->
iface
,
fmt
->
altsetting
);
subs
->
interface
=
fmt
->
iface
;
subs
->
altset_idx
=
fmt
->
altset_idx
;
}
/* create a data pipe */
ep
=
fmt
->
endpoint
&
USB_ENDPOINT_NUMBER_MASK
;
if
(
is_playback
)
subs
->
datapipe
=
usb_sndisocpipe
(
dev
,
ep
);
else
subs
->
datapipe
=
usb_rcvisocpipe
(
dev
,
ep
);
subs
->
datainterval
=
fmt
->
datainterval
;
subs
->
syncpipe
=
subs
->
syncinterval
=
0
;
subs
->
maxpacksize
=
fmt
->
maxpacksize
;
subs
->
syncmaxsize
=
0
;
subs
->
fill_max
=
0
;
subs
->
data_endpoint
=
snd_usb_add_endpoint
(
subs
->
stream
->
chip
,
alts
,
fmt
->
endpoint
,
subs
->
direction
,
SND_USB_ENDPOINT_TYPE_DATA
);
if
(
!
subs
->
data_endpoint
)
return
-
EINVAL
;
/* we need a sync pipe in async OUT or adaptive IN mode */
/* check the number of EP, since some devices have broken
...
...
@@ -273,8 +326,25 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
* assume it as adaptive-out or sync-in.
*/
attr
=
fmt
->
ep_attr
&
USB_ENDPOINT_SYNCTYPE
;
switch
(
subs
->
stream
->
chip
->
usb_id
)
{
case
USB_ID
(
0x0763
,
0x2080
):
/* M-Audio FastTrack Ultra */
case
USB_ID
(
0x0763
,
0x2081
):
if
(
is_playback
)
{
implicit_fb
=
1
;
ep
=
0x81
;
iface
=
usb_ifnum_to_if
(
dev
,
2
);
if
(
!
iface
||
iface
->
num_altsetting
==
0
)
return
-
EINVAL
;
alts
=
&
iface
->
altsetting
[
1
];
goto
add_sync_ep
;
}
}
if
(((
is_playback
&&
attr
==
USB_ENDPOINT_SYNC_ASYNC
)
||
(
!
is_playback
&&
attr
==
USB_ENDPOINT_SYNC_ADAPTIVE
))
&&
(
!
is_playback
&&
attr
==
USB_ENDPOINT_SYNC_ADAPTIVE
))
&&
altsd
->
bNumEndpoints
>=
2
)
{
/* check sync-pipe endpoint */
/* ... and check descriptor size before accessing bSynchAddress
...
...
@@ -282,7 +352,8 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
the audio fields in the endpoint descriptors */
if
((
get_endpoint
(
alts
,
1
)
->
bmAttributes
&
USB_ENDPOINT_XFERTYPE_MASK
)
!=
0x01
||
(
get_endpoint
(
alts
,
1
)
->
bLength
>=
USB_DT_ENDPOINT_AUDIO_SIZE
&&
get_endpoint
(
alts
,
1
)
->
bSynchAddress
!=
0
))
{
get_endpoint
(
alts
,
1
)
->
bSynchAddress
!=
0
&&
!
implicit_fb
))
{
snd_printk
(
KERN_ERR
"%d:%d:%d : invalid synch pipe
\n
"
,
dev
->
devnum
,
fmt
->
iface
,
fmt
->
altsetting
);
return
-
EINVAL
;
...
...
@@ -290,33 +361,27 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
ep
=
get_endpoint
(
alts
,
1
)
->
bEndpointAddress
;
if
(
get_endpoint
(
alts
,
0
)
->
bLength
>=
USB_DT_ENDPOINT_AUDIO_SIZE
&&
((
is_playback
&&
ep
!=
(
unsigned
int
)(
get_endpoint
(
alts
,
0
)
->
bSynchAddress
|
USB_DIR_IN
))
||
(
!
is_playback
&&
ep
!=
(
unsigned
int
)(
get_endpoint
(
alts
,
0
)
->
bSynchAddress
&
~
USB_DIR_IN
))))
{
(
!
is_playback
&&
ep
!=
(
unsigned
int
)(
get_endpoint
(
alts
,
0
)
->
bSynchAddress
&
~
USB_DIR_IN
))
||
(
is_playback
&&
!
implicit_fb
)))
{
snd_printk
(
KERN_ERR
"%d:%d:%d : invalid synch pipe
\n
"
,
dev
->
devnum
,
fmt
->
iface
,
fmt
->
altsetting
);
return
-
EINVAL
;
}
ep
&=
USB_ENDPOINT_NUMBER_MASK
;
if
(
is_playback
)
subs
->
syncpipe
=
usb_rcvisocpipe
(
dev
,
ep
);
else
subs
->
syncpipe
=
usb_sndisocpipe
(
dev
,
ep
);
if
(
get_endpoint
(
alts
,
1
)
->
bLength
>=
USB_DT_ENDPOINT_AUDIO_SIZE
&&
get_endpoint
(
alts
,
1
)
->
bRefresh
>=
1
&&
get_endpoint
(
alts
,
1
)
->
bRefresh
<=
9
)
subs
->
syncinterval
=
get_endpoint
(
alts
,
1
)
->
bRefresh
;
else
if
(
snd_usb_get_speed
(
subs
->
dev
)
==
USB_SPEED_FULL
)
subs
->
syncinterval
=
1
;
else
if
(
get_endpoint
(
alts
,
1
)
->
bInterval
>=
1
&&
get_endpoint
(
alts
,
1
)
->
bInterval
<=
16
)
subs
->
syncinterval
=
get_endpoint
(
alts
,
1
)
->
bInterval
-
1
;
else
subs
->
syncinterval
=
3
;
subs
->
syncmaxsize
=
le16_to_cpu
(
get_endpoint
(
alts
,
1
)
->
wMaxPacketSize
);
}
/* always fill max packet size */
if
(
fmt
->
attributes
&
UAC_EP_CS_ATTR_FILL_MAX
)
subs
->
fill_max
=
1
;
implicit_fb
=
(
get_endpoint
(
alts
,
1
)
->
bmAttributes
&
USB_ENDPOINT_USAGE_MASK
)
==
USB_ENDPOINT_USAGE_IMPLICIT_FB
;
add_sync_ep:
subs
->
sync_endpoint
=
snd_usb_add_endpoint
(
subs
->
stream
->
chip
,
alts
,
ep
,
!
subs
->
direction
,
implicit_fb
?
SND_USB_ENDPOINT_TYPE_DATA
:
SND_USB_ENDPOINT_TYPE_SYNC
);
if
(
!
subs
->
sync_endpoint
)
return
-
EINVAL
;
subs
->
data_endpoint
->
sync_master
=
subs
->
sync_endpoint
;
}
if
((
err
=
snd_usb_init_pitch
(
subs
->
stream
->
chip
,
subs
->
interface
,
alts
,
fmt
))
<
0
)
return
err
;
...
...
@@ -390,12 +455,22 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
if
(
changed
)
{
mutex_lock
(
&
subs
->
stream
->
chip
->
shutdown_mutex
);
/* format changed */
snd_usb_release_substream_urbs
(
subs
,
0
);
/* influenced: period_bytes, channels, rate, format, */
ret
=
snd_usb_init_substream_urbs
(
subs
,
params_period_bytes
(
hw_params
),
params_rate
(
hw_params
),
snd_pcm_format_physical_width
(
params_format
(
hw_params
))
*
params_channels
(
hw_params
));
stop_endpoints
(
subs
,
0
,
0
,
0
);
deactivate_endpoints
(
subs
);
ret
=
activate_endpoints
(
subs
);
if
(
ret
<
0
)
goto
unlock
;
ret
=
snd_usb_endpoint_set_params
(
subs
->
data_endpoint
,
hw_params
,
fmt
,
subs
->
sync_endpoint
);
if
(
ret
<
0
)
goto
unlock
;
if
(
subs
->
sync_endpoint
)
ret
=
snd_usb_endpoint_set_params
(
subs
->
sync_endpoint
,
hw_params
,
fmt
,
NULL
);
unlock:
mutex_unlock
(
&
subs
->
stream
->
chip
->
shutdown_mutex
);
}
...
...
@@ -415,7 +490,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
subs
->
cur_rate
=
0
;
subs
->
period_bytes
=
0
;
mutex_lock
(
&
subs
->
stream
->
chip
->
shutdown_mutex
);
s
nd_usb_release_substream_urbs
(
subs
,
0
);
s
top_endpoints
(
subs
,
0
,
1
,
1
);
mutex_unlock
(
&
subs
->
stream
->
chip
->
shutdown_mutex
);
return
snd_pcm_lib_free_vmalloc_buffer
(
substream
);
}
...
...
@@ -435,19 +510,28 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
return
-
ENXIO
;
}
if
(
snd_BUG_ON
(
!
subs
->
data_endpoint
))
return
-
EIO
;
/* some unit conversions in runtime */
subs
->
maxframesize
=
bytes_to_frames
(
runtime
,
subs
->
maxpacksize
);
subs
->
curframesize
=
bytes_to_frames
(
runtime
,
subs
->
curpacksize
);
subs
->
data_endpoint
->
maxframesize
=
bytes_to_frames
(
runtime
,
subs
->
data_endpoint
->
maxpacksize
);
subs
->
data_endpoint
->
curframesize
=
bytes_to_frames
(
runtime
,
subs
->
data_endpoint
->
curpacksize
);
/* reset the pointer */
subs
->
hwptr_done
=
0
;
subs
->
transfer_done
=
0
;
subs
->
phase
=
0
;
subs
->
last_delay
=
0
;
subs
->
last_frame_number
=
0
;
runtime
->
delay
=
0
;
return
snd_usb_substream_prepare
(
subs
,
runtime
);
/* for playback, submit the URBs now; otherwise, the first hwptr_done
* updates for all URBs would happen at the same time when starting */
if
(
subs
->
direction
==
SNDRV_PCM_STREAM_PLAYBACK
)
return
start_endpoints
(
subs
);
return
0
;
}
static
struct
snd_pcm_hardware
snd_usb_hardware
=
...
...
@@ -842,16 +926,171 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
static
int
snd_usb_pcm_close
(
struct
snd_pcm_substream
*
substream
,
int
direction
)
{
int
ret
;
struct
snd_usb_stream
*
as
=
snd_pcm_substream_chip
(
substream
);
struct
snd_usb_substream
*
subs
=
&
as
->
substream
[
direction
];
if
(
!
as
->
chip
->
shutdown
&&
subs
->
interface
>=
0
)
{
usb_set_interface
(
subs
->
dev
,
subs
->
interface
,
0
);
subs
->
interface
=
-
1
;
}
stop_endpoints
(
subs
,
0
,
0
,
0
);
ret
=
deactivate_endpoints
(
subs
);
subs
->
pcm_substream
=
NULL
;
snd_usb_autosuspend
(
subs
->
stream
->
chip
);
return
0
;
return
ret
;
}
/* Since a URB can handle only a single linear buffer, we must use double
* buffering when the data to be transferred overflows the buffer boundary.
* To avoid inconsistencies when updating hwptr_done, we use double buffering
* for all URBs.
*/
static
void
retire_capture_urb
(
struct
snd_usb_substream
*
subs
,
struct
urb
*
urb
)
{
struct
snd_pcm_runtime
*
runtime
=
subs
->
pcm_substream
->
runtime
;
unsigned
int
stride
,
frames
,
bytes
,
oldptr
;
int
i
,
period_elapsed
=
0
;
unsigned
long
flags
;
unsigned
char
*
cp
;
stride
=
runtime
->
frame_bits
>>
3
;
for
(
i
=
0
;
i
<
urb
->
number_of_packets
;
i
++
)
{
cp
=
(
unsigned
char
*
)
urb
->
transfer_buffer
+
urb
->
iso_frame_desc
[
i
].
offset
;
if
(
urb
->
iso_frame_desc
[
i
].
status
&&
printk_ratelimit
())
{
snd_printdd
(
KERN_ERR
"frame %d active: %d
\n
"
,
i
,
urb
->
iso_frame_desc
[
i
].
status
);
// continue;
}
bytes
=
urb
->
iso_frame_desc
[
i
].
actual_length
;
frames
=
bytes
/
stride
;
if
(
!
subs
->
txfr_quirk
)
bytes
=
frames
*
stride
;
if
(
bytes
%
(
runtime
->
sample_bits
>>
3
)
!=
0
)
{
#ifdef CONFIG_SND_DEBUG_VERBOSE
int
oldbytes
=
bytes
;
#endif
bytes
=
frames
*
stride
;
snd_printdd
(
KERN_ERR
"Corrected urb data len. %d->%d
\n
"
,
oldbytes
,
bytes
);
}
/* update the current pointer */
spin_lock_irqsave
(
&
subs
->
lock
,
flags
);
oldptr
=
subs
->
hwptr_done
;
subs
->
hwptr_done
+=
bytes
;
if
(
subs
->
hwptr_done
>=
runtime
->
buffer_size
*
stride
)
subs
->
hwptr_done
-=
runtime
->
buffer_size
*
stride
;
frames
=
(
bytes
+
(
oldptr
%
stride
))
/
stride
;
subs
->
transfer_done
+=
frames
;
if
(
subs
->
transfer_done
>=
runtime
->
period_size
)
{
subs
->
transfer_done
-=
runtime
->
period_size
;
period_elapsed
=
1
;
}
spin_unlock_irqrestore
(
&
subs
->
lock
,
flags
);
/* copy a data chunk */
if
(
oldptr
+
bytes
>
runtime
->
buffer_size
*
stride
)
{
unsigned
int
bytes1
=
runtime
->
buffer_size
*
stride
-
oldptr
;
memcpy
(
runtime
->
dma_area
+
oldptr
,
cp
,
bytes1
);
memcpy
(
runtime
->
dma_area
,
cp
+
bytes1
,
bytes
-
bytes1
);
}
else
{
memcpy
(
runtime
->
dma_area
+
oldptr
,
cp
,
bytes
);
}
}
if
(
period_elapsed
)
snd_pcm_period_elapsed
(
subs
->
pcm_substream
);
}
static
void
prepare_playback_urb
(
struct
snd_usb_substream
*
subs
,
struct
urb
*
urb
)
{
struct
snd_pcm_runtime
*
runtime
=
subs
->
pcm_substream
->
runtime
;
struct
snd_urb_ctx
*
ctx
=
urb
->
context
;
unsigned
int
counts
,
frames
,
bytes
;
int
i
,
stride
,
period_elapsed
=
0
;
unsigned
long
flags
;
stride
=
runtime
->
frame_bits
>>
3
;
frames
=
0
;
urb
->
number_of_packets
=
0
;
spin_lock_irqsave
(
&
subs
->
lock
,
flags
);
for
(
i
=
0
;
i
<
ctx
->
packets
;
i
++
)
{
counts
=
ctx
->
packet_size
[
i
];
/* set up descriptor */
urb
->
iso_frame_desc
[
i
].
offset
=
frames
*
stride
;
urb
->
iso_frame_desc
[
i
].
length
=
counts
*
stride
;
frames
+=
counts
;
urb
->
number_of_packets
++
;
subs
->
transfer_done
+=
counts
;
if
(
subs
->
transfer_done
>=
runtime
->
period_size
)
{
subs
->
transfer_done
-=
runtime
->
period_size
;
period_elapsed
=
1
;
if
(
subs
->
fmt_type
==
UAC_FORMAT_TYPE_II
)
{
if
(
subs
->
transfer_done
>
0
)
{
/* FIXME: fill-max mode is not
* supported yet */
frames
-=
subs
->
transfer_done
;
counts
-=
subs
->
transfer_done
;
urb
->
iso_frame_desc
[
i
].
length
=
counts
*
stride
;
subs
->
transfer_done
=
0
;
}
i
++
;
if
(
i
<
ctx
->
packets
)
{
/* add a transfer delimiter */
urb
->
iso_frame_desc
[
i
].
offset
=
frames
*
stride
;
urb
->
iso_frame_desc
[
i
].
length
=
0
;
urb
->
number_of_packets
++
;
}
break
;
}
}
if
(
period_elapsed
&&
!
snd_usb_endpoint_implict_feedback_sink
(
subs
->
data_endpoint
))
/* finish at the period boundary */
break
;
}
bytes
=
frames
*
stride
;
if
(
subs
->
hwptr_done
+
bytes
>
runtime
->
buffer_size
*
stride
)
{
/* err, the transferred area goes over buffer boundary. */
unsigned
int
bytes1
=
runtime
->
buffer_size
*
stride
-
subs
->
hwptr_done
;
memcpy
(
urb
->
transfer_buffer
,
runtime
->
dma_area
+
subs
->
hwptr_done
,
bytes1
);
memcpy
(
urb
->
transfer_buffer
+
bytes1
,
runtime
->
dma_area
,
bytes
-
bytes1
);
}
else
{
memcpy
(
urb
->
transfer_buffer
,
runtime
->
dma_area
+
subs
->
hwptr_done
,
bytes
);
}
subs
->
hwptr_done
+=
bytes
;
if
(
subs
->
hwptr_done
>=
runtime
->
buffer_size
*
stride
)
subs
->
hwptr_done
-=
runtime
->
buffer_size
*
stride
;
runtime
->
delay
+=
frames
;
spin_unlock_irqrestore
(
&
subs
->
lock
,
flags
);
urb
->
transfer_buffer_length
=
bytes
;
if
(
period_elapsed
)
snd_pcm_period_elapsed
(
subs
->
pcm_substream
);
}
/*
* process after playback data complete
* - decrease the delay count again
*/
static
void
retire_playback_urb
(
struct
snd_usb_substream
*
subs
,
struct
urb
*
urb
)
{
unsigned
long
flags
;
struct
snd_pcm_runtime
*
runtime
=
subs
->
pcm_substream
->
runtime
;
int
stride
=
runtime
->
frame_bits
>>
3
;
int
processed
=
urb
->
transfer_buffer_length
/
stride
;
spin_lock_irqsave
(
&
subs
->
lock
,
flags
);
if
(
processed
>
runtime
->
delay
)
runtime
->
delay
=
0
;
else
runtime
->
delay
-=
processed
;
spin_unlock_irqrestore
(
&
subs
->
lock
,
flags
);
}
static
int
snd_usb_playback_open
(
struct
snd_pcm_substream
*
substream
)
...
...
@@ -874,6 +1113,56 @@ static int snd_usb_capture_close(struct snd_pcm_substream *substream)
return
snd_usb_pcm_close
(
substream
,
SNDRV_PCM_STREAM_CAPTURE
);
}
static
int
snd_usb_substream_playback_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
)
{
struct
snd_usb_substream
*
subs
=
substream
->
runtime
->
private_data
;
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_START
:
case
SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
subs
->
data_endpoint
->
prepare_data_urb
=
prepare_playback_urb
;
subs
->
data_endpoint
->
retire_data_urb
=
retire_playback_urb
;
return
0
;
case
SNDRV_PCM_TRIGGER_STOP
:
stop_endpoints
(
subs
,
0
,
0
,
0
);
return
0
;
case
SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
subs
->
data_endpoint
->
prepare_data_urb
=
NULL
;
subs
->
data_endpoint
->
retire_data_urb
=
NULL
;
return
0
;
}
return
-
EINVAL
;
}
int
snd_usb_substream_capture_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
)
{
int
err
;
struct
snd_usb_substream
*
subs
=
substream
->
runtime
->
private_data
;
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_START
:
err
=
start_endpoints
(
subs
);
if
(
err
<
0
)
return
err
;
subs
->
data_endpoint
->
retire_data_urb
=
retire_capture_urb
;
return
0
;
case
SNDRV_PCM_TRIGGER_STOP
:
stop_endpoints
(
subs
,
0
,
0
,
0
);
return
0
;
case
SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
subs
->
data_endpoint
->
retire_data_urb
=
NULL
;
return
0
;
case
SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
subs
->
data_endpoint
->
retire_data_urb
=
retire_capture_urb
;
return
0
;
}
return
-
EINVAL
;
}
static
struct
snd_pcm_ops
snd_usb_playback_ops
=
{
.
open
=
snd_usb_playback_open
,
.
close
=
snd_usb_playback_close
,
...
...
sound/usb/proc.c
浏览文件 @
56599bb0
...
...
@@ -115,6 +115,25 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
}
}
static
void
proc_dump_ep_status
(
struct
snd_usb_substream
*
subs
,
struct
snd_usb_endpoint
*
ep
,
struct
snd_info_buffer
*
buffer
)
{
if
(
!
ep
)
return
;
snd_iprintf
(
buffer
,
" Packet Size = %d
\n
"
,
ep
->
curpacksize
);
snd_iprintf
(
buffer
,
" Momentary freq = %u Hz (%#x.%04x)
\n
"
,
snd_usb_get_speed
(
subs
->
dev
)
==
USB_SPEED_FULL
?
get_full_speed_hz
(
ep
->
freqm
)
:
get_high_speed_hz
(
ep
->
freqm
),
ep
->
freqm
>>
16
,
ep
->
freqm
&
0xffff
);
if
(
ep
->
freqshift
!=
INT_MIN
)
{
int
res
=
16
-
ep
->
freqshift
;
snd_iprintf
(
buffer
,
" Feedback Format = %d.%d
\n
"
,
(
ep
->
syncmaxsize
>
3
?
32
:
24
)
-
res
,
res
);
}
}
static
void
proc_dump_substream_status
(
struct
snd_usb_substream
*
subs
,
struct
snd_info_buffer
*
buffer
)
{
if
(
subs
->
running
)
{
...
...
@@ -126,17 +145,8 @@ static void proc_dump_substream_status(struct snd_usb_substream *subs, struct sn
for
(
i
=
0
;
i
<
subs
->
nurbs
;
i
++
)
snd_iprintf
(
buffer
,
"%d "
,
subs
->
dataurb
[
i
].
packets
);
snd_iprintf
(
buffer
,
"]
\n
"
);
snd_iprintf
(
buffer
,
" Packet Size = %d
\n
"
,
subs
->
curpacksize
);
snd_iprintf
(
buffer
,
" Momentary freq = %u Hz (%#x.%04x)
\n
"
,
snd_usb_get_speed
(
subs
->
dev
)
==
USB_SPEED_FULL
?
get_full_speed_hz
(
subs
->
freqm
)
:
get_high_speed_hz
(
subs
->
freqm
),
subs
->
freqm
>>
16
,
subs
->
freqm
&
0xffff
);
if
(
subs
->
freqshift
!=
INT_MIN
)
snd_iprintf
(
buffer
,
" Feedback Format = %d.%d
\n
"
,
(
subs
->
syncmaxsize
>
3
?
32
:
24
)
-
(
16
-
subs
->
freqshift
),
16
-
subs
->
freqshift
);
proc_dump_ep_status
(
subs
,
subs
->
data_endpoint
,
buffer
);
proc_dump_ep_status
(
subs
,
subs
->
sync_endpoint
,
buffer
);
}
else
{
snd_iprintf
(
buffer
,
" Status: Stop
\n
"
);
}
...
...
sound/usb/stream.c
浏览文件 @
56599bb0
...
...
@@ -73,6 +73,31 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
}
}
/*
* initialize the substream instance.
*/
static
void
snd_usb_init_substream
(
struct
snd_usb_stream
*
as
,
int
stream
,
struct
audioformat
*
fp
)
{
struct
snd_usb_substream
*
subs
=
&
as
->
substream
[
stream
];
INIT_LIST_HEAD
(
&
subs
->
fmt_list
);
spin_lock_init
(
&
subs
->
lock
);
subs
->
stream
=
as
;
subs
->
direction
=
stream
;
subs
->
dev
=
as
->
chip
->
dev
;
subs
->
txfr_quirk
=
as
->
chip
->
txfr_quirk
;
snd_usb_set_pcm_ops
(
as
->
pcm
,
stream
);
list_add_tail
(
&
fp
->
list
,
&
subs
->
fmt_list
);
subs
->
formats
|=
fp
->
formats
;
subs
->
num_formats
++
;
subs
->
fmt_type
=
fp
->
fmt_type
;
}
/*
* add this endpoint to the chip instance.
...
...
@@ -94,9 +119,9 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
if
(
as
->
fmt_type
!=
fp
->
fmt_type
)
continue
;
subs
=
&
as
->
substream
[
stream
];
if
(
!
subs
->
endpoint
)
if
(
!
subs
->
data_
endpoint
)
continue
;
if
(
subs
->
endpoint
==
fp
->
endpoint
)
{
if
(
subs
->
data_endpoint
->
ep_num
==
fp
->
endpoint
)
{
list_add_tail
(
&
fp
->
list
,
&
subs
->
fmt_list
);
subs
->
num_formats
++
;
subs
->
formats
|=
fp
->
formats
;
...
...
@@ -109,7 +134,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
if
(
as
->
fmt_type
!=
fp
->
fmt_type
)
continue
;
subs
=
&
as
->
substream
[
stream
];
if
(
subs
->
endpoint
)
if
(
subs
->
data_
endpoint
)
continue
;
err
=
snd_pcm_new_stream
(
as
->
pcm
,
stream
,
1
);
if
(
err
<
0
)
...
...
sound/usb/usbaudio.h
浏览文件 @
56599bb0
...
...
@@ -36,6 +36,7 @@ struct snd_usb_audio {
struct
snd_card
*
card
;
struct
usb_interface
*
pm_intf
;
u32
usb_id
;
struct
mutex
mutex
;
struct
mutex
shutdown_mutex
;
unsigned
int
shutdown
:
1
;
unsigned
int
probing
:
1
;
...
...
@@ -46,6 +47,7 @@ struct snd_usb_audio {
int
num_suspended_intf
;
struct
list_head
pcm_list
;
/* list of pcm streams */
struct
list_head
ep_list
;
/* list of audio-related endpoints */
int
pcm_devs
;
struct
list_head
midi_list
;
/* list of midi interfaces */
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录