Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
2e5dc73f
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看板
提交
2e5dc73f
编写于
2月 03, 2016
作者:
T
Takashi Iwai
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'topic/core-fixes' into for-linus
上级
2154cc0e
7f0973e9
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
243 addition
and
146 deletion
+243
-146
include/sound/rawmidi.h
include/sound/rawmidi.h
+4
-0
sound/core/rawmidi.c
sound/core/rawmidi.c
+94
-38
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_clientmgr.c
+3
-0
sound/core/seq/seq_ports.c
sound/core/seq/seq_ports.c
+130
-103
sound/core/seq/seq_virmidi.c
sound/core/seq/seq_virmidi.c
+12
-5
未找到文件。
include/sound/rawmidi.h
浏览文件 @
2e5dc73f
...
...
@@ -167,6 +167,10 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
int
snd_rawmidi_transmit_ack
(
struct
snd_rawmidi_substream
*
substream
,
int
count
);
int
snd_rawmidi_transmit
(
struct
snd_rawmidi_substream
*
substream
,
unsigned
char
*
buffer
,
int
count
);
int
__snd_rawmidi_transmit_peek
(
struct
snd_rawmidi_substream
*
substream
,
unsigned
char
*
buffer
,
int
count
);
int
__snd_rawmidi_transmit_ack
(
struct
snd_rawmidi_substream
*
substream
,
int
count
);
/* main midi functions */
...
...
sound/core/rawmidi.c
浏览文件 @
2e5dc73f
...
...
@@ -942,31 +942,36 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
unsigned
long
flags
;
long
result
=
0
,
count1
;
struct
snd_rawmidi_runtime
*
runtime
=
substream
->
runtime
;
unsigned
long
appl_ptr
;
spin_lock_irqsave
(
&
runtime
->
lock
,
flags
);
while
(
count
>
0
&&
runtime
->
avail
)
{
count1
=
runtime
->
buffer_size
-
runtime
->
appl_ptr
;
if
(
count1
>
count
)
count1
=
count
;
spin_lock_irqsave
(
&
runtime
->
lock
,
flags
);
if
(
count1
>
(
int
)
runtime
->
avail
)
count1
=
runtime
->
avail
;
/* update runtime->appl_ptr before unlocking for userbuf */
appl_ptr
=
runtime
->
appl_ptr
;
runtime
->
appl_ptr
+=
count1
;
runtime
->
appl_ptr
%=
runtime
->
buffer_size
;
runtime
->
avail
-=
count1
;
if
(
kernelbuf
)
memcpy
(
kernelbuf
+
result
,
runtime
->
buffer
+
runtime
->
appl_ptr
,
count1
);
memcpy
(
kernelbuf
+
result
,
runtime
->
buffer
+
appl_ptr
,
count1
);
if
(
userbuf
)
{
spin_unlock_irqrestore
(
&
runtime
->
lock
,
flags
);
if
(
copy_to_user
(
userbuf
+
result
,
runtime
->
buffer
+
runtime
->
appl_ptr
,
count1
))
{
runtime
->
buffer
+
appl_ptr
,
count1
))
{
return
result
>
0
?
result
:
-
EFAULT
;
}
spin_lock_irqsave
(
&
runtime
->
lock
,
flags
);
}
runtime
->
appl_ptr
+=
count1
;
runtime
->
appl_ptr
%=
runtime
->
buffer_size
;
runtime
->
avail
-=
count1
;
spin_unlock_irqrestore
(
&
runtime
->
lock
,
flags
);
result
+=
count1
;
count
-=
count1
;
}
spin_unlock_irqrestore
(
&
runtime
->
lock
,
flags
);
return
result
;
}
...
...
@@ -1055,23 +1060,16 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
EXPORT_SYMBOL
(
snd_rawmidi_transmit_empty
);
/**
* snd_rawmidi_transmit_peek - copy data from the internal buffer
*
__
snd_rawmidi_transmit_peek - copy data from the internal buffer
* @substream: the rawmidi substream
* @buffer: the buffer pointer
* @count: data size to transfer
*
* Copies data from the internal output buffer to the given buffer.
*
* Call this in the interrupt handler when the midi output is ready,
* and call snd_rawmidi_transmit_ack() after the transmission is
* finished.
*
* Return: The size of copied data, or a negative error code on failure.
* This is a variant of snd_rawmidi_transmit_peek() without spinlock.
*/
int
snd_rawmidi_transmit_peek
(
struct
snd_rawmidi_substream
*
substream
,
int
__
snd_rawmidi_transmit_peek
(
struct
snd_rawmidi_substream
*
substream
,
unsigned
char
*
buffer
,
int
count
)
{
unsigned
long
flags
;
int
result
,
count1
;
struct
snd_rawmidi_runtime
*
runtime
=
substream
->
runtime
;
...
...
@@ -1081,7 +1079,6 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
return
-
EINVAL
;
}
result
=
0
;
spin_lock_irqsave
(
&
runtime
->
lock
,
flags
);
if
(
runtime
->
avail
>=
runtime
->
buffer_size
)
{
/* warning: lowlevel layer MUST trigger down the hardware */
goto
__skip
;
...
...
@@ -1106,25 +1103,47 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
}
}
__skip:
return
result
;
}
EXPORT_SYMBOL
(
__snd_rawmidi_transmit_peek
);
/**
* snd_rawmidi_transmit_peek - copy data from the internal buffer
* @substream: the rawmidi substream
* @buffer: the buffer pointer
* @count: data size to transfer
*
* Copies data from the internal output buffer to the given buffer.
*
* Call this in the interrupt handler when the midi output is ready,
* and call snd_rawmidi_transmit_ack() after the transmission is
* finished.
*
* Return: The size of copied data, or a negative error code on failure.
*/
int
snd_rawmidi_transmit_peek
(
struct
snd_rawmidi_substream
*
substream
,
unsigned
char
*
buffer
,
int
count
)
{
struct
snd_rawmidi_runtime
*
runtime
=
substream
->
runtime
;
int
result
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
runtime
->
lock
,
flags
);
result
=
__snd_rawmidi_transmit_peek
(
substream
,
buffer
,
count
);
spin_unlock_irqrestore
(
&
runtime
->
lock
,
flags
);
return
result
;
}
EXPORT_SYMBOL
(
snd_rawmidi_transmit_peek
);
/**
* snd_rawmidi_transmit_ack - acknowledge the transmission
*
__
snd_rawmidi_transmit_ack - acknowledge the transmission
* @substream: the rawmidi substream
* @count: the transferred count
*
* Advances the hardware pointer for the internal output buffer with
* the given size and updates the condition.
* Call after the transmission is finished.
*
* Return: The advanced size if successful, or a negative error code on failure.
* This is a variant of __snd_rawmidi_transmit_ack() without spinlock.
*/
int
snd_rawmidi_transmit_ack
(
struct
snd_rawmidi_substream
*
substream
,
int
count
)
int
__
snd_rawmidi_transmit_ack
(
struct
snd_rawmidi_substream
*
substream
,
int
count
)
{
unsigned
long
flags
;
struct
snd_rawmidi_runtime
*
runtime
=
substream
->
runtime
;
if
(
runtime
->
buffer
==
NULL
)
{
...
...
@@ -1132,7 +1151,6 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
"snd_rawmidi_transmit_ack: output is not active!!!
\n
"
);
return
-
EINVAL
;
}
spin_lock_irqsave
(
&
runtime
->
lock
,
flags
);
snd_BUG_ON
(
runtime
->
avail
+
count
>
runtime
->
buffer_size
);
runtime
->
hw_ptr
+=
count
;
runtime
->
hw_ptr
%=
runtime
->
buffer_size
;
...
...
@@ -1142,9 +1160,32 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
if
(
runtime
->
drain
||
snd_rawmidi_ready
(
substream
))
wake_up
(
&
runtime
->
sleep
);
}
spin_unlock_irqrestore
(
&
runtime
->
lock
,
flags
);
return
count
;
}
EXPORT_SYMBOL
(
__snd_rawmidi_transmit_ack
);
/**
* snd_rawmidi_transmit_ack - acknowledge the transmission
* @substream: the rawmidi substream
* @count: the transferred count
*
* Advances the hardware pointer for the internal output buffer with
* the given size and updates the condition.
* Call after the transmission is finished.
*
* Return: The advanced size if successful, or a negative error code on failure.
*/
int
snd_rawmidi_transmit_ack
(
struct
snd_rawmidi_substream
*
substream
,
int
count
)
{
struct
snd_rawmidi_runtime
*
runtime
=
substream
->
runtime
;
int
result
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
runtime
->
lock
,
flags
);
result
=
__snd_rawmidi_transmit_ack
(
substream
,
count
);
spin_unlock_irqrestore
(
&
runtime
->
lock
,
flags
);
return
result
;
}
EXPORT_SYMBOL
(
snd_rawmidi_transmit_ack
);
/**
...
...
@@ -1160,12 +1201,22 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
int
snd_rawmidi_transmit
(
struct
snd_rawmidi_substream
*
substream
,
unsigned
char
*
buffer
,
int
count
)
{
struct
snd_rawmidi_runtime
*
runtime
=
substream
->
runtime
;
int
result
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
runtime
->
lock
,
flags
);
if
(
!
substream
->
opened
)
return
-
EBADFD
;
count
=
snd_rawmidi_transmit_peek
(
substream
,
buffer
,
count
);
if
(
count
<
0
)
return
count
;
return
snd_rawmidi_transmit_ack
(
substream
,
count
);
result
=
-
EBADFD
;
else
{
count
=
__snd_rawmidi_transmit_peek
(
substream
,
buffer
,
count
);
if
(
count
<=
0
)
result
=
count
;
else
result
=
__snd_rawmidi_transmit_ack
(
substream
,
count
);
}
spin_unlock_irqrestore
(
&
runtime
->
lock
,
flags
);
return
result
;
}
EXPORT_SYMBOL
(
snd_rawmidi_transmit
);
...
...
@@ -1177,6 +1228,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
unsigned
long
flags
;
long
count1
,
result
;
struct
snd_rawmidi_runtime
*
runtime
=
substream
->
runtime
;
unsigned
long
appl_ptr
;
if
(
!
kernelbuf
&&
!
userbuf
)
return
-
EINVAL
;
...
...
@@ -1197,12 +1249,19 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
count1
=
count
;
if
(
count1
>
(
long
)
runtime
->
avail
)
count1
=
runtime
->
avail
;
/* update runtime->appl_ptr before unlocking for userbuf */
appl_ptr
=
runtime
->
appl_ptr
;
runtime
->
appl_ptr
+=
count1
;
runtime
->
appl_ptr
%=
runtime
->
buffer_size
;
runtime
->
avail
-=
count1
;
if
(
kernelbuf
)
memcpy
(
runtime
->
buffer
+
runtime
->
appl_ptr
,
memcpy
(
runtime
->
buffer
+
appl_ptr
,
kernelbuf
+
result
,
count1
);
else
if
(
userbuf
)
{
spin_unlock_irqrestore
(
&
runtime
->
lock
,
flags
);
if
(
copy_from_user
(
runtime
->
buffer
+
runtime
->
appl_ptr
,
if
(
copy_from_user
(
runtime
->
buffer
+
appl_ptr
,
userbuf
+
result
,
count1
))
{
spin_lock_irqsave
(
&
runtime
->
lock
,
flags
);
result
=
result
>
0
?
result
:
-
EFAULT
;
...
...
@@ -1210,9 +1269,6 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
}
spin_lock_irqsave
(
&
runtime
->
lock
,
flags
);
}
runtime
->
appl_ptr
+=
count1
;
runtime
->
appl_ptr
%=
runtime
->
buffer_size
;
runtime
->
avail
-=
count1
;
result
+=
count1
;
count
-=
count1
;
}
...
...
sound/core/seq/seq_clientmgr.c
浏览文件 @
2e5dc73f
...
...
@@ -678,6 +678,9 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
else
down_read
(
&
grp
->
list_mutex
);
list_for_each_entry
(
subs
,
&
grp
->
list_head
,
src_list
)
{
/* both ports ready? */
if
(
atomic_read
(
&
subs
->
ref_count
)
!=
2
)
continue
;
event
->
dest
=
subs
->
info
.
dest
;
if
(
subs
->
info
.
flags
&
SNDRV_SEQ_PORT_SUBS_TIMESTAMP
)
/* convert time according to flag with subscription */
...
...
sound/core/seq/seq_ports.c
浏览文件 @
2e5dc73f
...
...
@@ -173,10 +173,6 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
}
/* */
enum
group_type
{
SRC_LIST
,
DEST_LIST
};
static
int
subscribe_port
(
struct
snd_seq_client
*
client
,
struct
snd_seq_client_port
*
port
,
struct
snd_seq_port_subs_info
*
grp
,
...
...
@@ -203,6 +199,20 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr,
return
NULL
;
}
static
void
delete_and_unsubscribe_port
(
struct
snd_seq_client
*
client
,
struct
snd_seq_client_port
*
port
,
struct
snd_seq_subscribers
*
subs
,
bool
is_src
,
bool
ack
);
static
inline
struct
snd_seq_subscribers
*
get_subscriber
(
struct
list_head
*
p
,
bool
is_src
)
{
if
(
is_src
)
return
list_entry
(
p
,
struct
snd_seq_subscribers
,
src_list
);
else
return
list_entry
(
p
,
struct
snd_seq_subscribers
,
dest_list
);
}
/*
* remove all subscribers on the list
* this is called from port_delete, for each src and dest list.
...
...
@@ -210,7 +220,7 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr,
static
void
clear_subscriber_list
(
struct
snd_seq_client
*
client
,
struct
snd_seq_client_port
*
port
,
struct
snd_seq_port_subs_info
*
grp
,
int
grptype
)
int
is_src
)
{
struct
list_head
*
p
,
*
n
;
...
...
@@ -219,15 +229,13 @@ static void clear_subscriber_list(struct snd_seq_client *client,
struct
snd_seq_client
*
c
;
struct
snd_seq_client_port
*
aport
;
if
(
grptype
==
SRC_LIST
)
{
subs
=
list_entry
(
p
,
struct
snd_seq_subscribers
,
src_list
);
subs
=
get_subscriber
(
p
,
is_src
);
if
(
is_src
)
aport
=
get_client_port
(
&
subs
->
info
.
dest
,
&
c
);
}
else
{
subs
=
list_entry
(
p
,
struct
snd_seq_subscribers
,
dest_list
);
else
aport
=
get_client_port
(
&
subs
->
info
.
sender
,
&
c
);
}
list_del
(
p
);
unsubscribe_port
(
client
,
port
,
grp
,
&
subs
->
info
,
0
);
delete_and_unsubscribe_port
(
client
,
port
,
subs
,
is_src
,
false
);
if
(
!
aport
)
{
/* looks like the connected port is being deleted.
* we decrease the counter, and when both ports are deleted
...
...
@@ -235,21 +243,14 @@ static void clear_subscriber_list(struct snd_seq_client *client,
*/
if
(
atomic_dec_and_test
(
&
subs
->
ref_count
))
kfree
(
subs
);
}
else
{
/* ok we got the connected port */
struct
snd_seq_port_subs_info
*
agrp
;
agrp
=
(
grptype
==
SRC_LIST
)
?
&
aport
->
c_dest
:
&
aport
->
c_src
;
down_write
(
&
agrp
->
list_mutex
);
if
(
grptype
==
SRC_LIST
)
list_del
(
&
subs
->
dest_list
);
else
list_del
(
&
subs
->
src_list
);
up_write
(
&
agrp
->
list_mutex
);
unsubscribe_port
(
c
,
aport
,
agrp
,
&
subs
->
info
,
1
);
kfree
(
subs
);
snd_seq_port_unlock
(
aport
);
snd_seq_client_unlock
(
c
);
continue
;
}
/* ok we got the connected port */
delete_and_unsubscribe_port
(
c
,
aport
,
subs
,
!
is_src
,
true
);
kfree
(
subs
);
snd_seq_port_unlock
(
aport
);
snd_seq_client_unlock
(
c
);
}
}
...
...
@@ -262,8 +263,8 @@ static int port_delete(struct snd_seq_client *client,
snd_use_lock_sync
(
&
port
->
use_lock
);
/* clear subscribers info */
clear_subscriber_list
(
client
,
port
,
&
port
->
c_src
,
SRC_LIST
);
clear_subscriber_list
(
client
,
port
,
&
port
->
c_dest
,
DEST_LIST
);
clear_subscriber_list
(
client
,
port
,
&
port
->
c_src
,
true
);
clear_subscriber_list
(
client
,
port
,
&
port
->
c_dest
,
false
);
if
(
port
->
private_free
)
port
->
private_free
(
port
->
private_data
);
...
...
@@ -479,85 +480,120 @@ static int match_subs_info(struct snd_seq_port_subscribe *r,
return
0
;
}
/* connect two ports */
int
snd_seq_port_connect
(
struct
snd_seq_client
*
connector
,
struct
snd_seq_client
*
src_client
,
struct
snd_seq_client_port
*
src_port
,
struct
snd_seq_client
*
dest_client
,
struct
snd_seq_client_port
*
dest_port
,
struct
snd_seq_port_subscribe
*
info
)
static
int
check_and_subscribe_port
(
struct
snd_seq_client
*
client
,
struct
snd_seq_client_port
*
port
,
struct
snd_seq_subscribers
*
subs
,
bool
is_src
,
bool
exclusive
,
bool
ack
)
{
struct
snd_seq_port_subs_info
*
src
=
&
src_port
->
c_src
;
struct
snd_seq_port_subs_info
*
dest
=
&
dest_port
->
c_dest
;
struct
snd_seq_subscribers
*
subs
,
*
s
;
int
err
,
src_called
=
0
;
unsigned
long
flags
;
int
exclusive
;
struct
snd_seq_port_subs_info
*
grp
;
struct
list_head
*
p
;
struct
snd_seq_subscribers
*
s
;
int
err
;
subs
=
kzalloc
(
sizeof
(
*
subs
),
GFP_KERNEL
);
if
(
!
subs
)
return
-
ENOMEM
;
subs
->
info
=
*
info
;
atomic_set
(
&
subs
->
ref_count
,
2
);
down_write
(
&
src
->
list_mutex
);
down_write_nested
(
&
dest
->
list_mutex
,
SINGLE_DEPTH_NESTING
);
exclusive
=
info
->
flags
&
SNDRV_SEQ_PORT_SUBS_EXCLUSIVE
?
1
:
0
;
grp
=
is_src
?
&
port
->
c_src
:
&
port
->
c_dest
;
err
=
-
EBUSY
;
down_write
(
&
grp
->
list_mutex
);
if
(
exclusive
)
{
if
(
!
list_empty
(
&
src
->
list_head
)
||
!
list_empty
(
&
dest
->
list_head
))
if
(
!
list_empty
(
&
grp
->
list_head
))
goto
__error
;
}
else
{
if
(
src
->
exclusive
||
dest
->
exclusive
)
if
(
grp
->
exclusive
)
goto
__error
;
/* check whether already exists */
list_for_each_entry
(
s
,
&
src
->
list_head
,
src_list
)
{
if
(
match_subs_info
(
info
,
&
s
->
info
))
goto
__error
;
}
list_for_each_entry
(
s
,
&
dest
->
list_head
,
dest_list
)
{
if
(
match_subs_info
(
info
,
&
s
->
info
))
list_for_each
(
p
,
&
grp
->
list_head
)
{
s
=
get_subscriber
(
p
,
is_src
);
if
(
match_subs_info
(
&
subs
->
info
,
&
s
->
info
))
goto
__error
;
}
}
if
((
err
=
subscribe_port
(
src_client
,
src_port
,
src
,
info
,
connector
->
number
!=
src_client
->
number
))
<
0
)
goto
__error
;
src_called
=
1
;
if
((
err
=
subscribe_port
(
dest_client
,
dest_port
,
dest
,
info
,
connector
->
number
!=
dest_client
->
number
))
<
0
)
err
=
subscribe_port
(
client
,
port
,
grp
,
&
subs
->
info
,
ack
);
if
(
err
<
0
)
{
grp
->
exclusive
=
0
;
goto
__error
;
}
/* add to list */
write_lock_irqsave
(
&
src
->
list_lock
,
flags
);
// write_lock(&dest->list_lock); // no other lock yet
list_add_tail
(
&
subs
->
src_list
,
&
src
->
list_head
);
list_add_tail
(
&
subs
->
dest_list
,
&
dest
->
list_head
);
// write_unlock(&dest->list_lock); // no other lock yet
write_unlock_irqrestore
(
&
src
->
list_lock
,
flags
);
write_lock_irq
(
&
grp
->
list_lock
);
if
(
is_src
)
list_add_tail
(
&
subs
->
src_list
,
&
grp
->
list_head
);
else
list_add_tail
(
&
subs
->
dest_list
,
&
grp
->
list_head
);
grp
->
exclusive
=
exclusive
;
atomic_inc
(
&
subs
->
ref_count
);
write_unlock_irq
(
&
grp
->
list_lock
);
err
=
0
;
__error:
up_write
(
&
grp
->
list_mutex
);
return
err
;
}
src
->
exclusive
=
dest
->
exclusive
=
exclusive
;
static
void
delete_and_unsubscribe_port
(
struct
snd_seq_client
*
client
,
struct
snd_seq_client_port
*
port
,
struct
snd_seq_subscribers
*
subs
,
bool
is_src
,
bool
ack
)
{
struct
snd_seq_port_subs_info
*
grp
;
grp
=
is_src
?
&
port
->
c_src
:
&
port
->
c_dest
;
down_write
(
&
grp
->
list_mutex
);
write_lock_irq
(
&
grp
->
list_lock
);
if
(
is_src
)
list_del
(
&
subs
->
src_list
);
else
list_del
(
&
subs
->
dest_list
);
grp
->
exclusive
=
0
;
write_unlock_irq
(
&
grp
->
list_lock
);
up_write
(
&
grp
->
list_mutex
);
unsubscribe_port
(
client
,
port
,
grp
,
&
subs
->
info
,
ack
);
}
/* connect two ports */
int
snd_seq_port_connect
(
struct
snd_seq_client
*
connector
,
struct
snd_seq_client
*
src_client
,
struct
snd_seq_client_port
*
src_port
,
struct
snd_seq_client
*
dest_client
,
struct
snd_seq_client_port
*
dest_port
,
struct
snd_seq_port_subscribe
*
info
)
{
struct
snd_seq_subscribers
*
subs
;
bool
exclusive
;
int
err
;
subs
=
kzalloc
(
sizeof
(
*
subs
),
GFP_KERNEL
);
if
(
!
subs
)
return
-
ENOMEM
;
subs
->
info
=
*
info
;
atomic_set
(
&
subs
->
ref_count
,
0
);
INIT_LIST_HEAD
(
&
subs
->
src_list
);
INIT_LIST_HEAD
(
&
subs
->
dest_list
);
exclusive
=
!!
(
info
->
flags
&
SNDRV_SEQ_PORT_SUBS_EXCLUSIVE
);
err
=
check_and_subscribe_port
(
src_client
,
src_port
,
subs
,
true
,
exclusive
,
connector
->
number
!=
src_client
->
number
);
if
(
err
<
0
)
goto
error
;
err
=
check_and_subscribe_port
(
dest_client
,
dest_port
,
subs
,
false
,
exclusive
,
connector
->
number
!=
dest_client
->
number
);
if
(
err
<
0
)
goto
error_dest
;
up_write
(
&
dest
->
list_mutex
);
up_write
(
&
src
->
list_mutex
);
return
0
;
__error
:
if
(
src_called
)
unsubscribe_port
(
src_client
,
src_port
,
src
,
info
,
connector
->
number
!=
src_client
->
number
);
error_dest
:
delete_and_unsubscribe_port
(
src_client
,
src_port
,
subs
,
true
,
connector
->
number
!=
src_client
->
number
);
error:
kfree
(
subs
);
up_write
(
&
dest
->
list_mutex
);
up_write
(
&
src
->
list_mutex
);
return
err
;
}
/* remove the connection */
int
snd_seq_port_disconnect
(
struct
snd_seq_client
*
connector
,
struct
snd_seq_client
*
src_client
,
...
...
@@ -567,37 +603,28 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
struct
snd_seq_port_subscribe
*
info
)
{
struct
snd_seq_port_subs_info
*
src
=
&
src_port
->
c_src
;
struct
snd_seq_port_subs_info
*
dest
=
&
dest_port
->
c_dest
;
struct
snd_seq_subscribers
*
subs
;
int
err
=
-
ENOENT
;
unsigned
long
flags
;
down_write
(
&
src
->
list_mutex
);
down_write_nested
(
&
dest
->
list_mutex
,
SINGLE_DEPTH_NESTING
);
/* look for the connection */
list_for_each_entry
(
subs
,
&
src
->
list_head
,
src_list
)
{
if
(
match_subs_info
(
info
,
&
subs
->
info
))
{
write_lock_irqsave
(
&
src
->
list_lock
,
flags
);
// write_lock(&dest->list_lock); // no lock yet
list_del
(
&
subs
->
src_list
);
list_del
(
&
subs
->
dest_list
);
// write_unlock(&dest->list_lock);
write_unlock_irqrestore
(
&
src
->
list_lock
,
flags
);
src
->
exclusive
=
dest
->
exclusive
=
0
;
unsubscribe_port
(
src_client
,
src_port
,
src
,
info
,
connector
->
number
!=
src_client
->
number
);
unsubscribe_port
(
dest_client
,
dest_port
,
dest
,
info
,
connector
->
number
!=
dest_client
->
number
);
kfree
(
subs
);
atomic_dec
(
&
subs
->
ref_count
);
/* mark as not ready */
err
=
0
;
break
;
}
}
up_write
(
&
dest
->
list_mutex
);
up_write
(
&
src
->
list_mutex
);
return
err
;
if
(
err
<
0
)
return
err
;
delete_and_unsubscribe_port
(
src_client
,
src_port
,
subs
,
true
,
connector
->
number
!=
src_client
->
number
);
delete_and_unsubscribe_port
(
dest_client
,
dest_port
,
subs
,
false
,
connector
->
number
!=
dest_client
->
number
);
kfree
(
subs
);
return
0
;
}
...
...
sound/core/seq/seq_virmidi.c
浏览文件 @
2e5dc73f
...
...
@@ -155,21 +155,26 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream,
struct
snd_virmidi
*
vmidi
=
substream
->
runtime
->
private_data
;
int
count
,
res
;
unsigned
char
buf
[
32
],
*
pbuf
;
unsigned
long
flags
;
if
(
up
)
{
vmidi
->
trigger
=
1
;
if
(
vmidi
->
seq_mode
==
SNDRV_VIRMIDI_SEQ_DISPATCH
&&
!
(
vmidi
->
rdev
->
flags
&
SNDRV_VIRMIDI_SUBSCRIBE
))
{
snd_rawmidi_transmit_ack
(
substream
,
substream
->
runtime
->
buffer_size
-
substream
->
runtime
->
avail
);
return
;
/* ignored */
while
(
snd_rawmidi_transmit
(
substream
,
buf
,
sizeof
(
buf
))
>
0
)
{
/* ignored */
}
return
;
}
if
(
vmidi
->
event
.
type
!=
SNDRV_SEQ_EVENT_NONE
)
{
if
(
snd_seq_kernel_client_dispatch
(
vmidi
->
client
,
&
vmidi
->
event
,
in_atomic
(),
0
)
<
0
)
return
;
vmidi
->
event
.
type
=
SNDRV_SEQ_EVENT_NONE
;
}
spin_lock_irqsave
(
&
substream
->
runtime
->
lock
,
flags
);
while
(
1
)
{
count
=
snd_rawmidi_transmit_peek
(
substream
,
buf
,
sizeof
(
buf
));
count
=
__
snd_rawmidi_transmit_peek
(
substream
,
buf
,
sizeof
(
buf
));
if
(
count
<=
0
)
break
;
pbuf
=
buf
;
...
...
@@ -179,16 +184,18 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream,
snd_midi_event_reset_encode
(
vmidi
->
parser
);
continue
;
}
snd_rawmidi_transmit_ack
(
substream
,
res
);
__
snd_rawmidi_transmit_ack
(
substream
,
res
);
pbuf
+=
res
;
count
-=
res
;
if
(
vmidi
->
event
.
type
!=
SNDRV_SEQ_EVENT_NONE
)
{
if
(
snd_seq_kernel_client_dispatch
(
vmidi
->
client
,
&
vmidi
->
event
,
in_atomic
(),
0
)
<
0
)
return
;
goto
out
;
vmidi
->
event
.
type
=
SNDRV_SEQ_EVENT_NONE
;
}
}
}
out:
spin_unlock_irqrestore
(
&
substream
->
runtime
->
lock
,
flags
);
}
else
{
vmidi
->
trigger
=
0
;
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录