2 * OSS compatible sequencer driver
4 * read/write/select interface to device file
6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "seq_oss_device.h"
24 #include "seq_oss_readq.h"
25 #include "seq_oss_writeq.h"
26 #include "seq_oss_synth.h"
27 #include <sound/seq_oss_legacy.h>
28 #include "seq_oss_event.h"
29 #include "seq_oss_timer.h"
30 #include "../seq_clientmgr.h"
36 static int insert_queue(struct seq_oss_devinfo
*dp
, union evrec
*rec
, struct file
*opt
);
44 snd_seq_oss_read(struct seq_oss_devinfo
*dp
, char __user
*buf
, int count
)
46 struct seq_oss_readq
*readq
= dp
->readq
;
47 int result
= 0, err
= 0;
52 if (readq
== NULL
|| ! is_read_mode(dp
->file_mode
))
55 while (count
>= SHORT_EVENT_SIZE
) {
56 snd_seq_oss_readq_lock(readq
, flags
);
57 err
= snd_seq_oss_readq_pick(readq
, &rec
);
59 !is_nonblock_mode(dp
->file_mode
) && result
== 0) {
60 snd_seq_oss_readq_unlock(readq
, flags
);
61 snd_seq_oss_readq_wait(readq
);
62 snd_seq_oss_readq_lock(readq
, flags
);
63 if (signal_pending(current
))
66 err
= snd_seq_oss_readq_pick(readq
, &rec
);
69 snd_seq_oss_readq_unlock(readq
, flags
);
72 ev_len
= ev_length(&rec
);
74 snd_seq_oss_readq_unlock(readq
, flags
);
77 snd_seq_oss_readq_free(readq
);
78 snd_seq_oss_readq_unlock(readq
, flags
);
79 if (copy_to_user(buf
, &rec
, ev_len
)) {
87 return result
> 0 ? result
: err
;
96 snd_seq_oss_write(struct seq_oss_devinfo
*dp
, const char __user
*buf
, int count
, struct file
*opt
)
98 int result
= 0, err
= 0;
102 if (! is_write_mode(dp
->file_mode
) || dp
->writeq
== NULL
)
105 while (count
>= SHORT_EVENT_SIZE
) {
106 if (copy_from_user(&rec
, buf
, SHORT_EVENT_SIZE
)) {
110 if (rec
.s
.code
== SEQ_FULLSIZE
) {
116 fmt
= (*(unsigned short *)rec
.c
) & 0xffff;
117 /* FIXME the return value isn't correct */
118 return snd_seq_oss_synth_load_patch(dp
, rec
.s
.dev
,
121 if (ev_is_long(&rec
)) {
123 if (rec
.s
.code
== SEQ_EXTENDED
&&
124 dp
->seq_mode
== SNDRV_SEQ_OSS_MODE_MUSIC
) {
128 ev_size
= LONG_EVENT_SIZE
;
131 /* copy the reset 4 bytes */
132 if (copy_from_user(rec
.c
+ SHORT_EVENT_SIZE
,
133 buf
+ SHORT_EVENT_SIZE
,
134 LONG_EVENT_SIZE
- SHORT_EVENT_SIZE
)) {
140 if (dp
->seq_mode
== SNDRV_SEQ_OSS_MODE_MUSIC
) {
144 ev_size
= SHORT_EVENT_SIZE
;
148 if ((err
= insert_queue(dp
, &rec
, opt
)) < 0)
155 return result
> 0 ? result
: err
;
160 * insert event record to write queue
161 * return: 0 = OK, non-zero = NG
164 insert_queue(struct seq_oss_devinfo
*dp
, union evrec
*rec
, struct file
*opt
)
167 struct snd_seq_event event
;
169 /* if this is a timing event, process the current time */
170 if (snd_seq_oss_process_timer_event(dp
->timer
, rec
))
171 return 0; /* no need to insert queue */
173 /* parse this event */
174 memset(&event
, 0, sizeof(event
));
175 /* set dummy -- to be sure */
176 event
.type
= SNDRV_SEQ_EVENT_NOTEOFF
;
177 snd_seq_oss_fill_addr(dp
, &event
, dp
->addr
.port
, dp
->addr
.client
);
179 if (snd_seq_oss_process_event(dp
, rec
, &event
))
180 return 0; /* invalid event - no need to insert queue */
182 event
.time
.tick
= snd_seq_oss_timer_cur_tick(dp
->timer
);
183 if (dp
->timer
->realtime
|| !dp
->timer
->running
) {
184 snd_seq_oss_dispatch(dp
, &event
, 0, 0);
186 if (is_nonblock_mode(dp
->file_mode
))
187 rc
= snd_seq_kernel_client_enqueue(dp
->cseq
, &event
, 0, 0);
189 rc
= snd_seq_kernel_client_enqueue_blocking(dp
->cseq
, &event
, opt
, 0, 0);
200 snd_seq_oss_poll(struct seq_oss_devinfo
*dp
, struct file
*file
, poll_table
* wait
)
205 if (dp
->readq
&& is_read_mode(dp
->file_mode
)) {
206 if (snd_seq_oss_readq_poll(dp
->readq
, file
, wait
))
207 mask
|= EPOLLIN
| EPOLLRDNORM
;
211 if (dp
->writeq
&& is_write_mode(dp
->file_mode
)) {
212 if (snd_seq_kernel_client_write_poll(dp
->cseq
, file
, wait
))
213 mask
|= EPOLLOUT
| EPOLLWRNORM
;