~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/isa/msnd/msnd.c

Version: ~ [ linux-5.4-rc7 ] ~ [ linux-5.3.11 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.84 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.154 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.201 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.201 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.77 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp