#include "insignia.h" #include "host_def.h" /*[ Name: gfi_sflop.c Derived From: 2.0 gfi_sflop.c Author: Jerry Kramskoy Created On: Unknown Sccs ID: @(#)gfi_sflop.c 1.16 08/14/92 Purpose: Interface between FLA and the IBM PC. The PC acts as a server for remote procedure calls from the base product to access the 8272A controller. Notes: Invalid FDC commands should be trapped by FLA (c)Copyright Insignia Solutions Ltd., 1990. All rights reserved. ]*/ #ifdef SLAVEPC /* bigger than max pkt so as to accom extra header chars*/ #define MEGAPKTPLUS 1040 USHORT megapkt = 512; /* packet size should be in range 120 < mega < 1024 */ #include #include TypesH #include TimeH #include "xt.h" #include "bios.h" #include "timeval.h" #include "config.h" #include "timer.h" #include "dma.h" #include "gfi.h" #include "gfisflop.h" #include "host.h" #include "error.h" #include "trace.h" #include "fla.h" #include "debug.h" #ifdef SEGMENTATION /* * The following #define specifies the code segment into which this * module will by placed by the MPW C compiler on the Mac II running * MultiFinder. */ #include "SLAVE_FLOPPY.seg" #endif /* * ============================================================================ * Local static data and defines * ============================================================================ */ #undef NO #define DMA_DISKETTE_CHANNEL 2 #define NO 2 #define MRD 1 #define MWT 0 /* * FDC command definitions * ======================= */ typedef struct { int comid; /* FDC command numbers */ int dma; /* see below */ int intstatus; /* see below */ int delay; /* delay needed */ int n_resblk; /* number of result bytes */ int n_comblk; /* number of command bytes */ } FDC_CMD_INFO; /* * dma flag * = NO ... no dma for this command * = MRD ... dma read (mem -> FDC) * = MWT ... dma write (FDC -> mem) */ /* interrupt status * = 0 ... command does not generate an interrupt. * = 1 ... command does generate interrupt which is cleared by * reading the FDC * = 2 ... command generates an interrupt ... a sense interrupt command * must be issued to get the FDC results and re-enable further * command input to the FDC */ FDC_CMD_INFO fdc_cmd_info[] = { /* * com_id dma intstatus n_resblk * delay n_comblk */ { RDDATA, MWT, 1, 0, 7, 9 }, { RDDELDATA, MWT, 1, 0, 7, 9 }, { WTDATA, MRD, 1, 0, 7, 9 }, { WTDELDATA, MRD, 1, 0, 7, 9 }, { RDTRACK, MWT, 1, 0, 7, 9 }, { RDID, NO, 1, 0, 7, 2 }, { FMTTRACK, MRD, 1, 0, 7, 6 }, { SCANEQ, MRD, 1, 0, 7, 9 }, { SCANLE, MRD, 1, 0, 7, 9 }, { SCANHE, MRD, 1, 0, 7, 9 }, { RECAL, NO, 2, 0, 2, 2 }, { SENSINT, NO, 0, 0, 2, 1 }, { SPECIFY, NO, 0, 1, 0, 3 }, { SENSDRIVE, NO, 0, 0, 1, 2 }, { SEEK, NO, 2, 0, 2, 3 }, }; #define MAX_FDC_CMD sizeof(fdc_cmd_info)/sizeof(fdc_cmd_info[0]) LOCAL UTINY sensint = 8; LOCAL half_word channel = DMA_DISKETTE_CHANNEL; LOCAL SHORT gfi_slave_drive_off IPT1( UTINY, drive ); LOCAL SHORT gfi_slave_drive_on IPT1( UTINY, drive ); LOCAL SHORT gfi_slave_change_line IPT1( UTINY, drive ); LOCAL SHORT gfi_slave_drive_type IPT1( UTINY, drive ); LOCAL SHORT gfi_slave_high IPT2( UTINY, drive, half_word, n); LOCAL SHORT gfi_slave_reset IPT2( FDC_RESULT_BLOCK *, res, UTINY, drive ); LOCAL SHORT gfi_slave_command IPT2( FDC_CMD_BLOCK *, ip, FDC_RESULT_BLOCK *, res); LOCAL wt_diskdata IPT2(unsigned int,n,int *,status); LOCAL void cominfo IPT2(FDC_CMD_BLOCK *,cmd_block,FDC_CMD_INFO *,cmd_info); LOCAL BOOL slave_opened; LOCAL UTINY slave_type[MAX_DISKETTES]; LOCAL SHORT old_a_type, old_b_type; /* * ============================================================================ * External functions * ============================================================================ */ GLOBAL void gfi_slave_change IFN2(UTINY, hostID, BOOL, apply) { int status; UNUSED(hostID); if (apply && slave_opened) { logout(&status); host_runtime_set(C_FLOPPY_SERVER, GFI_REAL_DISKETTE_SERVER); host_rpc_close(); slave_opened = FALSE; } } GLOBAL SHORT gfi_slave_active IFN3(UTINY, hostID, BOOL, active, CHAR *, err) { GFI_FUNCTION_ENTRY *tabP; int status; SHORT result; UTINY i; BOOL slaveServer; UNUSED(hostID); UNUSED(err); slaveServer = (host_runtime_inquire(C_FLOPPY_SERVER)==GFI_SLAVE_SERVER); if (active) { CHAR *slaveName = host_expand_environment_vars((CHAR *) config_inquire(C_SLAVEPC_DEVICE, NULL)); if (!*slaveName) { if (slaveServer) { gfi_empty_active(hostID,TRUE,err); } config_set_active(C_SLAVEPC_DEVICE, FALSE); return C_CONFIG_OP_OK; } /* * When SoftPC has already started talking to SlavePC just * return that the open operation is ok, no need to attempt * to re-open the link. Maintain the flag telling us * whether SlavePC is attached. */ if (!slave_opened) { if ( result = host_rpc_open(slaveName) ) return result; /* failed to open */ else { if (!host_rpc_reset()) { login(&status); if (status != SUCCESS) { host_rpc_close(); return EG_SLAVEPC_NO_LOGIN; } } else { host_rpc_close(); return EG_SLAVEPC_NO_RESET; } } } slave_opened = TRUE; if (!slaveServer) return C_CONFIG_OP_OK; for ( i = 0; i < MAX_DISKETTES; i ++) { if (gfi_slave_drive_type(i) == GFI_DRIVE_TYPE_NULL) continue; tabP = &gfi_function_table[i]; tabP->command_fn = gfi_slave_command; tabP->drive_on_fn = gfi_slave_drive_on; tabP->drive_off_fn = gfi_slave_drive_off; tabP->reset_fn = gfi_slave_reset; tabP->high_fn = gfi_slave_high; tabP->drive_type_fn = gfi_slave_drive_type; tabP->change_fn = gfi_slave_change_line; } } else /* detach the floppy */ { gfi_slave_drive_type(0); gfi_slave_drive_type(1); if (slave_opened) { logout(&status); status = host_rpc_close(); slave_opened = FALSE; } assert0(!status, "gfi_sfloppy: host_rpc_close() failed\n"); if (!slaveServer) return C_CONFIG_OP_OK; for ( i = 0; i < MAX_DISKETTES; i ++) gfi_empty_active(C_FLOPPY_A_DEVICE+i,TRUE,err); gfi_function_table[0].drive_type_fn = gfi_slave_drive_type; if (slave_type[1] != GFI_DRIVE_TYPE_NULL) gfi_function_table[1].drive_type_fn = gfi_slave_drive_type; } return C_CONFIG_OP_OK; } /****************************** on ***************************** * purpose * provide interface to slave PC for turning on drive motor *************************************************************** */ LOCAL SHORT gfi_slave_drive_on IFN1(UTINY, drive) { int status; static unsigned char DRIVE_A_ON = 0x1c; static unsigned char DRIVE_B_ON = 0x2d; note_trace1( GFI_VERBOSE, "GFI-slavefloppy: DRIVE %x ON", drive ); #ifndef PROD #endif timer_int_enabled = 0; if( drive==0 ) wt_digital_output_register(DRIVE_A_ON, 0, &status); else if( drive==1 ) wt_digital_output_register(DRIVE_B_ON, 0, &status); else always_trace0( "gfi_slave_drive_on(): ERROR: bad drive parameter" ); timer_int_enabled = 1; return(SUCCESS); } /****************************** off ***************************** * purpose * provide interface to slave PC for turning off drive motor **************************************************************** */ LOCAL SHORT gfi_slave_drive_off IFN1(UTINY, drive) { int status; static unsigned char DRIVE_A_OFF = 0xc; static unsigned char DRIVE_B_OFF = 0xd; note_trace1( GFI_VERBOSE, "GFI-slavefloppy: DRIVE %x OFF", drive ); #ifndef PROD #endif timer_int_enabled = 0; if( drive==0 ) wt_digital_output_register(DRIVE_A_OFF, 0, &status); else if( drive==1 ) wt_digital_output_register(DRIVE_B_OFF, 0, &status); else always_trace0( "gfi_slave_drive_off(): ERROR: bad drive parameter" ); timer_int_enabled = 1; return(SUCCESS); } /***************************** high **************************** * purpose * provide interface to slave PC for selecting specified data rate *************************************************************** */ LOCAL SHORT gfi_slave_high IFN2(UTINY, drive, half_word, rate) { int status; UNUSED(drive); switch( rate ){ case 0: datarate( DCR_RATE_500, &status ); break; case 1: datarate( DCR_RATE_300, &status ); break; case 2: datarate( DCR_RATE_250, &status ); break; default: always_trace0("ERROR:gfi_slave_high(): bad rate value"); break; } if( status != SUCCESS ) always_trace0( "ERROR: gfi_slave_high()" ); return(status); } /************************** drive type ************************* * purpose * provide interface to slave PC for returning drive type *************************************************************** */ LOCAL SHORT gfi_slave_drive_type IFN1(UTINY, drive) { int status; unsigned char dtype; /* * Return the last drive type if the slave device is * not currently opened. */ if (!slave_opened) return (slave_type[drive]); note_trace1( GFI_VERBOSE, "gfi_slave_drive_type(): drive %x", drive ); drivetype( drive, &dtype, &status ); note_trace2( GFI_VERBOSE, "dtype=%x status=%x", dtype, status ); #ifndef PROD switch( dtype ) { case GFI_DRIVE_TYPE_NULL: note_trace0( GFI_VERBOSE, "Bad drive" ); break; case GFI_DRIVE_TYPE_360: note_trace0( GFI_VERBOSE, "360k" ); break; case GFI_DRIVE_TYPE_12: note_trace0( GFI_VERBOSE, "1.2M" ); break; case GFI_DRIVE_TYPE_720: note_trace0( GFI_VERBOSE, "720k" ); break; case GFI_DRIVE_TYPE_144: note_trace0( GFI_VERBOSE, "1.44M" ); break; default: always_trace0( "Unrecognised drive value" ); break; } #endif /* !PROD */ if ( status != SUCCESS ) always_trace0( "ERROR: gfi_slave_drive_type()" ); slave_type[drive] = dtype; return dtype; /* return(GFI_DRIVE_TYPE_360); */ } /************************* diskette change ********************* * purpose * provide interface to slave PC for diskette change notification *************************************************************** */ LOCAL SHORT gfi_slave_change_line IFN1(UTINY, drive) { int status, changed; diskchange( drive, &changed, &status ); note_trace2( GFI_VERBOSE, "drive %x %s", drive, changed ? "CHANGED" : "NOT CHANGED" ); if( changed!=1 && changed!=0 ) always_trace1( "ERROR: gfi_slave_change_line(): bad value:%x", changed ); if( status != SUCCESS ) always_trace0( "ERROR: gfi_slave_change_line()" ); return( changed ); } /****************************** reset ***************************** * purpose * provide interface to slave PC for resetting the FDC ****************************************************************** */ LOCAL SHORT gfi_slave_reset IFN2(FDC_RESULT_BLOCK *, r, UTINY, drive) { int status, i; static unsigned char DRIVE_RESET = 0x08; static unsigned char DRIVE_A_OFF = 0x0c; static unsigned char DRIVE_B_OFF = 0x0d; static unsigned char RECALIBRATE[] = {7, 0}; unsigned char res[10]; unsigned char drive_off; int nres; note_trace1( GFI_VERBOSE, "GFI-slavefloppy: Reset command drive %x", drive ); #ifndef PROD #endif if( drive==0 ) drive_off = DRIVE_A_OFF; else if( drive==1 ) drive_off = DRIVE_B_OFF; else always_trace0( "gfi_slave_reset(): ERROR: bad drive parameter"); clrintflag(&status); if (status != FDCSUCCESS) return(status); wt_digital_output_register(DRIVE_RESET, 0, &status); if (status == FDCSUCCESS) { timer_int_enabled = 0; wt_digital_output_register(drive_off, 1, &status); timer_int_enabled = 1; if (status == FDCSUCCESS) { wt_floppy_disk_controller(1,&sensint,0, 0, &status); if (status == FDCSUCCESS) { rd_floppy_disk_controller(&nres, res, &status); if (status == FDCSUCCESS) { for (i=0; i 0) { nbytes = (ln > megapkt)? megapkt: ln; dma_request(channel, diskdata, nbytes); if (wt_disk_buffer(nbytes, diskdata, ioff, status)) return(1); else if (*status != FDCSUCCESS) break; ln -= nbytes; ioff += nbytes; } return(0); } /******************************* rd_diskdata ********************************* */ rd_diskdata(n, status) unsigned int n; int *status; { char diskdata[1024]; word nbytes, ln; int ioff; int errors=0; ln = (word) n; ioff = 0; note_trace1( GFI_VERBOSE, "Reading 0x%x bytes...", n ); while (ln > 0) { nbytes = (ln > megapkt)? megapkt: ln; if (rd_disk_buffer(nbytes, diskdata, ioff, status)){ return(1); } dma_request(channel, diskdata, nbytes); if (*status != FDCSUCCESS){ ++errors; break; } ln -= nbytes; ioff += nbytes; } #ifndef PROD if( errors>0 ){ note_trace3( GFI_VERBOSE, "Read 0x%x bytes of 0x%x with errors=%d",ioff , n, errors ); }else note_trace1( GFI_VERBOSE, "Read 0x%x bytes OK", ioff ); #endif return(0); } /****************************** cominfo ************************************* */ LOCAL void cominfo IFN2(FDC_CMD_BLOCK *,cmd_block,FDC_CMD_INFO *,cmd_info) { int i; for (i = 0; i < MAX_FDC_CMD; i++) if (fdc_cmd_info[i].comid == get_c0_cmd(cmd_block)) break; if (i >= MAX_FDC_CMD) cmd_info->comid = -1; else if (fdc_cmd_info[i].comid == SENSINT) cmd_info->comid = -2; else *cmd_info = fdc_cmd_info[i]; } #endif /* SLAVEPC */