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