2005-04-16 15:20:36 -07:00
/*
*
* device driver for philips saa7134 based TV cards
* oss dsp interface
*
* ( c ) 2001 , 02 Gerd Knorr < kraxel @ bytesex . org > [ SuSE Labs ]
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/init.h>
# include <linux/list.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/soundcard.h>
# include "saa7134-reg.h"
# include "saa7134.h"
/* ------------------------------------------------------------------ */
static unsigned int oss_debug = 0 ;
module_param ( oss_debug , int , 0644 ) ;
MODULE_PARM_DESC ( oss_debug , " enable debug messages [oss] " ) ;
static unsigned int oss_rate = 0 ;
module_param ( oss_rate , int , 0444 ) ;
MODULE_PARM_DESC ( oss_rate , " sample rate (valid are: 32000,48000) " ) ;
# define dprintk(fmt, arg...) if (oss_debug) \
printk ( KERN_DEBUG " %s/oss: " fmt , dev - > name , # # arg )
2005-11-08 21:37:11 -08:00
2005-04-16 15:20:36 -07:00
/* ------------------------------------------------------------------ */
static int dsp_buffer_conf ( struct saa7134_dev * dev , int blksize , int blocks )
{
if ( blksize < 0x100 )
blksize = 0x100 ;
if ( blksize > 0x10000 )
blksize = 0x10000 ;
if ( blocks < 2 )
blocks = 2 ;
if ( ( blksize * blocks ) > 1024 * 1024 )
blocks = 1024 * 1024 / blksize ;
dev - > oss . blocks = blocks ;
dev - > oss . blksize = blksize ;
dev - > oss . bufsize = blksize * blocks ;
dprintk ( " buffer config: %d blocks / %d bytes, %d kB total \n " ,
blocks , blksize , blksize * blocks / 1024 ) ;
return 0 ;
}
static int dsp_buffer_init ( struct saa7134_dev * dev )
{
int err ;
if ( ! dev - > oss . bufsize )
BUG ( ) ;
videobuf_dma_init ( & dev - > oss . dma ) ;
err = videobuf_dma_init_kernel ( & dev - > oss . dma , PCI_DMA_FROMDEVICE ,
2005-06-23 22:05:09 -07:00
( dev - > oss . bufsize + PAGE_SIZE ) > > PAGE_SHIFT ) ;
2005-04-16 15:20:36 -07:00
if ( 0 ! = err )
return err ;
return 0 ;
}
static int dsp_buffer_free ( struct saa7134_dev * dev )
{
if ( ! dev - > oss . blksize )
BUG ( ) ;
videobuf_dma_free ( & dev - > oss . dma ) ;
dev - > oss . blocks = 0 ;
dev - > oss . blksize = 0 ;
dev - > oss . bufsize = 0 ;
return 0 ;
}
static void dsp_dma_start ( struct saa7134_dev * dev )
{
dev - > oss . dma_blk = 0 ;
dev - > oss . dma_running = 1 ;
saa7134_set_dmabits ( dev ) ;
}
static void dsp_dma_stop ( struct saa7134_dev * dev )
{
dev - > oss . dma_blk = - 1 ;
dev - > oss . dma_running = 0 ;
saa7134_set_dmabits ( dev ) ;
}
static int dsp_rec_start ( struct saa7134_dev * dev )
{
int err , bswap , sign ;
u32 fmt , control ;
unsigned long flags ;
/* prepare buffer */
if ( 0 ! = ( err = videobuf_dma_pci_map ( dev - > pci , & dev - > oss . dma ) ) )
return err ;
if ( 0 ! = ( err = saa7134_pgtable_alloc ( dev - > pci , & dev - > oss . pt ) ) )
goto fail1 ;
if ( 0 ! = ( err = saa7134_pgtable_build ( dev - > pci , & dev - > oss . pt ,
dev - > oss . dma . sglist ,
dev - > oss . dma . sglen ,
0 ) ) )
goto fail2 ;
/* sample format */
switch ( dev - > oss . afmt ) {
case AFMT_U8 :
case AFMT_S8 : fmt = 0x00 ; break ;
case AFMT_U16_LE :
case AFMT_U16_BE :
case AFMT_S16_LE :
case AFMT_S16_BE : fmt = 0x01 ; break ;
default :
err = - EINVAL ;
goto fail2 ;
}
switch ( dev - > oss . afmt ) {
case AFMT_S8 :
case AFMT_S16_LE :
case AFMT_S16_BE : sign = 1 ; break ;
default : sign = 0 ; break ;
}
switch ( dev - > oss . afmt ) {
case AFMT_U16_BE :
case AFMT_S16_BE : bswap = 1 ; break ;
default : bswap = 0 ; break ;
}
switch ( dev - > pci - > device ) {
case PCI_DEVICE_ID_PHILIPS_SAA7134 :
if ( 1 = = dev - > oss . channels )
fmt | = ( 1 < < 3 ) ;
if ( 2 = = dev - > oss . channels )
fmt | = ( 3 < < 3 ) ;
if ( sign )
fmt | = 0x04 ;
fmt | = ( TV = = dev - > oss . input ) ? 0xc0 : 0x80 ;
2005-06-23 22:05:09 -07:00
saa_writeb ( SAA7134_NUM_SAMPLES0 , ( ( dev - > oss . blksize - 1 ) & 0x0000ff ) ) ;
saa_writeb ( SAA7134_NUM_SAMPLES1 , ( ( dev - > oss . blksize - 1 ) & 0x00ff00 ) > > 8 ) ;
saa_writeb ( SAA7134_NUM_SAMPLES2 , ( ( dev - > oss . blksize - 1 ) & 0xff0000 ) > > 16 ) ;
2005-04-16 15:20:36 -07:00
saa_writeb ( SAA7134_AUDIO_FORMAT_CTRL , fmt ) ;
2005-06-23 22:05:09 -07:00
2005-04-16 15:20:36 -07:00
break ;
case PCI_DEVICE_ID_PHILIPS_SAA7133 :
case PCI_DEVICE_ID_PHILIPS_SAA7135 :
if ( 1 = = dev - > oss . channels )
fmt | = ( 1 < < 4 ) ;
if ( 2 = = dev - > oss . channels )
fmt | = ( 2 < < 4 ) ;
if ( ! sign )
fmt | = 0x04 ;
2005-11-08 21:37:11 -08:00
saa_writel ( SAA7133_NUM_SAMPLES , dev - > oss . blksize - 4 ) ;
saa_writel ( SAA7133_AUDIO_CHANNEL , 0x543210 | ( fmt < < 24 ) ) ;
2005-04-16 15:20:36 -07:00
break ;
}
dprintk ( " rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c \n " ,
dev - > oss . afmt , dev - > oss . channels , fmt ,
bswap ? ' b ' : ' - ' ) ;
/* dma: setup channel 6 (= AUDIO) */
control = SAA7134_RS_CONTROL_BURST_16 |
SAA7134_RS_CONTROL_ME |
( dev - > oss . pt . dma > > 12 ) ;
if ( bswap )
control | = SAA7134_RS_CONTROL_BSWAP ;
saa_writel ( SAA7134_RS_BA1 ( 6 ) , 0 ) ;
saa_writel ( SAA7134_RS_BA2 ( 6 ) , dev - > oss . blksize ) ;
saa_writel ( SAA7134_RS_PITCH ( 6 ) , 0 ) ;
saa_writel ( SAA7134_RS_CONTROL ( 6 ) , control ) ;
/* start dma */
dev - > oss . recording_on = 1 ;
spin_lock_irqsave ( & dev - > slock , flags ) ;
dsp_dma_start ( dev ) ;
spin_unlock_irqrestore ( & dev - > slock , flags ) ;
return 0 ;
fail2 :
saa7134_pgtable_free ( dev - > pci , & dev - > oss . pt ) ;
fail1 :
videobuf_dma_pci_unmap ( dev - > pci , & dev - > oss . dma ) ;
return err ;
}
static int dsp_rec_stop ( struct saa7134_dev * dev )
{
unsigned long flags ;
dprintk ( " rec_stop dma_blk=%d \n " , dev - > oss . dma_blk ) ;
/* stop dma */
dev - > oss . recording_on = 0 ;
spin_lock_irqsave ( & dev - > slock , flags ) ;
dsp_dma_stop ( dev ) ;
spin_unlock_irqrestore ( & dev - > slock , flags ) ;
/* unlock buffer */
saa7134_pgtable_free ( dev - > pci , & dev - > oss . pt ) ;
videobuf_dma_pci_unmap ( dev - > pci , & dev - > oss . dma ) ;
return 0 ;
}
/* ------------------------------------------------------------------ */
static int dsp_open ( struct inode * inode , struct file * file )
{
int minor = iminor ( inode ) ;
struct saa7134_dev * h , * dev = NULL ;
struct list_head * list ;
int err ;
list_for_each ( list , & saa7134_devlist ) {
h = list_entry ( list , struct saa7134_dev , devlist ) ;
if ( h - > oss . minor_dsp = = minor )
dev = h ;
}
if ( NULL = = dev )
return - ENODEV ;
down ( & dev - > oss . lock ) ;
err = - EBUSY ;
if ( dev - > oss . users_dsp )
goto fail1 ;
dev - > oss . users_dsp + + ;
file - > private_data = dev ;
dev - > oss . afmt = AFMT_U8 ;
dev - > oss . channels = 1 ;
dev - > oss . read_count = 0 ;
dev - > oss . read_offset = 0 ;
dsp_buffer_conf ( dev , PAGE_SIZE , 64 ) ;
err = dsp_buffer_init ( dev ) ;
if ( 0 ! = err )
goto fail2 ;
up ( & dev - > oss . lock ) ;
return 0 ;
fail2 :
dev - > oss . users_dsp - - ;
fail1 :
up ( & dev - > oss . lock ) ;
return err ;
}
static int dsp_release ( struct inode * inode , struct file * file )
{
struct saa7134_dev * dev = file - > private_data ;
down ( & dev - > oss . lock ) ;
if ( dev - > oss . recording_on )
dsp_rec_stop ( dev ) ;
dsp_buffer_free ( dev ) ;
dev - > oss . users_dsp - - ;
file - > private_data = NULL ;
up ( & dev - > oss . lock ) ;
return 0 ;
}
static ssize_t dsp_read ( struct file * file , char __user * buffer ,
size_t count , loff_t * ppos )
{
struct saa7134_dev * dev = file - > private_data ;
DECLARE_WAITQUEUE ( wait , current ) ;
unsigned int bytes ;
unsigned long flags ;
int err , ret = 0 ;
add_wait_queue ( & dev - > oss . wq , & wait ) ;
down ( & dev - > oss . lock ) ;
while ( count > 0 ) {
/* wait for data if needed */
if ( 0 = = dev - > oss . read_count ) {
if ( ! dev - > oss . recording_on ) {
err = dsp_rec_start ( dev ) ;
if ( err < 0 ) {
if ( 0 = = ret )
ret = err ;
break ;
}
}
if ( dev - > oss . recording_on & &
! dev - > oss . dma_running ) {
/* recover from overruns */
spin_lock_irqsave ( & dev - > slock , flags ) ;
dsp_dma_start ( dev ) ;
spin_unlock_irqrestore ( & dev - > slock , flags ) ;
}
if ( file - > f_flags & O_NONBLOCK ) {
if ( 0 = = ret )
ret = - EAGAIN ;
break ;
}
up ( & dev - > oss . lock ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
if ( 0 = = dev - > oss . read_count )
schedule ( ) ;
set_current_state ( TASK_RUNNING ) ;
down ( & dev - > oss . lock ) ;
if ( signal_pending ( current ) ) {
if ( 0 = = ret )
ret = - EINTR ;
break ;
}
}
/* copy data to userspace */
bytes = count ;
if ( bytes > dev - > oss . read_count )
bytes = dev - > oss . read_count ;
if ( bytes > dev - > oss . bufsize - dev - > oss . read_offset )
bytes = dev - > oss . bufsize - dev - > oss . read_offset ;
if ( copy_to_user ( buffer + ret ,
dev - > oss . dma . vmalloc + dev - > oss . read_offset ,
bytes ) ) {
if ( 0 = = ret )
ret = - EFAULT ;
break ;
}
ret + = bytes ;
count - = bytes ;
dev - > oss . read_count - = bytes ;
dev - > oss . read_offset + = bytes ;
if ( dev - > oss . read_offset = = dev - > oss . bufsize )
dev - > oss . read_offset = 0 ;
}
up ( & dev - > oss . lock ) ;
remove_wait_queue ( & dev - > oss . wq , & wait ) ;
return ret ;
}
static ssize_t dsp_write ( struct file * file , const char __user * buffer ,
size_t count , loff_t * ppos )
{
return - EINVAL ;
}
static int dsp_ioctl ( struct inode * inode , struct file * file ,
unsigned int cmd , unsigned long arg )
{
struct saa7134_dev * dev = file - > private_data ;
void __user * argp = ( void __user * ) arg ;
int __user * p = argp ;
int val = 0 ;
if ( oss_debug > 1 )
saa7134_print_ioctl ( dev - > name , cmd ) ;
switch ( cmd ) {
case OSS_GETVERSION :
return put_user ( SOUND_VERSION , p ) ;
case SNDCTL_DSP_GETCAPS :
return 0 ;
case SNDCTL_DSP_SPEED :
if ( get_user ( val , p ) )
return - EFAULT ;
/* fall through */
case SOUND_PCM_READ_RATE :
return put_user ( dev - > oss . rate , p ) ;
case SNDCTL_DSP_STEREO :
if ( get_user ( val , p ) )
return - EFAULT ;
down ( & dev - > oss . lock ) ;
dev - > oss . channels = val ? 2 : 1 ;
if ( dev - > oss . recording_on ) {
dsp_rec_stop ( dev ) ;
dsp_rec_start ( dev ) ;
}
up ( & dev - > oss . lock ) ;
return put_user ( dev - > oss . channels - 1 , p ) ;
case SNDCTL_DSP_CHANNELS :
if ( get_user ( val , p ) )
return - EFAULT ;
if ( val ! = 1 & & val ! = 2 )
return - EINVAL ;
down ( & dev - > oss . lock ) ;
dev - > oss . channels = val ;
if ( dev - > oss . recording_on ) {
dsp_rec_stop ( dev ) ;
dsp_rec_start ( dev ) ;
}
up ( & dev - > oss . lock ) ;
/* fall through */
case SOUND_PCM_READ_CHANNELS :
return put_user ( dev - > oss . channels , p ) ;
case SNDCTL_DSP_GETFMTS : /* Returns a mask */
return put_user ( AFMT_U8 | AFMT_S8 |
AFMT_U16_LE | AFMT_U16_BE |
AFMT_S16_LE | AFMT_S16_BE , p ) ;
case SNDCTL_DSP_SETFMT : /* Selects ONE fmt */
if ( get_user ( val , p ) )
return - EFAULT ;
switch ( val ) {
case AFMT_QUERY :
/* nothing to do */
break ;
case AFMT_U8 :
case AFMT_S8 :
case AFMT_U16_LE :
case AFMT_U16_BE :
case AFMT_S16_LE :
case AFMT_S16_BE :
down ( & dev - > oss . lock ) ;
dev - > oss . afmt = val ;
if ( dev - > oss . recording_on ) {
dsp_rec_stop ( dev ) ;
dsp_rec_start ( dev ) ;
}
up ( & dev - > oss . lock ) ;
return put_user ( dev - > oss . afmt , p ) ;
default :
return - EINVAL ;
}
case SOUND_PCM_READ_BITS :
switch ( dev - > oss . afmt ) {
case AFMT_U8 :
case AFMT_S8 :
return put_user ( 8 , p ) ;
case AFMT_U16_LE :
case AFMT_U16_BE :
case AFMT_S16_LE :
case AFMT_S16_BE :
return put_user ( 16 , p ) ;
default :
return - EINVAL ;
}
case SNDCTL_DSP_NONBLOCK :
file - > f_flags | = O_NONBLOCK ;
return 0 ;
case SNDCTL_DSP_RESET :
down ( & dev - > oss . lock ) ;
if ( dev - > oss . recording_on )
dsp_rec_stop ( dev ) ;
up ( & dev - > oss . lock ) ;
return 0 ;
case SNDCTL_DSP_GETBLKSIZE :
return put_user ( dev - > oss . blksize , p ) ;
case SNDCTL_DSP_SETFRAGMENT :
if ( get_user ( val , p ) )
return - EFAULT ;
if ( dev - > oss . recording_on )
return - EBUSY ;
dsp_buffer_free ( dev ) ;
/* used to be arg >> 16 instead of val >> 16; fixed */
dsp_buffer_conf ( dev , 1 < < ( val & 0xffff ) , ( val > > 16 ) & 0xffff ) ;
dsp_buffer_init ( dev ) ;
return 0 ;
case SNDCTL_DSP_SYNC :
/* NOP */
return 0 ;
case SNDCTL_DSP_GETISPACE :
{
audio_buf_info info ;
info . fragsize = dev - > oss . blksize ;
info . fragstotal = dev - > oss . blocks ;
info . bytes = dev - > oss . read_count ;
info . fragments = info . bytes / info . fragsize ;
if ( copy_to_user ( argp , & info , sizeof ( info ) ) )
return - EFAULT ;
return 0 ;
}
default :
return - EINVAL ;
}
}
static unsigned int dsp_poll ( struct file * file , struct poll_table_struct * wait )
{
struct saa7134_dev * dev = file - > private_data ;
unsigned int mask = 0 ;
poll_wait ( file , & dev - > oss . wq , wait ) ;
if ( 0 = = dev - > oss . read_count ) {
down ( & dev - > oss . lock ) ;
if ( ! dev - > oss . recording_on )
dsp_rec_start ( dev ) ;
up ( & dev - > oss . lock ) ;
} else
mask | = ( POLLIN | POLLRDNORM ) ;
return mask ;
}
struct file_operations saa7134_dsp_fops = {
. owner = THIS_MODULE ,
. open = dsp_open ,
. release = dsp_release ,
. read = dsp_read ,
. write = dsp_write ,
. ioctl = dsp_ioctl ,
. poll = dsp_poll ,
. llseek = no_llseek ,
} ;
/* ------------------------------------------------------------------ */
static int
mixer_recsrc_7134 ( struct saa7134_dev * dev )
{
int analog_io , rate ;
switch ( dev - > oss . input ) {
case TV :
saa_andorb ( SAA7134_AUDIO_FORMAT_CTRL , 0xc0 , 0xc0 ) ;
saa_andorb ( SAA7134_SIF_SAMPLE_FREQ , 0x03 , 0x00 ) ;
break ;
case LINE1 :
case LINE2 :
case LINE2_LEFT :
analog_io = ( LINE1 = = dev - > oss . input ) ? 0x00 : 0x08 ;
rate = ( 32000 = = dev - > oss . rate ) ? 0x01 : 0x03 ;
saa_andorb ( SAA7134_ANALOG_IO_SELECT , 0x08 , analog_io ) ;
saa_andorb ( SAA7134_AUDIO_FORMAT_CTRL , 0xc0 , 0x80 ) ;
saa_andorb ( SAA7134_SIF_SAMPLE_FREQ , 0x03 , rate ) ;
break ;
}
return 0 ;
}
static int
mixer_recsrc_7133 ( struct saa7134_dev * dev )
{
2005-07-12 13:59:01 -07:00
u32 anabar , xbarin ;
2005-04-16 15:20:36 -07:00
2005-07-12 13:59:01 -07:00
xbarin = 0x03 ; // adc
anabar = 0 ;
2005-04-16 15:20:36 -07:00
switch ( dev - > oss . input ) {
case TV :
2005-07-12 13:59:01 -07:00
xbarin = 0 ; // Demodulator
anabar = 2 ; // DACs
2005-04-16 15:20:36 -07:00
break ;
case LINE1 :
2005-07-12 13:59:01 -07:00
anabar = 0 ; // aux1, aux1
2005-04-16 15:20:36 -07:00
break ;
case LINE2 :
case LINE2_LEFT :
2005-07-12 13:59:01 -07:00
anabar = 9 ; // aux2, aux2
2005-04-16 15:20:36 -07:00
break ;
}
2005-07-12 13:59:01 -07:00
/* output xbar always main channel */
saa_dsp_writel ( dev , 0x46c > > 2 , 0xbbbb10 ) ;
saa_dsp_writel ( dev , 0x464 > > 2 , xbarin ) ;
saa_writel ( 0x594 > > 2 , anabar ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
static int
mixer_recsrc ( struct saa7134_dev * dev , enum saa7134_audio_in src )
{
static const char * iname [ ] = { " Oops " , " TV " , " LINE1 " , " LINE2 " } ;
dev - > oss . count + + ;
dev - > oss . input = src ;
dprintk ( " mixer input = %s \n " , iname [ dev - > oss . input ] ) ;
switch ( dev - > pci - > device ) {
case PCI_DEVICE_ID_PHILIPS_SAA7134 :
mixer_recsrc_7134 ( dev ) ;
break ;
case PCI_DEVICE_ID_PHILIPS_SAA7133 :
case PCI_DEVICE_ID_PHILIPS_SAA7135 :
mixer_recsrc_7133 ( dev ) ;
break ;
}
return 0 ;
}
static int
mixer_level ( struct saa7134_dev * dev , enum saa7134_audio_in src , int level )
{
switch ( dev - > pci - > device ) {
case PCI_DEVICE_ID_PHILIPS_SAA7134 :
switch ( src ) {
case TV :
/* nothing */
break ;
case LINE1 :
saa_andorb ( SAA7134_ANALOG_IO_SELECT , 0x10 ,
( 100 = = level ) ? 0x00 : 0x10 ) ;
break ;
case LINE2 :
case LINE2_LEFT :
saa_andorb ( SAA7134_ANALOG_IO_SELECT , 0x20 ,
( 100 = = level ) ? 0x00 : 0x20 ) ;
break ;
}
break ;
case PCI_DEVICE_ID_PHILIPS_SAA7133 :
case PCI_DEVICE_ID_PHILIPS_SAA7135 :
/* nothing */
break ;
}
return 0 ;
}
/* ------------------------------------------------------------------ */
static int mixer_open ( struct inode * inode , struct file * file )
{
int minor = iminor ( inode ) ;
struct saa7134_dev * h , * dev = NULL ;
struct list_head * list ;
list_for_each ( list , & saa7134_devlist ) {
h = list_entry ( list , struct saa7134_dev , devlist ) ;
if ( h - > oss . minor_mixer = = minor )
dev = h ;
}
if ( NULL = = dev )
return - ENODEV ;
file - > private_data = dev ;
return 0 ;
}
static int mixer_release ( struct inode * inode , struct file * file )
{
file - > private_data = NULL ;
return 0 ;
}
static int mixer_ioctl ( struct inode * inode , struct file * file ,
unsigned int cmd , unsigned long arg )
{
struct saa7134_dev * dev = file - > private_data ;
enum saa7134_audio_in input ;
int val , ret ;
void __user * argp = ( void __user * ) arg ;
int __user * p = argp ;
if ( oss_debug > 1 )
saa7134_print_ioctl ( dev - > name , cmd ) ;
switch ( cmd ) {
case OSS_GETVERSION :
return put_user ( SOUND_VERSION , p ) ;
case SOUND_MIXER_INFO :
{
mixer_info info ;
memset ( & info , 0 , sizeof ( info ) ) ;
strlcpy ( info . id , " TV audio " , sizeof ( info . id ) ) ;
strlcpy ( info . name , dev - > name , sizeof ( info . name ) ) ;
info . modify_counter = dev - > oss . count ;
if ( copy_to_user ( argp , & info , sizeof ( info ) ) )
return - EFAULT ;
return 0 ;
}
case SOUND_OLD_MIXER_INFO :
{
_old_mixer_info info ;
memset ( & info , 0 , sizeof ( info ) ) ;
strlcpy ( info . id , " TV audio " , sizeof ( info . id ) ) ;
strlcpy ( info . name , dev - > name , sizeof ( info . name ) ) ;
if ( copy_to_user ( argp , & info , sizeof ( info ) ) )
return - EFAULT ;
return 0 ;
}
case MIXER_READ ( SOUND_MIXER_CAPS ) :
return put_user ( SOUND_CAP_EXCL_INPUT , p ) ;
case MIXER_READ ( SOUND_MIXER_STEREODEVS ) :
return put_user ( 0 , p ) ;
case MIXER_READ ( SOUND_MIXER_RECMASK ) :
case MIXER_READ ( SOUND_MIXER_DEVMASK ) :
val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2 ;
if ( 32000 = = dev - > oss . rate )
val | = SOUND_MASK_VIDEO ;
return put_user ( val , p ) ;
case MIXER_WRITE ( SOUND_MIXER_RECSRC ) :
if ( get_user ( val , p ) )
return - EFAULT ;
input = dev - > oss . input ;
if ( 32000 = = dev - > oss . rate & &
val & SOUND_MASK_VIDEO & & dev - > oss . input ! = TV )
input = TV ;
if ( val & SOUND_MASK_LINE1 & & dev - > oss . input ! = LINE1 )
input = LINE1 ;
if ( val & SOUND_MASK_LINE2 & & dev - > oss . input ! = LINE2 )
input = LINE2 ;
if ( input ! = dev - > oss . input )
mixer_recsrc ( dev , input ) ;
/* fall throuth */
case MIXER_READ ( SOUND_MIXER_RECSRC ) :
switch ( dev - > oss . input ) {
case TV : ret = SOUND_MASK_VIDEO ; break ;
case LINE1 : ret = SOUND_MASK_LINE1 ; break ;
case LINE2 : ret = SOUND_MASK_LINE2 ; break ;
default : ret = 0 ;
}
return put_user ( ret , p ) ;
case MIXER_WRITE ( SOUND_MIXER_VIDEO ) :
case MIXER_READ ( SOUND_MIXER_VIDEO ) :
if ( 32000 ! = dev - > oss . rate )
return - EINVAL ;
return put_user ( 100 | 100 < < 8 , p ) ;
case MIXER_WRITE ( SOUND_MIXER_LINE1 ) :
if ( get_user ( val , p ) )
return - EFAULT ;
val & = 0xff ;
val = ( val < = 50 ) ? 50 : 100 ;
dev - > oss . line1 = val ;
mixer_level ( dev , LINE1 , dev - > oss . line1 ) ;
/* fall throuth */
case MIXER_READ ( SOUND_MIXER_LINE1 ) :
return put_user ( dev - > oss . line1 | dev - > oss . line1 < < 8 , p ) ;
case MIXER_WRITE ( SOUND_MIXER_LINE2 ) :
if ( get_user ( val , p ) )
return - EFAULT ;
val & = 0xff ;
val = ( val < = 50 ) ? 50 : 100 ;
dev - > oss . line2 = val ;
mixer_level ( dev , LINE2 , dev - > oss . line2 ) ;
/* fall throuth */
case MIXER_READ ( SOUND_MIXER_LINE2 ) :
return put_user ( dev - > oss . line2 | dev - > oss . line2 < < 8 , p ) ;
default :
return - EINVAL ;
}
}
struct file_operations saa7134_mixer_fops = {
. owner = THIS_MODULE ,
. open = mixer_open ,
. release = mixer_release ,
. ioctl = mixer_ioctl ,
. llseek = no_llseek ,
} ;
/* ------------------------------------------------------------------ */
int saa7134_oss_init1 ( struct saa7134_dev * dev )
{
/* general */
init_MUTEX ( & dev - > oss . lock ) ;
init_waitqueue_head ( & dev - > oss . wq ) ;
switch ( dev - > pci - > device ) {
case PCI_DEVICE_ID_PHILIPS_SAA7133 :
case PCI_DEVICE_ID_PHILIPS_SAA7135 :
saa_writel ( 0x588 > > 2 , 0x00000fff ) ;
saa_writel ( 0x58c > > 2 , 0x00543210 ) ;
saa_dsp_writel ( dev , 0x46c > > 2 , 0xbbbbbb ) ;
break ;
}
/* dsp */
dev - > oss . rate = 32000 ;
if ( oss_rate )
dev - > oss . rate = oss_rate ;
dev - > oss . rate = ( dev - > oss . rate > 40000 ) ? 48000 : 32000 ;
/* mixer */
dev - > oss . line1 = 50 ;
dev - > oss . line2 = 50 ;
mixer_level ( dev , LINE1 , dev - > oss . line1 ) ;
mixer_level ( dev , LINE2 , dev - > oss . line2 ) ;
mixer_recsrc ( dev , ( dev - > oss . rate = = 32000 ) ? TV : LINE2 ) ;
return 0 ;
}
int saa7134_oss_fini ( struct saa7134_dev * dev )
{
/* nothing */
return 0 ;
}
void saa7134_irq_oss_done ( struct saa7134_dev * dev , unsigned long status )
{
int next_blk , reg = 0 ;
spin_lock ( & dev - > slock ) ;
if ( UNSET = = dev - > oss . dma_blk ) {
dprintk ( " irq: recording stopped \n " ) ;
goto done ;
}
if ( 0 ! = ( status & 0x0f000000 ) )
dprintk ( " irq: lost %ld \n " , ( status > > 24 ) & 0x0f ) ;
if ( 0 = = ( status & 0x10000000 ) ) {
/* odd */
if ( 0 = = ( dev - > oss . dma_blk & 0x01 ) )
reg = SAA7134_RS_BA1 ( 6 ) ;
} else {
/* even */
2005-06-23 22:05:09 -07:00
if ( 1 = = ( dev - > oss . dma_blk & 0x01 ) )
2005-04-16 15:20:36 -07:00
reg = SAA7134_RS_BA2 ( 6 ) ;
}
if ( 0 = = reg ) {
dprintk ( " irq: field oops [%s] \n " ,
( status & 0x10000000 ) ? " even " : " odd " ) ;
goto done ;
}
if ( dev - > oss . read_count > = dev - > oss . blksize * ( dev - > oss . blocks - 2 ) ) {
dprintk ( " irq: overrun [full=%d/%d] \n " , dev - > oss . read_count ,
dev - > oss . bufsize ) ;
dsp_dma_stop ( dev ) ;
goto done ;
}
/* next block addr */
next_blk = ( dev - > oss . dma_blk + 2 ) % dev - > oss . blocks ;
saa_writel ( reg , next_blk * dev - > oss . blksize ) ;
if ( oss_debug > 2 )
dprintk ( " irq: ok, %s, next_blk=%d, addr=%x \n " ,
( status & 0x10000000 ) ? " even " : " odd " , next_blk ,
next_blk * dev - > oss . blksize ) ;
/* update status & wake waiting readers */
dev - > oss . dma_blk = ( dev - > oss . dma_blk + 1 ) % dev - > oss . blocks ;
dev - > oss . read_count + = dev - > oss . blksize ;
wake_up ( & dev - > oss . wq ) ;
done :
spin_unlock ( & dev - > slock ) ;
}
/* ----------------------------------------------------------- */
/*
* Local variables :
* c - basic - offset : 8
* End :
*/