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
44void snd_msnd_init_queue(void __iomem *base, int start, int size)
45{
46 writew(PCTODSP_BASED(start), addr: base + JQS_wStart);
47 writew(PCTODSP_OFFSET(size) - 1, addr: base + JQS_wSize);
48 writew(val: 0, addr: base + JQS_wHead);
49 writew(val: 0, addr: base + JQS_wTail);
50}
51EXPORT_SYMBOL(snd_msnd_init_queue);
52
53static 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(port: io + HP_ISR) & HPISR_TXDE)
60 return 0;
61
62 return -EIO;
63}
64
65static 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(port: io + HP_CVR) & HPCVR_HC))
72 return 0;
73
74 return -EIO;
75}
76
77int snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd)
78{
79 guard(spinlock_irqsave)(l: &dev->lock);
80 if (snd_msnd_wait_HC0(dev) == 0) {
81 outb(value: cmd, port: 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}
89EXPORT_SYMBOL(snd_msnd_send_dsp_cmd);
90
91int 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(value: high, port: io + HP_TXH);
98 outb(value: mid, port: io + HP_TXM);
99 outb(value: low, port: 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}
107EXPORT_SYMBOL(snd_msnd_send_word);
108
109int 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(port: dev->io + HP_RXL);
124 inb(port: dev->io + HP_CVR);
125
126 return 0;
127}
128EXPORT_SYMBOL(snd_msnd_upload_host);
129
130int 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)(l: &dev->lock);
138 if (snd_msnd_wait_TXDE(dev) == 0) {
139 outb(inb(port: dev->io + HP_ICR) | HPICR_TREQ, port: dev->io + HP_ICR);
140 if (dev->type == msndClassic)
141 outb(value: dev->irqid, port: dev->io + HP_IRQM);
142
143 outb(inb(port: dev->io + HP_ICR) & ~HPICR_TREQ, port: dev->io + HP_ICR);
144 outb(inb(port: dev->io + HP_ICR) | HPICR_RREQ, port: dev->io + HP_ICR);
145 enable_irq(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}
155EXPORT_SYMBOL(snd_msnd_enable_irq);
156
157int 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)(l: &dev->lock);
169 if (snd_msnd_wait_TXDE(dev) == 0) {
170 outb(inb(port: dev->io + HP_ICR) & ~HPICR_RREQ, port: dev->io + HP_ICR);
171 if (dev->type == msndClassic)
172 outb(HPIRQ_NONE, port: dev->io + HP_IRQM);
173 disable_irq(irq: dev->irq);
174 return 0;
175 }
176
177 dev_dbg(dev->card->dev, LOGNAME ": Disable IRQ failed\n");
178
179 return -EIO;
180}
181EXPORT_SYMBOL(snd_msnd_disable_irq);
182
183static 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
189static 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, addr: &chip->flags);
194/* interruptible_sleep_on_timeout(
195 &chip->writeflush,
196 get_play_delay_jiffies(&chip, chip->DAPF.len));*/
197 clear_bit(F_WRITEFLUSH, addr: &chip->flags);
198 if (!signal_pending(current))
199 schedule_timeout_interruptible(
200 timeout: get_play_delay_jiffies(chip, size: chip->play_period_bytes));
201 clear_bit(F_WRITING, addr: &chip->flags);
202}
203
204void 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, addr: &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, addr: &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, addr: &chip->flags);
229 }
230}
231EXPORT_SYMBOL(snd_msnd_dsp_halt);
232
233
234int 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(addr: chip->DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
242 if (wTmp > readw(addr: chip->DARQ + JQS_wSize))
243 wTmp = 0;
244 while (wTmp == readw(addr: chip->DARQ + JQS_wHead) && timeout--)
245 udelay(usec: 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(addr: pDAQ) != PCTODSP_BASED(0x3000))
253 offset = 0x3000;
254 writew(PCTODSP_BASED(offset), addr: pDAQ);
255 }
256
257 writew(val: wTmp, addr: 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}
281EXPORT_SYMBOL(snd_msnd_DARQ);
282
283int 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(addr: chip->DAPQ + JQS_wTail);
293 while (DAPQ_tail != readw(addr: 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(val: chip->play_period_bytes, addr: 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(addr: DAQD + DAQDS_wStart) != PCTODSP_BASED(0x0))
313 offset = 0;
314
315 writew(PCTODSP_BASED(offset), addr: DAQD + DAQDS_wStart);
316 }
317 ++nbanks;
318
319 /* Then advance the tail */
320 DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
321 writew(val: DAPQ_tail, addr: 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}
331EXPORT_SYMBOL(snd_msnd_DAPQ);
332
333static 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), addr: chip->DAPQ + JQS_wHead);
344 writew(PCTODSP_OFFSET(0 * DAQDS__size), addr: 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 addr: pDAQ + DAQDS_wStart);
351 writew(val: 0, addr: pDAQ + DAQDS_wSize);
352 writew(val: 1, addr: pDAQ + DAQDS_wFormat);
353 writew(val: chip->play_sample_size, addr: pDAQ + DAQDS_wSampleSize);
354 writew(val: chip->play_channels, addr: pDAQ + DAQDS_wChannels);
355 writew(val: chip->play_sample_rate, addr: pDAQ + DAQDS_wSampleRate);
356 writew(HIMT_PLAY_DONE * 0x100 + n, addr: pDAQ + DAQDS_wIntMsg);
357 writew(val: n, addr: pDAQ + DAQDS_wFlags);
358 }
359}
360
361static 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), addr: chip->DARQ + JQS_wHead);
374 writew(PCTODSP_OFFSET(chip->last_recbank * DAQDS__size),
375 addr: 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), addr: pDAQ + DAQDS_wStart);
394 writew(val: pcm_count, addr: pDAQ + DAQDS_wSize);
395 writew(val: 1, addr: pDAQ + DAQDS_wFormat);
396 writew(val: chip->capture_sample_size, addr: pDAQ + DAQDS_wSampleSize);
397 writew(val: chip->capture_channels, addr: pDAQ + DAQDS_wChannels);
398 writew(val: chip->capture_sample_rate, addr: pDAQ + DAQDS_wSampleRate);
399 writew(HIMT_RECORD_DONE * 0x100 + n, addr: pDAQ + DAQDS_wIntMsg);
400 writew(val: n, addr: pDAQ + DAQDS_wFlags);
401 }
402}
403
404static 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
423static 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
443static 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, addr: &chip->flags);
449 clear_bit(F_WRITING, addr: &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
461static 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, addr: &chip->flags);
467 return 0;
468}
469
470
471static 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(format: params_format(p: params));
479 chip->play_channels = params_channels(p: params);
480 chip->play_sample_rate = params_rate(p: params);
481
482 for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
483 writew(val: chip->play_sample_size, addr: pDAQ + DAQDS_wSampleSize);
484 writew(val: chip->play_channels, addr: pDAQ + DAQDS_wChannels);
485 writew(val: chip->play_sample_rate, addr: 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
494static 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
506static 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, addr: &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, addr: &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
531static snd_pcm_uframes_t
532snd_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(runtime: substream->runtime, size: chip->playDMAPos);
537}
538
539
540static 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
550static 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, addr: &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
566static 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, addr: &chip->flags);
572 return 0;
573}
574
575static 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
587static 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, addr: &chip->flags);
595 if (snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_START) == 0)
596 return 0;
597
598 clear_bit(F_READING, addr: &chip->flags);
599 } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
600 clear_bit(F_READING, addr: &chip->flags);
601 snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
602 return 0;
603 }
604 return -EINVAL;
605}
606
607
608static snd_pcm_uframes_t
609snd_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, size: chip->captureDMAPos);
615}
616
617
618static 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(format: params_format(p: params));
626 chip->capture_channels = params_channels(p: params);
627 chip->capture_sample_rate = params_rate(p: params);
628
629 for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
630 writew(val: chip->capture_sample_size, addr: pDAQ + DAQDS_wSampleSize);
631 writew(val: chip->capture_channels, addr: pDAQ + DAQDS_wChannels);
632 writew(val: chip->capture_sample_rate, addr: pDAQ + DAQDS_wSampleRate);
633 }
634 return 0;
635}
636
637
638static 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
649int 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, id: "MSNDPINNACLE", device, playback_count: 1, capture_count: 1, rpcm: &pcm);
656 if (err < 0)
657 return err;
658
659 snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_PLAYBACK, ops: &snd_msnd_playback_ops);
660 snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_CAPTURE, ops: &snd_msnd_capture_ops);
661
662 pcm->private_data = chip;
663 strscpy(pcm->name, "Hurricane");
664
665 return 0;
666}
667EXPORT_SYMBOL(snd_msnd_pcm);
668
669MODULE_DESCRIPTION("Common routines for Turtle Beach Multisound drivers");
670MODULE_LICENSE("GPL");
671
672

source code of linux/sound/isa/msnd/msnd.c