Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
seq_oss_rw.c
Go to the documentation of this file.
1 /*
2  * OSS compatible sequencer driver
3  *
4  * read/write/select interface to device file
5  *
6  * Copyright (C) 1998,99 Takashi Iwai <[email protected]>
7  *
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.
12  *
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.
17  *
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
21  */
22 
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"
31 
32 
33 /*
34  * protoypes
35  */
36 static int insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt);
37 
38 
39 /*
40  * read interface
41  */
42 
43 int
44 snd_seq_oss_read(struct seq_oss_devinfo *dp, char __user *buf, int count)
45 {
46  struct seq_oss_readq *readq = dp->readq;
47  int result = 0, err = 0;
48  int ev_len;
49  union evrec rec;
50  unsigned long flags;
51 
52  if (readq == NULL || ! is_read_mode(dp->file_mode))
53  return -ENXIO;
54 
55  while (count >= SHORT_EVENT_SIZE) {
56  snd_seq_oss_readq_lock(readq, flags);
57  err = snd_seq_oss_readq_pick(readq, &rec);
58  if (err == -EAGAIN &&
59  !is_nonblock_mode(dp->file_mode) && result == 0) {
60  snd_seq_oss_readq_unlock(readq, flags);
62  snd_seq_oss_readq_lock(readq, flags);
63  if (signal_pending(current))
64  err = -ERESTARTSYS;
65  else
66  err = snd_seq_oss_readq_pick(readq, &rec);
67  }
68  if (err < 0) {
69  snd_seq_oss_readq_unlock(readq, flags);
70  break;
71  }
72  ev_len = ev_length(&rec);
73  if (ev_len < count) {
74  snd_seq_oss_readq_unlock(readq, flags);
75  break;
76  }
78  snd_seq_oss_readq_unlock(readq, flags);
79  if (copy_to_user(buf, &rec, ev_len)) {
80  err = -EFAULT;
81  break;
82  }
83  result += ev_len;
84  buf += ev_len;
85  count -= ev_len;
86  }
87  return result > 0 ? result : err;
88 }
89 
90 
91 /*
92  * write interface
93  */
94 
95 int
96 snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int count, struct file *opt)
97 {
98  int result = 0, err = 0;
99  int ev_size, fmt;
100  union evrec rec;
101 
102  if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
103  return -ENXIO;
104 
105  while (count >= SHORT_EVENT_SIZE) {
106  if (copy_from_user(&rec, buf, SHORT_EVENT_SIZE)) {
107  err = -EFAULT;
108  break;
109  }
110  if (rec.s.code == SEQ_FULLSIZE) {
111  /* load patch */
112  if (result > 0) {
113  err = -EINVAL;
114  break;
115  }
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,
119  fmt, buf, 0, count);
120  }
121  if (ev_is_long(&rec)) {
122  /* extended code */
123  if (rec.s.code == SEQ_EXTENDED &&
125  err = -EINVAL;
126  break;
127  }
128  ev_size = LONG_EVENT_SIZE;
129  if (count < ev_size)
130  break;
131  /* copy the reset 4 bytes */
133  buf + SHORT_EVENT_SIZE,
135  err = -EFAULT;
136  break;
137  }
138  } else {
139  /* old-type code */
140  if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
141  err = -EINVAL;
142  break;
143  }
144  ev_size = SHORT_EVENT_SIZE;
145  }
146 
147  /* insert queue */
148  if ((err = insert_queue(dp, &rec, opt)) < 0)
149  break;
150 
151  result += ev_size;
152  buf += ev_size;
153  count -= ev_size;
154  }
155  return result > 0 ? result : err;
156 }
157 
158 
159 /*
160  * insert event record to write queue
161  * return: 0 = OK, non-zero = NG
162  */
163 static int
164 insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
165 {
166  int rc = 0;
167  struct snd_seq_event event;
168 
169  /* if this is a timing event, process the current time */
171  return 0; /* no need to insert queue */
172 
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);
178 
179  if (snd_seq_oss_process_event(dp, rec, &event))
180  return 0; /* invalid event - no need to insert queue */
181 
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);
185  } else {
186  if (is_nonblock_mode(dp->file_mode))
187  rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, 0, 0);
188  else
189  rc = snd_seq_kernel_client_enqueue_blocking(dp->cseq, &event, opt, 0, 0);
190  }
191  return rc;
192 }
193 
194 
195 /*
196  * select / poll
197  */
198 
199 unsigned int
201 {
202  unsigned int mask = 0;
203 
204  /* input */
205  if (dp->readq && is_read_mode(dp->file_mode)) {
206  if (snd_seq_oss_readq_poll(dp->readq, file, wait))
207  mask |= POLLIN | POLLRDNORM;
208  }
209 
210  /* output */
211  if (dp->writeq && is_write_mode(dp->file_mode)) {
212  if (snd_seq_kernel_client_write_poll(dp->cseq, file, wait))
213  mask |= POLLOUT | POLLWRNORM;
214  }
215  return mask;
216 }