1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * OSS compatible sequencer driver
5 * read/write/select interface to device file
7 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
10 #include "seq_oss_device.h"
11 #include "seq_oss_readq.h"
12 #include "seq_oss_writeq.h"
13 #include "seq_oss_synth.h"
14 #include <sound/seq_oss_legacy.h>
15 #include "seq_oss_event.h"
16 #include "seq_oss_timer.h"
17 #include "../seq_clientmgr.h"
23 static int insert_queue(struct seq_oss_devinfo
*dp
, union evrec
*rec
, struct file
*opt
);
31 snd_seq_oss_read(struct seq_oss_devinfo
*dp
, char __user
*buf
, int count
)
33 struct seq_oss_readq
*readq
= dp
->readq
;
34 int result
= 0, err
= 0;
39 if (readq
== NULL
|| ! is_read_mode(dp
->file_mode
))
42 while (count
>= SHORT_EVENT_SIZE
) {
43 snd_seq_oss_readq_lock(readq
, flags
);
44 err
= snd_seq_oss_readq_pick(readq
, &rec
);
46 !is_nonblock_mode(dp
->file_mode
) && result
== 0) {
47 snd_seq_oss_readq_unlock(readq
, flags
);
48 snd_seq_oss_readq_wait(readq
);
49 snd_seq_oss_readq_lock(readq
, flags
);
50 if (signal_pending(current
))
53 err
= snd_seq_oss_readq_pick(readq
, &rec
);
56 snd_seq_oss_readq_unlock(readq
, flags
);
59 ev_len
= ev_length(&rec
);
61 snd_seq_oss_readq_unlock(readq
, flags
);
64 snd_seq_oss_readq_free(readq
);
65 snd_seq_oss_readq_unlock(readq
, flags
);
66 if (copy_to_user(buf
, &rec
, ev_len
)) {
74 return result
> 0 ? result
: err
;
83 snd_seq_oss_write(struct seq_oss_devinfo
*dp
, const char __user
*buf
, int count
, struct file
*opt
)
85 int result
= 0, err
= 0;
89 if (! is_write_mode(dp
->file_mode
) || dp
->writeq
== NULL
)
92 while (count
>= SHORT_EVENT_SIZE
) {
93 if (copy_from_user(&rec
, buf
, SHORT_EVENT_SIZE
)) {
97 if (rec
.s
.code
== SEQ_FULLSIZE
) {
103 fmt
= (*(unsigned short *)rec
.c
) & 0xffff;
104 /* FIXME the return value isn't correct */
105 return snd_seq_oss_synth_load_patch(dp
, rec
.s
.dev
,
108 if (ev_is_long(&rec
)) {
110 if (rec
.s
.code
== SEQ_EXTENDED
&&
111 dp
->seq_mode
== SNDRV_SEQ_OSS_MODE_MUSIC
) {
115 ev_size
= LONG_EVENT_SIZE
;
118 /* copy the reset 4 bytes */
119 if (copy_from_user(rec
.c
+ SHORT_EVENT_SIZE
,
120 buf
+ SHORT_EVENT_SIZE
,
121 LONG_EVENT_SIZE
- SHORT_EVENT_SIZE
)) {
127 if (dp
->seq_mode
== SNDRV_SEQ_OSS_MODE_MUSIC
) {
131 ev_size
= SHORT_EVENT_SIZE
;
135 if ((err
= insert_queue(dp
, &rec
, opt
)) < 0)
142 return result
> 0 ? result
: err
;
147 * insert event record to write queue
148 * return: 0 = OK, non-zero = NG
151 insert_queue(struct seq_oss_devinfo
*dp
, union evrec
*rec
, struct file
*opt
)
154 struct snd_seq_event event
;
156 /* if this is a timing event, process the current time */
157 if (snd_seq_oss_process_timer_event(dp
->timer
, rec
))
158 return 0; /* no need to insert queue */
160 /* parse this event */
161 memset(&event
, 0, sizeof(event
));
162 /* set dummy -- to be sure */
163 event
.type
= SNDRV_SEQ_EVENT_NOTEOFF
;
164 snd_seq_oss_fill_addr(dp
, &event
, dp
->addr
.client
, dp
->addr
.port
);
166 if (snd_seq_oss_process_event(dp
, rec
, &event
))
167 return 0; /* invalid event - no need to insert queue */
169 event
.time
.tick
= snd_seq_oss_timer_cur_tick(dp
->timer
);
170 if (dp
->timer
->realtime
|| !dp
->timer
->running
)
171 snd_seq_oss_dispatch(dp
, &event
, 0, 0);
173 rc
= snd_seq_kernel_client_enqueue(dp
->cseq
, &event
, opt
,
174 !is_nonblock_mode(dp
->file_mode
));
184 snd_seq_oss_poll(struct seq_oss_devinfo
*dp
, struct file
*file
, poll_table
* wait
)
189 if (dp
->readq
&& is_read_mode(dp
->file_mode
)) {
190 if (snd_seq_oss_readq_poll(dp
->readq
, file
, wait
))
191 mask
|= EPOLLIN
| EPOLLRDNORM
;
195 if (dp
->writeq
&& is_write_mode(dp
->file_mode
)) {
196 if (snd_seq_kernel_client_write_poll(dp
->cseq
, file
, wait
))
197 mask
|= EPOLLOUT
| EPOLLWRNORM
;