;------------------------------------------------------------------------------- ; ; GS/OS CompactFlash driver for Rich Dreher's CFFA card. ; ;------------------------------------------------------------------------------- ; ; Driver description: ; ; --Supports up to 2 CFFA cards, even if their slots are not set to Your Card. ; --Four 32 MB partitions + 5th and 6th partitions of up to 1 GB. ; --NO hot-swapping of cards (this is a CFFA hardware limitation if we take ; the approach of putting the Compact Flash device into "true IDE mode") ; --Format call wipes the first 64K of data. ; --Device name description: .CFFA.sp.ModelName (s=1..7, p=A..F); ; model name is truncated before last 12 characters if needed; ; letters are uppercased, blanks and slashes and colons are changed ; to underscores, and nonprinting characters are ignored. ; --Might support ATA devices up to 128GB, but this hasn't been tested. ; ; Device-specific Status calls: $8000 = return pointer to IDENTIFY buffer ; ; Device-specific Control calls: None ; ; ; References ; ---------- ; SanDisk CF card manual ; Rich Dreher's CFFA firmware source ; Apple IIgs GS/OS Driver Reference ; ;------------------------------------------------------------------------------- ; ; REVISION HISTORY ; ; Sun 17-Feb-2002 by David A. Lyons (dlyons@lyons42.com) ; Initial coding. Started with the "SCSI Driver Shell" sample code, ; "SCSI Driver main" and "SCSIHD.equates" from the Apple IIgs 6.0 CD. ; After day 1, we have read-only single-partition support for a fixed- ; size CF card with the board in slot 2. Runs well at 1 MHz, gets ; random I/O errors at 2.8 MHz. ; ; Sat 23-Feb-2002 DAL ; Worked on this off and on during the week, and today. Now the slot ; scanning is done (though I only have one CFFA card to test it with). ; It's read/write, implements implied partitioning as four 32 MB partitions ; followed by a single partition with all the remaining space on the disk. ; Format zeroes the first 64K of a partition. ; ; Sun 24-Feb-2002 DAL ; Device names are now ".CFFA.sp.CardModelNumber", for example: ; .CFFA.3A.DELKIN_CFLS1VT1-128 ; .CFFA.2B.DELKIN_CFLS1VT1-192 ; .CFFA.7D.LEXAR_ATA_FLASH ; .CFFA.7E.SANDISK_SDCFB-16 ; The first digit is the slot number, and the letter A-E indicates the ; partition. Maximum device name length is 27 characters (plus the "."), ; because Finder 6.0.1 displays "Device: Unknown" if the name is longer. ; CFFA cards are supported even if their slot is not set to "Your Card" ; in the control panel. In this case, interrupts are disabled while card ; access is in progress. It even works in slot 3. The "." before the ; slot digit will be a "*" if the card does not indicate it supports LBA. ; ; Sat 9-Mar-2002 DAL ; Fixed bug where only the first CFFA card found was recognized. ; Implemented BlockOffset. ; Implemented GSOSDriverCompatibilityLevel byte check ($CnF5). ; ; ; Wed 13-Mar-2002 DAL ; Must hit ClearCSMask on any entry to driver where a DIB is already set up. ; Changed the partitioning scheme to allow 6 partitions per slot. The 5th ; and 6th partitions can be up to 1 GB. The maximum partition sizes are now ; entirely in the DIB data, not in the code. ; ; Sat 16-Mar-2002 DAL ; working on GS/OS Caching ; ; sometime in April 2002 DAL ; Finished GS/OS caching support. ; ; Sun 19-May-2002 DAL ; Updated CheckDevice logic to match Rich's shipping firmware. ; Changed version word to $1000 (1.0 final). ; ;------------------------------------------------------------------------------- ;------------------------------------------------------------------------------- STRING ASIS BLANKS OFF PRINT NOGEN PRINT NOMDIR MACHINE M65816 ; ; Block offset -- first partition starts at this LBA on the Compact Flash card ; BlockOffset equ 0 GSOSDriverCompatibilityLevel equ 2 ; highest $CnF5 value we recognize on a CFFA card WAIT_100us EQU 4 WAIT_40ms EQU 124 WAIT_100ms EQU 197 ; ; Bit Location equates ; null equ %0000000000000000 bit_0 equ %0000000000000001 bit_1 equ %0000000000000010 bit_2 equ %0000000000000100 bit_3 equ %0000000000001000 bit_4 equ %0000000000010000 bit_5 equ %0000000000100000 bit_6 equ %0000000001000000 bit_7 equ %0000000010000000 bit_8 equ %0000000100000000 bit_9 equ %0000001000000000 bit_10 equ %0000010000000000 bit_11 equ %0000100000000000 bit_12 equ %0001000000000000 bit_13 equ %0010000000000000 bit_14 equ %0100000000000000 bit_15 equ %1000000000000000 ; ; Booleans ; true equ 1 false equ 0 drvr_vers equ $1000 ;Driver 1.0 final cmd_start equ $0000 ;Driver Startup Call cmd_open equ $0001 ;Driver Open Call cmd_read equ $0002 ;Driver Read Call cmd_write equ $0003 ;Driver Write Call cmd_close equ $0004 ;Driver Close Call cmd_status equ $0005 ;Driver Status Call cmd_control equ $0006 ;Driver Control Call cmd_flush equ $0007 ;Driver Flush Call cmd_shutdown equ $0008 ;Driver Shutdown Call ;------------------------------------------------------------------------------- block_size equ $200 cache_blks equ true ;------------------------------------------------------------------------------- warm_cold_flag equ $e101d0 ;word: 0 = cold startup/shutdown (BIT 0 ONLY) ; 1 = warm startup/shutdown (BIT 0 ONLY) ; ; System Service Calls we need. ; ;-------------------------------------------------------------------------- ; ; ENTRY: move_info via 'jsl' ; ; LONGWORD - Source buffer pointer ; LONGWORD - Destination buffer pointer ; LONGWORD - Transfer length ; WORD - Source buffer pointer ; SP --> ; ; A Reg = Undefined ; X Reg = Undefined ; Y Reg = Undefined ; Bank Reg = Undefined ; Dir Reg = GS/OS Direct Page ; P Reg = N V M X D I Z C E ; x x 0 0 0 x x x 0 ; ; EXIT: move_info via 'rtl' ; ; A Reg = Error Code ; X Reg = Undefined ; Y Reg = Undefined ; Bank Reg = Undefined ; Dir Reg = GS/OS Direct Page ; P Reg = N V M X D I Z C E ; x x 0 0 0 x x 0 0 No Error ; x x 0 0 0 x x 1 0 Error ; ;-------------------------------------------------------------------------- move_info equ $01fc70 moveblkcmd equ $0800 ;Block Move Option move_sinc_dinc equ $0805 ;Source Inc, Dest Inc move_sinc_ddec equ $0809 ;Source Inc, Dest Dec move_sdec_dinc equ $0806 ;Source Dec, Dest Inc move_sdec_ddec equ $080a ;Source Dec, Dest Dec move_scon_dcon equ $0800 ;Source con, Dest con move_sinc_dcon equ $0801 ;Source Inc, Dest con move_sdec_dcon equ $0802 ;Source Dec, Dest con move_scon_dinc equ $0804 ;Source con, Dest Inc move_scon_ddec equ $0808 ;Source con, Dest Dec ;-------------------------------------------------------------------------- ; ; ENTRY: set_disksw via 'jsl' ; ; A Reg = Undefined ; X Reg = Undefined ; Y Reg = Undefined ; Bank Reg = Undefined ; Dir Reg = GS/OS Direct Page ; P Reg = N V M X D I Z C E ; x x 0 0 0 x x x 0 ; ; EXIT: set_disksw via 'rtl' ; ; A Reg = Undefined ; X Reg = Undefined ; Y Reg = Undefined ; Bank Reg = Undefined ; Dir Reg = GS/OS Direct Page ; P Reg = N V M X D I Z C E ; x x 0 0 0 x x 0 0 No Error ; ;-------------------------------------------------------------------------- cache_find_blk equ $01fc04 cache_add_blk equ $01fc08 cache_kil_blk equ $01fc14 cache_del_vol equ $01fc18 set_disksw equ $01fc90 s_dispatch equ $01fca4 install_driver equ $01fca8 ; ; Direct Page Addresses. ; dev_num equ $0000 ;Device Number call_num equ $0002 ;Call Number buff_ptr equ $0004 ;Buffer Pointer rqst_cnt equ $0008 ;Request Count trans_cnt equ $000C ;Transfer Count block_num equ $0010 ;Block Number (Read/Write only) blk_size equ $0014 ;Block Size fst_num equ $0016 ;FST Number (Read/Write only) stat_code equ $0016 ;Status Command Code cont_code equ $0016 ;Control Command Code volume_id equ $0018 ;Volume ID (Read/Write only) cache_prio equ $001A ;Cache Priority Value (Read/Write only) cache_ptr equ $001C ;Cache Pointer (Read/Write only) dib_ptr equ $0020 ;DIB Pointer ; ; Memory attribute equates ; attrlock equ bit_15 ;Block is locked down. attrfixed equ bit_14 ;Block can't move in mem attrpurg1 equ bit_8 ;Purge level 1 attrpurg2 equ bit_9 ;Purge level 2 attrpurg3 equ bit_8+bit_9 ;Purge level 3 attrnocross equ bit_4 ;May not cross banks attrnospec equ bit_3 ;don't use special mem attrpage equ bit_2 ;Page alligned attraddr equ bit_1 ;Remain at fixed address attrbank equ bit_0 ;Remain in fixed bank ; ; Device Characteristics. ; ram_rom_disk equ bit_15 ;RAM or ROM Disk if Set gened_drvr equ bit_14 ;Generated Driver if Set linked_dvc equ bit_13 ;Linked Device if Set call_active equ bit_12 ;Device Busy if Set restartable equ bit_11 ;Restartable from ram if Set mhz_1 equ null ;1 Mhz Device mhz_2_6 equ bit_8 ;2.6 Mhz Device mhz_gt_2_6 equ bit_9 ;>2.6 Mhz Device speed_ind equ bit_8+bit_9 ;Device is speed independent blk_device equ bit_7 ;Block Device if Set write_allow equ bit_6 ;Write is Allowed if Set read_allow equ bit_5 ;Read is Allowed if Set format_allow equ bit_3 ;Format is Allowed if Set removable equ bit_2 ;Removable Media if Set ; ; Error_Codes. ; no_error equ $0000 bad_dev_number equ $0011 drvr_bad_req equ $0020 drvr_bad_code equ $0021 drvr_bad_parm equ $0022 drvr_not_open equ $0023 drvr_prior_open equ $0024 drvr_io equ $0027 drvr_no_dev equ $0028 drvr_busy equ $0029 drvr_wrt_prot equ $002b drvr_bad_cnt equ $002c drvr_bad_blk equ $002d drvr_dsk_swch equ $002e drvr_off_line equ $002f ; ; Apple IIgs Softswitches ; SLOTREG equ $C02D ; internal/external ROM in slot 1, 2, 4, 5, 6, 7 SETINTC3ROM equ $C00A ; enable internal slot 3 ROM SETSLOTC3ROM equ $C00B ; enable external slot 3 ROM RDC3ROM equ $C017 ; bit 7 set if slot C3 space enabled ;------------------------------------------------------------------------- ; ; Tradtional DIB (GS/OS Device Driver Reference, p179) ; ;------------------------------------------------------------------------- dib RECORD $0000 linkptr ds.l 1 ; DIB Link Pointer (LONG) entry ds.l 1 ; Pointer to Drvrs Main Entry (LONG) dvcchar ds.w 1 ; Device Characteristics (WORD) blkcnt ds.l 1 ; Block Count for this device (LONG) namelen ds.b 1 ; Length of Descriptive Name (PSTR) disname ds.b 31 ; Field for this devices Name (STR) slotnum ds.w 1 ; Device Slot Number from MGR. (WORD) unitnum ds.w 1 ; Device Unit Number from MGR. (WORD) versnum ds.w 1 ; Version Number for our Driver (WORD) dvcid ds.w 1 ; ID of Device we talk to (WORD) headlnk ds.w 1 ; Head Device Link (WORD) fdvclnk ds.w 1 ; Forward Device Link (WORD) ext_ptr ds.l 1 ; Pointer to DIB Extension (LONG) devnum ds.w 1 ; DIB Device Number (WORD) ;------------------------------------------------------------------------- ; additional device-specific fields ;------------------------------------------------------------------------- MaxBlocks ds.l 1 ; maximum number of blocks in this partition XForHardware ds.w 1 ; $0010 for slot 1 .. $0070 for slot 7 HWBlockOffset ds.l 1 ; hardware block number for this dev's block 0 end equ * ENDR ;------------------------------------------------------------------------- ; ; Identify Drive information (result of an ATA Identify Drive command) ; ;------------------------------------------------------------------------- identifyDrive RECORD $0000 variousBits ds.w 1 ;word 0 defaultNumCyl ds.w 1 ;word 1 ds.w 1 ;word 2 (reserved) defaultNumHeads ds.w 1 ;word 3 numUnfmtBytesPerTrk ds.w 1 ;word 4 numUnfmtBytesPerSec ds.w 1 ;word 5 defNumSecPerTrk ds.w 1 ;word 6 numSecPerCard ds.w 2 ;word 7 = MSW, 8 = LSW reserved2 ds.w 1 ;word 9 serialNumber ds.w 10 ;words 10..19 (ASCII, right justified) bufferType ds.w 1 ;word 20 bufferSizeInBlocks ds.w 1 ;word 21 (buffer size in 512-byte increments) numECCforRWLong ds.w 1 ;word 22 (# of ECC bytes passed on Read/Write Long command) firmwareRevString ds.w 4 ;words 23-26 (firmware revision in ASCII, each word big-endian) modelString ds.w 20 ;words 27-46 (left justified, each word big-endian) maxSectorsForRWMultiple ds.w 1 ;word 47 doubleWordSupport ds.w 1 ;word 48 capabilities ds.w 1 ;word 49 (such as DMA = bit 8, LBA = bit 9) ds.w 1 ;word 50 (reserved) PIOTimingMode ds.w 1 ;word 51 DMATimingMode ds.w 1 ;word 52 fieldValidity ds.w 1 ;word 53 curNumCylinders ds.w 1 ;word 54 curNumHeads ds.w 1 ;word 55 curSectorsPerTrack ds.w 1 ;word 56 currentSectorsInLBA ds.w 2 ;words 57-58 (57 = LSW, 58 = MSW) multSectorValid ds.w 1 ;word 59 totalSectorsInLBA ds.w 2 ;words 60-61 ds.w 2 ;words 62-63 (reserved) advancedPIOSupport ds.w 1 ;word 64 ds.w 2 ;words 65-66 (reserved) minPIOxferNoFlow ds.w 1 ;word 67 minPIOxferIORDYFlow ds.w 1 ;word 68 ds.w 59 ;words 69-127 (reserved) vendorUnique ds.w 32 ;words 128-159 ds.w 96 ;words 160-255 (reserved) end equ * if (end <> 512) then error endif ENDR macro &lab DebugBreakIfCarrySet &lab bcc @ok brk @ok endm PRINT OFF INCLUDE 'M16.MEMORY' INCLUDE 'M16.UTIL2' PRINT ON ;-------------------------------------------------------------------------- ; ; Header as required by the device dispatcher for drivers. ; ;-------------------------------------------------------------------------- start PROC dc.w dib_1-start dc.w 12 ;number of devices dc.w ctrl_list-start ;offset to control list 1 dc.w ctrl_list-start ;offset to control list 2 dc.w ctrl_list-start ;offset to control list 3 dc.w ctrl_list-start ;offset to control list 4 dc.w ctrl_list-start ;offset to control list 5 dc.w ctrl_list-start ;offset to control list 6 dc.w ctrl_list-start ;offset to control list 7 dc.w ctrl_list-start ;offset to control list 8 dc.w ctrl_list-start ;offset to control list 9 dc.w ctrl_list-start ;offset to control list 10 dc.w ctrl_list-start ;offset to control list 11 dc.w ctrl_list-start ;offset to control list 12 ctrl_list dc.l null dc.l null ;-------------------------------------------------------------------------- characteristics equ restartable++\ ;Restartable from ram if Set (WORD) speed_ind++\ ;Device is speed ind if Set blk_device++\ ;Block Device if Set write_allow++\ ;Write is Allowed if Set read_allow++\ ;Read is Allowed if Set format_allow ;Format is Allowed if Set OurDeviceID equ $0013 ;generic hard drive (GS/OS Driver Ref, p.185) OffsetForSlotDigit equ 6 ;how far into (lengthbyte)'CFFA.nn' to stuff slot# OffsetForPartitionLetter equ 7 OffsetForSpecialCharacter equ 5 ;to indicate a special condition, name is 'CFFA*nn...' ;------------------------------------------------------------------------- ; ; These twelve DIBs support 6 partitions for each of two CFFA boards, such ; as 4 32-MB devices and one larger device. ; ; If you add or remove DIBs to support a different partition layout, be ; sure to: update MaxDIBsPerSlot appropriately; keep Card2FirstDIB at the ; appropriate spot; keep the DIBs in a linked list (DIB Link Pointer ; field, 0 for last one); give each DIB an appropriate "Device Unit Number" ; starting with 1 for each slot; set "Max block count" and "hardware ; block number" fields appropriately. Always leave the "block count" 0! ; It must get set up at driver startup time. ; ;------------------------------------------------------------------------- MaxDIBsPerSlot equ 6 Card1FirstDIB dib_1 dc.l dib_2 ; DIB Link Pointer (LONG) dc.l drvr_main ; Pointer to Drvrs Main Entry (LONG) dc.w characteristics dc.l $00000000 ; Block Count for this device (LONG) dc.b 7,'CFFA.nn ' ; 32-byte field: name w/ leading length byte dc.w $0000 ; Device Slot Number (WORD) dc.w $0001 ; Device Unit Number (WORD) dc.w drvr_vers ; Version Number for our Driver (WORD) dc.w OurDeviceID ; ID of Device we talk to (WORD) dc.w $0000 ; Head Device Link (WORD) dc.w $0000 ; Forward Device Link (WORD) dc.l @extended ; extendedDIBPtr dc.w $0000 ; DIB Device Number (WORD) @extended dc.l $00010000 ; Max block count dc.w 0 ; X value for hardware access dc.l $00000000+BlockOffset ; hardware block number of this dev's block 0 dib_2 dc.l dib_3 ; DIB Link Pointer (LONG) dc.l drvr_main ; Pointer to Drvrs Main Entry (LONG) dc.w characteristics dc.l $00000000 ; Block Count for this device (LONG) dc.b 7,'CFFA.nn ' ; 32-byte field: name w/ leading length byte dc.w $0000 ; Device Slot Number (WORD) dc.w $0002 ; Device Unit Number (WORD) dc.w drvr_vers ; Version Number for our Driver (WORD) dc.w OurDeviceID ; ID of Device we talk to (WORD) dc.w $0000 ; Head Device Link (WORD) dc.w $0000 ; Forward Device Link (WORD) dc.l @extended ; extendedDIBPtr dc.w $0000 ; DIB Device Number (WORD) @extended dc.l $00010000 ; Max block count dc.w 0 ; X value for hardware access dc.l $00010000+BlockOffset ; hardware block number of this dev's block 0 dib_3 dc.l dib_4 ; DIB Link Pointer (LONG) dc.l drvr_main ; Pointer to Drvrs Main Entry (LONG) dc.w characteristics dc.l $00000000 ; Block Count for this device (LONG) dc.b 7,'CFFA.nn ' ; 32-byte field: name w/ leading length byte dc.w $0000 ; Device Slot Number (WORD) dc.w $0003 ; Device Unit Number (WORD) dc.w drvr_vers ; Version Number for our Driver (WORD) dc.w OurDeviceID ; ID of Device we talk to (WORD) dc.w $0000 ; Head Device Link (WORD) dc.w $0000 ; Forward Device Link (WORD) dc.l @extended ; extendedDIBPtr dc.w $0000 ; DIB Device Number (WORD) @extended dc.l $00010000 ; Max block count dc.w 0 ; X value for hardware access dc.l $00020000+BlockOffset ; hardware block number of this dev's block 0 dib_4 dc.l dib_5 ; DIB Link Pointer (LONG) dc.l drvr_main ; Pointer to Drvrs Main Entry (LONG) dc.w characteristics dc.l $00000000 ; Block Count for this device (LONG) dc.b 7,'CFFA.nn ' ; 32-byte field: name w/ leading length byte dc.w $0000 ; Device Slot Number (WORD) dc.w $0004 ; Device Unit Number (WORD) dc.w drvr_vers ; Version Number for our Driver (WORD) dc.w OurDeviceID ; ID of Device we talk to (WORD) dc.w $0000 ; Head Device Link (WORD) dc.w $0000 ; Forward Device Link (WORD) dc.l @extended ; extendedDIBPtr dc.w $0000 ; DIB Device Number (WORD) @extended dc.l $00010000 ; Max block count dc.w 0 ; X value for hardware access dc.l $00030000+BlockOffset ; hardware block number of this dev's block 0 dib_5 dc.l dib_6 ; DIB Link Pointer (LONG) dc.l drvr_main ; Pointer to Drvrs Main Entry (LONG) dc.w characteristics dc.l $00000000 ; Block Count for this device (LONG) dc.b 7,'CFFA.nn ' ; 32-byte field: name w/ leading length byte dc.w $0000 ; Device Slot Number (WORD) dc.w $0005 ; Device Unit Number (WORD) dc.w drvr_vers ; Version Number for our Driver (WORD) dc.w OurDeviceID ; ID of Device we talk to (WORD) dc.w $0000 ; Head Device Link (WORD) dc.w $0000 ; Forward Device Link (WORD) dc.l @extended ; extendedDIBPtr dc.w $0000 ; DIB Device Number (WORD) @extended dc.l $00200000 ; Max block count (1 GB) dc.w 0 ; X value for hardware access dc.l $00040000+BlockOffset ; hardware block number of this dev's block 0 dib_6 dc.l dib_7 ; DIB Link Pointer (LONG) dc.l drvr_main ; Pointer to Drvrs Main Entry (LONG) dc.w characteristics dc.l $00000000 ; Block Count for this device (LONG) dc.b 7,'CFFA.nn ' ; 32-byte field: name w/ leading length byte dc.w $0000 ; Device Slot Number (WORD) dc.w $0006 ; Device Unit Number (WORD) dc.w drvr_vers ; Version Number for our Driver (WORD) dc.w OurDeviceID ; ID of Device we talk to (WORD) dc.w $0000 ; Head Device Link (WORD) dc.w $0000 ; Forward Device Link (WORD) dc.l @extended ; extendedDIBPtr dc.w $0000 ; DIB Device Number (WORD) @extended dc.l $00200000 ; Max block count (1 GB) dc.w 0 ; X value for hardware access dc.l $00240000+BlockOffset ; hardware block number of this dev's block 0 Card2FirstDIB dib_7 dc.l dib_8 ; DIB Link Pointer (LONG) dc.l drvr_main ; Pointer to Drvrs Main Entry (LONG) dc.w characteristics dc.l $00000000 ; Block Count for this device (LONG) dc.b 7,'CFFA.nn ' ; 32-byte field: name w/ leading length byte dc.w $0000 ; Device Slot Number (WORD) dc.w $0001 ; Device Unit Number (WORD) dc.w drvr_vers ; Version Number for our Driver (WORD) dc.w OurDeviceID ; ID of Device we talk to (WORD) dc.w $0000 ; Head Device Link (WORD) dc.w $0000 ; Forward Device Link (WORD) dc.l @extended ; extendedDIBPtr dc.w $0000 ; DIB Device Number (WORD) @extended dc.l $00010000 ; Max block count dc.w 0 ; X value for hardware access dc.l $00000000+BlockOffset ; hardware block number of this dev's block 0 dib_8 dc.l dib_9 ; DIB Link Pointer (LONG) dc.l drvr_main ; Pointer to Drvrs Main Entry (LONG) dc.w characteristics dc.l $00000000 ; Block Count for this device (LONG) dc.b 7,'CFFA.nn ' ; 32-byte field: name w/ leading length byte dc.w $0000 ; Device Slot Number (WORD) dc.w $0002 ; Device Unit Number (WORD) dc.w drvr_vers ; Version Number for our Driver (WORD) dc.w OurDeviceID ; ID of Device we talk to (WORD) dc.w $0000 ; Head Device Link (WORD) dc.w $0000 ; Forward Device Link (WORD) dc.l @extended ; extendedDIBPtr dc.w $0000 ; DIB Device Number (WORD) @extended dc.l $00010000 ; Max block count dc.w 0 ; X value for hardware access dc.l $00010000+BlockOffset ; hardware block number of this dev's block 0 dib_9 dc.l dib_10 ; DIB Link Pointer (LONG) dc.l drvr_main ; Pointer to Drvrs Main Entry (LONG) dc.w characteristics dc.l $00000000 ; Block Count for this device (LONG) dc.b 7,'CFFA.nn ' ; 32-byte field: name w/ leading length byte dc.w $0000 ; Device Slot Number (WORD) dc.w $0003 ; Device Unit Number (WORD) dc.w drvr_vers ; Version Number for our Driver (WORD) dc.w OurDeviceID ; ID of Device we talk to (WORD) dc.w $0000 ; Head Device Link (WORD) dc.w $0000 ; Forward Device Link (WORD) dc.l @extended ; extendedDIBPtr dc.w $0000 ; DIB Device Number (WORD) @extended dc.l $00010000 ; Max block count dc.w 0 ; X value for hardware access dc.l $00020000+BlockOffset ; hardware block number of this dev's block 0 dib_10 dc.l dib_11 ; DIB Link Pointer (LONG) dc.l drvr_main ; Pointer to Drvrs Main Entry (LONG) dc.w characteristics dc.l $00000000 ; Block Count for this device (LONG) dc.b 7,'CFFA.nn ' ; 32-byte field: name w/ leading length byte dc.w $0000 ; Device Slot Number (WORD) dc.w $0004 ; Device Unit Number (WORD) dc.w drvr_vers ; Version Number for our Driver (WORD) dc.w OurDeviceID ; ID of Device we talk to (WORD) dc.w $0000 ; Head Device Link (WORD) dc.w $0000 ; Forward Device Link (WORD) dc.l @extended ; extendedDIBPtr dc.w $0000 ; DIB Device Number (WORD) @extended dc.l $00010000 ; Max block count dc.w 0 ; X value for hardware access dc.l $00030000+BlockOffset ; hardware block number of this dev's block 0 dib_11 dc.l dib_12 ; DIB Link Pointer (LONG) dc.l drvr_main ; Pointer to Drvrs Main Entry (LONG) dc.w characteristics dc.l $00000000 ; Block Count for this device (LONG) dc.b 7,'CFFA.nn ' ; 32-byte field: name w/ leading length byte dc.w $0000 ; Device Slot Number (WORD) dc.w $0005 ; Device Unit Number (WORD) dc.w drvr_vers ; Version Number for our Driver (WORD) dc.w OurDeviceID ; ID of Device we talk to (WORD) dc.w $0000 ; Head Device Link (WORD) dc.w $0000 ; Forward Device Link (WORD) dc.l @extended ; extendedDIBPtr dc.w $0000 ; DIB Device Number (WORD) @extended dc.l $00200000 ; Max block count dc.w 0 ; X value for hardware access dc.l $00040000+BlockOffset ; hardware block number of this dev's block 0 dib_12 dc.l $00000000 ; DIB Link Pointer (LONG) dc.l drvr_main ; Pointer to Drvrs Main Entry (LONG) dc.w characteristics dc.l $00000000 ; Block Count for this device (LONG) dc.b 7,'CFFA.nn ' ; 32-byte field: name w/ leading length byte dc.w $0000 ; Device Slot Number (WORD) dc.w $0006 ; Device Unit Number (WORD) dc.w drvr_vers ; Version Number for our Driver (WORD) dc.w OurDeviceID ; ID of Device we talk to (WORD) dc.w $0000 ; Head Device Link (WORD) dc.w $0000 ; Forward Device Link (WORD) dc.l @extended ; extendedDIBPtr dc.w $0000 ; DIB Device Number (WORD) @extended dc.l $00200000 ; Max block count dc.w 0 ; X value for hardware access dc.l $00240000+BlockOffset ; hardware block number of this dev's block 0 if (*-dib_1 <> (12*dib.end)) then error: DIBs are wrong size endif ;-------------------------------------------------------------------------- ; ; Main entry to the driver. ; State of the machine is: ; ; Acc = Call Number ; $0000 = Startup ; $0001 = Open ; $0002 = Read ; $0003 = Write ; $0004 = Close ; $0005 = Status ; $0006 = Control ; $0007 = Flush ; $0008 = Shutdown ; Y register = Unspecified ; X register = Unspecified ; P register = 0=M=X=e ; Direct Page = GS/OS Direct Page ; Data Bank = Unspecified ; Stack Pointer = GS/OS Stack ; System Speed = Fast ; ;-------------------------------------------------------------------------- drvr_main equ * ;; sta >$dddddd ; enable when debugging with a logic analyzer cmp #(mainDispEnd-mainDispatch)/2 bge @error ; ; Preserve caller's Data Bank and set ours ; phb phk plb asl a tax jsr DisableInterruptsIfNeeded phx jsr SetupXForHardware beq @noX shortm lda >ClearCSMask,x ;reset MASK bit in PLD for normal CS0 signaling longm @noX plx jsr (mainDispatch,x) jsr RestoreInterruptsIfNeeded plb bcs @have_error lda #0 @have_error rtl @error lda #drvr_bad_code sec rtl ;-------------------------------------------------------------------------- ; ; DisableInterruptsIfNeeded ; ; Input: dib_ptr ; ; Output: X is preserved ; DisabledInts is meaningful ; ; If this device's DIB is flagged "hardware independent," that means it's ; not in a normally-swapped-in slot that GS/OS can see, so we have to go ; to special lengths to access it. ; ;-------------------------------------------------------------------------- DisableInterruptsIfNeeded equ * stz |DisabledInts ldy #dib.slotnum lda [SLOTREG sta |OldSlotReg lda >RDC3ROM sta |OldRDC3ROM lda #$F6 ; external slots 1, 2, 4, 5, 6, 7 sta >SLOTREG sta >SETSLOTC3ROM ; external slot 3 longm rts ;-------------------------------------------------------------------------- ; ; RestoreInterruptsIfNeeded ; ; Must preserve A, Carry ; ;-------------------------------------------------------------------------- RestoreInterruptsIfNeeded equ * ldx |DisabledInts beq @ok shortm pha lda |OldSlotReg sta >SLOTREG bit |OldRDC3ROM bmi @keepC3 sta >SETINTC3ROM @keepC3 pla longm cli @ok rts ;-------------------------------------------------------------------------- ; ; TranslateToGSOSSlotNumber ; ; Input: A = slot number (1..7) ; ; Output: GS/OS slot number, 8..15 for an external slot, or ; $8000 + 8..15 for an external slot that we must mark ; as "independent of hardware" because it was supposed ; to be invisible, and we want to handle the SLOTREG ; diddling manually. ; ; When we turn on the $8000 bit, GS/OS skips trying to ; call the SLOT_ARBITER to swap in our slot, which wouldn't ; work because the SLOT_ARBITER doesn't implement any ; slot switching. ; ;-------------------------------------------------------------------------- TranslateToGSOSSlotNumber equ * cmp #3 beq @slot3 tax shortm lda |OldSlotReg bit |SlotBitTable,x longm bne @normal txa ora #$8008 ; independent of hardware, external slot rts @normal txa ora #$0008 ; just a regular external slot rts @slot3 bit |OldRDC3ROM bmi @done @special ora #$8000 ; tell GS/OS "independent of hardware" @done ora #$0008 ; external slot (not internal GS port) rts SlotBitTable dc.b $FF ;slot 0 bogus dc.b $02 ;slot 1 dc.b $04 ;slot 2 dc.b $FF ;slot 3 bogus dc.b $10 ;slot 4 dc.b $20 ;slot 5 dc.b $40 ;slot 6 dc.b $80 ;slot 7 DisabledInts dc.w 0 OldSlotReg dc.b 0 OldRDC3ROM dc.b 0 ;-------------------------------------------------------------------------- ; ; Driver dispatch table ; ; These routines return with CLC for no error, or ; SEC + A = error code. ; ;-------------------------------------------------------------------------- mainDispatch dc.w Startup dc.w Open dc.w Read dc.w Write dc.w Close dc.w Status dc.w Control dc.w Flush dc.w Shutdown mainDispEnd equ * ;-------------------------------------------------------------------------- ; ; Startup call ; ; Gets called once per DIB. Return no-error if we want GS/OS to use this ; DIB. ; ; The first time we're called, scan the slots for CFFA boards & set up all ; our DIBs depending on the block counts of the devices we find. ; ;-------------------------------------------------------------------------- Startup lda |first_startup beq @alreadyScanned stz |first_startup pei $0000F6,X cmp #$4643 ; the 'CF' bne @next lda >$0000F8,X cmp #$4146 ; the 'FA' bne @next lda >$0000F5,X ; make sure this card is compatible with us and #$00ff cmp #GSOSDriverCompatibilityLevel+1 bcs @next ; skip it, just let GS/OS's generated SmartPort driver handle it phx pei ClearCSMask,x ;reset MASK bit in PLD for normal CS0 signaling longm jsr ResetDriveFirstTime jsr IdentifyDevice ; dib_ptr in, dib's blkcnt out bcc @ok ldy #dib.blkcnt ; error: make sure blkcnt is 0 lda #0 sta [ATADataHigh,x ;Clear high byte data latch lda #$06 ;Reset bit=1, Disable INTRQ=1 sta >ATADevCtrl,x longm ; ; Per ATA-6 spec, need to wait 5us minimum. Use a delay of 100us. ; Should cover accelerated Apples up to 20MHz (even if Wait doesn't ; account for the accleration). ; lda #WAIT_100us jsr Wait shortm lda #$02 ;Reset bit=0, Disable INTRQ=1 sta >ATADevCtrl,x longm ; ; Per ATA-6 spec, need to wait 2ms minimum. Use a delay of 40ms. ; Should cover accelerated Apples up to 20MHz (even if Wait doesn't ; account for the acceleration). ; lda #WAIT_40ms jsr Wait ; ; Per ATA-6 spec, wait for busy to clear, by calling IDEWaitReady ; jsr IDEWaitReady rts ;-------------------------------------------------------------------------- ; ; Find the CF card's model name in the Identify Drive data. Put a ; trailing $00 at the last non-blank. Append as many characters as ; will fit to the device name. ; ; The Finder's has a buffer that's too small, so we can't return a ; full-length 31-character device name (Finder shows "Device: Unknown" ; in Get Info if we return more than 27 characters). ; ; If our device name is too long, we truncate from near the middle, ; keeping the last 12 characters. ; ;-------------------------------------------------------------------------- AppendCFModelToDeviceName equ * shortm ; check for an empty modelString (drive returned all blanks) lda IdentifyBuffer+IdentifyDrive.modelString beq @done lda #'.' jsr AppendCharToDeviceName ldx #IdentifyDrive.modelString @appendMore lda IdentifyBuffer,x beq @done jsr TranslateCharacter jsr AppendCharToDeviceName inx cpx #IdentifyDrive.modelString+40 bcc @appendMore @done longm rts ;-------------------------------------------------------------------------- ; ; AppendCharToDeviceName ; ; If the device name is too full, center-truncate so that we ; keep the last 12 characters. ; ; CALLED WITH SHORT ACCUMULATOR ; ;-------------------------------------------------------------------------- longa off AppendCharToDeviceName equ * cmp #0 beq @done pha ldy #dib.nameLen lda [ ignored cmp #'/' beq @underscore cmp #':' beq @underscore cmp #' ' beq @underscore ;blank -> underscore bcc @ignore ;control characters -> ignored cmp #'a' bcc @ok cmp #'z'+1 bcs @ok and #$5F ;shift to uppercase rts @underscore lda #'_' @ok rts @ignore lda #0 rts longa on ;-------------------------------------------------------------------------- ; ; Open call ; Close call ; ; Open and Close apply to character devices only. ; We just need to return no-error. ; ;-------------------------------------------------------------------------- Open equ * Close equ * clc rts ;-------------------------------------------------------------------------- ; ; Flush call ; ; Flush is for character devices only. Driver Ref ; p. 252 says we should return error $20, drvr_bad_req. ; ;-------------------------------------------------------------------------- Flush lda #drvr_bad_req sec rts ;-------------------------------------------------------------------------- ; ; Shutdown call ; ; Shutdown doesn't need to do anything, either. ; ; Driver Ref p. 253 says "If more than one device is ; associated with a single code segment, only the last ; device to be shut down should return no error. Other ; devices should return an I/O error to prevent the ; segment from being purged before the last device is ; shut down." ; ; I don't know if this means multiple DIBs, or something ; more complex. ; ;-------------------------------------------------------------------------- Shutdown equ * clc rts ;-------------------------------------------------------------------------- ; ; Read call ; ; In: dib_ptr, block_num, rqst_cnt, buff_ptr, etc. ; ; Out: CLC for no error, or SEC + A = error ; trans_cnt ; ;-------------------------------------------------------------------------- Read jsr VerifyRW bcs @out pei ATADataHigh,x ; clear the CFFA data latch lda #ATACRead sta >ATACommand,x longm jsr Read512Bytes bcs @error ; Add block to cache if requested lda ATAStatus,x ; Check for error response from device and #$09 cmp #01 ; if DRQ=0 and ERR=1 a device error occured beq @ioError longm ; ; Sector is ready to read ; lda ATADataHigh,x ;Clear the high byte of the 16 bit interface data latch longm jsr IDEWaitReady jsr Block2LBA ;tell the device the block number bcc @ok rts @ok shortm ; 8-bit Accumulator lda #ATACWrite sta >ATACommand,x ; Issue the read command to the drive jsr IDEWaitReady ; Wait for BUSY flag to clear shortm lda >ATAStatus,x ; Check for error response from device and #$09 cmp #01 ; if DRQ=0 and ERR=1 a device error occured beq @ioError longm ; ; Sector is ready to WRITE ; lda no error, and the CF card is pointed at the right block ; SEC -> A = error code ; ; This function translates the block number sent in the PRODOS request ; packet, into the Logical Block Address. ; The least significant 16 bits becomes the ProDOS block#. ; The most significant 16 becomes the ProDOS Drive # ; ; ; A ProDOS block and a IDE sector are both 512 bytes typically. ; ; Logical Block Mode, the Logical Block Address is interpreted as follows: ; LBA07-LBA00: Sector Number Register D7-D0. ; LBA15-LBA08: Cylinder Low Register D7-D0. ; LBA23-LBA16: Cylinder High Register D7-D0. ; LBA27-LBA24: Drive/Head Register bits HS3-HS0. ; ;------------------------------------------------------------------------------ Block2LBA equ * ; validate the block_num against [dib_ptr],dib.blkcnt ldy #dib.blkcnt+2 lda $0FFF.FFFF @ok shortm xba ora #$E0 sta >ATAHead,x ;1, (LBA), 1, (Drive), LBA 27-24; where LBA=1, Drive=0 xba sta >ATACylinderH,x ; LBA bits 23-16 pla sta >ATASector,x ; LBA bits 7-0 pla sta >ATACylinder,x ; LBA bits 15-8 lda #1 sta >ATASectorCnt,x longm clc rts ;------------------------------------------------------------------------------ ; IDEWaitReady - Waits for BUSY flag to clear, and returns DRQ bit status ; ; Input: ; X = requested slot number in form $n0 where n = slot 1 to 7 ; Ouput: ; Z flag = !DRQ status bit ; ; (In the firmware, this returned Carry flag = DRQ status bit; ; BCS becomes BNE; BCC becomes BEQ) ; ;------------------------------------------------------------------------------ IDEWaitReady equ * shortm lda >ATAAltStatus,x ;** ignore result ** make sure to wait long enough before reading real status @loop lda >ATAStatus,x bmi @loop ;Wait for BUSY (bit 7) to be zero bit #$08 longm rts ;------------------------------------------------------------------------------ ; CheckDevice - Check to see if a device is attached to the interface. ; ; Input: ; X = requested slot number in form $n0 where n = slot 1 to 7 ; Output: ; Carry flag: 0 = Device Present, 1 = Device Missing ; ; CPU Registers changed: A, P ; ; Checks to see if the drive status is readable and equal to $50 ; If so, return with the Carry clear, otherwise return with the carry set. ; ;------------------------------------------------------------------------------ CheckDevice phy shortm lda >ClearCSMask,x ;reset MASK bit in PLD for normal CS0 signaling lda #$E0 ;$E0 = [1, LBA, 1, Drive, LBA 27-24] where LBA=1, Drive=0 sta >ATAHead,x ;Make sure ATA master drivce is accessed longm ldy #0 chkLoop shortm lda >ATAAltStatus,x ;;; lda >ATAError,x lda >ATAStatus,x and #%11010000 cmp #$50 ;if RDY=1 and DSC=1 longm beq DeviceFound lda #WAIT_100ms jsr Wait ;Wait 100ms for device to be ready iny cpy #100 ;Wait up to 10 seconds for drive to be ready bne chkLoop sec ;drive is not attached ply rts DeviceFound clc ;drive is attached ply rts ;----------------------------------------------------------------------------- ; ; Call the firmware WAIT routine ($FCA8) ; ; INPUT: A = time to wait ; ;----------------------------------------------------------------------------- Wait equ * phx phy pha ;space for P pha ;space for A pha ;space for X pha ;space for Y pha ; A value = time to wait pha ; X value pha ; Y value pea $FCA8 ; ROM_Wait routine ldx #$2403 ;FWEntry jsl $e10000 pla pla pla pla ply plx rts ;------------------------------------------------------------------------ ; ; IdentifyDevice ; ; Input: ; dib_ptr ; ; Output: ; Carry flag: 0 = Okay, 1 = Error ; block_count is set up in the dib ; ;------------------------------------------------------------------------------ IdentifyDevice jsr SetupXForHardware jsr CheckDevice bcc sDriveOK rts sDriveOK shortm lda #0 sta >ATADataHigh,x ;clear high byte transfer latch longm jsr IDEWaitReady shortm lda #ATAIdentify sta >ATACommand,x ; Issue the read command to the drive longm pei