Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/isa/msnd/msnd.c
10817 views
1
/*********************************************************************
2
*
3
* 2002/06/30 Karsten Wiese:
4
* removed kernel-version dependencies.
5
* ripped from linux kernel 2.4.18 (OSS Implementation) by me.
6
* In the OSS Version, this file is compiled to a separate MODULE,
7
* that is used by the pinnacle and the classic driver.
8
* since there is no classic driver for alsa yet (i dont have a classic
9
* & writing one blindfold is difficult) this file's object is statically
10
* linked into the pinnacle-driver-module for now. look for the string
11
* "uncomment this to make this a module again"
12
* to do guess what.
13
*
14
* the following is a copy of the 2.4.18 OSS FREE file-heading comment:
15
*
16
* msnd.c - Driver Base
17
*
18
* Turtle Beach MultiSound Sound Card Driver for Linux
19
*
20
* Copyright (C) 1998 Andrew Veliath
21
*
22
* This program is free software; you can redistribute it and/or modify
23
* it under the terms of the GNU General Public License as published by
24
* the Free Software Foundation; either version 2 of the License, or
25
* (at your option) any later version.
26
*
27
* This program is distributed in the hope that it will be useful,
28
* but WITHOUT ANY WARRANTY; without even the implied warranty of
29
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30
* GNU General Public License for more details.
31
*
32
* You should have received a copy of the GNU General Public License
33
* along with this program; if not, write to the Free Software
34
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35
*
36
********************************************************************/
37
38
#include <linux/kernel.h>
39
#include <linux/types.h>
40
#include <linux/interrupt.h>
41
#include <linux/io.h>
42
#include <linux/fs.h>
43
#include <linux/delay.h>
44
45
#include <sound/core.h>
46
#include <sound/initval.h>
47
#include <sound/pcm.h>
48
#include <sound/pcm_params.h>
49
50
#include "msnd.h"
51
52
#define LOGNAME "msnd"
53
54
55
void snd_msnd_init_queue(void *base, int start, int size)
56
{
57
writew(PCTODSP_BASED(start), base + JQS_wStart);
58
writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
59
writew(0, base + JQS_wHead);
60
writew(0, base + JQS_wTail);
61
}
62
EXPORT_SYMBOL(snd_msnd_init_queue);
63
64
static int snd_msnd_wait_TXDE(struct snd_msnd *dev)
65
{
66
unsigned int io = dev->io;
67
int timeout = 1000;
68
69
while (timeout-- > 0)
70
if (inb(io + HP_ISR) & HPISR_TXDE)
71
return 0;
72
73
return -EIO;
74
}
75
76
static int snd_msnd_wait_HC0(struct snd_msnd *dev)
77
{
78
unsigned int io = dev->io;
79
int timeout = 1000;
80
81
while (timeout-- > 0)
82
if (!(inb(io + HP_CVR) & HPCVR_HC))
83
return 0;
84
85
return -EIO;
86
}
87
88
int snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd)
89
{
90
unsigned long flags;
91
92
spin_lock_irqsave(&dev->lock, flags);
93
if (snd_msnd_wait_HC0(dev) == 0) {
94
outb(cmd, dev->io + HP_CVR);
95
spin_unlock_irqrestore(&dev->lock, flags);
96
return 0;
97
}
98
spin_unlock_irqrestore(&dev->lock, flags);
99
100
snd_printd(KERN_ERR LOGNAME ": Send DSP command timeout\n");
101
102
return -EIO;
103
}
104
EXPORT_SYMBOL(snd_msnd_send_dsp_cmd);
105
106
int snd_msnd_send_word(struct snd_msnd *dev, unsigned char high,
107
unsigned char mid, unsigned char low)
108
{
109
unsigned int io = dev->io;
110
111
if (snd_msnd_wait_TXDE(dev) == 0) {
112
outb(high, io + HP_TXH);
113
outb(mid, io + HP_TXM);
114
outb(low, io + HP_TXL);
115
return 0;
116
}
117
118
snd_printd(KERN_ERR LOGNAME ": Send host word timeout\n");
119
120
return -EIO;
121
}
122
EXPORT_SYMBOL(snd_msnd_send_word);
123
124
int snd_msnd_upload_host(struct snd_msnd *dev, const u8 *bin, int len)
125
{
126
int i;
127
128
if (len % 3 != 0) {
129
snd_printk(KERN_ERR LOGNAME
130
": Upload host data not multiple of 3!\n");
131
return -EINVAL;
132
}
133
134
for (i = 0; i < len; i += 3)
135
if (snd_msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]))
136
return -EIO;
137
138
inb(dev->io + HP_RXL);
139
inb(dev->io + HP_CVR);
140
141
return 0;
142
}
143
EXPORT_SYMBOL(snd_msnd_upload_host);
144
145
int snd_msnd_enable_irq(struct snd_msnd *dev)
146
{
147
unsigned long flags;
148
149
if (dev->irq_ref++)
150
return 0;
151
152
snd_printdd(LOGNAME ": Enabling IRQ\n");
153
154
spin_lock_irqsave(&dev->lock, flags);
155
if (snd_msnd_wait_TXDE(dev) == 0) {
156
outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
157
if (dev->type == msndClassic)
158
outb(dev->irqid, dev->io + HP_IRQM);
159
160
outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
161
outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
162
enable_irq(dev->irq);
163
snd_msnd_init_queue(dev->DSPQ, dev->dspq_data_buff,
164
dev->dspq_buff_size);
165
spin_unlock_irqrestore(&dev->lock, flags);
166
return 0;
167
}
168
spin_unlock_irqrestore(&dev->lock, flags);
169
170
snd_printd(KERN_ERR LOGNAME ": Enable IRQ failed\n");
171
172
return -EIO;
173
}
174
EXPORT_SYMBOL(snd_msnd_enable_irq);
175
176
int snd_msnd_disable_irq(struct snd_msnd *dev)
177
{
178
unsigned long flags;
179
180
if (--dev->irq_ref > 0)
181
return 0;
182
183
if (dev->irq_ref < 0)
184
snd_printd(KERN_WARNING LOGNAME ": IRQ ref count is %d\n",
185
dev->irq_ref);
186
187
snd_printdd(LOGNAME ": Disabling IRQ\n");
188
189
spin_lock_irqsave(&dev->lock, flags);
190
if (snd_msnd_wait_TXDE(dev) == 0) {
191
outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
192
if (dev->type == msndClassic)
193
outb(HPIRQ_NONE, dev->io + HP_IRQM);
194
disable_irq(dev->irq);
195
spin_unlock_irqrestore(&dev->lock, flags);
196
return 0;
197
}
198
spin_unlock_irqrestore(&dev->lock, flags);
199
200
snd_printd(KERN_ERR LOGNAME ": Disable IRQ failed\n");
201
202
return -EIO;
203
}
204
EXPORT_SYMBOL(snd_msnd_disable_irq);
205
206
static inline long get_play_delay_jiffies(struct snd_msnd *chip, long size)
207
{
208
long tmp = (size * HZ * chip->play_sample_size) / 8;
209
return tmp / (chip->play_sample_rate * chip->play_channels);
210
}
211
212
static void snd_msnd_dsp_write_flush(struct snd_msnd *chip)
213
{
214
if (!(chip->mode & FMODE_WRITE) || !test_bit(F_WRITING, &chip->flags))
215
return;
216
set_bit(F_WRITEFLUSH, &chip->flags);
217
/* interruptible_sleep_on_timeout(
218
&chip->writeflush,
219
get_play_delay_jiffies(&chip, chip->DAPF.len));*/
220
clear_bit(F_WRITEFLUSH, &chip->flags);
221
if (!signal_pending(current))
222
schedule_timeout_interruptible(
223
get_play_delay_jiffies(chip, chip->play_period_bytes));
224
clear_bit(F_WRITING, &chip->flags);
225
}
226
227
void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file)
228
{
229
if ((file ? file->f_mode : chip->mode) & FMODE_READ) {
230
clear_bit(F_READING, &chip->flags);
231
snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
232
snd_msnd_disable_irq(chip);
233
if (file) {
234
snd_printd(KERN_INFO LOGNAME
235
": Stopping read for %p\n", file);
236
chip->mode &= ~FMODE_READ;
237
}
238
clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
239
}
240
if ((file ? file->f_mode : chip->mode) & FMODE_WRITE) {
241
if (test_bit(F_WRITING, &chip->flags)) {
242
snd_msnd_dsp_write_flush(chip);
243
snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
244
}
245
snd_msnd_disable_irq(chip);
246
if (file) {
247
snd_printd(KERN_INFO
248
LOGNAME ": Stopping write for %p\n", file);
249
chip->mode &= ~FMODE_WRITE;
250
}
251
clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
252
}
253
}
254
EXPORT_SYMBOL(snd_msnd_dsp_halt);
255
256
257
int snd_msnd_DARQ(struct snd_msnd *chip, int bank)
258
{
259
int /*size, n,*/ timeout = 3;
260
u16 wTmp;
261
/* void *DAQD; */
262
263
/* Increment the tail and check for queue wrap */
264
wTmp = readw(chip->DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
265
if (wTmp > readw(chip->DARQ + JQS_wSize))
266
wTmp = 0;
267
while (wTmp == readw(chip->DARQ + JQS_wHead) && timeout--)
268
udelay(1);
269
270
if (chip->capturePeriods == 2) {
271
void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF +
272
bank * DAQDS__size + DAQDS_wStart;
273
unsigned short offset = 0x3000 + chip->capturePeriodBytes;
274
275
if (readw(pDAQ) != PCTODSP_BASED(0x3000))
276
offset = 0x3000;
277
writew(PCTODSP_BASED(offset), pDAQ);
278
}
279
280
writew(wTmp, chip->DARQ + JQS_wTail);
281
282
#if 0
283
/* Get our digital audio queue struct */
284
DAQD = bank * DAQDS__size + chip->mappedbase + DARQ_DATA_BUFF;
285
286
/* Get length of data */
287
size = readw(DAQD + DAQDS_wSize);
288
289
/* Read data from the head (unprotected bank 1 access okay
290
since this is only called inside an interrupt) */
291
outb(HPBLKSEL_1, chip->io + HP_BLKS);
292
n = msnd_fifo_write(&chip->DARF,
293
(char *)(chip->base + bank * DAR_BUFF_SIZE),
294
size, 0);
295
if (n <= 0) {
296
outb(HPBLKSEL_0, chip->io + HP_BLKS);
297
return n;
298
}
299
outb(HPBLKSEL_0, chip->io + HP_BLKS);
300
#endif
301
302
return 1;
303
}
304
EXPORT_SYMBOL(snd_msnd_DARQ);
305
306
int snd_msnd_DAPQ(struct snd_msnd *chip, int start)
307
{
308
u16 DAPQ_tail;
309
int protect = start, nbanks = 0;
310
void *DAQD;
311
static int play_banks_submitted;
312
/* unsigned long flags;
313
spin_lock_irqsave(&chip->lock, flags); not necessary */
314
315
DAPQ_tail = readw(chip->DAPQ + JQS_wTail);
316
while (DAPQ_tail != readw(chip->DAPQ + JQS_wHead) || start) {
317
int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
318
319
if (start) {
320
start = 0;
321
play_banks_submitted = 0;
322
}
323
324
/* Get our digital audio queue struct */
325
DAQD = bank_num * DAQDS__size + chip->mappedbase +
326
DAPQ_DATA_BUFF;
327
328
/* Write size of this bank */
329
writew(chip->play_period_bytes, DAQD + DAQDS_wSize);
330
if (play_banks_submitted < 3)
331
++play_banks_submitted;
332
else if (chip->playPeriods == 2) {
333
unsigned short offset = chip->play_period_bytes;
334
335
if (readw(DAQD + DAQDS_wStart) != PCTODSP_BASED(0x0))
336
offset = 0;
337
338
writew(PCTODSP_BASED(offset), DAQD + DAQDS_wStart);
339
}
340
++nbanks;
341
342
/* Then advance the tail */
343
/*
344
if (protect)
345
snd_printd(KERN_INFO "B %X %lX\n",
346
bank_num, xtime.tv_usec);
347
*/
348
349
DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
350
writew(DAPQ_tail, chip->DAPQ + JQS_wTail);
351
/* Tell the DSP to play the bank */
352
snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_START);
353
if (protect)
354
if (2 == bank_num)
355
break;
356
}
357
/*
358
if (protect)
359
snd_printd(KERN_INFO "%lX\n", xtime.tv_usec);
360
*/
361
/* spin_unlock_irqrestore(&chip->lock, flags); not necessary */
362
return nbanks;
363
}
364
EXPORT_SYMBOL(snd_msnd_DAPQ);
365
366
static void snd_msnd_play_reset_queue(struct snd_msnd *chip,
367
unsigned int pcm_periods,
368
unsigned int pcm_count)
369
{
370
int n;
371
void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
372
373
chip->last_playbank = -1;
374
chip->playLimit = pcm_count * (pcm_periods - 1);
375
chip->playPeriods = pcm_periods;
376
writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wHead);
377
writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wTail);
378
379
chip->play_period_bytes = pcm_count;
380
381
for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
382
writew(PCTODSP_BASED((u32)(pcm_count * n)),
383
pDAQ + DAQDS_wStart);
384
writew(0, pDAQ + DAQDS_wSize);
385
writew(1, pDAQ + DAQDS_wFormat);
386
writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
387
writew(chip->play_channels, pDAQ + DAQDS_wChannels);
388
writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
389
writew(HIMT_PLAY_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
390
writew(n, pDAQ + DAQDS_wFlags);
391
}
392
}
393
394
static void snd_msnd_capture_reset_queue(struct snd_msnd *chip,
395
unsigned int pcm_periods,
396
unsigned int pcm_count)
397
{
398
int n;
399
void *pDAQ;
400
/* unsigned long flags; */
401
402
/* snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); */
403
404
chip->last_recbank = 2;
405
chip->captureLimit = pcm_count * (pcm_periods - 1);
406
chip->capturePeriods = pcm_periods;
407
writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DARQ + JQS_wHead);
408
writew(PCTODSP_OFFSET(chip->last_recbank * DAQDS__size),
409
chip->DARQ + JQS_wTail);
410
411
#if 0 /* Critical section: bank 1 access. this is how the OSS driver does it:*/
412
spin_lock_irqsave(&chip->lock, flags);
413
outb(HPBLKSEL_1, chip->io + HP_BLKS);
414
memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3);
415
outb(HPBLKSEL_0, chip->io + HP_BLKS);
416
spin_unlock_irqrestore(&chip->lock, flags);
417
#endif
418
419
chip->capturePeriodBytes = pcm_count;
420
snd_printdd("snd_msnd_capture_reset_queue() %i\n", pcm_count);
421
422
pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
423
424
for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
425
u32 tmp = pcm_count * n;
426
427
writew(PCTODSP_BASED(tmp + 0x3000), pDAQ + DAQDS_wStart);
428
writew(pcm_count, pDAQ + DAQDS_wSize);
429
writew(1, pDAQ + DAQDS_wFormat);
430
writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
431
writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
432
writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
433
writew(HIMT_RECORD_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
434
writew(n, pDAQ + DAQDS_wFlags);
435
}
436
}
437
438
static struct snd_pcm_hardware snd_msnd_playback = {
439
.info = SNDRV_PCM_INFO_MMAP |
440
SNDRV_PCM_INFO_INTERLEAVED |
441
SNDRV_PCM_INFO_MMAP_VALID |
442
SNDRV_PCM_INFO_BATCH,
443
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
444
.rates = SNDRV_PCM_RATE_8000_48000,
445
.rate_min = 8000,
446
.rate_max = 48000,
447
.channels_min = 1,
448
.channels_max = 2,
449
.buffer_bytes_max = 0x3000,
450
.period_bytes_min = 0x40,
451
.period_bytes_max = 0x1800,
452
.periods_min = 2,
453
.periods_max = 3,
454
.fifo_size = 0,
455
};
456
457
static struct snd_pcm_hardware snd_msnd_capture = {
458
.info = SNDRV_PCM_INFO_MMAP |
459
SNDRV_PCM_INFO_INTERLEAVED |
460
SNDRV_PCM_INFO_MMAP_VALID |
461
SNDRV_PCM_INFO_BATCH,
462
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
463
.rates = SNDRV_PCM_RATE_8000_48000,
464
.rate_min = 8000,
465
.rate_max = 48000,
466
.channels_min = 1,
467
.channels_max = 2,
468
.buffer_bytes_max = 0x3000,
469
.period_bytes_min = 0x40,
470
.period_bytes_max = 0x1800,
471
.periods_min = 2,
472
.periods_max = 3,
473
.fifo_size = 0,
474
};
475
476
477
static int snd_msnd_playback_open(struct snd_pcm_substream *substream)
478
{
479
struct snd_pcm_runtime *runtime = substream->runtime;
480
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
481
482
set_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
483
clear_bit(F_WRITING, &chip->flags);
484
snd_msnd_enable_irq(chip);
485
486
runtime->dma_area = chip->mappedbase;
487
runtime->dma_bytes = 0x3000;
488
489
chip->playback_substream = substream;
490
runtime->hw = snd_msnd_playback;
491
return 0;
492
}
493
494
static int snd_msnd_playback_close(struct snd_pcm_substream *substream)
495
{
496
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
497
498
snd_msnd_disable_irq(chip);
499
clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
500
return 0;
501
}
502
503
504
static int snd_msnd_playback_hw_params(struct snd_pcm_substream *substream,
505
struct snd_pcm_hw_params *params)
506
{
507
int i;
508
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
509
void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
510
511
chip->play_sample_size = snd_pcm_format_width(params_format(params));
512
chip->play_channels = params_channels(params);
513
chip->play_sample_rate = params_rate(params);
514
515
for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
516
writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
517
writew(chip->play_channels, pDAQ + DAQDS_wChannels);
518
writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
519
}
520
/* dont do this here:
521
* snd_msnd_calibrate_adc(chip->play_sample_rate);
522
*/
523
524
return 0;
525
}
526
527
static int snd_msnd_playback_prepare(struct snd_pcm_substream *substream)
528
{
529
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
530
unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
531
unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
532
unsigned int pcm_periods = pcm_size / pcm_count;
533
534
snd_msnd_play_reset_queue(chip, pcm_periods, pcm_count);
535
chip->playDMAPos = 0;
536
return 0;
537
}
538
539
static int snd_msnd_playback_trigger(struct snd_pcm_substream *substream,
540
int cmd)
541
{
542
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
543
int result = 0;
544
545
if (cmd == SNDRV_PCM_TRIGGER_START) {
546
snd_printdd("snd_msnd_playback_trigger(START)\n");
547
chip->banksPlayed = 0;
548
set_bit(F_WRITING, &chip->flags);
549
snd_msnd_DAPQ(chip, 1);
550
} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
551
snd_printdd("snd_msnd_playback_trigger(STop)\n");
552
/* interrupt diagnostic, comment this out later */
553
clear_bit(F_WRITING, &chip->flags);
554
snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
555
} else {
556
snd_printd(KERN_ERR "snd_msnd_playback_trigger(?????)\n");
557
result = -EINVAL;
558
}
559
560
snd_printdd("snd_msnd_playback_trigger() ENDE\n");
561
return result;
562
}
563
564
static snd_pcm_uframes_t
565
snd_msnd_playback_pointer(struct snd_pcm_substream *substream)
566
{
567
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
568
569
return bytes_to_frames(substream->runtime, chip->playDMAPos);
570
}
571
572
573
static struct snd_pcm_ops snd_msnd_playback_ops = {
574
.open = snd_msnd_playback_open,
575
.close = snd_msnd_playback_close,
576
.ioctl = snd_pcm_lib_ioctl,
577
.hw_params = snd_msnd_playback_hw_params,
578
.prepare = snd_msnd_playback_prepare,
579
.trigger = snd_msnd_playback_trigger,
580
.pointer = snd_msnd_playback_pointer,
581
};
582
583
static int snd_msnd_capture_open(struct snd_pcm_substream *substream)
584
{
585
struct snd_pcm_runtime *runtime = substream->runtime;
586
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
587
588
set_bit(F_AUDIO_READ_INUSE, &chip->flags);
589
snd_msnd_enable_irq(chip);
590
runtime->dma_area = chip->mappedbase + 0x3000;
591
runtime->dma_bytes = 0x3000;
592
memset(runtime->dma_area, 0, runtime->dma_bytes);
593
chip->capture_substream = substream;
594
runtime->hw = snd_msnd_capture;
595
return 0;
596
}
597
598
static int snd_msnd_capture_close(struct snd_pcm_substream *substream)
599
{
600
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
601
602
snd_msnd_disable_irq(chip);
603
clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
604
return 0;
605
}
606
607
static int snd_msnd_capture_prepare(struct snd_pcm_substream *substream)
608
{
609
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
610
unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
611
unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
612
unsigned int pcm_periods = pcm_size / pcm_count;
613
614
snd_msnd_capture_reset_queue(chip, pcm_periods, pcm_count);
615
chip->captureDMAPos = 0;
616
return 0;
617
}
618
619
static int snd_msnd_capture_trigger(struct snd_pcm_substream *substream,
620
int cmd)
621
{
622
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
623
624
if (cmd == SNDRV_PCM_TRIGGER_START) {
625
chip->last_recbank = -1;
626
set_bit(F_READING, &chip->flags);
627
if (snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_START) == 0)
628
return 0;
629
630
clear_bit(F_READING, &chip->flags);
631
} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
632
clear_bit(F_READING, &chip->flags);
633
snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
634
return 0;
635
}
636
return -EINVAL;
637
}
638
639
640
static snd_pcm_uframes_t
641
snd_msnd_capture_pointer(struct snd_pcm_substream *substream)
642
{
643
struct snd_pcm_runtime *runtime = substream->runtime;
644
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
645
646
return bytes_to_frames(runtime, chip->captureDMAPos);
647
}
648
649
650
static int snd_msnd_capture_hw_params(struct snd_pcm_substream *substream,
651
struct snd_pcm_hw_params *params)
652
{
653
int i;
654
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
655
void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
656
657
chip->capture_sample_size = snd_pcm_format_width(params_format(params));
658
chip->capture_channels = params_channels(params);
659
chip->capture_sample_rate = params_rate(params);
660
661
for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
662
writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
663
writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
664
writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
665
}
666
return 0;
667
}
668
669
670
static struct snd_pcm_ops snd_msnd_capture_ops = {
671
.open = snd_msnd_capture_open,
672
.close = snd_msnd_capture_close,
673
.ioctl = snd_pcm_lib_ioctl,
674
.hw_params = snd_msnd_capture_hw_params,
675
.prepare = snd_msnd_capture_prepare,
676
.trigger = snd_msnd_capture_trigger,
677
.pointer = snd_msnd_capture_pointer,
678
};
679
680
681
int snd_msnd_pcm(struct snd_card *card, int device,
682
struct snd_pcm **rpcm)
683
{
684
struct snd_msnd *chip = card->private_data;
685
struct snd_pcm *pcm;
686
int err;
687
688
err = snd_pcm_new(card, "MSNDPINNACLE", device, 1, 1, &pcm);
689
if (err < 0)
690
return err;
691
692
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_msnd_playback_ops);
693
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_msnd_capture_ops);
694
695
pcm->private_data = chip;
696
strcpy(pcm->name, "Hurricane");
697
698
699
if (rpcm)
700
*rpcm = pcm;
701
return 0;
702
}
703
EXPORT_SYMBOL(snd_msnd_pcm);
704
705
MODULE_DESCRIPTION("Common routines for Turtle Beach Multisound drivers");
706
MODULE_LICENSE("GPL");
707
708
709