2019-05-29 16:57:59 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2015-10-01 22:02:17 +09:00
/*
* tascam - hwdep . c - a part of driver for TASCAM FireWire series
*
* Copyright ( c ) 2015 Takashi Sakamoto
*/
/*
* This codes give three functionality .
*
* 1. get firewire node information
* 2. get notification about starting / stopping stream
* 3. lock / unlock stream
*/
# include "tascam.h"
2018-11-23 13:13:06 +09:00
static long tscm_hwdep_read_locked ( struct snd_tscm * tscm , char __user * buf ,
long count , loff_t * offset )
2020-03-11 01:09:08 +00:00
__releases ( & tscm - > lock )
2018-11-23 13:13:06 +09:00
{
struct snd_firewire_event_lock_status event = {
. type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS ,
} ;
event . status = ( tscm - > dev_lock_count > 0 ) ;
tscm - > dev_lock_changed = false ;
count = min_t ( long , count , sizeof ( event ) ) ;
spin_unlock_irq ( & tscm - > lock ) ;
if ( copy_to_user ( buf , & event , count ) )
return - EFAULT ;
return count ;
}
2018-11-23 13:13:07 +09:00
static long tscm_hwdep_read_queue ( struct snd_tscm * tscm , char __user * buf ,
long remained , loff_t * offset )
2020-03-11 01:09:07 +00:00
__releases ( & tscm - > lock )
2018-11-23 13:13:07 +09:00
{
char __user * pos = buf ;
unsigned int type = SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL ;
struct snd_firewire_tascam_change * entries = tscm - > queue ;
long count ;
// At least, one control event can be copied.
if ( remained < sizeof ( type ) + sizeof ( * entries ) ) {
spin_unlock_irq ( & tscm - > lock ) ;
return - EINVAL ;
}
// Copy the type field later.
count = sizeof ( type ) ;
remained - = sizeof ( type ) ;
pos + = sizeof ( type ) ;
while ( true ) {
unsigned int head_pos ;
unsigned int tail_pos ;
unsigned int length ;
if ( tscm - > pull_pos = = tscm - > push_pos )
break ;
else if ( tscm - > pull_pos < tscm - > push_pos )
tail_pos = tscm - > push_pos ;
else
tail_pos = SND_TSCM_QUEUE_COUNT ;
head_pos = tscm - > pull_pos ;
length = ( tail_pos - head_pos ) * sizeof ( * entries ) ;
if ( remained < length )
length = rounddown ( remained , sizeof ( * entries ) ) ;
if ( length = = 0 )
break ;
spin_unlock_irq ( & tscm - > lock ) ;
if ( copy_to_user ( pos , & entries [ head_pos ] , length ) )
return - EFAULT ;
spin_lock_irq ( & tscm - > lock ) ;
tscm - > pull_pos = tail_pos % SND_TSCM_QUEUE_COUNT ;
count + = length ;
remained - = length ;
pos + = length ;
}
spin_unlock_irq ( & tscm - > lock ) ;
if ( copy_to_user ( buf , & type , sizeof ( type ) ) )
return - EFAULT ;
return count ;
}
2015-10-01 22:02:17 +09:00
static long hwdep_read ( struct snd_hwdep * hwdep , char __user * buf , long count ,
loff_t * offset )
{
struct snd_tscm * tscm = hwdep - > private_data ;
DEFINE_WAIT ( wait ) ;
spin_lock_irq ( & tscm - > lock ) ;
2018-11-23 13:13:07 +09:00
while ( ! tscm - > dev_lock_changed & & tscm - > push_pos = = tscm - > pull_pos ) {
2015-10-01 22:02:17 +09:00
prepare_to_wait ( & tscm - > hwdep_wait , & wait , TASK_INTERRUPTIBLE ) ;
spin_unlock_irq ( & tscm - > lock ) ;
schedule ( ) ;
finish_wait ( & tscm - > hwdep_wait , & wait ) ;
if ( signal_pending ( current ) )
return - ERESTARTSYS ;
spin_lock_irq ( & tscm - > lock ) ;
}
2018-11-23 13:13:06 +09:00
// NOTE: The acquired lock should be released in callee side.
if ( tscm - > dev_lock_changed ) {
count = tscm_hwdep_read_locked ( tscm , buf , count , offset ) ;
2018-11-23 13:13:07 +09:00
} else if ( tscm - > push_pos ! = tscm - > pull_pos ) {
count = tscm_hwdep_read_queue ( tscm , buf , count , offset ) ;
2018-11-23 13:13:06 +09:00
} else {
spin_unlock_irq ( & tscm - > lock ) ;
count = 0 ;
}
2016-08-31 20:15:32 +09:00
2015-10-01 22:02:17 +09:00
return count ;
}
2017-07-02 23:27:36 -04:00
static __poll_t hwdep_poll ( struct snd_hwdep * hwdep , struct file * file ,
2015-10-01 22:02:17 +09:00
poll_table * wait )
{
struct snd_tscm * tscm = hwdep - > private_data ;
2017-07-02 23:27:36 -04:00
__poll_t events ;
2015-10-01 22:02:17 +09:00
poll_wait ( file , & tscm - > hwdep_wait , wait ) ;
spin_lock_irq ( & tscm - > lock ) ;
2018-11-23 13:13:07 +09:00
if ( tscm - > dev_lock_changed | | tscm - > push_pos ! = tscm - > pull_pos )
2018-02-11 14:34:03 -08:00
events = EPOLLIN | EPOLLRDNORM ;
2015-10-01 22:02:17 +09:00
else
events = 0 ;
spin_unlock_irq ( & tscm - > lock ) ;
return events ;
}
static int hwdep_get_info ( struct snd_tscm * tscm , void __user * arg )
{
struct fw_device * dev = fw_parent_device ( tscm - > unit ) ;
struct snd_firewire_get_info info ;
memset ( & info , 0 , sizeof ( info ) ) ;
info . type = SNDRV_FIREWIRE_TYPE_TASCAM ;
info . card = dev - > card - > index ;
* ( __be32 * ) & info . guid [ 0 ] = cpu_to_be32 ( dev - > config_rom [ 3 ] ) ;
* ( __be32 * ) & info . guid [ 4 ] = cpu_to_be32 ( dev - > config_rom [ 4 ] ) ;
ALSA: Convert strlcpy to strscpy when return value is unused
strlcpy is deprecated. see: Documentation/process/deprecated.rst
Change the calls that do not use the strlcpy return value to the
preferred strscpy.
Done with cocci script:
@@
expression e1, e2, e3;
@@
- strlcpy(
+ strscpy(
e1, e2, e3);
This cocci script leaves the instances where the return value is
used unchanged.
After this patch, sound/ has 3 uses of strlcpy() that need to be
manually inspected for conversion and changed one day.
$ git grep -w strlcpy sound/
sound/usb/card.c: len = strlcpy(card->longname, s, sizeof(card->longname));
sound/usb/mixer.c: return strlcpy(buf, p->name, buflen);
sound/usb/mixer.c: return strlcpy(buf, p->names[index], buflen);
Miscellenea:
o Remove trailing whitespace in conversion of sound/core/hwdep.c
Link: https://lore.kernel.org/lkml/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw@mail.gmail.com/
Signed-off-by: Joe Perches <joe@perches.com>
Acked-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/22b393d1790bb268769d0bab7bacf0866dcb0c14.camel@perches.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-01-04 09:17:34 -08:00
strscpy ( info . device_name , dev_name ( & dev - > device ) ,
2015-10-01 22:02:17 +09:00
sizeof ( info . device_name ) ) ;
if ( copy_to_user ( arg , & info , sizeof ( info ) ) )
return - EFAULT ;
return 0 ;
}
static int hwdep_lock ( struct snd_tscm * tscm )
{
int err ;
spin_lock_irq ( & tscm - > lock ) ;
if ( tscm - > dev_lock_count = = 0 ) {
tscm - > dev_lock_count = - 1 ;
err = 0 ;
} else {
err = - EBUSY ;
}
spin_unlock_irq ( & tscm - > lock ) ;
return err ;
}
static int hwdep_unlock ( struct snd_tscm * tscm )
{
int err ;
spin_lock_irq ( & tscm - > lock ) ;
if ( tscm - > dev_lock_count = = - 1 ) {
tscm - > dev_lock_count = 0 ;
err = 0 ;
} else {
err = - EBADFD ;
}
spin_unlock_irq ( & tscm - > lock ) ;
return err ;
}
2018-11-23 13:13:04 +09:00
static int tscm_hwdep_state ( struct snd_tscm * tscm , void __user * arg )
{
if ( copy_to_user ( arg , tscm - > state , sizeof ( tscm - > state ) ) )
return - EFAULT ;
return 0 ;
}
2015-10-01 22:02:17 +09:00
static int hwdep_release ( struct snd_hwdep * hwdep , struct file * file )
{
struct snd_tscm * tscm = hwdep - > private_data ;
spin_lock_irq ( & tscm - > lock ) ;
if ( tscm - > dev_lock_count = = - 1 )
tscm - > dev_lock_count = 0 ;
spin_unlock_irq ( & tscm - > lock ) ;
return 0 ;
}
static int hwdep_ioctl ( struct snd_hwdep * hwdep , struct file * file ,
unsigned int cmd , unsigned long arg )
{
struct snd_tscm * tscm = hwdep - > private_data ;
switch ( cmd ) {
case SNDRV_FIREWIRE_IOCTL_GET_INFO :
return hwdep_get_info ( tscm , ( void __user * ) arg ) ;
case SNDRV_FIREWIRE_IOCTL_LOCK :
return hwdep_lock ( tscm ) ;
case SNDRV_FIREWIRE_IOCTL_UNLOCK :
return hwdep_unlock ( tscm ) ;
2018-11-23 13:13:04 +09:00
case SNDRV_FIREWIRE_IOCTL_TASCAM_STATE :
return tscm_hwdep_state ( tscm , ( void __user * ) arg ) ;
2015-10-01 22:02:17 +09:00
default :
return - ENOIOCTLCMD ;
}
}
# ifdef CONFIG_COMPAT
static int hwdep_compat_ioctl ( struct snd_hwdep * hwdep , struct file * file ,
unsigned int cmd , unsigned long arg )
{
return hwdep_ioctl ( hwdep , file , cmd ,
( unsigned long ) compat_ptr ( arg ) ) ;
}
# else
# define hwdep_compat_ioctl NULL
# endif
int snd_tscm_create_hwdep_device ( struct snd_tscm * tscm )
{
2017-01-05 21:48:12 +09:00
static const struct snd_hwdep_ops ops = {
. read = hwdep_read ,
. release = hwdep_release ,
. poll = hwdep_poll ,
. ioctl = hwdep_ioctl ,
. ioctl_compat = hwdep_compat_ioctl ,
} ;
2015-10-01 22:02:17 +09:00
struct snd_hwdep * hwdep ;
int err ;
err = snd_hwdep_new ( tscm - > card , " Tascam " , 0 , & hwdep ) ;
if ( err < 0 )
return err ;
strcpy ( hwdep - > name , " Tascam " ) ;
hwdep - > iface = SNDRV_HWDEP_IFACE_FW_TASCAM ;
2017-01-05 21:48:12 +09:00
hwdep - > ops = ops ;
2015-10-01 22:02:17 +09:00
hwdep - > private_data = tscm ;
hwdep - > exclusive = true ;
2018-11-23 13:13:05 +09:00
tscm - > hwdep = hwdep ;
2015-10-01 22:02:17 +09:00
return err ;
}