2009-03-25 01:22:44 +03:00
# include <linux/kernel.h>
# include <linux/ide.h>
DEFINE_MUTEX ( ide_setting_mtx ) ;
ide_devset_get ( io_32bit , io_32bit ) ;
static int set_io_32bit ( ide_drive_t * drive , int arg )
{
if ( drive - > dev_flags & IDE_DFLAG_NO_IO_32BIT )
return - EPERM ;
if ( arg < 0 | | arg > 1 + ( SUPPORT_VLB_SYNC < < 1 ) )
return - EINVAL ;
drive - > io_32bit = arg ;
return 0 ;
}
ide_devset_get_flag ( ksettings , IDE_DFLAG_KEEP_SETTINGS ) ;
static int set_ksettings ( ide_drive_t * drive , int arg )
{
if ( arg < 0 | | arg > 1 )
return - EINVAL ;
if ( arg )
drive - > dev_flags | = IDE_DFLAG_KEEP_SETTINGS ;
else
drive - > dev_flags & = ~ IDE_DFLAG_KEEP_SETTINGS ;
return 0 ;
}
ide_devset_get_flag ( using_dma , IDE_DFLAG_USING_DMA ) ;
static int set_using_dma ( ide_drive_t * drive , int arg )
{
# ifdef CONFIG_BLK_DEV_IDEDMA
int err = - EPERM ;
if ( arg < 0 | | arg > 1 )
return - EINVAL ;
if ( ata_id_has_dma ( drive - > id ) = = 0 )
goto out ;
if ( drive - > hwif - > dma_ops = = NULL )
goto out ;
err = 0 ;
if ( arg ) {
if ( ide_set_dma ( drive ) )
err = - EIO ;
} else
ide_dma_off ( drive ) ;
out :
return err ;
# else
if ( arg < 0 | | arg > 1 )
return - EINVAL ;
return - EPERM ;
# endif
}
/*
* handle HDIO_SET_PIO_MODE ioctl abusers here , eventually it will go away
*/
static int set_pio_mode_abuse ( ide_hwif_t * hwif , u8 req_pio )
{
switch ( req_pio ) {
case 202 :
case 201 :
case 200 :
case 102 :
case 101 :
case 100 :
return ( hwif - > host_flags & IDE_HFLAG_ABUSE_DMA_MODES ) ? 1 : 0 ;
case 9 :
case 8 :
return ( hwif - > host_flags & IDE_HFLAG_ABUSE_PREFETCH ) ? 1 : 0 ;
case 7 :
case 6 :
return ( hwif - > host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL ) ? 1 : 0 ;
default :
return 0 ;
}
}
static int set_pio_mode ( ide_drive_t * drive , int arg )
{
ide_hwif_t * hwif = drive - > hwif ;
const struct ide_port_ops * port_ops = hwif - > port_ops ;
if ( arg < 0 | | arg > 255 )
return - EINVAL ;
if ( port_ops = = NULL | | port_ops - > set_pio_mode = = NULL | |
( hwif - > host_flags & IDE_HFLAG_NO_SET_MODE ) )
return - ENOSYS ;
if ( set_pio_mode_abuse ( drive - > hwif , arg ) ) {
if ( arg = = 8 | | arg = = 9 ) {
unsigned long flags ;
/* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
spin_lock_irqsave ( & hwif - > lock , flags ) ;
port_ops - > set_pio_mode ( drive , arg ) ;
spin_unlock_irqrestore ( & hwif - > lock , flags ) ;
} else
port_ops - > set_pio_mode ( drive , arg ) ;
} else {
int keep_dma = ! ! ( drive - > dev_flags & IDE_DFLAG_USING_DMA ) ;
ide_set_pio ( drive , arg ) ;
if ( hwif - > host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA ) {
if ( keep_dma )
ide_dma_on ( drive ) ;
}
}
return 0 ;
}
ide_devset_get_flag ( unmaskirq , IDE_DFLAG_UNMASK ) ;
static int set_unmaskirq ( ide_drive_t * drive , int arg )
{
if ( drive - > dev_flags & IDE_DFLAG_NO_UNMASK )
return - EPERM ;
if ( arg < 0 | | arg > 1 )
return - EINVAL ;
if ( arg )
drive - > dev_flags | = IDE_DFLAG_UNMASK ;
else
drive - > dev_flags & = ~ IDE_DFLAG_UNMASK ;
return 0 ;
}
ide_ext_devset_rw_sync ( io_32bit , io_32bit ) ;
ide_ext_devset_rw_sync ( keepsettings , ksettings ) ;
ide_ext_devset_rw_sync ( unmaskirq , unmaskirq ) ;
ide_ext_devset_rw_sync ( using_dma , using_dma ) ;
__IDE_DEVSET ( pio_mode , DS_SYNC , NULL , set_pio_mode ) ;
int ide_devset_execute ( ide_drive_t * drive , const struct ide_devset * setting ,
int arg )
{
struct request_queue * q = drive - > queue ;
struct request * rq ;
int ret = 0 ;
if ( ! ( setting - > flags & DS_SYNC ) )
return setting - > set ( drive , arg ) ;
rq = blk_get_request ( q , READ , __GFP_WAIT ) ;
rq - > cmd_type = REQ_TYPE_SPECIAL ;
rq - > cmd_len = 5 ;
rq - > cmd [ 0 ] = REQ_DEVSET_EXEC ;
* ( int * ) & rq - > cmd [ 1 ] = arg ;
rq - > special = setting - > set ;
if ( blk_execute_rq ( q , NULL , rq , 0 ) )
ret = rq - > errors ;
blk_put_request ( rq ) ;
return ret ;
}
ide_startstop_t ide_do_devset ( ide_drive_t * drive , struct request * rq )
{
int err , ( * setfunc ) ( ide_drive_t * , int ) = rq - > special ;
err = setfunc ( drive , * ( int * ) & rq - > cmd [ 1 ] ) ;
if ( err )
rq - > errors = err ;
2009-03-27 14:46:45 +03:00
ide_complete_rq ( drive , err , ide_rq_bytes ( rq ) ) ;
2009-03-25 01:22:44 +03:00
return ide_stopped ;
}