2009-05-14 10:05:58 +04:00
/**
* Copyright ( C ) 2008 , Creative Technology Ltd . All Rights Reserved .
*
* This source file is released under GPL v2 license ( no other versions ) .
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions .
*
* @ File ctdaio . c
*
* @ Brief
* This file contains the implementation of Digital Audio Input Output
* resource management object .
*
* @ Author Liu Chun
* @ Date May 23 2008
*
*/
# include "ctdaio.h"
# include "cthardware.h"
# include "ctimap.h"
# include <linux/slab.h>
# include <linux/kernel.h>
# define DAIO_OUT_MAX SPDIFOO
2011-06-11 12:02:06 +04:00
struct daio_usage {
2009-05-14 10:05:58 +04:00
unsigned short data ;
} ;
struct daio_rsc_idx {
unsigned short left ;
unsigned short right ;
} ;
2013-09-13 13:44:21 +04:00
static struct daio_rsc_idx idx_20k1 [ NUM_DAIOTYP ] = {
2009-05-14 10:05:58 +04:00
[ LINEO1 ] = { . left = 0x00 , . right = 0x01 } ,
[ LINEO2 ] = { . left = 0x18 , . right = 0x19 } ,
[ LINEO3 ] = { . left = 0x08 , . right = 0x09 } ,
[ LINEO4 ] = { . left = 0x10 , . right = 0x11 } ,
[ LINEIM ] = { . left = 0x1b5 , . right = 0x1bd } ,
[ SPDIFOO ] = { . left = 0x20 , . right = 0x21 } ,
[ SPDIFIO ] = { . left = 0x15 , . right = 0x1d } ,
[ SPDIFI1 ] = { . left = 0x95 , . right = 0x9d } ,
} ;
2013-09-13 13:44:21 +04:00
static struct daio_rsc_idx idx_20k2 [ NUM_DAIOTYP ] = {
2009-05-14 10:05:58 +04:00
[ LINEO1 ] = { . left = 0x40 , . right = 0x41 } ,
2009-07-20 19:00:14 +04:00
[ LINEO2 ] = { . left = 0x60 , . right = 0x61 } ,
2009-05-14 10:05:58 +04:00
[ LINEO3 ] = { . left = 0x50 , . right = 0x51 } ,
2009-07-20 19:00:14 +04:00
[ LINEO4 ] = { . left = 0x70 , . right = 0x71 } ,
2009-05-14 10:05:58 +04:00
[ LINEIM ] = { . left = 0x45 , . right = 0xc5 } ,
2011-06-11 12:02:06 +04:00
[ MIC ] = { . left = 0x55 , . right = 0xd5 } ,
2009-05-14 10:05:58 +04:00
[ SPDIFOO ] = { . left = 0x00 , . right = 0x01 } ,
[ SPDIFIO ] = { . left = 0x05 , . right = 0x85 } ,
} ;
static int daio_master ( struct rsc * rsc )
{
/* Actually, this is not the resource index of DAIO.
* For DAO , it is the input mapper index . And , for DAI ,
* it is the output time - slot index . */
return rsc - > conj = rsc - > idx ;
}
static int daio_index ( const struct rsc * rsc )
{
return rsc - > conj ;
}
static int daio_out_next_conj ( struct rsc * rsc )
{
return rsc - > conj + = 2 ;
}
static int daio_in_next_conj_20k1 ( struct rsc * rsc )
{
return rsc - > conj + = 0x200 ;
}
static int daio_in_next_conj_20k2 ( struct rsc * rsc )
{
return rsc - > conj + = 0x100 ;
}
2015-11-09 01:40:41 +03:00
static const struct rsc_ops daio_out_rsc_ops = {
2009-05-14 10:05:58 +04:00
. master = daio_master ,
. next_conj = daio_out_next_conj ,
. index = daio_index ,
. output_slot = NULL ,
} ;
2015-11-09 01:40:41 +03:00
static const struct rsc_ops daio_in_rsc_ops_20k1 = {
2009-05-14 10:05:58 +04:00
. master = daio_master ,
. next_conj = daio_in_next_conj_20k1 ,
. index = NULL ,
. output_slot = daio_index ,
} ;
2015-11-09 01:40:41 +03:00
static const struct rsc_ops daio_in_rsc_ops_20k2 = {
2009-05-14 10:05:58 +04:00
. master = daio_master ,
. next_conj = daio_in_next_conj_20k2 ,
. index = NULL ,
. output_slot = daio_index ,
} ;
static unsigned int daio_device_index ( enum DAIOTYP type , struct hw * hw )
{
2009-06-08 20:10:32 +04:00
switch ( hw - > chip_type ) {
2009-05-14 10:05:58 +04:00
case ATC20K1 :
switch ( type ) {
case SPDIFOO : return 0 ;
case SPDIFIO : return 0 ;
case SPDIFI1 : return 1 ;
case LINEO1 : return 4 ;
case LINEO2 : return 7 ;
case LINEO3 : return 5 ;
case LINEO4 : return 6 ;
case LINEIM : return 7 ;
default : return - EINVAL ;
}
case ATC20K2 :
switch ( type ) {
case SPDIFOO : return 0 ;
case SPDIFIO : return 0 ;
case LINEO1 : return 4 ;
case LINEO2 : return 7 ;
case LINEO3 : return 5 ;
case LINEO4 : return 6 ;
case LINEIM : return 4 ;
2011-06-11 12:02:06 +04:00
case MIC : return 5 ;
2009-05-14 10:05:58 +04:00
default : return - EINVAL ;
}
default :
return - EINVAL ;
}
}
static int dao_rsc_reinit ( struct dao * dao , const struct dao_desc * desc ) ;
static int dao_spdif_get_spos ( struct dao * dao , unsigned int * spos )
{
2014-09-29 13:03:23 +04:00
dao - > hw - > dao_get_spos ( dao - > ctrl_blk , spos ) ;
2009-05-14 10:05:58 +04:00
return 0 ;
}
static int dao_spdif_set_spos ( struct dao * dao , unsigned int spos )
{
2014-09-29 13:03:23 +04:00
dao - > hw - > dao_set_spos ( dao - > ctrl_blk , spos ) ;
2009-05-14 10:05:58 +04:00
return 0 ;
}
static int dao_commit_write ( struct dao * dao )
{
2014-09-29 13:03:23 +04:00
dao - > hw - > dao_commit_write ( dao - > hw ,
2009-05-14 10:05:58 +04:00
daio_device_index ( dao - > daio . type , dao - > hw ) , dao - > ctrl_blk ) ;
return 0 ;
}
static int dao_set_left_input ( struct dao * dao , struct rsc * input )
{
2009-06-08 16:57:57 +04:00
struct imapper * entry ;
2009-05-14 10:05:58 +04:00
struct daio * daio = & dao - > daio ;
2009-06-08 16:57:57 +04:00
int i ;
2009-05-14 10:05:58 +04:00
entry = kzalloc ( ( sizeof ( * entry ) * daio - > rscl . msr ) , GFP_KERNEL ) ;
2009-07-22 19:12:34 +04:00
if ( ! entry )
2009-05-14 10:05:58 +04:00
return - ENOMEM ;
2011-03-13 18:18:58 +03:00
dao - > ops - > clear_left_input ( dao ) ;
2009-05-14 10:05:58 +04:00
/* Program master and conjugate resources */
input - > ops - > master ( input ) ;
daio - > rscl . ops - > master ( & daio - > rscl ) ;
for ( i = 0 ; i < daio - > rscl . msr ; i + + , entry + + ) {
entry - > slot = input - > ops - > output_slot ( input ) ;
entry - > user = entry - > addr = daio - > rscl . ops - > index ( & daio - > rscl ) ;
dao - > mgr - > imap_add ( dao - > mgr , entry ) ;
dao - > imappers [ i ] = entry ;
input - > ops - > next_conj ( input ) ;
daio - > rscl . ops - > next_conj ( & daio - > rscl ) ;
}
input - > ops - > master ( input ) ;
daio - > rscl . ops - > master ( & daio - > rscl ) ;
return 0 ;
}
static int dao_set_right_input ( struct dao * dao , struct rsc * input )
{
2009-06-08 16:57:57 +04:00
struct imapper * entry ;
2009-05-14 10:05:58 +04:00
struct daio * daio = & dao - > daio ;
2009-06-08 16:57:57 +04:00
int i ;
2009-05-14 10:05:58 +04:00
entry = kzalloc ( ( sizeof ( * entry ) * daio - > rscr . msr ) , GFP_KERNEL ) ;
2009-07-22 19:12:34 +04:00
if ( ! entry )
2009-05-14 10:05:58 +04:00
return - ENOMEM ;
2011-03-13 18:18:58 +03:00
dao - > ops - > clear_right_input ( dao ) ;
2009-05-14 10:05:58 +04:00
/* Program master and conjugate resources */
input - > ops - > master ( input ) ;
daio - > rscr . ops - > master ( & daio - > rscr ) ;
for ( i = 0 ; i < daio - > rscr . msr ; i + + , entry + + ) {
entry - > slot = input - > ops - > output_slot ( input ) ;
entry - > user = entry - > addr = daio - > rscr . ops - > index ( & daio - > rscr ) ;
dao - > mgr - > imap_add ( dao - > mgr , entry ) ;
dao - > imappers [ daio - > rscl . msr + i ] = entry ;
input - > ops - > next_conj ( input ) ;
daio - > rscr . ops - > next_conj ( & daio - > rscr ) ;
}
input - > ops - > master ( input ) ;
daio - > rscr . ops - > master ( & daio - > rscr ) ;
return 0 ;
}
static int dao_clear_left_input ( struct dao * dao )
{
2009-06-08 16:57:57 +04:00
struct imapper * entry ;
2009-05-14 10:05:58 +04:00
struct daio * daio = & dao - > daio ;
2009-06-08 16:57:57 +04:00
int i ;
2009-05-14 10:05:58 +04:00
2009-07-22 19:12:34 +04:00
if ( ! dao - > imappers [ 0 ] )
2009-05-14 10:05:58 +04:00
return 0 ;
entry = dao - > imappers [ 0 ] ;
dao - > mgr - > imap_delete ( dao - > mgr , entry ) ;
/* Program conjugate resources */
for ( i = 1 ; i < daio - > rscl . msr ; i + + ) {
entry = dao - > imappers [ i ] ;
dao - > mgr - > imap_delete ( dao - > mgr , entry ) ;
dao - > imappers [ i ] = NULL ;
}
kfree ( dao - > imappers [ 0 ] ) ;
dao - > imappers [ 0 ] = NULL ;
return 0 ;
}
static int dao_clear_right_input ( struct dao * dao )
{
2009-06-08 16:57:57 +04:00
struct imapper * entry ;
2009-05-14 10:05:58 +04:00
struct daio * daio = & dao - > daio ;
2009-06-08 16:57:57 +04:00
int i ;
2009-05-14 10:05:58 +04:00
2009-07-22 19:12:34 +04:00
if ( ! dao - > imappers [ daio - > rscl . msr ] )
2009-05-14 10:05:58 +04:00
return 0 ;
entry = dao - > imappers [ daio - > rscl . msr ] ;
dao - > mgr - > imap_delete ( dao - > mgr , entry ) ;
/* Program conjugate resources */
for ( i = 1 ; i < daio - > rscr . msr ; i + + ) {
entry = dao - > imappers [ daio - > rscl . msr + i ] ;
dao - > mgr - > imap_delete ( dao - > mgr , entry ) ;
dao - > imappers [ daio - > rscl . msr + i ] = NULL ;
}
kfree ( dao - > imappers [ daio - > rscl . msr ] ) ;
dao - > imappers [ daio - > rscl . msr ] = NULL ;
return 0 ;
}
2015-11-09 01:40:41 +03:00
static const struct dao_rsc_ops dao_ops = {
2009-05-14 10:05:58 +04:00
. set_spos = dao_spdif_set_spos ,
. commit_write = dao_commit_write ,
. get_spos = dao_spdif_get_spos ,
. reinit = dao_rsc_reinit ,
. set_left_input = dao_set_left_input ,
. set_right_input = dao_set_right_input ,
. clear_left_input = dao_clear_left_input ,
. clear_right_input = dao_clear_right_input ,
} ;
static int dai_set_srt_srcl ( struct dai * dai , struct rsc * src )
{
src - > ops - > master ( src ) ;
2014-09-29 13:03:23 +04:00
dai - > hw - > dai_srt_set_srcm ( dai - > ctrl_blk , src - > ops - > index ( src ) ) ;
2009-05-14 10:05:58 +04:00
return 0 ;
}
static int dai_set_srt_srcr ( struct dai * dai , struct rsc * src )
{
src - > ops - > master ( src ) ;
2014-09-29 13:03:23 +04:00
dai - > hw - > dai_srt_set_srco ( dai - > ctrl_blk , src - > ops - > index ( src ) ) ;
2009-05-14 10:05:58 +04:00
return 0 ;
}
static int dai_set_srt_msr ( struct dai * dai , unsigned int msr )
{
2009-06-08 16:57:57 +04:00
unsigned int rsr ;
2009-05-14 10:05:58 +04:00
for ( rsr = 0 ; msr > 1 ; msr > > = 1 )
rsr + + ;
2014-09-29 13:03:23 +04:00
dai - > hw - > dai_srt_set_rsr ( dai - > ctrl_blk , rsr ) ;
2009-05-14 10:05:58 +04:00
return 0 ;
}
static int dai_set_enb_src ( struct dai * dai , unsigned int enb )
{
2014-09-29 13:03:23 +04:00
dai - > hw - > dai_srt_set_ec ( dai - > ctrl_blk , enb ) ;
2009-05-14 10:05:58 +04:00
return 0 ;
}
static int dai_set_enb_srt ( struct dai * dai , unsigned int enb )
{
2014-09-29 13:03:23 +04:00
dai - > hw - > dai_srt_set_et ( dai - > ctrl_blk , enb ) ;
2009-05-14 10:05:58 +04:00
return 0 ;
}
static int dai_commit_write ( struct dai * dai )
{
2014-09-29 13:03:23 +04:00
dai - > hw - > dai_commit_write ( dai - > hw ,
2009-05-14 10:05:58 +04:00
daio_device_index ( dai - > daio . type , dai - > hw ) , dai - > ctrl_blk ) ;
return 0 ;
}
2015-11-09 01:40:41 +03:00
static const struct dai_rsc_ops dai_ops = {
2009-05-14 10:05:58 +04:00
. set_srt_srcl = dai_set_srt_srcl ,
. set_srt_srcr = dai_set_srt_srcr ,
. set_srt_msr = dai_set_srt_msr ,
. set_enb_src = dai_set_enb_src ,
. set_enb_srt = dai_set_enb_srt ,
. commit_write = dai_commit_write ,
} ;
static int daio_rsc_init ( struct daio * daio ,
const struct daio_desc * desc ,
2014-09-29 13:03:21 +04:00
struct hw * hw )
2009-05-14 10:05:58 +04:00
{
2009-06-08 16:57:57 +04:00
int err ;
unsigned int idx_l , idx_r ;
2009-05-14 10:05:58 +04:00
2014-09-29 13:03:23 +04:00
switch ( hw - > chip_type ) {
2009-05-14 10:05:58 +04:00
case ATC20K1 :
idx_l = idx_20k1 [ desc - > type ] . left ;
idx_r = idx_20k1 [ desc - > type ] . right ;
break ;
case ATC20K2 :
idx_l = idx_20k2 [ desc - > type ] . left ;
idx_r = idx_20k2 [ desc - > type ] . right ;
break ;
default :
return - EINVAL ;
}
err = rsc_init ( & daio - > rscl , idx_l , DAIO , desc - > msr , hw ) ;
if ( err )
return err ;
err = rsc_init ( & daio - > rscr , idx_r , DAIO , desc - > msr , hw ) ;
if ( err )
goto error1 ;
/* Set daio->rscl/r->ops to daio specific ones */
if ( desc - > type < = DAIO_OUT_MAX ) {
daio - > rscl . ops = daio - > rscr . ops = & daio_out_rsc_ops ;
} else {
2014-09-29 13:03:23 +04:00
switch ( hw - > chip_type ) {
2009-05-14 10:05:58 +04:00
case ATC20K1 :
daio - > rscl . ops = daio - > rscr . ops = & daio_in_rsc_ops_20k1 ;
break ;
case ATC20K2 :
daio - > rscl . ops = daio - > rscr . ops = & daio_in_rsc_ops_20k2 ;
break ;
default :
break ;
}
}
daio - > type = desc - > type ;
return 0 ;
error1 :
rsc_uninit ( & daio - > rscl ) ;
return err ;
}
static int daio_rsc_uninit ( struct daio * daio )
{
rsc_uninit ( & daio - > rscl ) ;
rsc_uninit ( & daio - > rscr ) ;
return 0 ;
}
static int dao_rsc_init ( struct dao * dao ,
const struct daio_desc * desc ,
struct daio_mgr * mgr )
{
struct hw * hw = mgr - > mgr . hw ;
2009-06-08 16:57:57 +04:00
unsigned int conf ;
int err ;
2009-05-14 10:05:58 +04:00
err = daio_rsc_init ( & dao - > daio , desc , mgr - > mgr . hw ) ;
if ( err )
return err ;
dao - > imappers = kzalloc ( sizeof ( void * ) * desc - > msr * 2 , GFP_KERNEL ) ;
2009-07-22 19:12:34 +04:00
if ( ! dao - > imappers ) {
2009-05-14 10:05:58 +04:00
err = - ENOMEM ;
goto error1 ;
}
dao - > ops = & dao_ops ;
dao - > mgr = mgr ;
dao - > hw = hw ;
err = hw - > dao_get_ctrl_blk ( & dao - > ctrl_blk ) ;
if ( err )
goto error2 ;
hw - > daio_mgr_dsb_dao ( mgr - > mgr . ctrl_blk ,
daio_device_index ( dao - > daio . type , hw ) ) ;
hw - > daio_mgr_commit_write ( hw , mgr - > mgr . ctrl_blk ) ;
2009-06-08 16:57:57 +04:00
conf = ( desc - > msr & 0x7 ) | ( desc - > passthru < < 3 ) ;
2009-05-14 10:05:58 +04:00
hw - > daio_mgr_dao_init ( mgr - > mgr . ctrl_blk ,
daio_device_index ( dao - > daio . type , hw ) , conf ) ;
hw - > daio_mgr_enb_dao ( mgr - > mgr . ctrl_blk ,
daio_device_index ( dao - > daio . type , hw ) ) ;
hw - > daio_mgr_commit_write ( hw , mgr - > mgr . ctrl_blk ) ;
return 0 ;
error2 :
kfree ( dao - > imappers ) ;
dao - > imappers = NULL ;
error1 :
daio_rsc_uninit ( & dao - > daio ) ;
return err ;
}
static int dao_rsc_uninit ( struct dao * dao )
{
2009-07-22 19:12:34 +04:00
if ( dao - > imappers ) {
if ( dao - > imappers [ 0 ] )
2009-05-14 10:05:58 +04:00
dao_clear_left_input ( dao ) ;
2009-07-22 19:12:34 +04:00
if ( dao - > imappers [ dao - > daio . rscl . msr ] )
2009-05-14 10:05:58 +04:00
dao_clear_right_input ( dao ) ;
kfree ( dao - > imappers ) ;
dao - > imappers = NULL ;
}
2014-09-29 13:03:23 +04:00
dao - > hw - > dao_put_ctrl_blk ( dao - > ctrl_blk ) ;
2009-05-14 10:05:58 +04:00
dao - > hw = dao - > ctrl_blk = NULL ;
daio_rsc_uninit ( & dao - > daio ) ;
return 0 ;
}
static int dao_rsc_reinit ( struct dao * dao , const struct dao_desc * desc )
{
struct daio_mgr * mgr = dao - > mgr ;
struct daio_desc dsc = { 0 } ;
dsc . type = dao - > daio . type ;
dsc . msr = desc - > msr ;
dsc . passthru = desc - > passthru ;
dao_rsc_uninit ( dao ) ;
return dao_rsc_init ( dao , & dsc , mgr ) ;
}
static int dai_rsc_init ( struct dai * dai ,
const struct daio_desc * desc ,
struct daio_mgr * mgr )
{
2009-06-08 16:57:57 +04:00
int err ;
2009-05-14 10:05:58 +04:00
struct hw * hw = mgr - > mgr . hw ;
2009-06-08 16:57:57 +04:00
unsigned int rsr , msr ;
2009-05-14 10:05:58 +04:00
err = daio_rsc_init ( & dai - > daio , desc , mgr - > mgr . hw ) ;
if ( err )
return err ;
dai - > ops = & dai_ops ;
dai - > hw = mgr - > mgr . hw ;
err = hw - > dai_get_ctrl_blk ( & dai - > ctrl_blk ) ;
if ( err )
goto error1 ;
for ( rsr = 0 , msr = desc - > msr ; msr > 1 ; msr > > = 1 )
rsr + + ;
hw - > dai_srt_set_rsr ( dai - > ctrl_blk , rsr ) ;
hw - > dai_srt_set_drat ( dai - > ctrl_blk , 0 ) ;
/* default to disabling control of a SRC */
hw - > dai_srt_set_ec ( dai - > ctrl_blk , 0 ) ;
hw - > dai_srt_set_et ( dai - > ctrl_blk , 0 ) ; /* default to disabling SRT */
hw - > dai_commit_write ( hw ,
daio_device_index ( dai - > daio . type , dai - > hw ) , dai - > ctrl_blk ) ;
return 0 ;
error1 :
daio_rsc_uninit ( & dai - > daio ) ;
return err ;
}
static int dai_rsc_uninit ( struct dai * dai )
{
2014-09-29 13:03:23 +04:00
dai - > hw - > dai_put_ctrl_blk ( dai - > ctrl_blk ) ;
2009-05-14 10:05:58 +04:00
dai - > hw = dai - > ctrl_blk = NULL ;
daio_rsc_uninit ( & dai - > daio ) ;
return 0 ;
}
static int daio_mgr_get_rsc ( struct rsc_mgr * mgr , enum DAIOTYP type )
{
2011-06-11 12:02:06 +04:00
if ( ( ( struct daio_usage * ) mgr - > rscs ) - > data & ( 0x1 < < type ) )
2009-05-14 10:05:58 +04:00
return - ENOENT ;
2011-06-11 12:02:06 +04:00
( ( struct daio_usage * ) mgr - > rscs ) - > data | = ( 0x1 < < type ) ;
2009-05-14 10:05:58 +04:00
return 0 ;
}
static int daio_mgr_put_rsc ( struct rsc_mgr * mgr , enum DAIOTYP type )
{
2011-06-11 12:02:06 +04:00
( ( struct daio_usage * ) mgr - > rscs ) - > data & = ~ ( 0x1 < < type ) ;
2009-05-14 10:05:58 +04:00
return 0 ;
}
static int get_daio_rsc ( struct daio_mgr * mgr ,
const struct daio_desc * desc ,
struct daio * * rdaio )
{
2009-06-08 16:57:57 +04:00
int err ;
2009-05-14 10:05:58 +04:00
unsigned long flags ;
* rdaio = NULL ;
/* Check whether there are sufficient daio resources to meet request. */
spin_lock_irqsave ( & mgr - > mgr_lock , flags ) ;
err = daio_mgr_get_rsc ( & mgr - > mgr , desc - > type ) ;
spin_unlock_irqrestore ( & mgr - > mgr_lock , flags ) ;
if ( err ) {
2014-09-29 13:03:26 +04:00
dev_err ( mgr - > card - > dev ,
" Can't meet DAIO resource request! \n " ) ;
2009-05-14 10:05:58 +04:00
return err ;
}
2014-12-03 20:59:31 +03:00
err = - ENOMEM ;
2009-05-14 10:05:58 +04:00
/* Allocate mem for daio resource */
if ( desc - > type < = DAIO_OUT_MAX ) {
2014-12-03 20:59:31 +03:00
struct dao * dao = kzalloc ( sizeof ( * dao ) , GFP_KERNEL ) ;
if ( ! dao )
2009-05-14 10:05:58 +04:00
goto error ;
2014-12-03 20:59:31 +03:00
2009-05-14 10:05:58 +04:00
err = dao_rsc_init ( dao , desc , mgr ) ;
2014-12-03 20:59:31 +03:00
if ( err ) {
kfree ( dao ) ;
2009-05-14 10:05:58 +04:00
goto error ;
2014-12-03 20:59:31 +03:00
}
2009-05-14 10:05:58 +04:00
* rdaio = & dao - > daio ;
} else {
2014-12-03 20:59:31 +03:00
struct dai * dai = kzalloc ( sizeof ( * dai ) , GFP_KERNEL ) ;
if ( ! dai )
2009-05-14 10:05:58 +04:00
goto error ;
2014-12-03 20:59:31 +03:00
2009-05-14 10:05:58 +04:00
err = dai_rsc_init ( dai , desc , mgr ) ;
2014-12-03 20:59:31 +03:00
if ( err ) {
kfree ( dai ) ;
2009-05-14 10:05:58 +04:00
goto error ;
2014-12-03 20:59:31 +03:00
}
2009-05-14 10:05:58 +04:00
* rdaio = & dai - > daio ;
}
mgr - > daio_enable ( mgr , * rdaio ) ;
mgr - > commit_write ( mgr ) ;
return 0 ;
error :
spin_lock_irqsave ( & mgr - > mgr_lock , flags ) ;
daio_mgr_put_rsc ( & mgr - > mgr , desc - > type ) ;
spin_unlock_irqrestore ( & mgr - > mgr_lock , flags ) ;
return err ;
}
static int put_daio_rsc ( struct daio_mgr * mgr , struct daio * daio )
{
unsigned long flags ;
mgr - > daio_disable ( mgr , daio ) ;
mgr - > commit_write ( mgr ) ;
spin_lock_irqsave ( & mgr - > mgr_lock , flags ) ;
daio_mgr_put_rsc ( & mgr - > mgr , daio - > type ) ;
spin_unlock_irqrestore ( & mgr - > mgr_lock , flags ) ;
if ( daio - > type < = DAIO_OUT_MAX ) {
dao_rsc_uninit ( container_of ( daio , struct dao , daio ) ) ;
kfree ( container_of ( daio , struct dao , daio ) ) ;
} else {
dai_rsc_uninit ( container_of ( daio , struct dai , daio ) ) ;
kfree ( container_of ( daio , struct dai , daio ) ) ;
}
return 0 ;
}
static int daio_mgr_enb_daio ( struct daio_mgr * mgr , struct daio * daio )
{
struct hw * hw = mgr - > mgr . hw ;
if ( DAIO_OUT_MAX > = daio - > type ) {
hw - > daio_mgr_enb_dao ( mgr - > mgr . ctrl_blk ,
daio_device_index ( daio - > type , hw ) ) ;
} else {
hw - > daio_mgr_enb_dai ( mgr - > mgr . ctrl_blk ,
daio_device_index ( daio - > type , hw ) ) ;
}
return 0 ;
}
static int daio_mgr_dsb_daio ( struct daio_mgr * mgr , struct daio * daio )
{
struct hw * hw = mgr - > mgr . hw ;
if ( DAIO_OUT_MAX > = daio - > type ) {
hw - > daio_mgr_dsb_dao ( mgr - > mgr . ctrl_blk ,
daio_device_index ( daio - > type , hw ) ) ;
} else {
hw - > daio_mgr_dsb_dai ( mgr - > mgr . ctrl_blk ,
daio_device_index ( daio - > type , hw ) ) ;
}
return 0 ;
}
static int daio_map_op ( void * data , struct imapper * entry )
{
struct rsc_mgr * mgr = & ( ( struct daio_mgr * ) data ) - > mgr ;
struct hw * hw = mgr - > hw ;
hw - > daio_mgr_set_imaparc ( mgr - > ctrl_blk , entry - > slot ) ;
hw - > daio_mgr_set_imapnxt ( mgr - > ctrl_blk , entry - > next ) ;
hw - > daio_mgr_set_imapaddr ( mgr - > ctrl_blk , entry - > addr ) ;
hw - > daio_mgr_commit_write ( mgr - > hw , mgr - > ctrl_blk ) ;
return 0 ;
}
static int daio_imap_add ( struct daio_mgr * mgr , struct imapper * entry )
{
unsigned long flags ;
2009-06-08 16:57:57 +04:00
int err ;
2009-05-14 10:05:58 +04:00
spin_lock_irqsave ( & mgr - > imap_lock , flags ) ;
2009-07-22 19:12:34 +04:00
if ( ! entry - > addr & & mgr - > init_imap_added ) {
2009-05-14 10:05:58 +04:00
input_mapper_delete ( & mgr - > imappers , mgr - > init_imap ,
daio_map_op , mgr ) ;
mgr - > init_imap_added = 0 ;
}
err = input_mapper_add ( & mgr - > imappers , entry , daio_map_op , mgr ) ;
spin_unlock_irqrestore ( & mgr - > imap_lock , flags ) ;
return err ;
}
static int daio_imap_delete ( struct daio_mgr * mgr , struct imapper * entry )
{
unsigned long flags ;
2009-06-08 16:57:57 +04:00
int err ;
2009-05-14 10:05:58 +04:00
spin_lock_irqsave ( & mgr - > imap_lock , flags ) ;
err = input_mapper_delete ( & mgr - > imappers , entry , daio_map_op , mgr ) ;
if ( list_empty ( & mgr - > imappers ) ) {
input_mapper_add ( & mgr - > imappers , mgr - > init_imap ,
daio_map_op , mgr ) ;
mgr - > init_imap_added = 1 ;
}
spin_unlock_irqrestore ( & mgr - > imap_lock , flags ) ;
return err ;
}
static int daio_mgr_commit_write ( struct daio_mgr * mgr )
{
struct hw * hw = mgr - > mgr . hw ;
hw - > daio_mgr_commit_write ( hw , mgr - > mgr . ctrl_blk ) ;
return 0 ;
}
2014-09-29 13:03:21 +04:00
int daio_mgr_create ( struct hw * hw , struct daio_mgr * * rdaio_mgr )
2009-05-14 10:05:58 +04:00
{
2009-06-08 16:57:57 +04:00
int err , i ;
2009-05-14 10:05:58 +04:00
struct daio_mgr * daio_mgr ;
struct imapper * entry ;
* rdaio_mgr = NULL ;
daio_mgr = kzalloc ( sizeof ( * daio_mgr ) , GFP_KERNEL ) ;
2009-07-22 19:12:34 +04:00
if ( ! daio_mgr )
2009-05-14 10:05:58 +04:00
return - ENOMEM ;
2011-06-11 12:02:06 +04:00
err = rsc_mgr_init ( & daio_mgr - > mgr , DAIO , NUM_DAIOTYP , hw ) ;
2009-05-14 10:05:58 +04:00
if ( err )
goto error1 ;
spin_lock_init ( & daio_mgr - > mgr_lock ) ;
spin_lock_init ( & daio_mgr - > imap_lock ) ;
INIT_LIST_HEAD ( & daio_mgr - > imappers ) ;
entry = kzalloc ( sizeof ( * entry ) , GFP_KERNEL ) ;
2009-07-22 19:12:34 +04:00
if ( ! entry ) {
2009-05-14 10:05:58 +04:00
err = - ENOMEM ;
goto error2 ;
}
entry - > slot = entry - > addr = entry - > next = entry - > user = 0 ;
list_add ( & entry - > list , & daio_mgr - > imappers ) ;
daio_mgr - > init_imap = entry ;
daio_mgr - > init_imap_added = 1 ;
daio_mgr - > get_daio = get_daio_rsc ;
daio_mgr - > put_daio = put_daio_rsc ;
daio_mgr - > daio_enable = daio_mgr_enb_daio ;
daio_mgr - > daio_disable = daio_mgr_dsb_daio ;
daio_mgr - > imap_add = daio_imap_add ;
daio_mgr - > imap_delete = daio_imap_delete ;
daio_mgr - > commit_write = daio_mgr_commit_write ;
2014-09-29 13:03:24 +04:00
daio_mgr - > card = hw - > card ;
2009-05-14 10:05:58 +04:00
for ( i = 0 ; i < 8 ; i + + ) {
2014-09-29 13:03:23 +04:00
hw - > daio_mgr_dsb_dao ( daio_mgr - > mgr . ctrl_blk , i ) ;
hw - > daio_mgr_dsb_dai ( daio_mgr - > mgr . ctrl_blk , i ) ;
2009-05-14 10:05:58 +04:00
}
2014-09-29 13:03:23 +04:00
hw - > daio_mgr_commit_write ( hw , daio_mgr - > mgr . ctrl_blk ) ;
2009-05-14 10:05:58 +04:00
* rdaio_mgr = daio_mgr ;
return 0 ;
error2 :
rsc_mgr_uninit ( & daio_mgr - > mgr ) ;
error1 :
kfree ( daio_mgr ) ;
return err ;
}
int daio_mgr_destroy ( struct daio_mgr * daio_mgr )
{
unsigned long flags ;
/* free daio input mapper list */
spin_lock_irqsave ( & daio_mgr - > imap_lock , flags ) ;
free_input_mapper_list ( & daio_mgr - > imappers ) ;
spin_unlock_irqrestore ( & daio_mgr - > imap_lock , flags ) ;
rsc_mgr_uninit ( & daio_mgr - > mgr ) ;
kfree ( daio_mgr ) ;
return 0 ;
}