18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/********************************************************************* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * 2002/06/30 Karsten Wiese: 58c2ecf20Sopenharmony_ci * removed kernel-version dependencies. 68c2ecf20Sopenharmony_ci * ripped from linux kernel 2.4.18 (OSS Implementation) by me. 78c2ecf20Sopenharmony_ci * In the OSS Version, this file is compiled to a separate MODULE, 88c2ecf20Sopenharmony_ci * that is used by the pinnacle and the classic driver. 98c2ecf20Sopenharmony_ci * since there is no classic driver for alsa yet (i dont have a classic 108c2ecf20Sopenharmony_ci * & writing one blindfold is difficult) this file's object is statically 118c2ecf20Sopenharmony_ci * linked into the pinnacle-driver-module for now. look for the string 128c2ecf20Sopenharmony_ci * "uncomment this to make this a module again" 138c2ecf20Sopenharmony_ci * to do guess what. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * the following is a copy of the 2.4.18 OSS FREE file-heading comment: 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * msnd.c - Driver Base 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Turtle Beach MultiSound Sound Card Driver for Linux 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Copyright (C) 1998 Andrew Veliath 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci ********************************************************************/ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/kernel.h> 268c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 278c2ecf20Sopenharmony_ci#include <linux/types.h> 288c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 298c2ecf20Sopenharmony_ci#include <linux/io.h> 308c2ecf20Sopenharmony_ci#include <linux/fs.h> 318c2ecf20Sopenharmony_ci#include <linux/delay.h> 328c2ecf20Sopenharmony_ci#include <linux/module.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <sound/core.h> 358c2ecf20Sopenharmony_ci#include <sound/initval.h> 368c2ecf20Sopenharmony_ci#include <sound/pcm.h> 378c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "msnd.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define LOGNAME "msnd" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_civoid snd_msnd_init_queue(void __iomem *base, int start, int size) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci writew(PCTODSP_BASED(start), base + JQS_wStart); 478c2ecf20Sopenharmony_ci writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize); 488c2ecf20Sopenharmony_ci writew(0, base + JQS_wHead); 498c2ecf20Sopenharmony_ci writew(0, base + JQS_wTail); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_msnd_init_queue); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int snd_msnd_wait_TXDE(struct snd_msnd *dev) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci unsigned int io = dev->io; 568c2ecf20Sopenharmony_ci int timeout = 1000; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci while (timeout-- > 0) 598c2ecf20Sopenharmony_ci if (inb(io + HP_ISR) & HPISR_TXDE) 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return -EIO; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int snd_msnd_wait_HC0(struct snd_msnd *dev) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci unsigned int io = dev->io; 688c2ecf20Sopenharmony_ci int timeout = 1000; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci while (timeout-- > 0) 718c2ecf20Sopenharmony_ci if (!(inb(io + HP_CVR) & HPCVR_HC)) 728c2ecf20Sopenharmony_ci return 0; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return -EIO; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciint snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci unsigned long flags; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 828c2ecf20Sopenharmony_ci if (snd_msnd_wait_HC0(dev) == 0) { 838c2ecf20Sopenharmony_ci outb(cmd, dev->io + HP_CVR); 848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci snd_printd(KERN_ERR LOGNAME ": Send DSP command timeout\n"); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return -EIO; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_msnd_send_dsp_cmd); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ciint snd_msnd_send_word(struct snd_msnd *dev, unsigned char high, 968c2ecf20Sopenharmony_ci unsigned char mid, unsigned char low) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci unsigned int io = dev->io; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (snd_msnd_wait_TXDE(dev) == 0) { 1018c2ecf20Sopenharmony_ci outb(high, io + HP_TXH); 1028c2ecf20Sopenharmony_ci outb(mid, io + HP_TXM); 1038c2ecf20Sopenharmony_ci outb(low, io + HP_TXL); 1048c2ecf20Sopenharmony_ci return 0; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci snd_printd(KERN_ERR LOGNAME ": Send host word timeout\n"); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return -EIO; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_msnd_send_word); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ciint snd_msnd_upload_host(struct snd_msnd *dev, const u8 *bin, int len) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci int i; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (len % 3 != 0) { 1188c2ecf20Sopenharmony_ci snd_printk(KERN_ERR LOGNAME 1198c2ecf20Sopenharmony_ci ": Upload host data not multiple of 3!\n"); 1208c2ecf20Sopenharmony_ci return -EINVAL; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci for (i = 0; i < len; i += 3) 1248c2ecf20Sopenharmony_ci if (snd_msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2])) 1258c2ecf20Sopenharmony_ci return -EIO; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci inb(dev->io + HP_RXL); 1288c2ecf20Sopenharmony_ci inb(dev->io + HP_CVR); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_msnd_upload_host); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ciint snd_msnd_enable_irq(struct snd_msnd *dev) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci unsigned long flags; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (dev->irq_ref++) 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci snd_printdd(LOGNAME ": Enabling IRQ\n"); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 1448c2ecf20Sopenharmony_ci if (snd_msnd_wait_TXDE(dev) == 0) { 1458c2ecf20Sopenharmony_ci outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR); 1468c2ecf20Sopenharmony_ci if (dev->type == msndClassic) 1478c2ecf20Sopenharmony_ci outb(dev->irqid, dev->io + HP_IRQM); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR); 1508c2ecf20Sopenharmony_ci outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR); 1518c2ecf20Sopenharmony_ci enable_irq(dev->irq); 1528c2ecf20Sopenharmony_ci snd_msnd_init_queue(dev->DSPQ, dev->dspq_data_buff, 1538c2ecf20Sopenharmony_ci dev->dspq_buff_size); 1548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 1558c2ecf20Sopenharmony_ci return 0; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci snd_printd(KERN_ERR LOGNAME ": Enable IRQ failed\n"); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return -EIO; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_msnd_enable_irq); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ciint snd_msnd_disable_irq(struct snd_msnd *dev) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci unsigned long flags; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (--dev->irq_ref > 0) 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (dev->irq_ref < 0) 1738c2ecf20Sopenharmony_ci snd_printd(KERN_WARNING LOGNAME ": IRQ ref count is %d\n", 1748c2ecf20Sopenharmony_ci dev->irq_ref); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci snd_printdd(LOGNAME ": Disabling IRQ\n"); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 1798c2ecf20Sopenharmony_ci if (snd_msnd_wait_TXDE(dev) == 0) { 1808c2ecf20Sopenharmony_ci outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR); 1818c2ecf20Sopenharmony_ci if (dev->type == msndClassic) 1828c2ecf20Sopenharmony_ci outb(HPIRQ_NONE, dev->io + HP_IRQM); 1838c2ecf20Sopenharmony_ci disable_irq(dev->irq); 1848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci snd_printd(KERN_ERR LOGNAME ": Disable IRQ failed\n"); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return -EIO; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_msnd_disable_irq); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic inline long get_play_delay_jiffies(struct snd_msnd *chip, long size) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci long tmp = (size * HZ * chip->play_sample_size) / 8; 1988c2ecf20Sopenharmony_ci return tmp / (chip->play_sample_rate * chip->play_channels); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic void snd_msnd_dsp_write_flush(struct snd_msnd *chip) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci if (!(chip->mode & FMODE_WRITE) || !test_bit(F_WRITING, &chip->flags)) 2048c2ecf20Sopenharmony_ci return; 2058c2ecf20Sopenharmony_ci set_bit(F_WRITEFLUSH, &chip->flags); 2068c2ecf20Sopenharmony_ci/* interruptible_sleep_on_timeout( 2078c2ecf20Sopenharmony_ci &chip->writeflush, 2088c2ecf20Sopenharmony_ci get_play_delay_jiffies(&chip, chip->DAPF.len));*/ 2098c2ecf20Sopenharmony_ci clear_bit(F_WRITEFLUSH, &chip->flags); 2108c2ecf20Sopenharmony_ci if (!signal_pending(current)) 2118c2ecf20Sopenharmony_ci schedule_timeout_interruptible( 2128c2ecf20Sopenharmony_ci get_play_delay_jiffies(chip, chip->play_period_bytes)); 2138c2ecf20Sopenharmony_ci clear_bit(F_WRITING, &chip->flags); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_civoid snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci if ((file ? file->f_mode : chip->mode) & FMODE_READ) { 2198c2ecf20Sopenharmony_ci clear_bit(F_READING, &chip->flags); 2208c2ecf20Sopenharmony_ci snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP); 2218c2ecf20Sopenharmony_ci snd_msnd_disable_irq(chip); 2228c2ecf20Sopenharmony_ci if (file) { 2238c2ecf20Sopenharmony_ci snd_printd(KERN_INFO LOGNAME 2248c2ecf20Sopenharmony_ci ": Stopping read for %p\n", file); 2258c2ecf20Sopenharmony_ci chip->mode &= ~FMODE_READ; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci clear_bit(F_AUDIO_READ_INUSE, &chip->flags); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci if ((file ? file->f_mode : chip->mode) & FMODE_WRITE) { 2308c2ecf20Sopenharmony_ci if (test_bit(F_WRITING, &chip->flags)) { 2318c2ecf20Sopenharmony_ci snd_msnd_dsp_write_flush(chip); 2328c2ecf20Sopenharmony_ci snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP); 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci snd_msnd_disable_irq(chip); 2358c2ecf20Sopenharmony_ci if (file) { 2368c2ecf20Sopenharmony_ci snd_printd(KERN_INFO 2378c2ecf20Sopenharmony_ci LOGNAME ": Stopping write for %p\n", file); 2388c2ecf20Sopenharmony_ci chip->mode &= ~FMODE_WRITE; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_msnd_dsp_halt); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciint snd_msnd_DARQ(struct snd_msnd *chip, int bank) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci int /*size, n,*/ timeout = 3; 2498c2ecf20Sopenharmony_ci u16 wTmp; 2508c2ecf20Sopenharmony_ci /* void *DAQD; */ 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* Increment the tail and check for queue wrap */ 2538c2ecf20Sopenharmony_ci wTmp = readw(chip->DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size); 2548c2ecf20Sopenharmony_ci if (wTmp > readw(chip->DARQ + JQS_wSize)) 2558c2ecf20Sopenharmony_ci wTmp = 0; 2568c2ecf20Sopenharmony_ci while (wTmp == readw(chip->DARQ + JQS_wHead) && timeout--) 2578c2ecf20Sopenharmony_ci udelay(1); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (chip->capturePeriods == 2) { 2608c2ecf20Sopenharmony_ci void __iomem *pDAQ = chip->mappedbase + DARQ_DATA_BUFF + 2618c2ecf20Sopenharmony_ci bank * DAQDS__size + DAQDS_wStart; 2628c2ecf20Sopenharmony_ci unsigned short offset = 0x3000 + chip->capturePeriodBytes; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (readw(pDAQ) != PCTODSP_BASED(0x3000)) 2658c2ecf20Sopenharmony_ci offset = 0x3000; 2668c2ecf20Sopenharmony_ci writew(PCTODSP_BASED(offset), pDAQ); 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci writew(wTmp, chip->DARQ + JQS_wTail); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci#if 0 2728c2ecf20Sopenharmony_ci /* Get our digital audio queue struct */ 2738c2ecf20Sopenharmony_ci DAQD = bank * DAQDS__size + chip->mappedbase + DARQ_DATA_BUFF; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* Get length of data */ 2768c2ecf20Sopenharmony_ci size = readw(DAQD + DAQDS_wSize); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Read data from the head (unprotected bank 1 access okay 2798c2ecf20Sopenharmony_ci since this is only called inside an interrupt) */ 2808c2ecf20Sopenharmony_ci outb(HPBLKSEL_1, chip->io + HP_BLKS); 2818c2ecf20Sopenharmony_ci n = msnd_fifo_write(&chip->DARF, 2828c2ecf20Sopenharmony_ci (char *)(chip->base + bank * DAR_BUFF_SIZE), 2838c2ecf20Sopenharmony_ci size, 0); 2848c2ecf20Sopenharmony_ci if (n <= 0) { 2858c2ecf20Sopenharmony_ci outb(HPBLKSEL_0, chip->io + HP_BLKS); 2868c2ecf20Sopenharmony_ci return n; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci outb(HPBLKSEL_0, chip->io + HP_BLKS); 2898c2ecf20Sopenharmony_ci#endif 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return 1; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_msnd_DARQ); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ciint snd_msnd_DAPQ(struct snd_msnd *chip, int start) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci u16 DAPQ_tail; 2988c2ecf20Sopenharmony_ci int protect = start, nbanks = 0; 2998c2ecf20Sopenharmony_ci void __iomem *DAQD; 3008c2ecf20Sopenharmony_ci static int play_banks_submitted; 3018c2ecf20Sopenharmony_ci /* unsigned long flags; 3028c2ecf20Sopenharmony_ci spin_lock_irqsave(&chip->lock, flags); not necessary */ 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci DAPQ_tail = readw(chip->DAPQ + JQS_wTail); 3058c2ecf20Sopenharmony_ci while (DAPQ_tail != readw(chip->DAPQ + JQS_wHead) || start) { 3068c2ecf20Sopenharmony_ci int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (start) { 3098c2ecf20Sopenharmony_ci start = 0; 3108c2ecf20Sopenharmony_ci play_banks_submitted = 0; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* Get our digital audio queue struct */ 3148c2ecf20Sopenharmony_ci DAQD = bank_num * DAQDS__size + chip->mappedbase + 3158c2ecf20Sopenharmony_ci DAPQ_DATA_BUFF; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Write size of this bank */ 3188c2ecf20Sopenharmony_ci writew(chip->play_period_bytes, DAQD + DAQDS_wSize); 3198c2ecf20Sopenharmony_ci if (play_banks_submitted < 3) 3208c2ecf20Sopenharmony_ci ++play_banks_submitted; 3218c2ecf20Sopenharmony_ci else if (chip->playPeriods == 2) { 3228c2ecf20Sopenharmony_ci unsigned short offset = chip->play_period_bytes; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (readw(DAQD + DAQDS_wStart) != PCTODSP_BASED(0x0)) 3258c2ecf20Sopenharmony_ci offset = 0; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci writew(PCTODSP_BASED(offset), DAQD + DAQDS_wStart); 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci ++nbanks; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* Then advance the tail */ 3328c2ecf20Sopenharmony_ci /* 3338c2ecf20Sopenharmony_ci if (protect) 3348c2ecf20Sopenharmony_ci snd_printd(KERN_INFO "B %X %lX\n", 3358c2ecf20Sopenharmony_ci bank_num, xtime.tv_usec); 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size); 3398c2ecf20Sopenharmony_ci writew(DAPQ_tail, chip->DAPQ + JQS_wTail); 3408c2ecf20Sopenharmony_ci /* Tell the DSP to play the bank */ 3418c2ecf20Sopenharmony_ci snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_START); 3428c2ecf20Sopenharmony_ci if (protect) 3438c2ecf20Sopenharmony_ci if (2 == bank_num) 3448c2ecf20Sopenharmony_ci break; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci /* 3478c2ecf20Sopenharmony_ci if (protect) 3488c2ecf20Sopenharmony_ci snd_printd(KERN_INFO "%lX\n", xtime.tv_usec); 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci /* spin_unlock_irqrestore(&chip->lock, flags); not necessary */ 3518c2ecf20Sopenharmony_ci return nbanks; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_msnd_DAPQ); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic void snd_msnd_play_reset_queue(struct snd_msnd *chip, 3568c2ecf20Sopenharmony_ci unsigned int pcm_periods, 3578c2ecf20Sopenharmony_ci unsigned int pcm_count) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci int n; 3608c2ecf20Sopenharmony_ci void __iomem *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci chip->last_playbank = -1; 3638c2ecf20Sopenharmony_ci chip->playLimit = pcm_count * (pcm_periods - 1); 3648c2ecf20Sopenharmony_ci chip->playPeriods = pcm_periods; 3658c2ecf20Sopenharmony_ci writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wHead); 3668c2ecf20Sopenharmony_ci writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wTail); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci chip->play_period_bytes = pcm_count; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) { 3718c2ecf20Sopenharmony_ci writew(PCTODSP_BASED((u32)(pcm_count * n)), 3728c2ecf20Sopenharmony_ci pDAQ + DAQDS_wStart); 3738c2ecf20Sopenharmony_ci writew(0, pDAQ + DAQDS_wSize); 3748c2ecf20Sopenharmony_ci writew(1, pDAQ + DAQDS_wFormat); 3758c2ecf20Sopenharmony_ci writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize); 3768c2ecf20Sopenharmony_ci writew(chip->play_channels, pDAQ + DAQDS_wChannels); 3778c2ecf20Sopenharmony_ci writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate); 3788c2ecf20Sopenharmony_ci writew(HIMT_PLAY_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg); 3798c2ecf20Sopenharmony_ci writew(n, pDAQ + DAQDS_wFlags); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic void snd_msnd_capture_reset_queue(struct snd_msnd *chip, 3848c2ecf20Sopenharmony_ci unsigned int pcm_periods, 3858c2ecf20Sopenharmony_ci unsigned int pcm_count) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci int n; 3888c2ecf20Sopenharmony_ci void __iomem *pDAQ; 3898c2ecf20Sopenharmony_ci /* unsigned long flags; */ 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); */ 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci chip->last_recbank = 2; 3948c2ecf20Sopenharmony_ci chip->captureLimit = pcm_count * (pcm_periods - 1); 3958c2ecf20Sopenharmony_ci chip->capturePeriods = pcm_periods; 3968c2ecf20Sopenharmony_ci writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DARQ + JQS_wHead); 3978c2ecf20Sopenharmony_ci writew(PCTODSP_OFFSET(chip->last_recbank * DAQDS__size), 3988c2ecf20Sopenharmony_ci chip->DARQ + JQS_wTail); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci#if 0 /* Critical section: bank 1 access. this is how the OSS driver does it:*/ 4018c2ecf20Sopenharmony_ci spin_lock_irqsave(&chip->lock, flags); 4028c2ecf20Sopenharmony_ci outb(HPBLKSEL_1, chip->io + HP_BLKS); 4038c2ecf20Sopenharmony_ci memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3); 4048c2ecf20Sopenharmony_ci outb(HPBLKSEL_0, chip->io + HP_BLKS); 4058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chip->lock, flags); 4068c2ecf20Sopenharmony_ci#endif 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci chip->capturePeriodBytes = pcm_count; 4098c2ecf20Sopenharmony_ci snd_printdd("snd_msnd_capture_reset_queue() %i\n", pcm_count); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci pDAQ = chip->mappedbase + DARQ_DATA_BUFF; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) { 4148c2ecf20Sopenharmony_ci u32 tmp = pcm_count * n; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci writew(PCTODSP_BASED(tmp + 0x3000), pDAQ + DAQDS_wStart); 4178c2ecf20Sopenharmony_ci writew(pcm_count, pDAQ + DAQDS_wSize); 4188c2ecf20Sopenharmony_ci writew(1, pDAQ + DAQDS_wFormat); 4198c2ecf20Sopenharmony_ci writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize); 4208c2ecf20Sopenharmony_ci writew(chip->capture_channels, pDAQ + DAQDS_wChannels); 4218c2ecf20Sopenharmony_ci writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate); 4228c2ecf20Sopenharmony_ci writew(HIMT_RECORD_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg); 4238c2ecf20Sopenharmony_ci writew(n, pDAQ + DAQDS_wFlags); 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_msnd_playback = { 4288c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_MMAP | 4298c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 4308c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 4318c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BATCH, 4328c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, 4338c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 4348c2ecf20Sopenharmony_ci .rate_min = 8000, 4358c2ecf20Sopenharmony_ci .rate_max = 48000, 4368c2ecf20Sopenharmony_ci .channels_min = 1, 4378c2ecf20Sopenharmony_ci .channels_max = 2, 4388c2ecf20Sopenharmony_ci .buffer_bytes_max = 0x3000, 4398c2ecf20Sopenharmony_ci .period_bytes_min = 0x40, 4408c2ecf20Sopenharmony_ci .period_bytes_max = 0x1800, 4418c2ecf20Sopenharmony_ci .periods_min = 2, 4428c2ecf20Sopenharmony_ci .periods_max = 3, 4438c2ecf20Sopenharmony_ci .fifo_size = 0, 4448c2ecf20Sopenharmony_ci}; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_msnd_capture = { 4478c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_MMAP | 4488c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 4498c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 4508c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BATCH, 4518c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, 4528c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 4538c2ecf20Sopenharmony_ci .rate_min = 8000, 4548c2ecf20Sopenharmony_ci .rate_max = 48000, 4558c2ecf20Sopenharmony_ci .channels_min = 1, 4568c2ecf20Sopenharmony_ci .channels_max = 2, 4578c2ecf20Sopenharmony_ci .buffer_bytes_max = 0x3000, 4588c2ecf20Sopenharmony_ci .period_bytes_min = 0x40, 4598c2ecf20Sopenharmony_ci .period_bytes_max = 0x1800, 4608c2ecf20Sopenharmony_ci .periods_min = 2, 4618c2ecf20Sopenharmony_ci .periods_max = 3, 4628c2ecf20Sopenharmony_ci .fifo_size = 0, 4638c2ecf20Sopenharmony_ci}; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic int snd_msnd_playback_open(struct snd_pcm_substream *substream) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 4698c2ecf20Sopenharmony_ci struct snd_msnd *chip = snd_pcm_substream_chip(substream); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci set_bit(F_AUDIO_WRITE_INUSE, &chip->flags); 4728c2ecf20Sopenharmony_ci clear_bit(F_WRITING, &chip->flags); 4738c2ecf20Sopenharmony_ci snd_msnd_enable_irq(chip); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci runtime->dma_area = (__force void *)chip->mappedbase; 4768c2ecf20Sopenharmony_ci runtime->dma_bytes = 0x3000; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci chip->playback_substream = substream; 4798c2ecf20Sopenharmony_ci runtime->hw = snd_msnd_playback; 4808c2ecf20Sopenharmony_ci return 0; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic int snd_msnd_playback_close(struct snd_pcm_substream *substream) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct snd_msnd *chip = snd_pcm_substream_chip(substream); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci snd_msnd_disable_irq(chip); 4888c2ecf20Sopenharmony_ci clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags); 4898c2ecf20Sopenharmony_ci return 0; 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic int snd_msnd_playback_hw_params(struct snd_pcm_substream *substream, 4948c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci int i; 4978c2ecf20Sopenharmony_ci struct snd_msnd *chip = snd_pcm_substream_chip(substream); 4988c2ecf20Sopenharmony_ci void __iomem *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci chip->play_sample_size = snd_pcm_format_width(params_format(params)); 5018c2ecf20Sopenharmony_ci chip->play_channels = params_channels(params); 5028c2ecf20Sopenharmony_ci chip->play_sample_rate = params_rate(params); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) { 5058c2ecf20Sopenharmony_ci writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize); 5068c2ecf20Sopenharmony_ci writew(chip->play_channels, pDAQ + DAQDS_wChannels); 5078c2ecf20Sopenharmony_ci writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate); 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci /* dont do this here: 5108c2ecf20Sopenharmony_ci * snd_msnd_calibrate_adc(chip->play_sample_rate); 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci return 0; 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic int snd_msnd_playback_prepare(struct snd_pcm_substream *substream) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci struct snd_msnd *chip = snd_pcm_substream_chip(substream); 5198c2ecf20Sopenharmony_ci unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream); 5208c2ecf20Sopenharmony_ci unsigned int pcm_count = snd_pcm_lib_period_bytes(substream); 5218c2ecf20Sopenharmony_ci unsigned int pcm_periods = pcm_size / pcm_count; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci snd_msnd_play_reset_queue(chip, pcm_periods, pcm_count); 5248c2ecf20Sopenharmony_ci chip->playDMAPos = 0; 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic int snd_msnd_playback_trigger(struct snd_pcm_substream *substream, 5298c2ecf20Sopenharmony_ci int cmd) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci struct snd_msnd *chip = snd_pcm_substream_chip(substream); 5328c2ecf20Sopenharmony_ci int result = 0; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) { 5358c2ecf20Sopenharmony_ci snd_printdd("snd_msnd_playback_trigger(START)\n"); 5368c2ecf20Sopenharmony_ci chip->banksPlayed = 0; 5378c2ecf20Sopenharmony_ci set_bit(F_WRITING, &chip->flags); 5388c2ecf20Sopenharmony_ci snd_msnd_DAPQ(chip, 1); 5398c2ecf20Sopenharmony_ci } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { 5408c2ecf20Sopenharmony_ci snd_printdd("snd_msnd_playback_trigger(STop)\n"); 5418c2ecf20Sopenharmony_ci /* interrupt diagnostic, comment this out later */ 5428c2ecf20Sopenharmony_ci clear_bit(F_WRITING, &chip->flags); 5438c2ecf20Sopenharmony_ci snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP); 5448c2ecf20Sopenharmony_ci } else { 5458c2ecf20Sopenharmony_ci snd_printd(KERN_ERR "snd_msnd_playback_trigger(?????)\n"); 5468c2ecf20Sopenharmony_ci result = -EINVAL; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci snd_printdd("snd_msnd_playback_trigger() ENDE\n"); 5508c2ecf20Sopenharmony_ci return result; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t 5548c2ecf20Sopenharmony_cisnd_msnd_playback_pointer(struct snd_pcm_substream *substream) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci struct snd_msnd *chip = snd_pcm_substream_chip(substream); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci return bytes_to_frames(substream->runtime, chip->playDMAPos); 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_msnd_playback_ops = { 5638c2ecf20Sopenharmony_ci .open = snd_msnd_playback_open, 5648c2ecf20Sopenharmony_ci .close = snd_msnd_playback_close, 5658c2ecf20Sopenharmony_ci .hw_params = snd_msnd_playback_hw_params, 5668c2ecf20Sopenharmony_ci .prepare = snd_msnd_playback_prepare, 5678c2ecf20Sopenharmony_ci .trigger = snd_msnd_playback_trigger, 5688c2ecf20Sopenharmony_ci .pointer = snd_msnd_playback_pointer, 5698c2ecf20Sopenharmony_ci}; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic int snd_msnd_capture_open(struct snd_pcm_substream *substream) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 5748c2ecf20Sopenharmony_ci struct snd_msnd *chip = snd_pcm_substream_chip(substream); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci set_bit(F_AUDIO_READ_INUSE, &chip->flags); 5778c2ecf20Sopenharmony_ci snd_msnd_enable_irq(chip); 5788c2ecf20Sopenharmony_ci runtime->dma_area = (__force void *)chip->mappedbase + 0x3000; 5798c2ecf20Sopenharmony_ci runtime->dma_bytes = 0x3000; 5808c2ecf20Sopenharmony_ci memset(runtime->dma_area, 0, runtime->dma_bytes); 5818c2ecf20Sopenharmony_ci chip->capture_substream = substream; 5828c2ecf20Sopenharmony_ci runtime->hw = snd_msnd_capture; 5838c2ecf20Sopenharmony_ci return 0; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int snd_msnd_capture_close(struct snd_pcm_substream *substream) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct snd_msnd *chip = snd_pcm_substream_chip(substream); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci snd_msnd_disable_irq(chip); 5918c2ecf20Sopenharmony_ci clear_bit(F_AUDIO_READ_INUSE, &chip->flags); 5928c2ecf20Sopenharmony_ci return 0; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic int snd_msnd_capture_prepare(struct snd_pcm_substream *substream) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci struct snd_msnd *chip = snd_pcm_substream_chip(substream); 5988c2ecf20Sopenharmony_ci unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream); 5998c2ecf20Sopenharmony_ci unsigned int pcm_count = snd_pcm_lib_period_bytes(substream); 6008c2ecf20Sopenharmony_ci unsigned int pcm_periods = pcm_size / pcm_count; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci snd_msnd_capture_reset_queue(chip, pcm_periods, pcm_count); 6038c2ecf20Sopenharmony_ci chip->captureDMAPos = 0; 6048c2ecf20Sopenharmony_ci return 0; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int snd_msnd_capture_trigger(struct snd_pcm_substream *substream, 6088c2ecf20Sopenharmony_ci int cmd) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct snd_msnd *chip = snd_pcm_substream_chip(substream); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_START) { 6138c2ecf20Sopenharmony_ci chip->last_recbank = -1; 6148c2ecf20Sopenharmony_ci set_bit(F_READING, &chip->flags); 6158c2ecf20Sopenharmony_ci if (snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_START) == 0) 6168c2ecf20Sopenharmony_ci return 0; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci clear_bit(F_READING, &chip->flags); 6198c2ecf20Sopenharmony_ci } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { 6208c2ecf20Sopenharmony_ci clear_bit(F_READING, &chip->flags); 6218c2ecf20Sopenharmony_ci snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP); 6228c2ecf20Sopenharmony_ci return 0; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci return -EINVAL; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t 6298c2ecf20Sopenharmony_cisnd_msnd_capture_pointer(struct snd_pcm_substream *substream) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 6328c2ecf20Sopenharmony_ci struct snd_msnd *chip = snd_pcm_substream_chip(substream); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci return bytes_to_frames(runtime, chip->captureDMAPos); 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic int snd_msnd_capture_hw_params(struct snd_pcm_substream *substream, 6398c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci int i; 6428c2ecf20Sopenharmony_ci struct snd_msnd *chip = snd_pcm_substream_chip(substream); 6438c2ecf20Sopenharmony_ci void __iomem *pDAQ = chip->mappedbase + DARQ_DATA_BUFF; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci chip->capture_sample_size = snd_pcm_format_width(params_format(params)); 6468c2ecf20Sopenharmony_ci chip->capture_channels = params_channels(params); 6478c2ecf20Sopenharmony_ci chip->capture_sample_rate = params_rate(params); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) { 6508c2ecf20Sopenharmony_ci writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize); 6518c2ecf20Sopenharmony_ci writew(chip->capture_channels, pDAQ + DAQDS_wChannels); 6528c2ecf20Sopenharmony_ci writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate); 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci return 0; 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_msnd_capture_ops = { 6598c2ecf20Sopenharmony_ci .open = snd_msnd_capture_open, 6608c2ecf20Sopenharmony_ci .close = snd_msnd_capture_close, 6618c2ecf20Sopenharmony_ci .hw_params = snd_msnd_capture_hw_params, 6628c2ecf20Sopenharmony_ci .prepare = snd_msnd_capture_prepare, 6638c2ecf20Sopenharmony_ci .trigger = snd_msnd_capture_trigger, 6648c2ecf20Sopenharmony_ci .pointer = snd_msnd_capture_pointer, 6658c2ecf20Sopenharmony_ci}; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ciint snd_msnd_pcm(struct snd_card *card, int device) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci struct snd_msnd *chip = card->private_data; 6718c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 6728c2ecf20Sopenharmony_ci int err; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci err = snd_pcm_new(card, "MSNDPINNACLE", device, 1, 1, &pcm); 6758c2ecf20Sopenharmony_ci if (err < 0) 6768c2ecf20Sopenharmony_ci return err; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_msnd_playback_ops); 6798c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_msnd_capture_ops); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci pcm->private_data = chip; 6828c2ecf20Sopenharmony_ci strcpy(pcm->name, "Hurricane"); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci return 0; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_msnd_pcm); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Common routines for Turtle Beach Multisound drivers"); 6898c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6908c2ecf20Sopenharmony_ci 691