2019-05-20 20:07:57 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2007-07-27 20:58:06 +04:00
/*
* HWDEP Interface for HD - audio codec
*
* Copyright ( c ) 2007 Takashi Iwai < tiwai @ suse . de >
*/
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/compat.h>
2018-04-24 08:50:50 +03:00
# include <linux/nospec.h>
2007-07-27 20:58:06 +04:00
# include <sound/core.h>
2018-08-22 23:24:57 +03:00
# include <sound/hda_codec.h>
2007-07-27 20:58:06 +04:00
# include "hda_local.h"
# include <sound/hda_hwdep.h>
2008-07-30 17:01:46 +04:00
# include <sound/minors.h>
2007-07-27 20:58:06 +04:00
/*
* write / read an out - of - bound verb
*/
static int verb_write_ioctl ( struct hda_codec * codec ,
struct hda_verb_ioctl __user * arg )
{
u32 verb , res ;
if ( get_user ( verb , & arg - > verb ) )
return - EFAULT ;
res = snd_hda_codec_read ( codec , verb > > 24 , 0 ,
( verb > > 8 ) & 0xffff , verb & 0xff ) ;
if ( put_user ( res , & arg - > res ) )
return - EFAULT ;
return 0 ;
}
static int get_wcap_ioctl ( struct hda_codec * codec ,
struct hda_verb_ioctl __user * arg )
{
u32 verb , res ;
if ( get_user ( verb , & arg - > verb ) )
return - EFAULT ;
2018-04-24 08:50:50 +03:00
/* open-code get_wcaps(verb>>24) with nospec */
verb > > = 24 ;
if ( verb < codec - > core . start_nid | |
verb > = codec - > core . start_nid + codec - > core . num_nodes ) {
res = 0 ;
} else {
verb - = codec - > core . start_nid ;
verb = array_index_nospec ( verb , codec - > core . num_nodes ) ;
res = codec - > wcaps [ verb ] ;
}
2007-07-27 20:58:06 +04:00
if ( put_user ( res , & arg - > res ) )
return - EFAULT ;
return 0 ;
}
/*
*/
static int hda_hwdep_ioctl ( struct snd_hwdep * hw , struct file * file ,
unsigned int cmd , unsigned long arg )
{
struct hda_codec * codec = hw - > private_data ;
void __user * argp = ( void __user * ) arg ;
switch ( cmd ) {
case HDA_IOCTL_PVERSION :
return put_user ( HDA_HWDEP_VERSION , ( int __user * ) argp ) ;
case HDA_IOCTL_VERB_WRITE :
return verb_write_ioctl ( codec , argp ) ;
case HDA_IOCTL_GET_WCAP :
return get_wcap_ioctl ( codec , argp ) ;
}
return - ENOIOCTLCMD ;
}
# ifdef CONFIG_COMPAT
static int hda_hwdep_ioctl_compat ( struct snd_hwdep * hw , struct file * file ,
unsigned int cmd , unsigned long arg )
{
2007-07-31 13:08:10 +04:00
return hda_hwdep_ioctl ( hw , file , cmd , ( unsigned long ) compat_ptr ( arg ) ) ;
2007-07-27 20:58:06 +04:00
}
# endif
static int hda_hwdep_open ( struct snd_hwdep * hw , struct file * file )
{
2008-05-20 14:15:15 +04:00
# ifndef CONFIG_SND_DEBUG_VERBOSE
2007-07-27 20:58:06 +04:00
if ( ! capable ( CAP_SYS_RAWIO ) )
return - EACCES ;
# endif
return 0 ;
}
2012-12-07 10:41:56 +04:00
int snd_hda_create_hwdep ( struct hda_codec * codec )
2007-07-27 20:58:06 +04:00
{
char hwname [ 16 ] ;
struct snd_hwdep * hwdep ;
int err ;
sprintf ( hwname , " HDA Codec %d " , codec - > addr ) ;
2015-02-27 18:09:22 +03:00
err = snd_hwdep_new ( codec - > card , hwname , codec - > addr , & hwdep ) ;
2007-07-27 20:58:06 +04:00
if ( err < 0 )
return err ;
codec - > hwdep = hwdep ;
sprintf ( hwdep - > name , " HDA Codec %d " , codec - > addr ) ;
hwdep - > iface = SNDRV_HWDEP_IFACE_HDA ;
hwdep - > private_data = codec ;
hwdep - > exclusive = 1 ;
hwdep - > ops . open = hda_hwdep_open ;
hwdep - > ops . ioctl = hda_hwdep_ioctl ;
# ifdef CONFIG_COMPAT
hwdep - > ops . ioctl_compat = hda_hwdep_ioctl_compat ;
# endif
2015-01-29 19:13:32 +03:00
/* for sysfs */
hwdep - > dev . groups = snd_hda_dev_attr_groups ;
dev_set_drvdata ( & hwdep - > dev , codec ) ;
2014-02-25 10:53:47 +04:00
2007-07-27 20:58:06 +04:00
return 0 ;
}