//************************************************************* // // reg_config() - Check the host adapter and determine the // number and type of drives attached. // // This process is not documented by any of the ATA standards. // // Infomation is returned by this function is in // reg_config_info[] -- see ATAIO.H. // //************************************************************* int reg_config( void ) { int numDev = 0; unsigned char sc; unsigned char sn; unsigned char cl; unsigned char ch; unsigned char st; unsigned char devCtrl; // setup register values devCtrl = CB_DC_HD15 | ( int_use_intr_flag ? 0 : CB_DC_NIEN ); // mark start of config in low level trace trc_llt( 0, 0, TRC_LLT_S_CFG ); // assume there are no devices reg_config_info[0] = REG_CONFIG_TYPE_NONE; reg_config_info[1] = REG_CONFIG_TYPE_NONE; // set up Device Control register pio_outbyte( CB_DC, devCtrl ); // lets see if there is a device 0 pio_outbyte( CB_DH, CB_DH_DEV0 ); DELAY400NS; pio_outbyte( CB_SC, 0x55 ); pio_outbyte( CB_SN, 0xaa ); pio_outbyte( CB_SC, 0xaa ); pio_outbyte( CB_SN, 0x55 ); pio_outbyte( CB_SC, 0x55 ); pio_outbyte( CB_SN, 0xaa ); sc = pio_inbyte( CB_SC ); sn = pio_inbyte( CB_SN ); if ( ( sc == 0x55 ) && ( sn == 0xaa ) ) reg_config_info[0] = REG_CONFIG_TYPE_UNKN; // lets see if there is a device 1 pio_outbyte( CB_DH, CB_DH_DEV1 ); DELAY400NS; pio_outbyte( CB_SC, 0x55 ); pio_outbyte( CB_SN, 0xaa ); pio_outbyte( CB_SC, 0xaa ); pio_outbyte( CB_SN, 0x55 ); pio_outbyte( CB_SC, 0x55 ); pio_outbyte( CB_SN, 0xaa ); sc = pio_inbyte( CB_SC ); sn = pio_inbyte( CB_SN ); if ( ( sc == 0x55 ) && ( sn == 0xaa ) ) reg_config_info[1] = REG_CONFIG_TYPE_UNKN; // now we think we know which devices, if any are there, // so lets try a soft reset (ignoring any errors). pio_outbyte( CB_DH, CB_DH_DEV0 ); DELAY400NS; reg_reset( 0, 0 ); // lets check device 0 again, is device 0 really there? // is it ATA or ATAPI? pio_outbyte( CB_DH, CB_DH_DEV0 ); DELAY400NS; sc = pio_inbyte( CB_SC ); sn = pio_inbyte( CB_SN ); if ( ( sc == 0x01 ) && ( sn == 0x01 ) ) { reg_config_info[0] = REG_CONFIG_TYPE_UNKN; cl = pio_inbyte( CB_CL ); ch = pio_inbyte( CB_CH ); st = pio_inbyte( CB_STAT ); if ( ( cl == 0x14 ) && ( ch == 0xeb ) ) reg_config_info[0] = REG_CONFIG_TYPE_ATAPI; else if ( ( cl == 0x00 ) && ( ch == 0x00 ) && ( st != 0x00 ) ) reg_config_info[0] = REG_CONFIG_TYPE_ATA; } // lets check device 1 again, is device 1 really there? // is it ATA or ATAPI? pio_outbyte( CB_DH, CB_DH_DEV1 ); DELAY400NS; sc = pio_inbyte( CB_SC ); sn = pio_inbyte( CB_SN ); if ( ( sc == 0x01 ) && ( sn == 0x01 ) ) { reg_config_info[1] = REG_CONFIG_TYPE_UNKN; cl = pio_inbyte( CB_CL ); ch = pio_inbyte( CB_CH ); st = pio_inbyte( CB_STAT ); if ( ( cl == 0x14 ) && ( ch == 0xeb ) ) reg_config_info[1] = REG_CONFIG_TYPE_ATAPI; else if ( ( cl == 0x00 ) && ( ch == 0x00 ) && ( st != 0x00 ) ) reg_config_info[1] = REG_CONFIG_TYPE_ATA; } // If possible, select a device that exists, try device 0 first. if ( reg_config_info[1] != REG_CONFIG_TYPE_NONE ) { pio_outbyte( CB_DH, CB_DH_DEV1 ); DELAY400NS; numDev ++ ; } if ( reg_config_info[0] != REG_CONFIG_TYPE_NONE ) { pio_outbyte( CB_DH, CB_DH_DEV0 ); DELAY400NS; numDev ++ ; } // mark end of config in low level trace trc_llt( 0, 0, TRC_LLT_E_CFG ); // return the number of devices found return numDev; } //************************************************************* // // reg_reset() - Execute a Software Reset. // // See ATA-2 Section 9.2, ATA-3 Section 9.2, ATA-4 Section 8.3. // //************************************************************* int reg_reset( int skipFlag, int devRtrn ) { unsigned char sc; unsigned char sn; unsigned char status; unsigned char devCtrl; // setup register values devCtrl = CB_DC_HD15 | ( int_use_intr_flag ? 0 : CB_DC_NIEN ); // mark start of reset in low level trace trc_llt( 0, 0, TRC_LLT_S_RST ); // Reset error return data. sub_zero_return_data(); reg_cmd_info.flg = TRC_FLAG_SRST; reg_cmd_info.ct = TRC_TYPE_ASR; // initialize the command timeout counter tmr_set_timeout(); // Set and then reset the soft reset bit in the Device Control // register. This causes device 0 be selected. if ( ! skipFlag ) { pio_outbyte( CB_DC, devCtrl | CB_DC_SRST ); DELAY400NS; pio_outbyte( CB_DC, devCtrl ); DELAY400NS; } // If there is a device 0, wait for device 0 to set BSY=0. if ( reg_config_info[0] != REG_CONFIG_TYPE_NONE ) { sub_atapi_delay( 0 ); trc_llt( 0, 0, TRC_LLT_PNBSY ); while ( 1 ) { status = pio_inbyte( CB_STAT ); if ( ( status & CB_STAT_BSY ) == 0 ) break; if ( tmr_chk_timeout() ) { trc_llt( 0, 0, TRC_LLT_TOUT ); reg_cmd_info.to = 1; reg_cmd_info.ec = 1; trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR ); break; } } } // If there is a device 1, wait until device 1 allows // register access. if ( reg_config_info[1] != REG_CONFIG_TYPE_NONE ) { sub_atapi_delay( 1 ); trc_llt( 0, 0, TRC_LLT_PNBSY ); while ( 1 ) { pio_outbyte( CB_DH, CB_DH_DEV1 ); DELAY400NS; sc = pio_inbyte( CB_SC ); sn = pio_inbyte( CB_SN ); if ( ( sc == 0x01 ) && ( sn == 0x01 ) ) break; if ( tmr_chk_timeout() ) { trc_llt( 0, 0, TRC_LLT_TOUT ); reg_cmd_info.to = 1; reg_cmd_info.ec = 2; trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR ); break; } } // Now check if drive 1 set BSY=0. if ( reg_cmd_info.ec == 0 ) { if ( pio_inbyte( CB_STAT ) & CB_STAT_BSY ) { reg_cmd_info.ec = 3; trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR ); } } } // RESET_DONE: // We are done but now we must select the device the caller // requested before we trace the command. This will cause // the correct data to be returned in reg_cmd_info. pio_outbyte( CB_DH, devRtrn ? CB_DH_DEV1 : CB_DH_DEV0 ); DELAY400NS; sub_trace_command(); // If possible, select a device that exists, // try device 0 first. if ( reg_config_info[1] != REG_CONFIG_TYPE_NONE ) { pio_outbyte( CB_DH, CB_DH_DEV1 ); DELAY400NS; } if ( reg_config_info[0] != REG_CONFIG_TYPE_NONE ) { pio_outbyte( CB_DH, CB_DH_DEV0 ); DELAY400NS; } // mark end of reset in low level trace trc_llt( 0, 0, TRC_LLT_E_RST ); // All done. The return values of this function are described in // ATAIO.H. if ( reg_cmd_info.ec ) return 1; return 0; }