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

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

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

~ [ 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