Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | ********************************************************************** | |
3 | * audio.c -- /dev/dsp interface for emu10k1 driver | |
4 | * Copyright 1999, 2000 Creative Labs, Inc. | |
5 | * | |
6 | ********************************************************************** | |
7 | * | |
8 | * Date Author Summary of changes | |
9 | * ---- ------ ------------------ | |
10 | * October 20, 1999 Bertrand Lee base code release | |
11 | * November 2, 1999 Alan Cox cleaned up types/leaks | |
12 | * | |
13 | ********************************************************************** | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or | |
16 | * modify it under the terms of the GNU General Public License as | |
17 | * published by the Free Software Foundation; either version 2 of | |
18 | * the License, or (at your option) any later version. | |
19 | * | |
20 | * This program is distributed in the hope that it will be useful, | |
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 | * GNU General Public License for more details. | |
24 | * | |
25 | * You should have received a copy of the GNU General Public | |
26 | * License along with this program; if not, write to the Free | |
27 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, | |
28 | * USA. | |
29 | * | |
30 | ********************************************************************** | |
31 | */ | |
32 | ||
33 | #include <linux/module.h> | |
34 | #include <linux/poll.h> | |
35 | #include <linux/slab.h> | |
36 | #include <linux/bitops.h> | |
37 | #include <asm/io.h> | |
38 | #include <linux/sched.h> | |
f23f6e08 | 39 | #include <linux/mm.h> |
1da177e4 LT |
40 | #include <linux/smp_lock.h> |
41 | ||
42 | #include "hwaccess.h" | |
43 | #include "cardwo.h" | |
44 | #include "cardwi.h" | |
45 | #include "recmgr.h" | |
46 | #include "irqmgr.h" | |
47 | #include "audio.h" | |
48 | #include "8010.h" | |
49 | ||
50 | static void calculate_ofrag(struct woinst *); | |
51 | static void calculate_ifrag(struct wiinst *); | |
52 | ||
53 | static void emu10k1_waveout_bh(unsigned long refdata); | |
54 | static void emu10k1_wavein_bh(unsigned long refdata); | |
55 | ||
56 | /* Audio file operations */ | |
57 | static ssize_t emu10k1_audio_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos) | |
58 | { | |
59 | struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; | |
60 | struct wiinst *wiinst = wave_dev->wiinst; | |
61 | ssize_t ret = 0; | |
62 | unsigned long flags; | |
63 | ||
64 | DPD(3, "emu10k1_audio_read(), buffer=%p, count=%d\n", buffer, (u32) count); | |
65 | ||
66 | if (!access_ok(VERIFY_WRITE, buffer, count)) | |
67 | return -EFAULT; | |
68 | ||
69 | spin_lock_irqsave(&wiinst->lock, flags); | |
70 | ||
71 | if (wiinst->mmapped) { | |
72 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
73 | return -ENXIO; | |
74 | } | |
75 | ||
76 | if (wiinst->state == WAVE_STATE_CLOSED) { | |
77 | calculate_ifrag(wiinst); | |
78 | ||
79 | while (emu10k1_wavein_open(wave_dev) < 0) { | |
80 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
81 | ||
82 | if (file->f_flags & O_NONBLOCK) | |
83 | return -EAGAIN; | |
84 | ||
85 | interruptible_sleep_on(&wave_dev->card->open_wait); | |
86 | ||
87 | if (signal_pending(current)) | |
88 | return -ERESTARTSYS; | |
89 | ||
90 | spin_lock_irqsave(&wiinst->lock, flags); | |
91 | } | |
92 | } | |
93 | ||
94 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
95 | ||
96 | while (count > 0) { | |
97 | u32 bytestocopy; | |
98 | ||
99 | spin_lock_irqsave(&wiinst->lock, flags); | |
100 | ||
101 | if (!(wiinst->state & WAVE_STATE_STARTED) | |
102 | && (wave_dev->enablebits & PCM_ENABLE_INPUT)) | |
103 | emu10k1_wavein_start(wave_dev); | |
104 | ||
105 | emu10k1_wavein_update(wave_dev->card, wiinst); | |
106 | emu10k1_wavein_getxfersize(wiinst, &bytestocopy); | |
107 | ||
108 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
109 | ||
110 | DPD(3, "bytestocopy --> %d\n", bytestocopy); | |
111 | ||
112 | if ((bytestocopy >= wiinst->buffer.fragment_size) | |
113 | || (bytestocopy >= count)) { | |
114 | bytestocopy = min_t(u32, bytestocopy, count); | |
115 | ||
116 | emu10k1_wavein_xferdata(wiinst, (u8 __user *)buffer, &bytestocopy); | |
117 | ||
118 | count -= bytestocopy; | |
119 | buffer += bytestocopy; | |
120 | ret += bytestocopy; | |
121 | } | |
122 | ||
123 | if (count > 0) { | |
124 | if ((file->f_flags & O_NONBLOCK) | |
125 | || (!(wave_dev->enablebits & PCM_ENABLE_INPUT))) | |
126 | return (ret ? ret : -EAGAIN); | |
127 | ||
128 | interruptible_sleep_on(&wiinst->wait_queue); | |
129 | ||
130 | if (signal_pending(current)) | |
131 | return (ret ? ret : -ERESTARTSYS); | |
132 | ||
133 | } | |
134 | } | |
135 | ||
136 | DPD(3, "bytes copied -> %d\n", (u32) ret); | |
137 | ||
138 | return ret; | |
139 | } | |
140 | ||
141 | static ssize_t emu10k1_audio_write(struct file *file, const char __user *buffer, size_t count, loff_t * ppos) | |
142 | { | |
143 | struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; | |
144 | struct woinst *woinst = wave_dev->woinst; | |
145 | ssize_t ret; | |
146 | unsigned long flags; | |
147 | ||
148 | DPD(3, "emu10k1_audio_write(), buffer=%p, count=%d\n", buffer, (u32) count); | |
149 | ||
150 | if (!access_ok(VERIFY_READ, buffer, count)) | |
151 | return -EFAULT; | |
152 | ||
153 | spin_lock_irqsave(&woinst->lock, flags); | |
154 | ||
155 | if (woinst->mmapped) { | |
156 | spin_unlock_irqrestore(&woinst->lock, flags); | |
157 | return -ENXIO; | |
158 | } | |
159 | // This is for emu10k1 revs less than 7, we need to go through tram | |
160 | if (woinst->format.passthrough == 1) { | |
161 | int r; | |
162 | ||
163 | woinst->buffer.ossfragshift = PT_BLOCKSIZE_LOG2; | |
164 | woinst->buffer.numfrags = PT_BLOCKCOUNT; | |
165 | calculate_ofrag(woinst); | |
166 | ||
167 | r = emu10k1_pt_write(file, buffer, count); | |
168 | spin_unlock_irqrestore(&woinst->lock, flags); | |
169 | return r; | |
170 | } | |
171 | ||
172 | if (woinst->state == WAVE_STATE_CLOSED) { | |
173 | calculate_ofrag(woinst); | |
174 | ||
175 | while (emu10k1_waveout_open(wave_dev) < 0) { | |
176 | spin_unlock_irqrestore(&woinst->lock, flags); | |
177 | ||
178 | if (file->f_flags & O_NONBLOCK) | |
179 | return -EAGAIN; | |
180 | ||
181 | interruptible_sleep_on(&wave_dev->card->open_wait); | |
182 | ||
183 | if (signal_pending(current)) | |
184 | return -ERESTARTSYS; | |
185 | ||
186 | spin_lock_irqsave(&woinst->lock, flags); | |
187 | } | |
188 | } | |
189 | ||
190 | spin_unlock_irqrestore(&woinst->lock, flags); | |
191 | ||
192 | ret = 0; | |
193 | if (count % woinst->format.bytespersample) | |
194 | return -EINVAL; | |
195 | ||
196 | count /= woinst->num_voices; | |
197 | ||
198 | while (count > 0) { | |
199 | u32 bytestocopy; | |
200 | ||
201 | spin_lock_irqsave(&woinst->lock, flags); | |
202 | emu10k1_waveout_update(woinst); | |
203 | emu10k1_waveout_getxfersize(woinst, &bytestocopy); | |
204 | spin_unlock_irqrestore(&woinst->lock, flags); | |
205 | ||
206 | DPD(3, "bytestocopy --> %d\n", bytestocopy); | |
207 | ||
208 | if ((bytestocopy >= woinst->buffer.fragment_size) | |
209 | || (bytestocopy >= count)) { | |
210 | ||
211 | bytestocopy = min_t(u32, bytestocopy, count); | |
212 | ||
213 | emu10k1_waveout_xferdata(woinst, (u8 __user *) buffer, &bytestocopy); | |
214 | ||
215 | count -= bytestocopy; | |
216 | buffer += bytestocopy * woinst->num_voices; | |
217 | ret += bytestocopy * woinst->num_voices; | |
218 | ||
219 | spin_lock_irqsave(&woinst->lock, flags); | |
220 | woinst->total_copied += bytestocopy; | |
221 | ||
222 | if (!(woinst->state & WAVE_STATE_STARTED) | |
223 | && (wave_dev->enablebits & PCM_ENABLE_OUTPUT) | |
224 | && (woinst->total_copied >= woinst->buffer.fragment_size)) | |
225 | emu10k1_waveout_start(wave_dev); | |
226 | ||
227 | spin_unlock_irqrestore(&woinst->lock, flags); | |
228 | } | |
229 | ||
230 | if (count > 0) { | |
231 | if ((file->f_flags & O_NONBLOCK) | |
232 | || (!(wave_dev->enablebits & PCM_ENABLE_OUTPUT))) | |
233 | return (ret ? ret : -EAGAIN); | |
234 | ||
235 | interruptible_sleep_on(&woinst->wait_queue); | |
236 | ||
237 | if (signal_pending(current)) | |
238 | return (ret ? ret : -ERESTARTSYS); | |
239 | } | |
240 | } | |
241 | ||
242 | DPD(3, "bytes copied -> %d\n", (u32) ret); | |
243 | ||
244 | return ret; | |
245 | } | |
246 | ||
247 | static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | |
248 | { | |
249 | struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; | |
250 | struct woinst *woinst = NULL; | |
251 | struct wiinst *wiinst = NULL; | |
252 | int val = 0; | |
253 | u32 bytestocopy; | |
254 | unsigned long flags; | |
255 | int __user *p = (int __user *)arg; | |
256 | ||
257 | DPF(4, "emu10k1_audio_ioctl()\n"); | |
258 | ||
259 | if (file->f_mode & FMODE_WRITE) | |
260 | woinst = wave_dev->woinst; | |
261 | ||
262 | if (file->f_mode & FMODE_READ) | |
263 | wiinst = wave_dev->wiinst; | |
264 | ||
265 | switch (cmd) { | |
266 | case OSS_GETVERSION: | |
267 | DPF(2, "OSS_GETVERSION:\n"); | |
268 | return put_user(SOUND_VERSION, p); | |
269 | ||
270 | case SNDCTL_DSP_RESET: | |
271 | DPF(2, "SNDCTL_DSP_RESET:\n"); | |
272 | wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT; | |
273 | ||
274 | if (file->f_mode & FMODE_WRITE) { | |
275 | spin_lock_irqsave(&woinst->lock, flags); | |
276 | ||
277 | if (woinst->state & WAVE_STATE_OPEN) { | |
278 | emu10k1_waveout_close(wave_dev); | |
279 | } | |
280 | ||
281 | woinst->mmapped = 0; | |
282 | woinst->total_copied = 0; | |
283 | woinst->total_played = 0; | |
284 | woinst->blocks = 0; | |
285 | ||
286 | spin_unlock_irqrestore(&woinst->lock, flags); | |
287 | } | |
288 | ||
289 | if (file->f_mode & FMODE_READ) { | |
290 | spin_lock_irqsave(&wiinst->lock, flags); | |
291 | ||
292 | if (wiinst->state & WAVE_STATE_OPEN) { | |
293 | emu10k1_wavein_close(wave_dev); | |
294 | } | |
295 | ||
296 | wiinst->mmapped = 0; | |
297 | wiinst->total_recorded = 0; | |
298 | wiinst->blocks = 0; | |
299 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
300 | } | |
301 | ||
302 | break; | |
303 | ||
304 | case SNDCTL_DSP_SYNC: | |
305 | DPF(2, "SNDCTL_DSP_SYNC:\n"); | |
306 | ||
307 | if (file->f_mode & FMODE_WRITE) { | |
308 | ||
309 | spin_lock_irqsave(&woinst->lock, flags); | |
310 | ||
311 | if (woinst->state & WAVE_STATE_OPEN) { | |
312 | ||
313 | if (woinst->state & WAVE_STATE_STARTED) | |
314 | while ((woinst->total_played < woinst->total_copied) | |
315 | && !signal_pending(current)) { | |
316 | spin_unlock_irqrestore(&woinst->lock, flags); | |
317 | interruptible_sleep_on(&woinst->wait_queue); | |
318 | spin_lock_irqsave(&woinst->lock, flags); | |
319 | } | |
320 | emu10k1_waveout_close(wave_dev); | |
321 | } | |
322 | ||
323 | woinst->mmapped = 0; | |
324 | woinst->total_copied = 0; | |
325 | woinst->total_played = 0; | |
326 | woinst->blocks = 0; | |
327 | ||
328 | spin_unlock_irqrestore(&woinst->lock, flags); | |
329 | } | |
330 | ||
331 | if (file->f_mode & FMODE_READ) { | |
332 | spin_lock_irqsave(&wiinst->lock, flags); | |
333 | ||
334 | if (wiinst->state & WAVE_STATE_OPEN) { | |
335 | emu10k1_wavein_close(wave_dev); | |
336 | } | |
337 | ||
338 | wiinst->mmapped = 0; | |
339 | wiinst->total_recorded = 0; | |
340 | wiinst->blocks = 0; | |
341 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
342 | } | |
343 | ||
344 | break; | |
345 | ||
346 | case SNDCTL_DSP_SETDUPLEX: | |
347 | DPF(2, "SNDCTL_DSP_SETDUPLEX:\n"); | |
348 | break; | |
349 | ||
350 | case SNDCTL_DSP_GETCAPS: | |
351 | DPF(2, "SNDCTL_DSP_GETCAPS:\n"); | |
352 | return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | | |
353 | DSP_CAP_TRIGGER | DSP_CAP_MMAP | | |
354 | DSP_CAP_COPROC| DSP_CAP_MULTI, p); | |
355 | case SNDCTL_DSP_SPEED: | |
356 | DPF(2, "SNDCTL_DSP_SPEED:\n"); | |
357 | ||
358 | if (get_user(val, p)) | |
359 | return -EFAULT; | |
360 | ||
361 | DPD(2, "val is %d\n", val); | |
362 | ||
363 | if (val > 0) { | |
364 | if (file->f_mode & FMODE_READ) { | |
365 | struct wave_format format; | |
366 | ||
367 | spin_lock_irqsave(&wiinst->lock, flags); | |
368 | ||
369 | format = wiinst->format; | |
370 | format.samplingrate = val; | |
371 | ||
372 | if (emu10k1_wavein_setformat(wave_dev, &format) < 0) { | |
373 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
374 | return -EINVAL; | |
375 | } | |
376 | ||
377 | val = wiinst->format.samplingrate; | |
378 | ||
379 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
380 | ||
381 | DPD(2, "set recording sampling rate -> %d\n", val); | |
382 | } | |
383 | ||
384 | if (file->f_mode & FMODE_WRITE) { | |
385 | struct wave_format format; | |
386 | ||
387 | spin_lock_irqsave(&woinst->lock, flags); | |
388 | ||
389 | format = woinst->format; | |
390 | format.samplingrate = val; | |
391 | ||
392 | if (emu10k1_waveout_setformat(wave_dev, &format) < 0) { | |
393 | spin_unlock_irqrestore(&woinst->lock, flags); | |
394 | return -EINVAL; | |
395 | } | |
396 | ||
397 | val = woinst->format.samplingrate; | |
398 | ||
399 | spin_unlock_irqrestore(&woinst->lock, flags); | |
400 | ||
401 | DPD(2, "set playback sampling rate -> %d\n", val); | |
402 | } | |
403 | ||
404 | return put_user(val, p); | |
405 | } else { | |
406 | if (file->f_mode & FMODE_READ) | |
407 | val = wiinst->format.samplingrate; | |
408 | else if (file->f_mode & FMODE_WRITE) | |
409 | val = woinst->format.samplingrate; | |
410 | ||
411 | return put_user(val, p); | |
412 | } | |
413 | break; | |
414 | ||
415 | case SNDCTL_DSP_STEREO: | |
416 | DPF(2, "SNDCTL_DSP_STEREO:\n"); | |
417 | ||
418 | if (get_user(val, p)) | |
419 | return -EFAULT; | |
420 | ||
421 | DPD(2, " val is %d\n", val); | |
422 | ||
423 | if (file->f_mode & FMODE_READ) { | |
424 | struct wave_format format; | |
425 | ||
426 | spin_lock_irqsave(&wiinst->lock, flags); | |
427 | ||
428 | format = wiinst->format; | |
429 | format.channels = val ? 2 : 1; | |
430 | ||
431 | if (emu10k1_wavein_setformat(wave_dev, &format) < 0) { | |
432 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
433 | return -EINVAL; | |
434 | } | |
435 | ||
436 | val = wiinst->format.channels - 1; | |
437 | ||
438 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
439 | DPD(2, "set recording stereo -> %d\n", val); | |
440 | } | |
441 | ||
442 | if (file->f_mode & FMODE_WRITE) { | |
443 | struct wave_format format; | |
444 | ||
445 | spin_lock_irqsave(&woinst->lock, flags); | |
446 | ||
447 | format = woinst->format; | |
448 | format.channels = val ? 2 : 1; | |
449 | ||
450 | if (emu10k1_waveout_setformat(wave_dev, &format) < 0) { | |
451 | spin_unlock_irqrestore(&woinst->lock, flags); | |
452 | return -EINVAL; | |
453 | } | |
454 | ||
455 | val = woinst->format.channels - 1; | |
456 | ||
457 | spin_unlock_irqrestore(&woinst->lock, flags); | |
458 | ||
459 | DPD(2, "set playback stereo -> %d\n", val); | |
460 | } | |
461 | ||
462 | return put_user(val, p); | |
463 | ||
464 | break; | |
465 | ||
466 | case SNDCTL_DSP_CHANNELS: | |
467 | DPF(2, "SNDCTL_DSP_CHANNELS:\n"); | |
468 | ||
469 | if (get_user(val, p)) | |
470 | return -EFAULT; | |
471 | ||
472 | DPD(2, " val is %d\n", val); | |
473 | ||
474 | if (val > 0) { | |
475 | if (file->f_mode & FMODE_READ) { | |
476 | struct wave_format format; | |
477 | ||
478 | spin_lock_irqsave(&wiinst->lock, flags); | |
479 | ||
480 | format = wiinst->format; | |
481 | format.channels = val; | |
482 | ||
483 | if (emu10k1_wavein_setformat(wave_dev, &format) < 0) { | |
484 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
485 | return -EINVAL; | |
486 | } | |
487 | val = wiinst->format.channels; | |
488 | ||
489 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
490 | DPD(2, "set recording number of channels -> %d\n", val); | |
491 | } | |
492 | ||
493 | if (file->f_mode & FMODE_WRITE) { | |
494 | struct wave_format format; | |
495 | ||
496 | spin_lock_irqsave(&woinst->lock, flags); | |
497 | ||
498 | format = woinst->format; | |
499 | format.channels = val; | |
500 | ||
501 | if (emu10k1_waveout_setformat(wave_dev, &format) < 0) { | |
502 | spin_unlock_irqrestore(&woinst->lock, flags); | |
503 | return -EINVAL; | |
504 | } | |
505 | ||
506 | val = woinst->format.channels; | |
507 | ||
508 | spin_unlock_irqrestore(&woinst->lock, flags); | |
509 | DPD(2, "set playback number of channels -> %d\n", val); | |
510 | } | |
511 | ||
512 | return put_user(val, p); | |
513 | } else { | |
514 | if (file->f_mode & FMODE_READ) | |
515 | val = wiinst->format.channels; | |
516 | else if (file->f_mode & FMODE_WRITE) | |
517 | val = woinst->format.channels; | |
518 | ||
519 | return put_user(val, p); | |
520 | } | |
521 | break; | |
522 | ||
523 | case SNDCTL_DSP_GETFMTS: | |
524 | DPF(2, "SNDCTL_DSP_GETFMTS:\n"); | |
525 | ||
526 | if (file->f_mode & FMODE_READ) | |
527 | val = AFMT_S16_LE; | |
528 | else if (file->f_mode & FMODE_WRITE) { | |
529 | val = AFMT_S16_LE | AFMT_U8; | |
530 | if (emu10k1_find_control_gpr(&wave_dev->card->mgr, | |
531 | wave_dev->card->pt.patch_name, | |
532 | wave_dev->card->pt.enable_gpr_name) >= 0) | |
533 | val |= AFMT_AC3; | |
534 | } | |
535 | return put_user(val, p); | |
536 | ||
537 | case SNDCTL_DSP_SETFMT: /* Same as SNDCTL_DSP_SAMPLESIZE */ | |
538 | DPF(2, "SNDCTL_DSP_SETFMT:\n"); | |
539 | ||
540 | if (get_user(val, p)) | |
541 | return -EFAULT; | |
542 | ||
543 | DPD(2, " val is %d\n", val); | |
544 | ||
545 | if (val != AFMT_QUERY) { | |
546 | if (file->f_mode & FMODE_READ) { | |
547 | struct wave_format format; | |
548 | ||
549 | spin_lock_irqsave(&wiinst->lock, flags); | |
550 | ||
551 | format = wiinst->format; | |
552 | format.id = val; | |
553 | ||
554 | if (emu10k1_wavein_setformat(wave_dev, &format) < 0) { | |
555 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
556 | return -EINVAL; | |
557 | } | |
558 | ||
559 | val = wiinst->format.id; | |
560 | ||
561 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
562 | DPD(2, "set recording format -> %d\n", val); | |
563 | } | |
564 | ||
565 | if (file->f_mode & FMODE_WRITE) { | |
566 | struct wave_format format; | |
567 | ||
568 | spin_lock_irqsave(&woinst->lock, flags); | |
569 | ||
570 | format = woinst->format; | |
571 | format.id = val; | |
572 | ||
573 | if (emu10k1_waveout_setformat(wave_dev, &format) < 0) { | |
574 | spin_unlock_irqrestore(&woinst->lock, flags); | |
575 | return -EINVAL; | |
576 | } | |
577 | ||
578 | val = woinst->format.id; | |
579 | ||
580 | spin_unlock_irqrestore(&woinst->lock, flags); | |
581 | DPD(2, "set playback format -> %d\n", val); | |
582 | } | |
583 | ||
584 | return put_user(val, p); | |
585 | } else { | |
586 | if (file->f_mode & FMODE_READ) | |
587 | val = wiinst->format.id; | |
588 | else if (file->f_mode & FMODE_WRITE) | |
589 | val = woinst->format.id; | |
590 | ||
591 | return put_user(val, p); | |
592 | } | |
593 | break; | |
594 | ||
595 | case SOUND_PCM_READ_BITS: | |
596 | ||
597 | if (file->f_mode & FMODE_READ) | |
598 | val = wiinst->format.bitsperchannel; | |
599 | else if (file->f_mode & FMODE_WRITE) | |
600 | val = woinst->format.bitsperchannel; | |
601 | ||
602 | return put_user(val, p); | |
603 | ||
604 | case SOUND_PCM_READ_RATE: | |
605 | ||
606 | if (file->f_mode & FMODE_READ) | |
607 | val = wiinst->format.samplingrate; | |
608 | else if (file->f_mode & FMODE_WRITE) | |
609 | val = woinst->format.samplingrate; | |
610 | ||
611 | return put_user(val, p); | |
612 | ||
613 | case SOUND_PCM_READ_CHANNELS: | |
614 | ||
615 | if (file->f_mode & FMODE_READ) | |
616 | val = wiinst->format.channels; | |
617 | else if (file->f_mode & FMODE_WRITE) | |
618 | val = woinst->format.channels; | |
619 | ||
620 | return put_user(val, p); | |
621 | ||
622 | case SOUND_PCM_WRITE_FILTER: | |
623 | DPF(2, "SOUND_PCM_WRITE_FILTER: not implemented\n"); | |
624 | break; | |
625 | ||
626 | case SOUND_PCM_READ_FILTER: | |
627 | DPF(2, "SOUND_PCM_READ_FILTER: not implemented\n"); | |
628 | break; | |
629 | ||
630 | case SNDCTL_DSP_SETSYNCRO: | |
631 | DPF(2, "SNDCTL_DSP_SETSYNCRO: not implemented\n"); | |
632 | break; | |
633 | ||
634 | case SNDCTL_DSP_GETTRIGGER: | |
635 | DPF(2, "SNDCTL_DSP_GETTRIGGER:\n"); | |
636 | ||
637 | if (file->f_mode & FMODE_WRITE && (wave_dev->enablebits & PCM_ENABLE_OUTPUT)) | |
638 | val |= PCM_ENABLE_OUTPUT; | |
639 | ||
640 | if (file->f_mode & FMODE_READ && (wave_dev->enablebits & PCM_ENABLE_INPUT)) | |
641 | val |= PCM_ENABLE_INPUT; | |
642 | ||
643 | return put_user(val, p); | |
644 | ||
645 | case SNDCTL_DSP_SETTRIGGER: | |
646 | DPF(2, "SNDCTL_DSP_SETTRIGGER:\n"); | |
647 | ||
648 | if (get_user(val, p)) | |
649 | return -EFAULT; | |
650 | ||
651 | if (file->f_mode & FMODE_WRITE) { | |
652 | spin_lock_irqsave(&woinst->lock, flags); | |
653 | ||
654 | if (val & PCM_ENABLE_OUTPUT) { | |
655 | wave_dev->enablebits |= PCM_ENABLE_OUTPUT; | |
656 | if (woinst->state & WAVE_STATE_OPEN) | |
657 | emu10k1_waveout_start(wave_dev); | |
658 | } else { | |
659 | wave_dev->enablebits &= ~PCM_ENABLE_OUTPUT; | |
660 | if (woinst->state & WAVE_STATE_STARTED) | |
661 | emu10k1_waveout_stop(wave_dev); | |
662 | } | |
663 | ||
664 | spin_unlock_irqrestore(&woinst->lock, flags); | |
665 | } | |
666 | ||
667 | if (file->f_mode & FMODE_READ) { | |
668 | spin_lock_irqsave(&wiinst->lock, flags); | |
669 | ||
670 | if (val & PCM_ENABLE_INPUT) { | |
671 | wave_dev->enablebits |= PCM_ENABLE_INPUT; | |
672 | if (wiinst->state & WAVE_STATE_OPEN) | |
673 | emu10k1_wavein_start(wave_dev); | |
674 | } else { | |
675 | wave_dev->enablebits &= ~PCM_ENABLE_INPUT; | |
676 | if (wiinst->state & WAVE_STATE_STARTED) | |
677 | emu10k1_wavein_stop(wave_dev); | |
678 | } | |
679 | ||
680 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
681 | } | |
682 | break; | |
683 | ||
684 | case SNDCTL_DSP_GETOSPACE: | |
685 | { | |
686 | audio_buf_info info; | |
687 | ||
688 | DPF(4, "SNDCTL_DSP_GETOSPACE:\n"); | |
689 | ||
690 | if (!(file->f_mode & FMODE_WRITE)) | |
691 | return -EINVAL; | |
692 | ||
693 | spin_lock_irqsave(&woinst->lock, flags); | |
694 | ||
695 | if (woinst->state & WAVE_STATE_OPEN) { | |
696 | emu10k1_waveout_update(woinst); | |
697 | emu10k1_waveout_getxfersize(woinst, &bytestocopy); | |
698 | info.bytes = bytestocopy; | |
699 | } else { | |
700 | calculate_ofrag(woinst); | |
701 | info.bytes = woinst->buffer.size; | |
702 | } | |
703 | spin_unlock_irqrestore(&woinst->lock, flags); | |
704 | ||
705 | info.bytes *= woinst->num_voices; | |
706 | info.fragsize = woinst->buffer.fragment_size * woinst->num_voices; | |
707 | info.fragstotal = woinst->buffer.numfrags * woinst->num_voices; | |
708 | info.fragments = info.bytes / info.fragsize; | |
709 | ||
710 | if (copy_to_user(p, &info, sizeof(info))) | |
711 | return -EFAULT; | |
712 | } | |
713 | break; | |
714 | ||
715 | case SNDCTL_DSP_GETISPACE: | |
716 | { | |
717 | audio_buf_info info; | |
718 | ||
719 | DPF(4, "SNDCTL_DSP_GETISPACE:\n"); | |
720 | ||
721 | if (!(file->f_mode & FMODE_READ)) | |
722 | return -EINVAL; | |
723 | ||
724 | spin_lock_irqsave(&wiinst->lock, flags); | |
725 | if (wiinst->state & WAVE_STATE_OPEN) { | |
726 | emu10k1_wavein_update(wave_dev->card, wiinst); | |
727 | emu10k1_wavein_getxfersize(wiinst, &bytestocopy); | |
728 | info.bytes = bytestocopy; | |
729 | } else { | |
730 | calculate_ifrag(wiinst); | |
731 | info.bytes = 0; | |
732 | } | |
733 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
734 | ||
735 | info.fragstotal = wiinst->buffer.numfrags; | |
736 | info.fragments = info.bytes / wiinst->buffer.fragment_size; | |
737 | info.fragsize = wiinst->buffer.fragment_size; | |
738 | ||
739 | if (copy_to_user(p, &info, sizeof(info))) | |
740 | return -EFAULT; | |
741 | } | |
742 | break; | |
743 | ||
744 | case SNDCTL_DSP_NONBLOCK: | |
745 | DPF(2, "SNDCTL_DSP_NONBLOCK:\n"); | |
746 | ||
747 | file->f_flags |= O_NONBLOCK; | |
748 | break; | |
749 | ||
750 | case SNDCTL_DSP_GETODELAY: | |
751 | DPF(4, "SNDCTL_DSP_GETODELAY:\n"); | |
752 | ||
753 | if (!(file->f_mode & FMODE_WRITE)) | |
754 | return -EINVAL; | |
755 | ||
756 | spin_lock_irqsave(&woinst->lock, flags); | |
757 | if (woinst->state & WAVE_STATE_OPEN) { | |
758 | emu10k1_waveout_update(woinst); | |
759 | emu10k1_waveout_getxfersize(woinst, &bytestocopy); | |
760 | val = woinst->buffer.size - bytestocopy; | |
761 | } else | |
762 | val = 0; | |
763 | ||
764 | val *= woinst->num_voices; | |
765 | spin_unlock_irqrestore(&woinst->lock, flags); | |
766 | ||
767 | return put_user(val, p); | |
768 | ||
769 | case SNDCTL_DSP_GETIPTR: | |
770 | { | |
771 | count_info cinfo; | |
772 | ||
773 | DPF(4, "SNDCTL_DSP_GETIPTR: \n"); | |
774 | ||
775 | if (!(file->f_mode & FMODE_READ)) | |
776 | return -EINVAL; | |
777 | ||
778 | spin_lock_irqsave(&wiinst->lock, flags); | |
779 | ||
780 | if (wiinst->state & WAVE_STATE_OPEN) { | |
781 | emu10k1_wavein_update(wave_dev->card, wiinst); | |
782 | cinfo.ptr = wiinst->buffer.hw_pos; | |
783 | cinfo.bytes = cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % wiinst->buffer.size; | |
784 | cinfo.blocks = cinfo.bytes / wiinst->buffer.fragment_size - wiinst->blocks; | |
785 | wiinst->blocks = cinfo.bytes / wiinst->buffer.fragment_size; | |
786 | } else { | |
787 | cinfo.ptr = 0; | |
788 | cinfo.bytes = 0; | |
789 | cinfo.blocks = 0; | |
790 | } | |
791 | ||
792 | if (wiinst->mmapped) | |
793 | wiinst->buffer.bytestocopy %= wiinst->buffer.fragment_size; | |
794 | ||
795 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
796 | ||
797 | if (copy_to_user(p, &cinfo, sizeof(cinfo))) | |
798 | return -EFAULT; | |
799 | } | |
800 | break; | |
801 | ||
802 | case SNDCTL_DSP_GETOPTR: | |
803 | { | |
804 | count_info cinfo; | |
805 | ||
806 | DPF(4, "SNDCTL_DSP_GETOPTR:\n"); | |
807 | ||
808 | if (!(file->f_mode & FMODE_WRITE)) | |
809 | return -EINVAL; | |
810 | ||
811 | spin_lock_irqsave(&woinst->lock, flags); | |
812 | ||
813 | if (woinst->state & WAVE_STATE_OPEN || | |
814 | ((woinst->format.passthrough == 1) && wave_dev->card->pt.state)) { | |
815 | int num_fragments; | |
816 | ||
817 | if (woinst->format.passthrough == 1) { | |
818 | emu10k1_pt_waveout_update(wave_dev); | |
819 | cinfo.bytes = woinst->total_played; | |
820 | } else { | |
821 | emu10k1_waveout_update(woinst); | |
822 | cinfo.bytes = woinst->total_played; | |
823 | } | |
824 | ||
825 | cinfo.ptr = woinst->buffer.hw_pos; | |
826 | num_fragments = cinfo.bytes / woinst->buffer.fragment_size; | |
827 | cinfo.blocks = num_fragments - woinst->blocks; | |
828 | woinst->blocks = num_fragments; | |
829 | ||
830 | cinfo.bytes *= woinst->num_voices; | |
831 | cinfo.ptr *= woinst->num_voices; | |
832 | } else { | |
833 | cinfo.ptr = 0; | |
834 | cinfo.bytes = 0; | |
835 | cinfo.blocks = 0; | |
836 | } | |
837 | ||
838 | if (woinst->mmapped) | |
839 | woinst->buffer.free_bytes %= woinst->buffer.fragment_size; | |
840 | ||
841 | spin_unlock_irqrestore(&woinst->lock, flags); | |
842 | ||
843 | if (copy_to_user(p, &cinfo, sizeof(cinfo))) | |
844 | return -EFAULT; | |
845 | } | |
846 | break; | |
847 | ||
848 | case SNDCTL_DSP_GETBLKSIZE: | |
849 | DPF(2, "SNDCTL_DSP_GETBLKSIZE:\n"); | |
850 | ||
851 | if (file->f_mode & FMODE_WRITE) { | |
852 | spin_lock_irqsave(&woinst->lock, flags); | |
853 | ||
854 | calculate_ofrag(woinst); | |
855 | val = woinst->buffer.fragment_size * woinst->num_voices; | |
856 | ||
857 | spin_unlock_irqrestore(&woinst->lock, flags); | |
858 | } | |
859 | ||
860 | if (file->f_mode & FMODE_READ) { | |
861 | spin_lock_irqsave(&wiinst->lock, flags); | |
862 | ||
863 | calculate_ifrag(wiinst); | |
864 | val = wiinst->buffer.fragment_size; | |
865 | ||
866 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
867 | } | |
868 | ||
869 | return put_user(val, p); | |
870 | ||
871 | break; | |
872 | ||
873 | case SNDCTL_DSP_POST: | |
874 | if (file->f_mode & FMODE_WRITE) { | |
875 | spin_lock_irqsave(&woinst->lock, flags); | |
876 | ||
877 | if (!(woinst->state & WAVE_STATE_STARTED) | |
878 | && (wave_dev->enablebits & PCM_ENABLE_OUTPUT) | |
879 | && (woinst->total_copied > 0)) | |
880 | emu10k1_waveout_start(wave_dev); | |
881 | ||
882 | spin_unlock_irqrestore(&woinst->lock, flags); | |
883 | } | |
884 | ||
885 | break; | |
886 | ||
887 | case SNDCTL_DSP_SUBDIVIDE: | |
888 | DPF(2, "SNDCTL_DSP_SUBDIVIDE: not implemented\n"); | |
889 | break; | |
890 | ||
891 | case SNDCTL_DSP_SETFRAGMENT: | |
892 | DPF(2, "SNDCTL_DSP_SETFRAGMENT:\n"); | |
893 | ||
894 | if (get_user(val, p)) | |
895 | return -EFAULT; | |
896 | ||
897 | DPD(2, "val is %#x\n", val); | |
898 | ||
899 | if (val == 0) | |
900 | return -EIO; | |
901 | ||
902 | if (file->f_mode & FMODE_WRITE) { | |
903 | /* digital pass-through fragment count and size are fixed values */ | |
904 | if (woinst->state & WAVE_STATE_OPEN || (woinst->format.passthrough == 1)) | |
905 | return -EINVAL; /* too late to change */ | |
906 | ||
907 | woinst->buffer.ossfragshift = val & 0xffff; | |
908 | woinst->buffer.numfrags = (val >> 16) & 0xffff; | |
909 | } | |
910 | ||
911 | if (file->f_mode & FMODE_READ) { | |
912 | if (wiinst->state & WAVE_STATE_OPEN) | |
913 | return -EINVAL; /* too late to change */ | |
914 | ||
915 | wiinst->buffer.ossfragshift = val & 0xffff; | |
916 | wiinst->buffer.numfrags = (val >> 16) & 0xffff; | |
917 | } | |
918 | ||
919 | break; | |
920 | ||
921 | case SNDCTL_COPR_LOAD: | |
922 | { | |
923 | copr_buffer *buf; | |
924 | u32 i; | |
925 | ||
926 | DPF(4, "SNDCTL_COPR_LOAD:\n"); | |
927 | ||
928 | buf = kmalloc(sizeof(copr_buffer), GFP_KERNEL); | |
929 | if (!buf) | |
930 | return -ENOMEM; | |
931 | ||
932 | if (copy_from_user(buf, p, sizeof(copr_buffer))) { | |
933 | kfree (buf); | |
934 | return -EFAULT; | |
935 | } | |
936 | ||
937 | if ((buf->command != CMD_READ) && (buf->command != CMD_WRITE)) { | |
938 | kfree (buf); | |
939 | return -EINVAL; | |
940 | } | |
941 | ||
942 | if (buf->command == CMD_WRITE) { | |
943 | ||
944 | #ifdef DBGEMU | |
945 | if ((buf->offs < 0) || (buf->offs + buf->len > 0xe00) || (buf->len > 1000)) { | |
946 | #else | |
947 | if (((buf->offs < 0x100) || (buf->offs + buf->len > (wave_dev->card->is_audigy ? 0xe00 : 0x800)) || (buf->len > 1000) | |
948 | ) && !( | |
949 | //any register allowed raw access to users goes here: | |
950 | (buf->offs == DBG || | |
951 | buf->offs == A_DBG) | |
952 | && (buf->len == 1))) { | |
953 | #endif | |
954 | kfree(buf); | |
955 | return -EINVAL; | |
956 | } | |
957 | } else { | |
958 | if ((buf->offs < 0) || (buf->offs + buf->len > 0xe00) || (buf->len > 1000)) { | |
959 | kfree(buf); | |
960 | return -EINVAL; | |
961 | } | |
962 | } | |
963 | ||
964 | if (((unsigned)buf->flags) > 0x3f) | |
965 | buf->flags = 0; | |
966 | ||
967 | if (buf->command == CMD_READ) { | |
968 | for (i = 0; i < buf->len; i++) | |
969 | ((u32 *) buf->data)[i] = sblive_readptr(wave_dev->card, buf->offs + i, buf->flags); | |
970 | ||
971 | if (copy_to_user(p, buf, sizeof(copr_buffer))) { | |
972 | kfree(buf); | |
973 | return -EFAULT; | |
974 | } | |
975 | } else { | |
976 | for (i = 0; i < buf->len; i++) | |
977 | sblive_writeptr(wave_dev->card, buf->offs + i, buf->flags, ((u32 *) buf->data)[i]); | |
978 | } | |
979 | ||
980 | kfree (buf); | |
981 | break; | |
982 | } | |
983 | ||
984 | default: /* Default is unrecognized command */ | |
985 | DPD(2, "default: %#x\n", cmd); | |
986 | return -EINVAL; | |
987 | } | |
988 | return 0; | |
989 | } | |
990 | ||
991 | static struct page *emu10k1_mm_nopage (struct vm_area_struct * vma, unsigned long address, int *type) | |
992 | { | |
993 | struct emu10k1_wavedevice *wave_dev = vma->vm_private_data; | |
994 | struct woinst *woinst = wave_dev->woinst; | |
995 | struct wiinst *wiinst = wave_dev->wiinst; | |
996 | struct page *dmapage; | |
997 | unsigned long pgoff; | |
998 | int rd, wr; | |
999 | ||
1000 | DPF(3, "emu10k1_mm_nopage()\n"); | |
1001 | DPD(3, "addr: %#lx\n", address); | |
1002 | ||
1003 | if (address > vma->vm_end) { | |
1004 | DPF(1, "EXIT, returning NOPAGE_SIGBUS\n"); | |
1005 | return NOPAGE_SIGBUS; /* Disallow mremap */ | |
1006 | } | |
1007 | ||
1008 | pgoff = vma->vm_pgoff + ((address - vma->vm_start) >> PAGE_SHIFT); | |
1009 | if (woinst != NULL) | |
1010 | wr = woinst->mmapped; | |
1011 | else | |
1012 | wr = 0; | |
1013 | ||
1014 | if (wiinst != NULL) | |
1015 | rd = wiinst->mmapped; | |
1016 | else | |
1017 | rd = 0; | |
1018 | ||
1019 | /* if full-duplex (read+write) and we have two sets of bufs, | |
1020 | * then the playback buffers come first, sez soundcard.c */ | |
1021 | if (wr) { | |
1022 | if (pgoff >= woinst->buffer.pages) { | |
1023 | pgoff -= woinst->buffer.pages; | |
1024 | dmapage = virt_to_page ((u8 *) wiinst->buffer.addr + pgoff * PAGE_SIZE); | |
1025 | } else | |
1026 | dmapage = virt_to_page (woinst->voice[0].mem.addr[pgoff]); | |
1027 | } else { | |
1028 | dmapage = virt_to_page ((u8 *) wiinst->buffer.addr + pgoff * PAGE_SIZE); | |
1029 | } | |
1030 | ||
1031 | get_page (dmapage); | |
1032 | ||
1033 | DPD(3, "page: %#lx\n", (unsigned long) dmapage); | |
1034 | if (type) | |
1035 | *type = VM_FAULT_MINOR; | |
1036 | return dmapage; | |
1037 | } | |
1038 | ||
1039 | static struct vm_operations_struct emu10k1_mm_ops = { | |
1040 | .nopage = emu10k1_mm_nopage, | |
1041 | }; | |
1042 | ||
1043 | static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma) | |
1044 | { | |
1045 | struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; | |
1046 | unsigned long max_pages, n_pages, pgoffset; | |
1047 | struct woinst *woinst = NULL; | |
1048 | struct wiinst *wiinst = NULL; | |
1049 | unsigned long flags; | |
1050 | ||
1051 | DPF(2, "emu10k1_audio_mmap()\n"); | |
1052 | ||
1053 | max_pages = 0; | |
1054 | if (vma->vm_flags & VM_WRITE) { | |
1055 | woinst = wave_dev->woinst; | |
1056 | ||
1057 | spin_lock_irqsave(&woinst->lock, flags); | |
1058 | ||
1059 | /* No m'mapping possible for multichannel */ | |
1060 | if (woinst->num_voices > 1) { | |
1061 | spin_unlock_irqrestore(&woinst->lock, flags); | |
1062 | return -EINVAL; | |
1063 | } | |
1064 | ||
1065 | if (woinst->state == WAVE_STATE_CLOSED) { | |
1066 | calculate_ofrag(woinst); | |
1067 | ||
1068 | if (emu10k1_waveout_open(wave_dev) < 0) { | |
1069 | spin_unlock_irqrestore(&woinst->lock, flags); | |
1070 | ERROR(); | |
1071 | return -EINVAL; | |
1072 | } | |
1073 | } | |
1074 | ||
1075 | woinst->mmapped = 1; | |
1076 | max_pages += woinst->buffer.pages; | |
1077 | spin_unlock_irqrestore(&woinst->lock, flags); | |
1078 | } | |
1079 | ||
1080 | if (vma->vm_flags & VM_READ) { | |
1081 | wiinst = wave_dev->wiinst; | |
1082 | ||
1083 | spin_lock_irqsave(&wiinst->lock, flags); | |
1084 | if (wiinst->state == WAVE_STATE_CLOSED) { | |
1085 | calculate_ifrag(wiinst); | |
1086 | ||
1087 | if (emu10k1_wavein_open(wave_dev) < 0) { | |
1088 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
1089 | ERROR(); | |
1090 | return -EINVAL; | |
1091 | } | |
1092 | } | |
1093 | ||
1094 | wiinst->mmapped = 1; | |
1095 | max_pages += wiinst->buffer.pages; | |
1096 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
1097 | } | |
1098 | ||
1099 | n_pages = ((vma->vm_end - vma->vm_start) + PAGE_SIZE - 1) >> PAGE_SHIFT; | |
1100 | pgoffset = vma->vm_pgoff; | |
1101 | ||
1102 | DPD(2, "vma_start: %#lx, vma_end: %#lx, vma_offset: %ld\n", vma->vm_start, vma->vm_end, pgoffset); | |
1103 | DPD(2, "n_pages: %ld, max_pages: %ld\n", n_pages, max_pages); | |
1104 | ||
1105 | if (pgoffset + n_pages > max_pages) | |
1106 | return -EINVAL; | |
1107 | ||
1108 | vma->vm_flags |= VM_RESERVED; | |
1109 | vma->vm_ops = &emu10k1_mm_ops; | |
1110 | vma->vm_private_data = wave_dev; | |
1111 | return 0; | |
1112 | } | |
1113 | ||
1114 | static int emu10k1_audio_open(struct inode *inode, struct file *file) | |
1115 | { | |
1116 | int minor = iminor(inode); | |
1117 | struct emu10k1_card *card = NULL; | |
1118 | struct list_head *entry; | |
1119 | struct emu10k1_wavedevice *wave_dev; | |
1120 | ||
1121 | DPF(2, "emu10k1_audio_open()\n"); | |
1122 | ||
1123 | /* Check for correct device to open */ | |
1124 | ||
1125 | list_for_each(entry, &emu10k1_devs) { | |
1126 | card = list_entry(entry, struct emu10k1_card, list); | |
1127 | ||
1128 | if (!((card->audio_dev ^ minor) & ~0xf) || !((card->audio_dev1 ^ minor) & ~0xf)) | |
1129 | goto match; | |
1130 | } | |
1131 | ||
1132 | return -ENODEV; | |
1133 | ||
1134 | match: | |
1135 | ||
1136 | wave_dev = (struct emu10k1_wavedevice *) kmalloc(sizeof(struct emu10k1_wavedevice), GFP_KERNEL); | |
1137 | ||
1138 | if (wave_dev == NULL) { | |
1139 | ERROR(); | |
1140 | return -ENOMEM; | |
1141 | } | |
1142 | ||
1143 | wave_dev->card = card; | |
1144 | wave_dev->wiinst = NULL; | |
1145 | wave_dev->woinst = NULL; | |
1146 | wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT; /* Default */ | |
1147 | ||
1148 | if (file->f_mode & FMODE_READ) { | |
1149 | /* Recording */ | |
1150 | struct wiinst *wiinst; | |
1151 | ||
1152 | if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) { | |
1153 | ERROR(); | |
1154 | kfree(wave_dev); | |
1155 | return -ENOMEM; | |
1156 | } | |
1157 | ||
1158 | wiinst->recsrc = card->wavein.recsrc; | |
1159 | wiinst->fxwc = card->wavein.fxwc; | |
1160 | ||
1161 | switch (wiinst->recsrc) { | |
1162 | case WAVERECORD_AC97: | |
1163 | wiinst->format.id = AFMT_S16_LE; | |
1164 | wiinst->format.samplingrate = 8000; | |
1165 | wiinst->format.bitsperchannel = 16; | |
1166 | wiinst->format.channels = 1; | |
1167 | break; | |
1168 | case WAVERECORD_MIC: | |
1169 | wiinst->format.id = AFMT_S16_LE; | |
1170 | wiinst->format.samplingrate = 8000; | |
1171 | wiinst->format.bitsperchannel = 16; | |
1172 | wiinst->format.channels = 1; | |
1173 | break; | |
1174 | case WAVERECORD_FX: | |
1175 | wiinst->format.id = AFMT_S16_LE; | |
1176 | wiinst->format.samplingrate = 48000; | |
1177 | wiinst->format.bitsperchannel = 16; | |
1178 | wiinst->format.channels = hweight32(wiinst->fxwc); | |
1179 | break; | |
1180 | default: | |
1181 | kfree(wave_dev); | |
1182 | kfree(wiinst); | |
1183 | BUG(); | |
1184 | break; | |
1185 | } | |
1186 | ||
1187 | wiinst->state = WAVE_STATE_CLOSED; | |
1188 | ||
1189 | wiinst->buffer.ossfragshift = 0; | |
1190 | wiinst->buffer.fragment_size = 0; | |
1191 | wiinst->buffer.numfrags = 0; | |
1192 | ||
1193 | init_waitqueue_head(&wiinst->wait_queue); | |
1194 | ||
1195 | wiinst->mmapped = 0; | |
1196 | wiinst->total_recorded = 0; | |
1197 | wiinst->blocks = 0; | |
1198 | spin_lock_init(&wiinst->lock); | |
1199 | tasklet_init(&wiinst->timer.tasklet, emu10k1_wavein_bh, (unsigned long) wave_dev); | |
1200 | wave_dev->wiinst = wiinst; | |
1201 | emu10k1_wavein_setformat(wave_dev, &wiinst->format); | |
1202 | } | |
1203 | ||
1204 | if (file->f_mode & FMODE_WRITE) { | |
1205 | struct woinst *woinst; | |
1206 | int i; | |
1207 | ||
1208 | if ((woinst = (struct woinst *) kmalloc(sizeof(struct woinst), GFP_KERNEL)) == NULL) { | |
1209 | ERROR(); | |
1210 | kfree(wave_dev); | |
1211 | return -ENOMEM; | |
1212 | } | |
1213 | ||
1214 | if (wave_dev->wiinst != NULL) { | |
1215 | woinst->format = wave_dev->wiinst->format; | |
1216 | } else { | |
1217 | woinst->format.id = AFMT_U8; | |
1218 | woinst->format.samplingrate = 8000; | |
1219 | woinst->format.bitsperchannel = 8; | |
1220 | woinst->format.channels = 1; | |
1221 | } | |
1222 | ||
1223 | woinst->state = WAVE_STATE_CLOSED; | |
1224 | ||
1225 | woinst->buffer.fragment_size = 0; | |
1226 | woinst->buffer.ossfragshift = 0; | |
1227 | woinst->buffer.numfrags = 0; | |
1228 | woinst->device = (card->audio_dev1 == minor); | |
1229 | woinst->timer.state = TIMER_STATE_UNINSTALLED; | |
1230 | woinst->num_voices = 1; | |
1231 | for (i = 0; i < WAVEOUT_MAXVOICES; i++) { | |
1232 | woinst->voice[i].usage = VOICE_USAGE_FREE; | |
1233 | woinst->voice[i].mem.emupageindex = -1; | |
1234 | } | |
1235 | ||
1236 | init_waitqueue_head(&woinst->wait_queue); | |
1237 | ||
1238 | woinst->mmapped = 0; | |
1239 | woinst->total_copied = 0; | |
1240 | woinst->total_played = 0; | |
1241 | woinst->blocks = 0; | |
1242 | spin_lock_init(&woinst->lock); | |
1243 | tasklet_init(&woinst->timer.tasklet, emu10k1_waveout_bh, (unsigned long) wave_dev); | |
1244 | wave_dev->woinst = woinst; | |
1245 | emu10k1_waveout_setformat(wave_dev, &woinst->format); | |
1246 | } | |
1247 | ||
1248 | file->private_data = (void *) wave_dev; | |
1249 | ||
1250 | return nonseekable_open(inode, file); | |
1251 | } | |
1252 | ||
1253 | static int emu10k1_audio_release(struct inode *inode, struct file *file) | |
1254 | { | |
1255 | struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; | |
1256 | struct emu10k1_card *card; | |
1257 | unsigned long flags; | |
1258 | ||
1259 | card = wave_dev->card; | |
1260 | ||
1261 | DPF(2, "emu10k1_audio_release()\n"); | |
1262 | ||
1263 | if (file->f_mode & FMODE_WRITE) { | |
1264 | struct woinst *woinst = wave_dev->woinst; | |
1265 | ||
1266 | spin_lock_irqsave(&woinst->lock, flags); | |
1267 | if(woinst->format.passthrough==2) | |
1268 | card->pt.state=PT_STATE_PLAYING; | |
1269 | if (woinst->format.passthrough && card->pt.state != PT_STATE_INACTIVE){ | |
1270 | spin_lock(&card->pt.lock); | |
1271 | emu10k1_pt_stop(card); | |
1272 | spin_unlock(&card->pt.lock); | |
1273 | } | |
1274 | if (woinst->state & WAVE_STATE_OPEN) { | |
1275 | if (woinst->state & WAVE_STATE_STARTED) { | |
1276 | if (!(file->f_flags & O_NONBLOCK)) { | |
1277 | while (!signal_pending(current) | |
1278 | && (woinst->total_played < woinst->total_copied)) { | |
1279 | DPF(4, "Buffer hasn't been totally played, sleep....\n"); | |
1280 | spin_unlock_irqrestore(&woinst->lock, flags); | |
1281 | interruptible_sleep_on(&woinst->wait_queue); | |
1282 | spin_lock_irqsave(&woinst->lock, flags); | |
1283 | } | |
1284 | } | |
1285 | } | |
1286 | emu10k1_waveout_close(wave_dev); | |
1287 | } | |
1288 | ||
1289 | spin_unlock_irqrestore(&woinst->lock, flags); | |
1290 | /* remove the tasklet */ | |
1291 | tasklet_kill(&woinst->timer.tasklet); | |
1292 | kfree(wave_dev->woinst); | |
1293 | } | |
1294 | ||
1295 | if (file->f_mode & FMODE_READ) { | |
1296 | struct wiinst *wiinst = wave_dev->wiinst; | |
1297 | ||
1298 | spin_lock_irqsave(&wiinst->lock, flags); | |
1299 | ||
1300 | if (wiinst->state & WAVE_STATE_OPEN) { | |
1301 | emu10k1_wavein_close(wave_dev); | |
1302 | } | |
1303 | ||
1304 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
1305 | tasklet_kill(&wiinst->timer.tasklet); | |
1306 | kfree(wave_dev->wiinst); | |
1307 | } | |
1308 | ||
1309 | kfree(wave_dev); | |
1310 | ||
1311 | if (waitqueue_active(&card->open_wait)) | |
1312 | wake_up_interruptible(&card->open_wait); | |
1313 | ||
1314 | return 0; | |
1315 | } | |
1316 | ||
1317 | /* FIXME sort out poll() + mmap() */ | |
1318 | static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_struct *wait) | |
1319 | { | |
1320 | struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; | |
1321 | struct woinst *woinst = wave_dev->woinst; | |
1322 | struct wiinst *wiinst = wave_dev->wiinst; | |
1323 | unsigned int mask = 0; | |
1324 | u32 bytestocopy; | |
1325 | unsigned long flags; | |
1326 | ||
1327 | DPF(4, "emu10k1_audio_poll()\n"); | |
1328 | ||
1329 | if (file->f_mode & FMODE_WRITE) | |
1330 | poll_wait(file, &woinst->wait_queue, wait); | |
1331 | ||
1332 | if (file->f_mode & FMODE_READ) | |
1333 | poll_wait(file, &wiinst->wait_queue, wait); | |
1334 | ||
1335 | if (file->f_mode & FMODE_WRITE) { | |
1336 | spin_lock_irqsave(&woinst->lock, flags); | |
1337 | ||
1338 | if (woinst->state & WAVE_STATE_OPEN) { | |
1339 | emu10k1_waveout_update(woinst); | |
1340 | emu10k1_waveout_getxfersize(woinst, &bytestocopy); | |
1341 | ||
1342 | if (bytestocopy >= woinst->buffer.fragment_size) | |
1343 | mask |= POLLOUT | POLLWRNORM; | |
1344 | } else | |
1345 | mask |= POLLOUT | POLLWRNORM; | |
1346 | ||
1347 | spin_unlock_irqrestore(&woinst->lock, flags); | |
1348 | } | |
1349 | ||
1350 | if (file->f_mode & FMODE_READ) { | |
1351 | spin_lock_irqsave(&wiinst->lock, flags); | |
1352 | ||
1353 | if (wiinst->state & WAVE_STATE_OPEN) { | |
1354 | emu10k1_wavein_update(wave_dev->card, wiinst); | |
1355 | emu10k1_wavein_getxfersize(wiinst, &bytestocopy); | |
1356 | ||
1357 | if (bytestocopy >= wiinst->buffer.fragment_size) | |
1358 | mask |= POLLIN | POLLRDNORM; | |
1359 | } | |
1360 | ||
1361 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
1362 | } | |
1363 | ||
1364 | return mask; | |
1365 | } | |
1366 | ||
1367 | static void calculate_ofrag(struct woinst *woinst) | |
1368 | { | |
1369 | struct waveout_buffer *buffer = &woinst->buffer; | |
1370 | u32 fragsize; | |
1371 | ||
1372 | if (buffer->fragment_size) | |
1373 | return; | |
1374 | ||
1375 | if (!buffer->ossfragshift) { | |
1376 | fragsize = (woinst->format.bytespervoicesample * woinst->format.samplingrate * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1; | |
1377 | ||
1378 | while (fragsize) { | |
1379 | fragsize >>= 1; | |
1380 | buffer->ossfragshift++; | |
1381 | } | |
1382 | } | |
1383 | ||
1384 | if (buffer->ossfragshift < WAVEOUT_MINFRAGSHIFT) | |
1385 | buffer->ossfragshift = WAVEOUT_MINFRAGSHIFT; | |
1386 | ||
1387 | buffer->fragment_size = 1 << buffer->ossfragshift; | |
1388 | ||
1389 | while (buffer->fragment_size * WAVEOUT_MINFRAGS > WAVEOUT_MAXBUFSIZE) | |
1390 | buffer->fragment_size >>= 1; | |
1391 | ||
1392 | /* now we are sure that: | |
1393 | (2^WAVEOUT_MINFRAGSHIFT) <= (fragment_size = 2^n) <= (WAVEOUT_MAXBUFSIZE / WAVEOUT_MINFRAGS) | |
1394 | */ | |
1395 | ||
1396 | if (!buffer->numfrags) { | |
1397 | u32 numfrags; | |
1398 | ||
1399 | numfrags = (woinst->format.bytespervoicesample * woinst->format.samplingrate * WAVEOUT_DEFAULTBUFLEN) / | |
1400 | (buffer->fragment_size * 1000) - 1; | |
1401 | ||
1402 | buffer->numfrags = 1; | |
1403 | ||
1404 | while (numfrags) { | |
1405 | numfrags >>= 1; | |
1406 | buffer->numfrags <<= 1; | |
1407 | } | |
1408 | } | |
1409 | ||
1410 | if (buffer->numfrags < WAVEOUT_MINFRAGS) | |
1411 | buffer->numfrags = WAVEOUT_MINFRAGS; | |
1412 | ||
1413 | if (buffer->numfrags * buffer->fragment_size > WAVEOUT_MAXBUFSIZE) | |
1414 | buffer->numfrags = WAVEOUT_MAXBUFSIZE / buffer->fragment_size; | |
1415 | ||
1416 | if (buffer->numfrags < WAVEOUT_MINFRAGS) | |
1417 | BUG(); | |
1418 | ||
1419 | buffer->size = buffer->fragment_size * buffer->numfrags; | |
1420 | buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0); | |
1421 | ||
1422 | DPD(2, " calculated playback fragment_size -> %d\n", buffer->fragment_size); | |
1423 | DPD(2, " calculated playback numfrags -> %d\n", buffer->numfrags); | |
1424 | ||
1425 | return; | |
1426 | } | |
1427 | ||
1428 | static void calculate_ifrag(struct wiinst *wiinst) | |
1429 | { | |
1430 | struct wavein_buffer *buffer = &wiinst->buffer; | |
1431 | u32 fragsize, bufsize, size[4]; | |
1432 | int i, j; | |
1433 | ||
1434 | if (buffer->fragment_size) | |
1435 | return; | |
1436 | ||
1437 | if (!buffer->ossfragshift) { | |
1438 | fragsize = (wiinst->format.bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1; | |
1439 | ||
1440 | while (fragsize) { | |
1441 | fragsize >>= 1; | |
1442 | buffer->ossfragshift++; | |
1443 | } | |
1444 | } | |
1445 | ||
1446 | if (buffer->ossfragshift < WAVEIN_MINFRAGSHIFT) | |
1447 | buffer->ossfragshift = WAVEIN_MINFRAGSHIFT; | |
1448 | ||
1449 | buffer->fragment_size = 1 << buffer->ossfragshift; | |
1450 | ||
1451 | while (buffer->fragment_size * WAVEIN_MINFRAGS > WAVEIN_MAXBUFSIZE) | |
1452 | buffer->fragment_size >>= 1; | |
1453 | ||
1454 | /* now we are sure that: | |
1455 | (2^WAVEIN_MINFRAGSHIFT) <= (fragment_size = 2^n) <= (WAVEIN_MAXBUFSIZE / WAVEIN_MINFRAGS) | |
1456 | */ | |
1457 | ||
1458 | ||
1459 | if (!buffer->numfrags) | |
1460 | buffer->numfrags = (wiinst->format.bytespersec * WAVEIN_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1; | |
1461 | ||
1462 | if (buffer->numfrags < WAVEIN_MINFRAGS) | |
1463 | buffer->numfrags = WAVEIN_MINFRAGS; | |
1464 | ||
1465 | if (buffer->numfrags * buffer->fragment_size > WAVEIN_MAXBUFSIZE) | |
1466 | buffer->numfrags = WAVEIN_MAXBUFSIZE / buffer->fragment_size; | |
1467 | ||
1468 | if (buffer->numfrags < WAVEIN_MINFRAGS) | |
1469 | BUG(); | |
1470 | ||
1471 | bufsize = buffer->fragment_size * buffer->numfrags; | |
1472 | ||
1473 | /* the buffer size for recording is restricted to certain values, adjust it now */ | |
1474 | if (bufsize >= 0x10000) { | |
1475 | buffer->size = 0x10000; | |
1476 | buffer->sizeregval = 0x1f; | |
1477 | } else { | |
1478 | buffer->size = 0; | |
1479 | size[0] = 384; | |
1480 | size[1] = 448; | |
1481 | size[2] = 512; | |
1482 | size[3] = 640; | |
1483 | ||
1484 | for (i = 0; i < 8; i++) | |
1485 | for (j = 0; j < 4; j++) | |
1486 | if (bufsize >= size[j]) { | |
1487 | buffer->size = size[j]; | |
1488 | size[j] *= 2; | |
1489 | buffer->sizeregval = i * 4 + j + 1; | |
1490 | } else | |
1491 | goto exitloop; | |
1492 | exitloop: | |
1493 | if (buffer->size == 0) { | |
1494 | buffer->size = 384; | |
1495 | buffer->sizeregval = 0x01; | |
1496 | } | |
1497 | } | |
1498 | ||
1499 | /* adjust the fragment size so that buffer size is an integer multiple */ | |
1500 | while (buffer->size % buffer->fragment_size) | |
1501 | buffer->fragment_size >>= 1; | |
1502 | ||
1503 | buffer->numfrags = buffer->size / buffer->fragment_size; | |
1504 | buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0); | |
1505 | ||
1506 | DPD(2, " calculated recording fragment_size -> %d\n", buffer->fragment_size); | |
1507 | DPD(2, " calculated recording numfrags -> %d\n", buffer->numfrags); | |
1508 | DPD(2, " buffer size register -> %#04x\n", buffer->sizeregval); | |
1509 | ||
1510 | return; | |
1511 | } | |
1512 | ||
1513 | static void emu10k1_wavein_bh(unsigned long refdata) | |
1514 | { | |
1515 | struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata; | |
1516 | struct wiinst *wiinst = wave_dev->wiinst; | |
1517 | u32 bytestocopy; | |
1518 | unsigned long flags; | |
1519 | ||
1520 | if (!wiinst) | |
1521 | return; | |
1522 | ||
1523 | spin_lock_irqsave(&wiinst->lock, flags); | |
1524 | ||
1525 | if (!(wiinst->state & WAVE_STATE_STARTED)) { | |
1526 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
1527 | return; | |
1528 | } | |
1529 | ||
1530 | emu10k1_wavein_update(wave_dev->card, wiinst); | |
1531 | emu10k1_wavein_getxfersize(wiinst, &bytestocopy); | |
1532 | ||
1533 | spin_unlock_irqrestore(&wiinst->lock, flags); | |
1534 | ||
1535 | if (bytestocopy >= wiinst->buffer.fragment_size) { | |
1536 | if (waitqueue_active(&wiinst->wait_queue)) | |
1537 | wake_up_interruptible(&wiinst->wait_queue); | |
1538 | } else | |
1539 | DPD(3, "Not enough transfer size, %d\n", bytestocopy); | |
1540 | ||
1541 | return; | |
1542 | } | |
1543 | ||
1544 | static void emu10k1_waveout_bh(unsigned long refdata) | |
1545 | { | |
1546 | struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata; | |
1547 | struct woinst *woinst = wave_dev->woinst; | |
1548 | u32 bytestocopy; | |
1549 | unsigned long flags; | |
1550 | ||
1551 | if (!woinst) | |
1552 | return; | |
1553 | ||
1554 | spin_lock_irqsave(&woinst->lock, flags); | |
1555 | ||
1556 | if (!(woinst->state & WAVE_STATE_STARTED)) { | |
1557 | spin_unlock_irqrestore(&woinst->lock, flags); | |
1558 | return; | |
1559 | } | |
1560 | ||
1561 | emu10k1_waveout_update(woinst); | |
1562 | emu10k1_waveout_getxfersize(woinst, &bytestocopy); | |
1563 | ||
1564 | if (woinst->buffer.fill_silence) { | |
1565 | spin_unlock_irqrestore(&woinst->lock, flags); | |
1566 | emu10k1_waveout_fillsilence(woinst); | |
1567 | } else | |
1568 | spin_unlock_irqrestore(&woinst->lock, flags); | |
1569 | ||
1570 | if (bytestocopy >= woinst->buffer.fragment_size) { | |
1571 | if (waitqueue_active(&woinst->wait_queue)) | |
1572 | wake_up_interruptible(&woinst->wait_queue); | |
1573 | } else | |
1574 | DPD(3, "Not enough transfer size -> %d\n", bytestocopy); | |
1575 | ||
1576 | return; | |
1577 | } | |
1578 | ||
1579 | struct file_operations emu10k1_audio_fops = { | |
1580 | .owner = THIS_MODULE, | |
1581 | .llseek = no_llseek, | |
1582 | .read = emu10k1_audio_read, | |
1583 | .write = emu10k1_audio_write, | |
1584 | .poll = emu10k1_audio_poll, | |
1585 | .ioctl = emu10k1_audio_ioctl, | |
1586 | .mmap = emu10k1_audio_mmap, | |
1587 | .open = emu10k1_audio_open, | |
1588 | .release = emu10k1_audio_release, | |
1589 | }; |