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
nexedi
linux
Commits
2e5dc73f
Commit
2e5dc73f
authored
Feb 03, 2016
by
Takashi Iwai
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/core-fixes' into for-linus
parents
2154cc0e
7f0973e9
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
243 additions
and
146 deletions
+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
No files found.
include/sound/rawmidi.h
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
;
}
...
...
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