2019-05-20 10:19:02 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2009-01-24 15:35:28 +03:00
/*********************************************************************
*
* 2002 / 06 / 30 Karsten Wiese :
* removed kernel - version dependencies .
* ripped from linux kernel 2.4 .18 ( OSS Implementation ) by me .
* In the OSS Version , this file is compiled to a separate MODULE ,
* that is used by the pinnacle and the classic driver .
* since there is no classic driver for alsa yet ( i dont have a classic
* & writing one blindfold is difficult ) this file ' s object is statically
* linked into the pinnacle - driver - module for now . look for the string
* " uncomment this to make this a module again "
* to do guess what .
*
* the following is a copy of the 2.4 .18 OSS FREE file - heading comment :
*
* msnd . c - Driver Base
*
* Turtle Beach MultiSound Sound Card Driver for Linux
*
* Copyright ( C ) 1998 Andrew Veliath
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/kernel.h>
2017-02-02 21:15:33 +03:00
# include <linux/sched/signal.h>
2009-01-24 15:35:28 +03:00
# include <linux/types.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/fs.h>
# include <linux/delay.h>
2011-07-15 20:38:28 +04:00
# include <linux/module.h>
2009-01-24 15:35:28 +03:00
# include <sound/core.h>
# include <sound/initval.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include "msnd.h"
# define LOGNAME "msnd"
2018-07-26 00:00:47 +03:00
void snd_msnd_init_queue ( void __iomem * base , int start , int size )
2009-01-24 15:35:28 +03:00
{
writew ( PCTODSP_BASED ( start ) , base + JQS_wStart ) ;
writew ( PCTODSP_OFFSET ( size ) - 1 , base + JQS_wSize ) ;
writew ( 0 , base + JQS_wHead ) ;
writew ( 0 , base + JQS_wTail ) ;
}
EXPORT_SYMBOL ( snd_msnd_init_queue ) ;
static int snd_msnd_wait_TXDE ( struct snd_msnd * dev )
{
unsigned int io = dev - > io ;
int timeout = 1000 ;
while ( timeout - - > 0 )
if ( inb ( io + HP_ISR ) & HPISR_TXDE )
return 0 ;
return - EIO ;
}
static int snd_msnd_wait_HC0 ( struct snd_msnd * dev )
{
unsigned int io = dev - > io ;
int timeout = 1000 ;
while ( timeout - - > 0 )
if ( ! ( inb ( io + HP_CVR ) & HPCVR_HC ) )
return 0 ;
return - EIO ;
}
int snd_msnd_send_dsp_cmd ( struct snd_msnd * dev , u8 cmd )
{
unsigned long flags ;
spin_lock_irqsave ( & dev - > lock , flags ) ;
if ( snd_msnd_wait_HC0 ( dev ) = = 0 ) {
outb ( cmd , dev - > io + HP_CVR ) ;
spin_unlock_irqrestore ( & dev - > lock , flags ) ;
return 0 ;
}
spin_unlock_irqrestore ( & dev - > lock , flags ) ;
snd_printd ( KERN_ERR LOGNAME " : Send DSP command timeout \n " ) ;
return - EIO ;
}
EXPORT_SYMBOL ( snd_msnd_send_dsp_cmd ) ;
int snd_msnd_send_word ( struct snd_msnd * dev , unsigned char high ,
unsigned char mid , unsigned char low )
{
unsigned int io = dev - > io ;
if ( snd_msnd_wait_TXDE ( dev ) = = 0 ) {
outb ( high , io + HP_TXH ) ;
outb ( mid , io + HP_TXM ) ;
outb ( low , io + HP_TXL ) ;
return 0 ;
}
snd_printd ( KERN_ERR LOGNAME " : Send host word timeout \n " ) ;
return - EIO ;
}
EXPORT_SYMBOL ( snd_msnd_send_word ) ;
int snd_msnd_upload_host ( struct snd_msnd * dev , const u8 * bin , int len )
{
int i ;
if ( len % 3 ! = 0 ) {
snd_printk ( KERN_ERR LOGNAME
" : Upload host data not multiple of 3! \n " ) ;
return - EINVAL ;
}
for ( i = 0 ; i < len ; i + = 3 )
if ( snd_msnd_send_word ( dev , bin [ i ] , bin [ i + 1 ] , bin [ i + 2 ] ) )
return - EIO ;
inb ( dev - > io + HP_RXL ) ;
inb ( dev - > io + HP_CVR ) ;
return 0 ;
}
EXPORT_SYMBOL ( snd_msnd_upload_host ) ;
int snd_msnd_enable_irq ( struct snd_msnd * dev )
{
unsigned long flags ;
if ( dev - > irq_ref + + )
return 0 ;
snd_printdd ( LOGNAME " : Enabling IRQ \n " ) ;
spin_lock_irqsave ( & dev - > lock , flags ) ;
if ( snd_msnd_wait_TXDE ( dev ) = = 0 ) {
outb ( inb ( dev - > io + HP_ICR ) | HPICR_TREQ , dev - > io + HP_ICR ) ;
if ( dev - > type = = msndClassic )
outb ( dev - > irqid , dev - > io + HP_IRQM ) ;
outb ( inb ( dev - > io + HP_ICR ) & ~ HPICR_TREQ , dev - > io + HP_ICR ) ;
outb ( inb ( dev - > io + HP_ICR ) | HPICR_RREQ , dev - > io + HP_ICR ) ;
enable_irq ( dev - > irq ) ;
snd_msnd_init_queue ( dev - > DSPQ , dev - > dspq_data_buff ,
dev - > dspq_buff_size ) ;
spin_unlock_irqrestore ( & dev - > lock , flags ) ;
return 0 ;
}
spin_unlock_irqrestore ( & dev - > lock , flags ) ;
snd_printd ( KERN_ERR LOGNAME " : Enable IRQ failed \n " ) ;
return - EIO ;
}
EXPORT_SYMBOL ( snd_msnd_enable_irq ) ;
int snd_msnd_disable_irq ( struct snd_msnd * dev )
{
unsigned long flags ;
if ( - - dev - > irq_ref > 0 )
return 0 ;
if ( dev - > irq_ref < 0 )
snd_printd ( KERN_WARNING LOGNAME " : IRQ ref count is %d \n " ,
dev - > irq_ref ) ;
snd_printdd ( LOGNAME " : Disabling IRQ \n " ) ;
spin_lock_irqsave ( & dev - > lock , flags ) ;
if ( snd_msnd_wait_TXDE ( dev ) = = 0 ) {
outb ( inb ( dev - > io + HP_ICR ) & ~ HPICR_RREQ , dev - > io + HP_ICR ) ;
if ( dev - > type = = msndClassic )
outb ( HPIRQ_NONE , dev - > io + HP_IRQM ) ;
disable_irq ( dev - > irq ) ;
spin_unlock_irqrestore ( & dev - > lock , flags ) ;
return 0 ;
}
spin_unlock_irqrestore ( & dev - > lock , flags ) ;
snd_printd ( KERN_ERR LOGNAME " : Disable IRQ failed \n " ) ;
return - EIO ;
}
EXPORT_SYMBOL ( snd_msnd_disable_irq ) ;
static inline long get_play_delay_jiffies ( struct snd_msnd * chip , long size )
{
long tmp = ( size * HZ * chip - > play_sample_size ) / 8 ;
return tmp / ( chip - > play_sample_rate * chip - > play_channels ) ;
}
static void snd_msnd_dsp_write_flush ( struct snd_msnd * chip )
{
if ( ! ( chip - > mode & FMODE_WRITE ) | | ! test_bit ( F_WRITING , & chip - > flags ) )
return ;
set_bit ( F_WRITEFLUSH , & chip - > flags ) ;
/* interruptible_sleep_on_timeout(
& chip - > writeflush ,
get_play_delay_jiffies ( & chip , chip - > DAPF . len ) ) ; */
clear_bit ( F_WRITEFLUSH , & chip - > flags ) ;
if ( ! signal_pending ( current ) )
schedule_timeout_interruptible (
get_play_delay_jiffies ( chip , chip - > play_period_bytes ) ) ;
clear_bit ( F_WRITING , & chip - > flags ) ;
}
void snd_msnd_dsp_halt ( struct snd_msnd * chip , struct file * file )
{
if ( ( file ? file - > f_mode : chip - > mode ) & FMODE_READ ) {
clear_bit ( F_READING , & chip - > flags ) ;
snd_msnd_send_dsp_cmd ( chip , HDEX_RECORD_STOP ) ;
snd_msnd_disable_irq ( chip ) ;
if ( file ) {
snd_printd ( KERN_INFO LOGNAME
" : Stopping read for %p \n " , file ) ;
chip - > mode & = ~ FMODE_READ ;
}
clear_bit ( F_AUDIO_READ_INUSE , & chip - > flags ) ;
}
if ( ( file ? file - > f_mode : chip - > mode ) & FMODE_WRITE ) {
if ( test_bit ( F_WRITING , & chip - > flags ) ) {
snd_msnd_dsp_write_flush ( chip ) ;
snd_msnd_send_dsp_cmd ( chip , HDEX_PLAY_STOP ) ;
}
snd_msnd_disable_irq ( chip ) ;
if ( file ) {
snd_printd ( KERN_INFO
LOGNAME " : Stopping write for %p \n " , file ) ;
chip - > mode & = ~ FMODE_WRITE ;
}
clear_bit ( F_AUDIO_WRITE_INUSE , & chip - > flags ) ;
}
}
EXPORT_SYMBOL ( snd_msnd_dsp_halt ) ;
int snd_msnd_DARQ ( struct snd_msnd * chip , int bank )
{
int /*size, n,*/ timeout = 3 ;
u16 wTmp ;
/* void *DAQD; */
/* Increment the tail and check for queue wrap */
wTmp = readw ( chip - > DARQ + JQS_wTail ) + PCTODSP_OFFSET ( DAQDS__size ) ;
if ( wTmp > readw ( chip - > DARQ + JQS_wSize ) )
wTmp = 0 ;
while ( wTmp = = readw ( chip - > DARQ + JQS_wHead ) & & timeout - - )
udelay ( 1 ) ;
if ( chip - > capturePeriods = = 2 ) {
2018-07-26 00:00:47 +03:00
void __iomem * pDAQ = chip - > mappedbase + DARQ_DATA_BUFF +
2009-01-24 15:35:28 +03:00
bank * DAQDS__size + DAQDS_wStart ;
unsigned short offset = 0x3000 + chip - > capturePeriodBytes ;
if ( readw ( pDAQ ) ! = PCTODSP_BASED ( 0x3000 ) )
offset = 0x3000 ;
writew ( PCTODSP_BASED ( offset ) , pDAQ ) ;
}
writew ( wTmp , chip - > DARQ + JQS_wTail ) ;
#if 0
/* Get our digital audio queue struct */
DAQD = bank * DAQDS__size + chip - > mappedbase + DARQ_DATA_BUFF ;
/* Get length of data */
size = readw ( DAQD + DAQDS_wSize ) ;
/* Read data from the head (unprotected bank 1 access okay
since this is only called inside an interrupt ) */
outb ( HPBLKSEL_1 , chip - > io + HP_BLKS ) ;
n = msnd_fifo_write ( & chip - > DARF ,
( char * ) ( chip - > base + bank * DAR_BUFF_SIZE ) ,
size , 0 ) ;
if ( n < = 0 ) {
outb ( HPBLKSEL_0 , chip - > io + HP_BLKS ) ;
return n ;
}
outb ( HPBLKSEL_0 , chip - > io + HP_BLKS ) ;
# endif
return 1 ;
}
EXPORT_SYMBOL ( snd_msnd_DARQ ) ;
int snd_msnd_DAPQ ( struct snd_msnd * chip , int start )
{
u16 DAPQ_tail ;
int protect = start , nbanks = 0 ;
2018-07-26 00:00:47 +03:00
void __iomem * DAQD ;
2009-01-24 15:35:28 +03:00
static int play_banks_submitted ;
/* unsigned long flags;
spin_lock_irqsave ( & chip - > lock , flags ) ; not necessary */
DAPQ_tail = readw ( chip - > DAPQ + JQS_wTail ) ;
while ( DAPQ_tail ! = readw ( chip - > DAPQ + JQS_wHead ) | | start ) {
int bank_num = DAPQ_tail / PCTODSP_OFFSET ( DAQDS__size ) ;
if ( start ) {
start = 0 ;
play_banks_submitted = 0 ;
}
/* Get our digital audio queue struct */
DAQD = bank_num * DAQDS__size + chip - > mappedbase +
DAPQ_DATA_BUFF ;
/* Write size of this bank */
writew ( chip - > play_period_bytes , DAQD + DAQDS_wSize ) ;
if ( play_banks_submitted < 3 )
+ + play_banks_submitted ;
else if ( chip - > playPeriods = = 2 ) {
unsigned short offset = chip - > play_period_bytes ;
if ( readw ( DAQD + DAQDS_wStart ) ! = PCTODSP_BASED ( 0x0 ) )
offset = 0 ;
writew ( PCTODSP_BASED ( offset ) , DAQD + DAQDS_wStart ) ;
}
+ + nbanks ;
/* Then advance the tail */
/*
if ( protect )
snd_printd ( KERN_INFO " B %X %lX \n " ,
bank_num , xtime . tv_usec ) ;
*/
DAPQ_tail = ( + + bank_num % 3 ) * PCTODSP_OFFSET ( DAQDS__size ) ;
writew ( DAPQ_tail , chip - > DAPQ + JQS_wTail ) ;
/* Tell the DSP to play the bank */
snd_msnd_send_dsp_cmd ( chip , HDEX_PLAY_START ) ;
if ( protect )
if ( 2 = = bank_num )
break ;
}
/*
if ( protect )
snd_printd ( KERN_INFO " %lX \n " , xtime . tv_usec ) ;
*/
/* spin_unlock_irqrestore(&chip->lock, flags); not necessary */
return nbanks ;
}
EXPORT_SYMBOL ( snd_msnd_DAPQ ) ;
static void snd_msnd_play_reset_queue ( struct snd_msnd * chip ,
unsigned int pcm_periods ,
unsigned int pcm_count )
{
int n ;
2018-07-26 00:00:47 +03:00
void __iomem * pDAQ = chip - > mappedbase + DAPQ_DATA_BUFF ;
2009-01-24 15:35:28 +03:00
chip - > last_playbank = - 1 ;
chip - > playLimit = pcm_count * ( pcm_periods - 1 ) ;
chip - > playPeriods = pcm_periods ;
writew ( PCTODSP_OFFSET ( 0 * DAQDS__size ) , chip - > DAPQ + JQS_wHead ) ;
writew ( PCTODSP_OFFSET ( 0 * DAQDS__size ) , chip - > DAPQ + JQS_wTail ) ;
chip - > play_period_bytes = pcm_count ;
for ( n = 0 ; n < pcm_periods ; + + n , pDAQ + = DAQDS__size ) {
writew ( PCTODSP_BASED ( ( u32 ) ( pcm_count * n ) ) ,
pDAQ + DAQDS_wStart ) ;
writew ( 0 , pDAQ + DAQDS_wSize ) ;
writew ( 1 , pDAQ + DAQDS_wFormat ) ;
writew ( chip - > play_sample_size , pDAQ + DAQDS_wSampleSize ) ;
writew ( chip - > play_channels , pDAQ + DAQDS_wChannels ) ;
writew ( chip - > play_sample_rate , pDAQ + DAQDS_wSampleRate ) ;
writew ( HIMT_PLAY_DONE * 0x100 + n , pDAQ + DAQDS_wIntMsg ) ;
writew ( n , pDAQ + DAQDS_wFlags ) ;
}
}
static void snd_msnd_capture_reset_queue ( struct snd_msnd * chip ,
unsigned int pcm_periods ,
unsigned int pcm_count )
{
int n ;
2018-07-26 00:00:47 +03:00
void __iomem * pDAQ ;
2009-01-24 15:35:28 +03:00
/* unsigned long flags; */
/* snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); */
chip - > last_recbank = 2 ;
chip - > captureLimit = pcm_count * ( pcm_periods - 1 ) ;
chip - > capturePeriods = pcm_periods ;
writew ( PCTODSP_OFFSET ( 0 * DAQDS__size ) , chip - > DARQ + JQS_wHead ) ;
writew ( PCTODSP_OFFSET ( chip - > last_recbank * DAQDS__size ) ,
chip - > DARQ + JQS_wTail ) ;
#if 0 /* Critical section: bank 1 access. this is how the OSS driver does it:*/
spin_lock_irqsave ( & chip - > lock , flags ) ;
outb ( HPBLKSEL_1 , chip - > io + HP_BLKS ) ;
memset_io ( chip - > mappedbase , 0 , DAR_BUFF_SIZE * 3 ) ;
outb ( HPBLKSEL_0 , chip - > io + HP_BLKS ) ;
spin_unlock_irqrestore ( & chip - > lock , flags ) ;
# endif
chip - > capturePeriodBytes = pcm_count ;
snd_printdd ( " snd_msnd_capture_reset_queue() %i \n " , pcm_count ) ;
pDAQ = chip - > mappedbase + DARQ_DATA_BUFF ;
for ( n = 0 ; n < pcm_periods ; + + n , pDAQ + = DAQDS__size ) {
u32 tmp = pcm_count * n ;
writew ( PCTODSP_BASED ( tmp + 0x3000 ) , pDAQ + DAQDS_wStart ) ;
writew ( pcm_count , pDAQ + DAQDS_wSize ) ;
writew ( 1 , pDAQ + DAQDS_wFormat ) ;
writew ( chip - > capture_sample_size , pDAQ + DAQDS_wSampleSize ) ;
writew ( chip - > capture_channels , pDAQ + DAQDS_wChannels ) ;
writew ( chip - > capture_sample_rate , pDAQ + DAQDS_wSampleRate ) ;
writew ( HIMT_RECORD_DONE * 0x100 + n , pDAQ + DAQDS_wIntMsg ) ;
writew ( n , pDAQ + DAQDS_wFlags ) ;
}
}
2017-08-17 12:15:52 +03:00
static const struct snd_pcm_hardware snd_msnd_playback = {
2021-08-09 17:05:32 +03:00
. info = SNDRV_PCM_INFO_MMAP_IOMEM |
2009-01-24 15:35:28 +03:00
SNDRV_PCM_INFO_INTERLEAVED |
2009-04-28 14:25:59 +04:00
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BATCH ,
2009-01-24 15:35:28 +03:00
. formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE ,
. rates = SNDRV_PCM_RATE_8000_48000 ,
. rate_min = 8000 ,
. rate_max = 48000 ,
. channels_min = 1 ,
. channels_max = 2 ,
. buffer_bytes_max = 0x3000 ,
. period_bytes_min = 0x40 ,
. period_bytes_max = 0x1800 ,
. periods_min = 2 ,
. periods_max = 3 ,
. fifo_size = 0 ,
} ;
2017-08-17 12:15:52 +03:00
static const struct snd_pcm_hardware snd_msnd_capture = {
2021-08-09 17:05:32 +03:00
. info = SNDRV_PCM_INFO_MMAP_IOMEM |
2009-01-24 15:35:28 +03:00
SNDRV_PCM_INFO_INTERLEAVED |
2009-04-28 14:25:59 +04:00
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BATCH ,
2009-01-24 15:35:28 +03:00
. formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE ,
. rates = SNDRV_PCM_RATE_8000_48000 ,
. rate_min = 8000 ,
. rate_max = 48000 ,
. channels_min = 1 ,
. channels_max = 2 ,
. buffer_bytes_max = 0x3000 ,
. period_bytes_min = 0x40 ,
. period_bytes_max = 0x1800 ,
. periods_min = 2 ,
. periods_max = 3 ,
. fifo_size = 0 ,
} ;
static int snd_msnd_playback_open ( struct snd_pcm_substream * substream )
{
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_msnd * chip = snd_pcm_substream_chip ( substream ) ;
set_bit ( F_AUDIO_WRITE_INUSE , & chip - > flags ) ;
clear_bit ( F_WRITING , & chip - > flags ) ;
snd_msnd_enable_irq ( chip ) ;
2018-07-26 00:00:47 +03:00
runtime - > dma_area = ( __force void * ) chip - > mappedbase ;
2021-08-09 17:05:32 +03:00
runtime - > dma_addr = chip - > base ;
2009-01-24 15:35:28 +03:00
runtime - > dma_bytes = 0x3000 ;
chip - > playback_substream = substream ;
runtime - > hw = snd_msnd_playback ;
return 0 ;
}
static int snd_msnd_playback_close ( struct snd_pcm_substream * substream )
{
struct snd_msnd * chip = snd_pcm_substream_chip ( substream ) ;
snd_msnd_disable_irq ( chip ) ;
clear_bit ( F_AUDIO_WRITE_INUSE , & chip - > flags ) ;
return 0 ;
}
static int snd_msnd_playback_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
int i ;
struct snd_msnd * chip = snd_pcm_substream_chip ( substream ) ;
2018-07-26 00:00:47 +03:00
void __iomem * pDAQ = chip - > mappedbase + DAPQ_DATA_BUFF ;
2009-01-24 15:35:28 +03:00
chip - > play_sample_size = snd_pcm_format_width ( params_format ( params ) ) ;
chip - > play_channels = params_channels ( params ) ;
chip - > play_sample_rate = params_rate ( params ) ;
for ( i = 0 ; i < 3 ; + + i , pDAQ + = DAQDS__size ) {
writew ( chip - > play_sample_size , pDAQ + DAQDS_wSampleSize ) ;
writew ( chip - > play_channels , pDAQ + DAQDS_wChannels ) ;
writew ( chip - > play_sample_rate , pDAQ + DAQDS_wSampleRate ) ;
}
/* dont do this here:
* snd_msnd_calibrate_adc ( chip - > play_sample_rate ) ;
*/
return 0 ;
}
static int snd_msnd_playback_prepare ( struct snd_pcm_substream * substream )
{
struct snd_msnd * chip = snd_pcm_substream_chip ( substream ) ;
unsigned int pcm_size = snd_pcm_lib_buffer_bytes ( substream ) ;
unsigned int pcm_count = snd_pcm_lib_period_bytes ( substream ) ;
unsigned int pcm_periods = pcm_size / pcm_count ;
snd_msnd_play_reset_queue ( chip , pcm_periods , pcm_count ) ;
chip - > playDMAPos = 0 ;
return 0 ;
}
static int snd_msnd_playback_trigger ( struct snd_pcm_substream * substream ,
int cmd )
{
struct snd_msnd * chip = snd_pcm_substream_chip ( substream ) ;
int result = 0 ;
if ( cmd = = SNDRV_PCM_TRIGGER_START ) {
snd_printdd ( " snd_msnd_playback_trigger(START) \n " ) ;
chip - > banksPlayed = 0 ;
set_bit ( F_WRITING , & chip - > flags ) ;
snd_msnd_DAPQ ( chip , 1 ) ;
} else if ( cmd = = SNDRV_PCM_TRIGGER_STOP ) {
snd_printdd ( " snd_msnd_playback_trigger(STop) \n " ) ;
/* interrupt diagnostic, comment this out later */
clear_bit ( F_WRITING , & chip - > flags ) ;
snd_msnd_send_dsp_cmd ( chip , HDEX_PLAY_STOP ) ;
} else {
snd_printd ( KERN_ERR " snd_msnd_playback_trigger(?????) \n " ) ;
result = - EINVAL ;
}
snd_printdd ( " snd_msnd_playback_trigger() ENDE \n " ) ;
return result ;
}
static snd_pcm_uframes_t
snd_msnd_playback_pointer ( struct snd_pcm_substream * substream )
{
struct snd_msnd * chip = snd_pcm_substream_chip ( substream ) ;
return bytes_to_frames ( substream - > runtime , chip - > playDMAPos ) ;
}
2017-08-11 14:58:03 +03:00
static const struct snd_pcm_ops snd_msnd_playback_ops = {
2009-01-24 15:35:28 +03:00
. open = snd_msnd_playback_open ,
. close = snd_msnd_playback_close ,
. hw_params = snd_msnd_playback_hw_params ,
. prepare = snd_msnd_playback_prepare ,
. trigger = snd_msnd_playback_trigger ,
. pointer = snd_msnd_playback_pointer ,
2021-08-09 17:05:32 +03:00
. mmap = snd_pcm_lib_mmap_iomem ,
2009-01-24 15:35:28 +03:00
} ;
static int snd_msnd_capture_open ( struct snd_pcm_substream * substream )
{
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_msnd * chip = snd_pcm_substream_chip ( substream ) ;
set_bit ( F_AUDIO_READ_INUSE , & chip - > flags ) ;
snd_msnd_enable_irq ( chip ) ;
2018-07-26 00:00:47 +03:00
runtime - > dma_area = ( __force void * ) chip - > mappedbase + 0x3000 ;
2021-08-09 17:05:32 +03:00
runtime - > dma_addr = chip - > base + 0x3000 ;
2009-01-24 15:35:28 +03:00
runtime - > dma_bytes = 0x3000 ;
memset ( runtime - > dma_area , 0 , runtime - > dma_bytes ) ;
chip - > capture_substream = substream ;
runtime - > hw = snd_msnd_capture ;
return 0 ;
}
static int snd_msnd_capture_close ( struct snd_pcm_substream * substream )
{
struct snd_msnd * chip = snd_pcm_substream_chip ( substream ) ;
snd_msnd_disable_irq ( chip ) ;
clear_bit ( F_AUDIO_READ_INUSE , & chip - > flags ) ;
return 0 ;
}
static int snd_msnd_capture_prepare ( struct snd_pcm_substream * substream )
{
struct snd_msnd * chip = snd_pcm_substream_chip ( substream ) ;
unsigned int pcm_size = snd_pcm_lib_buffer_bytes ( substream ) ;
unsigned int pcm_count = snd_pcm_lib_period_bytes ( substream ) ;
unsigned int pcm_periods = pcm_size / pcm_count ;
snd_msnd_capture_reset_queue ( chip , pcm_periods , pcm_count ) ;
chip - > captureDMAPos = 0 ;
return 0 ;
}
static int snd_msnd_capture_trigger ( struct snd_pcm_substream * substream ,
int cmd )
{
struct snd_msnd * chip = snd_pcm_substream_chip ( substream ) ;
if ( cmd = = SNDRV_PCM_TRIGGER_START ) {
chip - > last_recbank = - 1 ;
set_bit ( F_READING , & chip - > flags ) ;
if ( snd_msnd_send_dsp_cmd ( chip , HDEX_RECORD_START ) = = 0 )
return 0 ;
clear_bit ( F_READING , & chip - > flags ) ;
} else if ( cmd = = SNDRV_PCM_TRIGGER_STOP ) {
clear_bit ( F_READING , & chip - > flags ) ;
snd_msnd_send_dsp_cmd ( chip , HDEX_RECORD_STOP ) ;
return 0 ;
}
return - EINVAL ;
}
static snd_pcm_uframes_t
snd_msnd_capture_pointer ( struct snd_pcm_substream * substream )
{
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_msnd * chip = snd_pcm_substream_chip ( substream ) ;
return bytes_to_frames ( runtime , chip - > captureDMAPos ) ;
}
static int snd_msnd_capture_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
int i ;
struct snd_msnd * chip = snd_pcm_substream_chip ( substream ) ;
2018-07-26 00:00:47 +03:00
void __iomem * pDAQ = chip - > mappedbase + DARQ_DATA_BUFF ;
2009-01-24 15:35:28 +03:00
chip - > capture_sample_size = snd_pcm_format_width ( params_format ( params ) ) ;
chip - > capture_channels = params_channels ( params ) ;
chip - > capture_sample_rate = params_rate ( params ) ;
for ( i = 0 ; i < 3 ; + + i , pDAQ + = DAQDS__size ) {
writew ( chip - > capture_sample_size , pDAQ + DAQDS_wSampleSize ) ;
writew ( chip - > capture_channels , pDAQ + DAQDS_wChannels ) ;
writew ( chip - > capture_sample_rate , pDAQ + DAQDS_wSampleRate ) ;
}
return 0 ;
}
2017-08-11 14:58:03 +03:00
static const struct snd_pcm_ops snd_msnd_capture_ops = {
2009-01-24 15:35:28 +03:00
. open = snd_msnd_capture_open ,
. close = snd_msnd_capture_close ,
. hw_params = snd_msnd_capture_hw_params ,
. prepare = snd_msnd_capture_prepare ,
. trigger = snd_msnd_capture_trigger ,
. pointer = snd_msnd_capture_pointer ,
2021-08-09 17:05:32 +03:00
. mmap = snd_pcm_lib_mmap_iomem ,
2009-01-24 15:35:28 +03:00
} ;
2015-01-02 14:24:40 +03:00
int snd_msnd_pcm ( struct snd_card * card , int device )
2009-01-24 15:35:28 +03:00
{
struct snd_msnd * chip = card - > private_data ;
struct snd_pcm * pcm ;
int err ;
err = snd_pcm_new ( card , " MSNDPINNACLE " , device , 1 , 1 , & pcm ) ;
if ( err < 0 )
return err ;
snd_pcm_set_ops ( pcm , SNDRV_PCM_STREAM_PLAYBACK , & snd_msnd_playback_ops ) ;
snd_pcm_set_ops ( pcm , SNDRV_PCM_STREAM_CAPTURE , & snd_msnd_capture_ops ) ;
pcm - > private_data = chip ;
strcpy ( pcm - > name , " Hurricane " ) ;
return 0 ;
}
EXPORT_SYMBOL ( snd_msnd_pcm ) ;
2009-02-01 23:13:15 +03:00
MODULE_DESCRIPTION ( " Common routines for Turtle Beach Multisound drivers " ) ;
MODULE_LICENSE ( " GPL " ) ;