2011-03-15 07:53:21 +01:00
/*
2014-11-29 00:59:25 +09:00
* oxfw . c - a part of driver for OXFW970 / 971 based devices
2011-03-15 07:53:21 +01:00
*
* Copyright ( c ) Clemens Ladisch < clemens @ ladisch . de >
* Licensed under the terms of the GNU General Public License , version 2.
*/
2014-11-29 00:59:27 +09:00
# include "oxfw.h"
2011-03-15 07:53:21 +01:00
# define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000)
/* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */
# define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020)
# define OXFORD_HARDWARE_ID_OXFW970 0x39443841
# define OXFORD_HARDWARE_ID_OXFW971 0x39373100
2014-12-09 00:10:45 +09:00
# define VENDOR_LOUD 0x000ff2
2011-03-15 07:53:21 +01:00
# define VENDOR_GRIFFIN 0x001292
2014-12-09 00:10:45 +09:00
# define VENDOR_BEHRINGER 0x001564
2011-03-15 07:53:21 +01:00
# define VENDOR_LACIE 0x00d04b
2015-10-18 17:09:40 +09:00
# define VENDOR_TASCAM 0x00022e
2015-12-22 09:15:45 +09:00
# define OUI_STANTON 0x001260
2011-03-15 07:53:21 +01:00
2015-09-20 21:18:55 +09:00
# define MODEL_SATELLITE 0x00200f
2011-03-15 07:53:21 +01:00
# define SPECIFIER_1394TA 0x00a02d
# define VERSION_AVC 0x010001
2014-11-29 00:59:25 +09:00
MODULE_DESCRIPTION ( " Oxford Semiconductor FW970/971 driver " ) ;
2011-03-15 07:53:21 +01:00
MODULE_AUTHOR ( " Clemens Ladisch <clemens@ladisch.de> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
2014-11-29 00:59:25 +09:00
MODULE_ALIAS ( " snd-firewire-speakers " ) ;
2015-12-22 09:15:45 +09:00
MODULE_ALIAS ( " snd-scs1x " ) ;
2011-03-15 07:53:21 +01:00
2015-12-16 20:37:57 +09:00
struct compat_info {
const char * driver_name ;
const char * vendor_name ;
const char * model_name ;
} ;
2014-12-09 00:10:45 +09:00
static bool detect_loud_models ( struct fw_unit * unit )
{
const char * const models [ ] = {
" Onyxi " ,
" Onyx-i " ,
" d.Pro " ,
" Mackie Onyx Satellite " ,
" Tapco LINK.firewire 4x6 " ,
" U.420 " } ;
char model [ 32 ] ;
unsigned int i ;
int err ;
err = fw_csr_string ( unit - > directory , CSR_MODEL ,
model , sizeof ( model ) ) ;
if ( err < 0 )
2014-12-12 22:28:10 +03:00
return false ;
2014-12-09 00:10:45 +09:00
for ( i = 0 ; i < ARRAY_SIZE ( models ) ; i + + ) {
if ( strcmp ( models [ i ] , model ) = = 0 )
break ;
}
return ( i < ARRAY_SIZE ( models ) ) ;
}
2014-12-09 00:10:40 +09:00
static int name_card ( struct snd_oxfw * oxfw )
2011-03-15 07:53:21 +01:00
{
2014-12-09 00:10:40 +09:00
struct fw_device * fw_dev = fw_parent_device ( oxfw - > unit ) ;
2015-12-16 20:37:57 +09:00
const struct compat_info * info ;
2014-12-09 00:10:45 +09:00
char vendor [ 24 ] ;
char model [ 32 ] ;
2014-12-09 00:10:40 +09:00
const char * d , * v , * m ;
u32 firmware ;
2011-03-15 07:53:21 +01:00
int err ;
2014-12-09 00:10:45 +09:00
/* get vendor name from root directory */
err = fw_csr_string ( fw_dev - > config_rom + 5 , CSR_VENDOR ,
vendor , sizeof ( vendor ) ) ;
if ( err < 0 )
goto end ;
/* get model name from unit directory */
err = fw_csr_string ( oxfw - > unit - > directory , CSR_MODEL ,
model , sizeof ( model ) ) ;
if ( err < 0 )
goto end ;
2014-12-09 00:10:40 +09:00
err = snd_fw_transaction ( oxfw - > unit , TCODE_READ_QUADLET_REQUEST ,
OXFORD_FIRMWARE_ID_ADDRESS , & firmware , 4 , 0 ) ;
if ( err < 0 )
goto end ;
be32_to_cpus ( & firmware ) ;
2014-12-09 00:10:45 +09:00
/* to apply card definitions */
2015-12-15 23:56:20 +09:00
if ( oxfw - > entry - > vendor_id = = VENDOR_GRIFFIN | |
oxfw - > entry - > vendor_id = = VENDOR_LACIE ) {
2015-12-16 20:37:57 +09:00
info = ( const struct compat_info * ) oxfw - > entry - > driver_data ;
2015-12-15 23:56:20 +09:00
d = info - > driver_name ;
v = info - > vendor_name ;
m = info - > model_name ;
2014-12-09 00:10:45 +09:00
} else {
d = " OXFW " ;
v = vendor ;
m = model ;
}
2014-12-09 00:10:40 +09:00
strcpy ( oxfw - > card - > driver , d ) ;
strcpy ( oxfw - > card - > mixername , m ) ;
strcpy ( oxfw - > card - > shortname , m ) ;
snprintf ( oxfw - > card - > longname , sizeof ( oxfw - > card - > longname ) ,
" %s %s (OXFW%x %04x), GUID %08x%08x at %s, S%d " ,
v , m , firmware > > 20 , firmware & 0xffff ,
fw_dev - > config_rom [ 3 ] , fw_dev - > config_rom [ 4 ] ,
dev_name ( & oxfw - > unit - > device ) , 100 < < fw_dev - > max_speed ) ;
end :
return err ;
2011-03-15 07:53:21 +01:00
}
2015-02-21 23:54:57 +09:00
/*
* This module releases the FireWire unit data after all ALSA character devices
* are released by applications . This is for releasing stream data or finishing
* transactions safely . Thus at returning from . remove ( ) , this module still keep
* references for the unit .
*/
2014-11-29 00:59:25 +09:00
static void oxfw_card_free ( struct snd_card * card )
2011-03-15 07:53:21 +01:00
{
2014-11-29 00:59:25 +09:00
struct snd_oxfw * oxfw = card - > private_data ;
2014-12-09 00:10:42 +09:00
unsigned int i ;
2015-02-21 23:55:00 +09:00
snd_oxfw_stream_destroy_simplex ( oxfw , & oxfw - > rx_stream ) ;
if ( oxfw - > has_output )
snd_oxfw_stream_destroy_simplex ( oxfw , & oxfw - > tx_stream ) ;
2015-02-21 23:54:57 +09:00
fw_unit_put ( oxfw - > unit ) ;
2014-12-09 00:10:46 +09:00
for ( i = 0 ; i < SND_OXFW_STREAM_FORMAT_ENTRIES ; i + + ) {
kfree ( oxfw - > tx_stream_formats [ i ] ) ;
2014-12-09 00:10:42 +09:00
kfree ( oxfw - > rx_stream_formats [ i ] ) ;
2014-12-09 00:10:46 +09:00
}
2011-03-15 07:53:21 +01:00
2015-12-16 20:37:54 +09:00
kfree ( oxfw - > spec ) ;
2014-11-29 00:59:25 +09:00
mutex_destroy ( & oxfw - > mutex ) ;
2011-03-15 07:53:21 +01:00
}
2015-12-15 23:56:21 +09:00
static int detect_quirks ( struct snd_oxfw * oxfw )
2015-09-20 21:18:55 +09:00
{
struct fw_device * fw_dev = fw_parent_device ( oxfw - > unit ) ;
struct fw_csr_iterator it ;
int key , val ;
int vendor , model ;
2015-12-15 23:56:21 +09:00
/*
* Add ALSA control elements for two models to keep compatibility to
* old firewire - speaker module .
*/
2015-12-16 20:37:56 +09:00
if ( oxfw - > entry - > vendor_id = = VENDOR_GRIFFIN )
return snd_oxfw_add_spkr ( oxfw , false ) ;
if ( oxfw - > entry - > vendor_id = = VENDOR_LACIE )
return snd_oxfw_add_spkr ( oxfw , true ) ;
2015-12-15 23:56:21 +09:00
2015-12-22 09:15:45 +09:00
/*
* Stanton models supports asynchronous transactions for unique MIDI
* messages .
*/
2015-12-22 09:15:46 +09:00
if ( oxfw - > entry - > vendor_id = = OUI_STANTON ) {
/* No physical MIDI ports. */
oxfw - > midi_input_ports = 0 ;
oxfw - > midi_output_ports = 0 ;
/* Output stream exists but no data channels are useful. */
oxfw - > has_output = false ;
2015-12-22 09:15:45 +09:00
return snd_oxfw_scs1x_add ( oxfw ) ;
2015-12-22 09:15:46 +09:00
}
2015-12-22 09:15:45 +09:00
2015-12-15 23:56:20 +09:00
/*
* TASCAM FireOne has physical control and requires a pair of additional
* MIDI ports .
*/
if ( oxfw - > entry - > vendor_id = = VENDOR_TASCAM ) {
oxfw - > midi_input_ports + + ;
oxfw - > midi_output_ports + + ;
2015-12-15 23:56:21 +09:00
return 0 ;
2015-12-15 23:56:20 +09:00
}
2015-09-20 21:18:55 +09:00
/* Seek from Root Directory of Config ROM. */
vendor = model = 0 ;
fw_csr_iterator_init ( & it , fw_dev - > config_rom + 5 ) ;
while ( fw_csr_iterator_next ( & it , & key , & val ) ) {
if ( key = = CSR_VENDOR )
vendor = val ;
else if ( key = = CSR_MODEL )
model = val ;
}
/*
* Mackie Onyx Satellite with base station has a quirk to report a wrong
* value in ' dbs ' field of CIP header against its format information .
*/
if ( vendor = = VENDOR_LOUD & & model = = MODEL_SATELLITE )
oxfw - > wrong_dbs = true ;
2015-12-15 23:56:21 +09:00
return 0 ;
2015-09-20 21:18:55 +09:00
}
2014-11-29 00:59:25 +09:00
static int oxfw_probe ( struct fw_unit * unit ,
2015-12-15 23:56:20 +09:00
const struct ieee1394_device_id * entry )
2011-03-15 07:53:21 +01:00
{
struct snd_card * card ;
2014-11-29 00:59:25 +09:00
struct snd_oxfw * oxfw ;
2011-03-15 07:53:21 +01:00
int err ;
2015-12-15 23:56:20 +09:00
if ( entry - > vendor_id = = VENDOR_LOUD & & ! detect_loud_models ( unit ) )
2014-12-09 00:10:45 +09:00
return - ENODEV ;
2014-01-29 14:23:55 +01:00
err = snd_card_new ( & unit - > device , - 1 , NULL , THIS_MODULE ,
2014-11-29 00:59:25 +09:00
sizeof ( * oxfw ) , & card ) ;
2011-03-15 07:53:21 +01:00
if ( err < 0 )
return err ;
2014-11-29 00:59:27 +09:00
card - > private_free = oxfw_card_free ;
2014-11-29 00:59:25 +09:00
oxfw = card - > private_data ;
oxfw - > card = card ;
mutex_init ( & oxfw - > mutex ) ;
2015-02-21 23:54:57 +09:00
oxfw - > unit = fw_unit_get ( unit ) ;
2015-12-15 23:56:20 +09:00
oxfw - > entry = entry ;
2014-12-09 00:10:48 +09:00
spin_lock_init ( & oxfw - > lock ) ;
2014-12-09 00:10:49 +09:00
init_waitqueue_head ( & oxfw - > hwdep_wait ) ;
2011-03-15 07:53:21 +01:00
2014-12-09 00:10:42 +09:00
err = snd_oxfw_stream_discover ( oxfw ) ;
if ( err < 0 )
goto error ;
2015-12-22 09:15:39 +09:00
err = name_card ( oxfw ) ;
2015-12-15 23:56:21 +09:00
if ( err < 0 )
goto error ;
2015-09-20 21:18:55 +09:00
2015-12-22 09:15:39 +09:00
err = detect_quirks ( oxfw ) ;
2014-12-09 00:10:40 +09:00
if ( err < 0 )
goto error ;
2011-03-15 07:53:21 +01:00
2014-11-29 00:59:28 +09:00
err = snd_oxfw_create_pcm ( oxfw ) ;
2011-03-15 07:53:21 +01:00
if ( err < 0 )
goto error ;
2014-12-09 00:10:43 +09:00
snd_oxfw_proc_init ( oxfw ) ;
2014-12-09 00:10:48 +09:00
err = snd_oxfw_create_midi ( oxfw ) ;
if ( err < 0 )
goto error ;
2014-12-09 00:10:49 +09:00
err = snd_oxfw_create_hwdep ( oxfw ) ;
if ( err < 0 )
goto error ;
2014-12-09 00:10:46 +09:00
err = snd_oxfw_stream_init_simplex ( oxfw , & oxfw - > rx_stream ) ;
2011-03-15 07:53:21 +01:00
if ( err < 0 )
goto error ;
2014-12-09 00:10:46 +09:00
if ( oxfw - > has_output ) {
err = snd_oxfw_stream_init_simplex ( oxfw , & oxfw - > tx_stream ) ;
if ( err < 0 )
goto error ;
}
2011-03-15 07:53:21 +01:00
2014-11-29 00:59:27 +09:00
err = snd_card_register ( card ) ;
if ( err < 0 ) {
2014-12-09 00:10:46 +09:00
snd_oxfw_stream_destroy_simplex ( oxfw , & oxfw - > rx_stream ) ;
if ( oxfw - > has_output )
snd_oxfw_stream_destroy_simplex ( oxfw , & oxfw - > tx_stream ) ;
2014-11-29 00:59:27 +09:00
goto error ;
}
2014-11-29 00:59:25 +09:00
dev_set_drvdata ( & unit - > device , oxfw ) ;
2011-03-15 07:53:21 +01:00
return 0 ;
error :
snd_card_free ( card ) ;
return err ;
}
2014-11-29 00:59:25 +09:00
static void oxfw_bus_reset ( struct fw_unit * unit )
2011-03-15 07:53:21 +01:00
{
2014-11-29 00:59:25 +09:00
struct snd_oxfw * oxfw = dev_get_drvdata ( & unit - > device ) ;
2011-03-15 07:53:21 +01:00
2014-11-29 00:59:25 +09:00
fcp_bus_reset ( oxfw - > unit ) ;
2011-03-15 07:53:21 +01:00
2014-11-29 00:59:27 +09:00
mutex_lock ( & oxfw - > mutex ) ;
2014-12-09 00:10:46 +09:00
snd_oxfw_stream_update_simplex ( oxfw , & oxfw - > rx_stream ) ;
if ( oxfw - > has_output )
snd_oxfw_stream_update_simplex ( oxfw , & oxfw - > tx_stream ) ;
2014-11-29 00:59:27 +09:00
mutex_unlock ( & oxfw - > mutex ) ;
2015-12-22 09:15:45 +09:00
if ( oxfw - > entry - > vendor_id = = OUI_STANTON )
snd_oxfw_scs1x_update ( oxfw ) ;
2011-03-15 07:53:21 +01:00
}
2014-11-29 00:59:25 +09:00
static void oxfw_remove ( struct fw_unit * unit )
2013-06-09 18:15:00 +02:00
{
2014-11-29 00:59:25 +09:00
struct snd_oxfw * oxfw = dev_get_drvdata ( & unit - > device ) ;
2013-06-09 18:15:00 +02:00
2015-02-21 23:54:57 +09:00
/* No need to wait for releasing card object in this context. */
2014-11-29 00:59:25 +09:00
snd_card_free_when_closed ( oxfw - > card ) ;
2013-06-09 18:15:00 +02:00
}
2015-12-16 20:37:57 +09:00
static const struct compat_info griffin_firewave = {
2013-06-09 18:15:00 +02:00
. driver_name = " FireWave " ,
2014-12-09 00:10:40 +09:00
. vendor_name = " Griffin " ,
. model_name = " FireWave " ,
2013-06-09 18:15:00 +02:00
} ;
2015-12-16 20:37:57 +09:00
static const struct compat_info lacie_speakers = {
2013-06-09 18:15:00 +02:00
. driver_name = " FWSpeakers " ,
2014-12-09 00:10:40 +09:00
. vendor_name = " LaCie " ,
. model_name = " FireWire Speakers " ,
2013-06-09 18:15:00 +02:00
} ;
2014-11-29 00:59:25 +09:00
static const struct ieee1394_device_id oxfw_id_table [ ] = {
2011-03-15 07:53:21 +01:00
{
. match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID |
IEEE1394_MATCH_SPECIFIER_ID |
IEEE1394_MATCH_VERSION ,
. vendor_id = VENDOR_GRIFFIN ,
. model_id = 0x00f970 ,
. specifier_id = SPECIFIER_1394TA ,
. version = VERSION_AVC ,
2013-06-09 18:15:00 +02:00
. driver_data = ( kernel_ulong_t ) & griffin_firewave ,
2011-03-15 07:53:21 +01:00
} ,
{
. match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID |
IEEE1394_MATCH_SPECIFIER_ID |
IEEE1394_MATCH_VERSION ,
. vendor_id = VENDOR_LACIE ,
. model_id = 0x00f970 ,
. specifier_id = SPECIFIER_1394TA ,
. version = VERSION_AVC ,
2013-06-09 18:15:00 +02:00
. driver_data = ( kernel_ulong_t ) & lacie_speakers ,
2011-03-15 07:53:21 +01:00
} ,
2014-12-09 00:10:45 +09:00
/* Behringer,F-Control Audio 202 */
{
. match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID ,
. vendor_id = VENDOR_BEHRINGER ,
. model_id = 0x00fc22 ,
} ,
/*
* Any Mackie ( Loud ) models ( name string / model id ) :
* Onyx - i series ( former models ) : 0x081216
* Mackie Onyx Satellite : 0x00200f
* Tapco LINK . firewire 4 x6 : 0x000460
* d .2 pro : Unknown
* d .4 pro : Unknown
* U .420 : Unknown
* U .420 d : Unknown
*/
{
. match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_SPECIFIER_ID |
IEEE1394_MATCH_VERSION ,
. vendor_id = VENDOR_LOUD ,
. specifier_id = SPECIFIER_1394TA ,
. version = VERSION_AVC ,
} ,
2015-10-18 17:09:40 +09:00
/* TASCAM, FireOne */
{
. match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID ,
. vendor_id = VENDOR_TASCAM ,
. model_id = 0x800007 ,
} ,
2015-12-22 09:15:45 +09:00
/* Stanton, Stanton Controllers & Systems 1 Mixer (SCS.1m) */
{
. match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID ,
. vendor_id = OUI_STANTON ,
. model_id = 0x001000 ,
} ,
/* Stanton, Stanton Controllers & Systems 1 Deck (SCS.1d) */
{
. match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID ,
. vendor_id = OUI_STANTON ,
. model_id = 0x002000 ,
} ,
2011-03-15 07:53:21 +01:00
{ }
} ;
2014-11-29 00:59:25 +09:00
MODULE_DEVICE_TABLE ( ieee1394 , oxfw_id_table ) ;
2011-03-15 07:53:21 +01:00
2014-11-29 00:59:25 +09:00
static struct fw_driver oxfw_driver = {
2011-03-15 07:53:21 +01:00
. driver = {
. owner = THIS_MODULE ,
. name = KBUILD_MODNAME ,
. bus = & fw_bus_type ,
} ,
2014-11-29 00:59:25 +09:00
. probe = oxfw_probe ,
. update = oxfw_bus_reset ,
. remove = oxfw_remove ,
. id_table = oxfw_id_table ,
2011-03-15 07:53:21 +01:00
} ;
2014-11-29 00:59:25 +09:00
static int __init snd_oxfw_init ( void )
2011-03-15 07:53:21 +01:00
{
2014-11-29 00:59:25 +09:00
return driver_register ( & oxfw_driver . driver ) ;
2011-03-15 07:53:21 +01:00
}
2014-11-29 00:59:25 +09:00
static void __exit snd_oxfw_exit ( void )
2011-03-15 07:53:21 +01:00
{
2014-11-29 00:59:25 +09:00
driver_unregister ( & oxfw_driver . driver ) ;
2011-03-15 07:53:21 +01:00
}
2014-11-29 00:59:25 +09:00
module_init ( snd_oxfw_init ) ;
module_exit ( snd_oxfw_exit ) ;