2005-04-17 02:20:36 +04:00
/*
2008-02-02 01:09:33 +03:00
* Q40 I / O port IDE Driver
2005-04-17 02:20:36 +04:00
*
* ( c ) Richard Zidlicky
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file COPYING in the main directory of this archive for
* more details .
*
*
*/
# include <linux/types.h>
# include <linux/mm.h>
# include <linux/interrupt.h>
# include <linux/blkdev.h>
# include <linux/hdreg.h>
# include <linux/ide.h>
/*
* Bases of the IDE interfaces
*/
# define Q40IDE_NUM_HWIFS 2
# define PCIDE_BASE1 0x1f0
# define PCIDE_BASE2 0x170
# define PCIDE_BASE3 0x1e8
# define PCIDE_BASE4 0x168
# define PCIDE_BASE5 0x1e0
# define PCIDE_BASE6 0x160
static const unsigned long pcide_bases [ Q40IDE_NUM_HWIFS ] = {
PCIDE_BASE1 , PCIDE_BASE2 , /* PCIDE_BASE3, PCIDE_BASE4 , PCIDE_BASE5,
PCIDE_BASE6 */
} ;
static int q40ide_default_irq ( unsigned long base )
{
switch ( base ) {
case 0x1f0 : return 14 ;
case 0x170 : return 15 ;
case 0x1e8 : return 11 ;
default :
return 0 ;
}
}
/*
2008-02-06 04:57:50 +03:00
* Addresses are pretranslated for Q40 ISA access .
2005-04-17 02:20:36 +04:00
*/
2008-04-28 09:59:35 +04:00
static void q40_ide_setup_ports ( hw_regs_t * hw , unsigned long base ,
2005-04-17 02:20:36 +04:00
ide_ack_intr_t * ack_intr ,
int irq )
{
2006-06-23 13:04:51 +04:00
memset ( hw , 0 , sizeof ( hw_regs_t ) ) ;
2008-04-28 09:59:35 +04:00
/* BIG FAT WARNING:
assumption : only DATA port is ever used in 16 bit mode */
hw - > io_ports . data_addr = Q40_ISA_IO_W ( base ) ;
hw - > io_ports . error_addr = Q40_ISA_IO_B ( base + 1 ) ;
hw - > io_ports . nsect_addr = Q40_ISA_IO_B ( base + 2 ) ;
hw - > io_ports . lbal_addr = Q40_ISA_IO_B ( base + 3 ) ;
hw - > io_ports . lbam_addr = Q40_ISA_IO_B ( base + 4 ) ;
hw - > io_ports . lbah_addr = Q40_ISA_IO_B ( base + 5 ) ;
hw - > io_ports . device_addr = Q40_ISA_IO_B ( base + 6 ) ;
hw - > io_ports . status_addr = Q40_ISA_IO_B ( base + 7 ) ;
hw - > io_ports . ctl_addr = Q40_ISA_IO_B ( base + 0x206 ) ;
2007-10-20 02:32:32 +04:00
2005-04-17 02:20:36 +04:00
hw - > irq = irq ;
hw - > ack_intr = ack_intr ;
2008-06-10 22:56:37 +04:00
hw - > chipset = ide_generic ;
2005-04-17 02:20:36 +04:00
}
2008-04-29 01:44:36 +04:00
static void q40ide_input_data ( ide_drive_t * drive , struct request * rq ,
void * buf , unsigned int len )
2008-04-29 01:44:36 +04:00
{
2008-04-29 01:44:36 +04:00
unsigned long data_addr = drive - > hwif - > io_ports . data_addr ;
2008-04-29 01:44:36 +04:00
if ( drive - > media = = ide_disk & & rq & & rq - > cmd_type = = REQ_TYPE_FS )
2008-04-29 01:44:36 +04:00
return insw ( data_addr , buf , ( len + 1 ) / 2 ) ;
2008-04-29 01:44:36 +04:00
2008-04-29 01:44:36 +04:00
insw_swapw ( data_addr , buf , ( len + 1 ) / 2 ) ;
2008-04-29 01:44:36 +04:00
}
2008-04-29 01:44:36 +04:00
static void q40ide_output_data ( ide_drive_t * drive , struct request * rq ,
void * buf , unsigned int len )
2008-04-29 01:44:36 +04:00
{
2008-04-29 01:44:36 +04:00
unsigned long data_addr = drive - > hwif - > io_ports . data_addr ;
2008-04-29 01:44:36 +04:00
if ( drive - > media = = ide_disk & & rq & & rq - > cmd_type = = REQ_TYPE_FS )
2008-04-29 01:44:36 +04:00
return outsw ( data_addr , buf , ( len + 1 ) / 2 ) ;
2008-04-29 01:44:36 +04:00
2008-04-29 01:44:36 +04:00
outsw_swapw ( data_addr , buf , ( len + 1 ) / 2 ) ;
2008-04-29 01:44:36 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-23 21:55:56 +04:00
/* Q40 has a byte-swapped IDE interface */
static const struct ide_tp_ops q40ide_tp_ops = {
. exec_command = ide_exec_command ,
. read_status = ide_read_status ,
. read_altstatus = ide_read_altstatus ,
. read_sff_dma_status = ide_read_sff_dma_status ,
. set_irq = ide_set_irq ,
. tf_load = ide_tf_load ,
. tf_read = ide_tf_read ,
. input_data = q40ide_input_data ,
. output_data = q40ide_output_data ,
} ;
static const struct ide_port_info q40ide_port_info = {
. tp_ops = & q40ide_tp_ops ,
. host_flags = IDE_HFLAG_NO_DMA ,
} ;
2005-04-17 02:20:36 +04:00
/*
* the static array is needed to have the name reported in / proc / ioports ,
2007-10-20 01:21:04 +04:00
* hwif - > name unfortunately isn ' t available yet
2005-04-17 02:20:36 +04:00
*/
static const char * q40_ide_names [ Q40IDE_NUM_HWIFS ] = {
" ide0 " , " ide1 "
} ;
/*
* Probe for Q40 IDE interfaces
*/
2008-01-26 22:13:07 +03:00
static int __init q40ide_init ( void )
2005-04-17 02:20:36 +04:00
{
2008-07-23 21:55:57 +04:00
struct ide_host * host ;
2005-04-17 02:20:36 +04:00
int i ;
2008-07-23 21:55:50 +04:00
hw_regs_t hw [ Q40IDE_NUM_HWIFS ] , * hws [ ] = { NULL , NULL , NULL , NULL } ;
2005-04-17 02:20:36 +04:00
if ( ! MACH_IS_Q40 )
2008-01-26 22:13:07 +03:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2008-01-26 22:13:09 +03:00
printk ( KERN_INFO " ide: Q40 IDE controller \n " ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < Q40IDE_NUM_HWIFS ; i + + ) {
2008-07-23 21:55:50 +04:00
const char * name = q40_ide_names [ i ] ;
2005-04-17 02:20:36 +04:00
if ( ! request_region ( pcide_bases [ i ] , 8 , name ) ) {
printk ( " could not reserve ports %lx-%lx for %s \n " ,
pcide_bases [ i ] , pcide_bases [ i ] + 8 , name ) ;
continue ;
}
if ( ! request_region ( pcide_bases [ i ] + 0x206 , 1 , name ) ) {
printk ( " could not reserve port %lx for %s \n " ,
pcide_bases [ i ] + 0x206 , name ) ;
release_region ( pcide_bases [ i ] , 8 ) ;
continue ;
}
2008-07-23 21:55:50 +04:00
q40_ide_setup_ports ( & hw [ i ] , pcide_bases [ i ] , NULL ,
2005-04-17 02:20:36 +04:00
q40ide_default_irq ( pcide_bases [ i ] ) ) ;
2008-01-26 22:13:06 +03:00
2008-07-23 21:55:57 +04:00
hws [ i ] = & hw [ i ] ;
2005-04-17 02:20:36 +04:00
}
2008-01-26 22:13:06 +03:00
2008-07-23 21:55:57 +04:00
host = ide_host_alloc ( & q40ide_port_info , hws ) ;
if ( host )
ide_host_register ( host , & q40ide_port_info , hws ) ;
2008-01-26 22:13:07 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-01-26 22:13:07 +03:00
module_init ( q40ide_init ) ;
2008-04-02 23:22:04 +04:00
MODULE_LICENSE ( " GPL " ) ;