changeset 1511:aa2a7c7dd3ec

Added from Jim Hathaway
author boisy
date Thu, 15 Jan 2004 00:26:48 +0000
parents 80a221f7a461
children f3557a63b11c
files 3rdparty/drivers/mmc/defsfile 3rdparty/drivers/mmc/makefile 3rdparty/drivers/mmc/mmcdesc.asm 3rdparty/drivers/mmc/mmcdrv.asm
diffstat 4 files changed, 930 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/3rdparty/drivers/mmc/defsfile	Thu Jan 15 00:26:48 2004 +0000
@@ -0,0 +1,4 @@
+    use os9defs
+    use rbfdefs
+    use systype
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/3rdparty/drivers/mmc/makefile	Thu Jan 15 00:26:48 2004 +0000
@@ -0,0 +1,51 @@
+# Jim Hathaway's MultiMediaCard NitrOS-9 driver
+
+include ../../../rules.mak
+
+DEPENDS		= ./makefile
+DRVRS		= mmcdrv_l1.dr mmcdrv_l2.dr mmcdrv_l1s.dr mmcdrv_l2s.dr 
+DESCS		= h0_mmc_l1.dd h0_mmc_l2.dd h1_mmc_l1.dd h1_mmc_l2.dd dd_mmc_l1.dd dd_mmc_l2.dd
+ALLOBJS		= $(DRVRS) $(DESCS)
+MMCL1FLAGS	= $(AFLAGS) -aLevel=1
+MMCL2FLAGS	= $(AFLAGS) -aLevel=2
+
+all:	$(ALLOBJS) $(DEPENDS)
+
+# Drivers - optimized for speed over size
+mmcdrv_l1.dr: mmcdrv.asm
+	$(AS) $(ASOUT)$@ $< $(MMCL1FLAGS)
+
+mmcdrv_l2.dr: mmcdrv.asm
+	$(AS) $(ASOUT)$@ $< $(MMCL2FLAGS)
+
+# Drivers - optimized for size over speed
+
+mmcdrv_l1s.dr: mmcdrv.asm
+	$(AS) $(ASOUT)$@ $< $(MMCL1FLAGS) -aSMALLC=1
+
+mmcdrv_l2s.dr: mmcdrv.asm
+	$(AS) $(ASOUT)$@ $< $(MMCL2FLAGS) -aSMALLC=1
+
+# Descriptors
+# ITDRV is the Drive 0 or 1 switch for device descriptors
+h0_mmc_l1.dd: mmcdesc.asm
+	$(AS) $(ASOUT)$@ $< $(MMCL1FLAGS) -aITDRV=0
+
+h0_mmc_l2.dd: mmcdesc.asm
+	$(AS) $(ASOUT)$@ $< $(MMCL2FLAGS) -aITDRV=0
+
+h1_mmc_l1.dd: mmcdesc.asm
+	$(AS) $(ASOUT)$@ $< $(MMCL1FLAGS) -aITDRV=1
+
+h1_mmc_l2.dd: mmcdesc.asm
+	$(AS) $(ASOUT)$@ $< $(MMCL2FLAGS) -aITDRV=1
+
+dd_mmc_l1.dd: mmcdesc.asm
+	$(AS) $(ASOUT)$@ $< $(MMCL1FLAGS) -aITDRV=0 -aDD=1
+
+dd_mmc_l2.dd: mmcdesc.asm
+	$(AS) $(ASOUT)$@ $< $(MMCL2FLAGS) -aITDRV=0 -aDD=1
+
+clean:
+	$(RM) $(ALLOBJS)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/3rdparty/drivers/mmc/mmcdesc.asm	Thu Jan 15 00:26:48 2004 +0000
@@ -0,0 +1,105 @@
+********************************************************************
+* H0 - MMC device descriptor
+*
+* $Id$
+*
+* MMC Defined Offsets
+*
+* Ed.    Comments                                       Who YY/MM/DD
+* ------------------------------------------------------------------
+
+         nam   H0        
+         ttl   MMC device descriptor
+
+* IT.STP (offset $14)
+*  Bit Meaning
+*  --- ---------------------------------------------------------------
+* 
+* IT.TYP (offset $15)
+*  Bit Meaning
+*  --- ---------------------------------------------------------------
+*  7   Hard Disk:  1 = hard disk, 0 = floppy disk
+*  6   Fudge LSN0: 0 = OS-9 disk, 1 = non-OS-9 disk
+* 
+* IT.DNS (offset $16)
+*  Bit Meaning
+*  --- ---------------------------------------------------------------
+*  1   Force CHS:     1 = Use CHS, 0 = Use LBA if drive supports it
+*  0   Master/Slave:  0 = master, 1 = slave
+*
+
+* Interface Address
+ADDR     set   $FF7A     
+
+Master   set   %00000000
+Slave    set   %00000001
+ForceCHS set   %00000010
+
+DriveSel set   Master
+
+
+* Driver specific fields
+ITDRV    set   $00       
+ITSTP    set   $00       
+ITTYP    set   $80       
+ITDNS    set   ITDRV
+
+ITSOFS1  set   $00       
+ITSOFS2  set   $00       
+ITSOFS3  set   $00       
+
+* Default Geometry
+* For speed sectors per track set to 16 JMH
+Sides    set   $20       
+Cyls     set   $80      
+SectTrk  set   $0010     
+SectTrk0 set   $0010     
+Interlv  set   $01       
+SASiz    set   $08       
+
+         ifp1            
+         use   defsfile  
+         endc            
+
+tylg     set   Devic+Objct
+atrv     set   ReEnt+rev 
+rev      set   $0        
+
+         mod   eom,name,tylg,atrv,mgrnam,drvnam
+
+         fcb   $FF        mode byte
+         fcb   HW.Page    extended controller address
+         fdb   ADDR       physical controller address
+         fcb   initsize-*-1 initilization table size
+         fcb   DT.RBF     device type:0=scf,1=rbf,2=pipe,3=scf
+         fcb   ITDRV      drive number
+         fcb   ITSTP      step rate
+         fcb   ITTYP      drive device type
+         fcb   ITDNS      media density
+         fdb   Cyls       number of cylinders (tracks)
+         fcb   Sides      number of sides
+         fcb   $01        verify disk writes:0=on
+         fdb   SectTrk    # of sectors per track
+         fdb   SectTrk0   # of sectors per track (track 0)
+         fcb   Interlv    sector interleave factor
+         fcb   SASiz      minimum size of sector allocation
+initsize equ   *         
+*IDE Driver specific additions to the device descriptor go here
+* NOTE: These do NOT get copied into the path descriptor; they
+*       cannot due to the fact that there is simply NO ROOM in
+*       the path descriptor to do so.  The driver must access
+*       these values directly from the descriptor.
+         fcb   0,0,0,0,0,0,0,0,0
+
+         ifne  DD        
+name     fcs   /DD/      
+         else            
+name     fcc   /H/       
+         fcb   ITDRV+$B0 
+         endc            
+mgrnam   fcs   /RBF/     
+drvnam   fcs   /MMCDRV/   
+
+         emod            
+eom      equ   *         
+         end             
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/3rdparty/drivers/mmc/mmcdrv.asm	Thu Jan 15 00:26:48 2004 +0000
@@ -0,0 +1,770 @@
+********************************************************************
+* MMCDRV Color Computer MultiMedia Card Driver
+* Version 2.0.1
+* Copyright (C) 2003 Jim Hathaway III KG4KNB@hat3.net
+********************************************************************
+ 
+************************************************************************
+* Updates:
+* 06/16/03 - Copied code from version 321 driver and changed for asm
+*            Did this to see if there is some other issue with ASM 
+*            cross assembly of this module.  Still having problems when 
+*            trying to write any file to a MMC formatted with the
+*            newer driver driver.  This driver seems to work with ASM
+*            there must be a bug with the other modified version
+* 06/17/03 - Moved from 001b version to 100 after testing showed no
+*            issues.
+*            Worked on making code similar to other code.  Need to test
+*            this code as is to see if it will still work.
+*            Made EXTREME changes to the code.  Will need mucho debugo
+* 06/18/03 - More time working through.
+* 06/19/03 - Fixed a bug in the read code that did not set PD.BUF correctly
+*            Y was being loaded with V.PORT before PD.BUF,y was calculated
+*            Write sector routine was missing Y=V.Port setup as well as
+*            MDN,u setup before calling GREAD.  
+*            LSN0PROC - missing RTS, also moved clearing of the LSN0 flag
+*            to the LSN0PROC subroutine and removed it from the READ
+*            subroutine. Found and fixed several bugs today.  Including
+*            the problem last night with an iniz causing the driver to 
+*            loop and access the card.
+* 06/24/03 - Found a bug in the error return routines, comb should have 
+*            been done BEFORE the error number is loaded.  Was causing
+*            a read error 244 to be returned as error 011
+* 06/29/03 - Found final bug causing problems in nlevel2.  IF an error
+*            was returned from the chkrs routine the delay was not called
+*            before exit, then the calling routine went back and sent the
+*            command again and stepped on the spi transfer.  After all
+*            bytes are written or read at slow speed the delay routine
+*            MUST be called!
+*************************************************************************
+
+NUMDRIVE equ   2              Max. # of device descriptors for this driver
+CMDREAD  equ   $51            Command to read a single block
+CMDWRITE equ   $58            Command to write a sector
+MMCCSB   equ   $80            MMC control register slow clock bit
+MMCCRO   equ   1              MMC control register offset from data port
+DLYAMT   equ   $28            Standard delay amount used in DLYSTART
+CRDPULS  equ   $A             Number of times to loop for card init
+
+         nam   MMCDRV
+         ttl   MMC device driver for CoCo
+
+         ifp1
+         use   defsfile
+         endc
+
+tylg     set   Drivr+Objct   
+atrv     set   ReEnt+rev
+rev      set   $02
+edition  equ   2
+
+         mod   eom,name,tylg,atrv,start,size
+
+         org   0
+         rmb   DRVBEG+(DRVMEM*NUMDRIVE)
+
+* Start of driver-specific statics
+LSN0     rmb   1              Byte flag to indicate LSN0
+MDN      rmb   1              MMC Drive Number
+SECT2WR  rmb   1              Determines the sector to write
+OS9SECT  rmb   2              Temp storage for OS9 sector address
+SECTPNT  rmb   2              Temp storage for Sector Buffer pointer
+BUFFER1  rmb   256            Sector buffer location for write cmds
+RCMDBLK  rmb   6
+WCMDBLK  rmb   6
+
+size     equ   .
+
+         fcb   $FF            mode byte
+
+name     fcs   /MMCDRV/       module name
+         fcb   edition        module edition
+
+
+* Start point
+start    lbra  INIT
+         lbra  READ
+         lbra  WRITE
+         lbra  GETSTA
+         lbra  SETSTA
+         lbra  TERM
+* End start
+
+********************************
+* Command bytes storage area
+********************************
+CMD0     fcb   $40,0,0,0,0,$95
+CMD1     fcb   $41,0,0,0,0,$95
+CMD13    fcb   $4D,0,0,0,0,$95
+CMD171   fcb   $50,0,0,1,0,$95
+CMD172   fcb   $50,0,0,2,0,$95
+
+***************************************************************
+* LSN0PROC - Process drive table when LSN0 is loaded.
+* Called from READ
+* Added pshs, puls y to preserve y holding the address of the 
+* MMC 6/19/03 JMH
+***************************************************************
+LSN0PROC pshs  y              Save y for return
+         ldb   MDN,u          Get drive number
+         decb                 Make drive 1 = 0, drive 2 = 1
+         lda   #DRVMEM        # bytes to copy from LSN0 to drive table
+         mul                  Compute drive table location
+         leay  DRVBEG,u       Point to start of drive tables
+         leay  d,y
+         ldx   SECTPNT,u      We need to get the sector buffer to use
+         lda   #DD.SIZ        Get drive table size
+RDCL1    ldb   ,x+            From copy
+         stb   ,y+            To Copy
+         deca                 Loop for entire path descriptor
+         bne   RDCL1          Loop till done
+         clr   LSN0,u         Set LSN0 false 0=f 1=t
+         puls  y,pc           Restore/return
+
+* End LSN0PROC
+
+***************************************************************
+* Send a command string to the MMC (6 bytes) with delay
+* Can be called as SNDCS for sending command and checking status
+* or just chkrs can be called to see if the card returns the 
+* correct response
+* Entry: X=Pointer to command string to send
+*        Y=MMC Command data port
+*        A=Used for loop and not preserved
+*  
+***************************************************************
+SNDCS    pshs  d,x            Save regs
+         ldb   #6             Number of command bytes
+SNDCLS   lda   ,x+            Get command byte
+         sta   ,y             Send command byte
+         lbsr  DLYSTRT        Call our delay routine
+         decb                 Are we done?
+         bne   SNDCLS         Keep looping until complete
+         puls  d,x            Restore regs
+
+CHKRS    pshs  d
+         clrb
+CHKRSL1  lbsr  DLYSTRT        Call our delay routine
+         cmpa  ,y             Check for response
+         beq   CHKRSG         Response is good, exit without error
+         decb                 Keep looping?
+         bne   CHKRSL1        Done yet?
+
+CHKRSB   lbsr  DLYSTRT        Call our delay routine
+         comb                 Set error state
+         puls  d,pc           Cleanup/Return
+CHKRSG   lbsr  DLYSTRT        Call our delay routine
+         clrb                 Set no error
+         puls  d,pc           Restore / Return
+
+*********************************************************************
+* Delay Routine - For use during initialization to slow down the 
+* read and write commands to the MMC because we must use a speed of 
+* less than 400k for the clock until CMD1 is issued (per MMC specs.)
+*********************************************************************
+DLYSTRT  pshs  b              Save b register for return
+         ldb   #DLYAMT        Standard delay amount
+DLYLP1   decb                 Start of delay loop
+         bne   DLYLP1         End of delay loop
+         puls  b,pc           Get value of b register back
+* End delay routine
+
+*******************************************************************
+* INIT - Standard OS9 init function.  Enable all MMCs if present and
+*        request sector buffer block.  Also set drive tables values.
+********************************************************************
+INIT     ldy   V.PORT,u       Get MMC base port address
+         lda   #NUMDRIVE      Number of cards to init
+
+INITL1   sta   MDN,u          Get card number
+         lbsr  INITCRD        Try and init card
+         deca   
+         bne   INITL1         Keep looping
+ 
+         lda   #CMDREAD       Setup bytes for each command area
+         sta   RCMDBLK,u      Save them to each area
+         lda   #CMDWRITE
+         sta   WCMDBLK,u
+         ldd   #$0095         Final two cmd bytes
+         std   RCMDBLK+4,u    Save last two cmd bytes for read
+         std   WCMDBLK+4,u    Save last two cmd bytes for write
+
+         clr   LSN0,u         Set LSN0 false 0=f 1=t
+
+         leax  DRVBEG,u       Point to start of drive tables
+         ldb   #NUMDRIVE      Number of drives supported
+         stb   V.NDRV,u       Store the number of drives
+         lda   #$ff
+INITL2   sta   DD.TOT,x       DD.TOT MSB to bogus value
+         sta   V.TRAK,x       Init current track # to bogus value
+         leax  DRVMEM,x       Get next drive table location
+         decb                 Loop counter
+         bne   INITL2         Keep looping?
+
+         clr   MMCCRO,y       Deselect any cards in use
+         
+GETSTA
+SETSTA
+TERM
+         clrb 
+         rts
+
+********************************************************************
+* WRITE SECTOR
+* Must read in correct sector then write out
+* a 512 byte sector.  MMCs only support 512 byte sectors
+* for write.
+********************************************************************
+WRITE    stb   RCMDBLK+1,u    Save LSN for read command
+         stx   RCMDBLK+2,u    Save LSN for read command
+
+         stb   WCMDBLK+1,u    Save LSN for write command
+         stx   WCMDBLK+2,u    Save LSN for write command
+
+         ldx   PD.BUF,y       Get real sector address for later
+         stx   OS9SECT,u      Save os9 sector address for later
+
+         lda   WCMDBLK+3,u    Adjust WLSN
+         anda  #$FE           Mask bit 0
+         sta   WCMDBLK+3,u    Adjust WLSN
+
+         lda   RCMDBLK+3,u    Get lowest LSN byte
+         anda  #1             Mask bits 7-1
+         sta   SECT2WR,u      Save it for later
+         beq   WRROWE         Go RO WE 1=(RE,WO) 0=(RO,WE)         
+
+WRREWO   ldd   RCMDBLK+2,u    Get upper LSN
+         subd  #1
+         std   RCMDBLK+2,u
+         ldb   RCMDBLK+1,u
+         sbcb  #0
+         stb   RCMDBLK+1,u
+
+         bra   WRGO
+
+WRROWE   ldd   RCMDBLK+2,u    Get upper LSN
+         addd  #1
+         std   RCMDBLK+2,u
+         ldb   RCMDBLK+1,u
+         adcb  #0
+         stb   RCMDBLK+1,u
+   
+WRGO     leax  BUFFER1,u
+         stx   SECTPNT,u      Save sector buffer for read
+
+         lda   PD.DRV,y       Get drive # requested
+         inca 
+         sta   MDN,u          Save requested drive number
+
+         ldy   V.PORT,u       Get MMC base port address
+
+         lbsr  GREAD          Go get buffered sector
+         lbcs  EWRITE         Write error
+
+WRGO1    leax  CMD172,pcr     Get command to change sector to 512 bytes
+         lda   #$00           Expected response
+         lbsr  SNDCF          Go send the command (cmd17-2)
+         lbcs  ENOTRDY        Not ready
+
+         leax  WCMDBLK,u      Get address of write command block
+         lda   #$00           Expected response
+         lbsr  SNDCF          Send this command without delay
+         lbcs  ENOTRDY        Not ready
+
+         lda   #254           Start of data sector byte
+         sta   ,y             Save start of sector byte
+
+WRGO2    tst   SECT2WR,u      1=(RE,WO) 0=(RO,WE)
+         bne   WRREWO1        
+           
+WRROWE1  ldx   OS9SECT,u      Get real sector buffer
+         bsr   WRSEC          Go write 256 bytes
+         leax  BUFFER1,u      Get buffered sector
+         bra   WRDC1          Data send complete
+
+WRREWO1  leax  BUFFER1,u      Get buffered sector buffer
+         bsr   WRSEC          Go write 256 bytes
+         ldx   OS9SECT,u      Get real sector buffer
+WRDC1    bsr   WRSEC          Go write 256 bytes
+
+* dropped the code to send two crc bytes - the routine
+* that reads the card to see if the $E5 response is given
+* also sends data, so no separate crc code is needed
+
+         lda   #$E5           Response - Data accepted tolken
+         lbsr  CHKRF          Check for correct response
+         lbcs  EWRITE         Write error
+
+         lda   #$FF           Response - Card complete with write
+         lbsr  CHKRF          Check for correct response
+         lbcs  EWRITE         Write error
+
+         leax  CMD13,pcr      Get check status command
+         lda   #$00           Expected response
+         lbsr  SNDCF          Go send the command (cmd13)
+         lbcs  EWRITE         Write error
+         lbsr  CHKRF          Check for correct response
+         lbcs  EWRITE         Write error
+
+         leax  CMD171,pcr     Get command to change sector to 256
+         lda   #$00           Expected response
+         lbsr  SNDCF          Go send the command (cmd17-1)
+         lbcs  ENOTRDY        Not ready
+ 
+         lbsr  WREXIT         Clean exit
+
+* End of write sector routine
+
+********************************************************
+* WRSEC - Write a single 256 byte sector to the MMC
+* Entry: Y=MMC data port address
+*        X=Sector location to copy from
+********************************************************
+         IFNE  SMALLC
+WRSEC    clrb                 Loop counter
+WRLP1    lda   ,x+            Get data byte
+         sta   ,y             Store data byte
+         decb
+         bne   WRLP1          Keep looping?
+         rts                  Return
+
+         ELSE
+
+WRSEC    leax  15,x
+         lda   #8             Number of loops to run
+         pshs  a              Used for loop counter
+WRBLK1   ldd   -15,x          Get 2 bytes
+         sta   ,y             Save byte 1
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 2
+         ldd   -13,x          Get 2 more bytes
+         sta   ,y             Save byte 3
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 4
+         ldd   -11,x          Get 2 more bytes
+         sta   ,y             Save byte 5
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 6
+         ldd   -9,x           Get 2 more bytes
+         sta   ,y             Save byte 7
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 8
+         ldd   -7,x           Get 2 more bytes
+         sta   ,y             Save byte 9
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 10
+         ldd   -5,x           Get 2 more bytes
+         sta   ,y             Save byte 11
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 12
+         ldd   -3,x           Get 2 more bytes
+         sta   ,y             Save byte 13
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 14
+         ldd   -1,x           Get 2 more bytes
+         sta   ,y             Save byte 15
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 16
+         ldd   1,x            Get 2 more bytes
+         sta   ,y             Save byte 17
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 18
+         ldd   3,x            Get 2 more bytes
+         sta   ,y             Save byte 19
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 20
+         ldd   5,x            Get 2 more bytes
+         sta   ,y             Save byte 21
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 22
+         ldd   7,x            Get 2 more bytes
+         sta   ,y             Save byte 23
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 24
+         ldd   9,x            Get 2 more bytes
+         sta   ,y             Save byte 25
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 26
+         ldd   11,x           Get 2 more bytes
+         sta   ,y             Save byte 27
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 28
+         ldd   13,x           Get 2 more bytes
+         sta   ,y             Save byte 29
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 30
+         ldd   15,x           Get 2 more bytes
+         sta   ,y             Save byte 31
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 32
+         leax  32,x           Add 32 bytes
+         dec   ,s             Loop counter 
+         bne   WRBLK1         Loop back and do it again
+         puls  a,pc           Clean stack, return
+
+         ENDC
+
+* End of WRSEC subroutine
+
+*************************************************
+* INITCRD : Init a single card
+* Entry: Y=MMC data port address
+*        MDN,u = card number (1..X)
+* Registers preserved
+*************************************************
+INITCRD  pshs  d,x
+
+         lda   #MMCCSB        Change MMC clock to slow speed
+         sta   MMCCRO,y       Write slow speed bit
+         lda   #CRDPULS       Clock pulses needed to init cards
+
+* Per MMC spec - before any commands are sent to the card 80 clock
+* pulses must be sent at a speed of less than 400k.  After init
+* is complete we will use the full speed of 3.56 Mhz.  This is the
+* clock speed of the serial shift.  8 cycles at 3.56 Mhz are required
+* to complete the SPI transfer.
+
+ICLKPL1  tst   ,y             Send 8 clock pulses to card
+         lbsr  DLYSTRT        Call our delay routine
+         deca                 Loop counter
+         bne   ICLKPL1        Loop until all clocks done
+
+         lda   MDN,u          Get card number
+         ora   #MMCCSB        Select slow clock bit
+         sta   MMCCRO,y       Write to MMC control register slow speed
+
+         leax  CMD0,pcr       x = cmd0 address
+         lda   #$01           Response
+         lbsr  SNDCS          Go send the command w/ delay
+         lbcs  INITCE1        This card is not ready exit
+
+         ldb   #20            Number of times to send CMD1 before error
+INCMD1L  leax  CMD1,pcr       Load address into x for cmd1
+         lda   #$00           Expected response
+         lbsr  SNDCS          Go send the command (cmd1)
+         bcc   INC1C          We got our response, continue
+         decb                 Loop counter
+         bne   INCMD1L        Keep trying to get a response of 0
+         lbcs  INITCE1        This card is not ready exit
+
+INC1C    lda   MDN,u          Get card number
+         sta   MMCCRO,y       Write to MMC control register full speed
+
+         leax  CMD171,pcr     Get command to change sector to 256 bytes
+         lda   #$00           Expected response
+         lbsr  SNDCF          Go send the command (cmd17-1) w/o delay
+         bcs   INITCE1        Error changing to 256 byte sector
+
+         clrb                 No error
+         puls d,x,pc          Clean exit
+
+INITCE1  comb                 Error, we could not init card
+         puls d,x,pc
+
+* End of INITCRD
+
+
+*****************************************************************
+* READ - Read a single 256 byte sector.  Uses GREAD to get the 
+*        sector into memory
+*****************************************************************
+READ     stb   RCMDBLK+1,u    Save LSN
+         stx   RCMDBLK+2,u    Save LSN
+
+         leax  0,x            Check for LSN0
+         bne   RDS1          
+         tstb                 Check for LSN0
+         bne   RDS1
+         inc   LSN0,u         Set LSN0 Flag                  
+
+RDS1     lda   PD.DRV,y       Get drive # requested
+         inca                 Set drive number correctly
+         sta   MDN,u          Save drive number
+
+         ldx   PD.BUF,y       Get physical sector buffer pointer
+         stx   SECTPNT,u      Store the sector buffer location
+
+         ldy   V.PORT,u       Get MMC base port address
+
+         bsr   GREAD          Get our sector
+         lbcs  EREAD          Exit with read error
+
+         tst   LSN0,u         Is this LSN0?
+         beq   RDEX1          Complete - return
+ 
+         lbsr  LSN0PROC       Process LSN0 information
+
+WREXIT
+RDEX1    clrb                 Set no errors
+         clr   MMCCRO,y       Deselect any cards in use
+         rts                  Read complete with no errors
+
+* End of READ
+
+***************************************************************
+* Send a command string to the MMC (6 bytes) w/o delay
+* Can be called as SNDCF for sending command and checking status
+* or just CHKRF can be called to see if the card returns the 
+* correct response
+* Entry: X = Pointer to command string to send
+*        Y = MMC Command data port
+*        A = Used for loop and not preserved
+***************************************************************
+SNDCF    
+         IFNE  SMALLC
+
+         pshs  d,x            Save regs
+         ldb   #$06           Loop amount
+SNDCFL1  lda   ,x+            Get command byte
+         sta   ,y             Save byte to card
+         decb                 Loop counter
+         bne   SNDCFL1        Keep looping?
+         puls  d,x            Restore regs
+
+         ELSE
+
+         pshs  d              Save regs
+         ldd   ,x             Get command bytes
+         sta   ,y             Save byte 1
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 2
+         ldd   2,x            Get command bytes
+         sta   ,y             Save byte 3
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 4
+         ldd   4,x            Get command bytes
+         sta   ,y             Save byte 5
+         nop                  Delay to complete SPI transfer
+         stb   ,y             Save byte 6
+         puls  d              Restore regs
+
+         ENDC
+
+* Try to quickly get a response from the MMC.  128 loops
+* is only a guess as to how long an average command response
+* might be.  After the 128 loops it is obvious that the card
+* may need more time to process the command (such as a write)
+* command.  At that point we sleep for 1 tick to give the 
+* card time to complete the request.  Then try another 255 times
+* to get the response before we return an error.
+* 6-24-03 JMH - Found something interesting in NLevel2 V030102 
+* testing last night.  The MMC would not initialize aparently
+* based on the LED pattern being displayed.  Level2 OS9 is able
+* to use this driver without problems.  As I think about it more
+* it might be the fact that in 6309 mode the CPU is able to 
+* execute instructions faster and so it is stepping on the 
+* spi shift.
+* 6-24-03 JMH - Moved pshs x lower into subroutine to save
+* some time if a sleep is not needed then there is no reason
+* to pshs x and puls x.
+
+CHKRF    pshs  d              Save regs
+         clrb                 Number of loops
+
+CHKRFL1  cmpa  ,y
+         beq   CHKRFG         Got our response
+         cmpa  ,y
+         beq   CHKRFG         Got our response
+         decb                 Loop counter 
+         bne   CHKRFL1        Keep looping?
+
+* This sleep should only occur when writing to the card
+         pshs  x              Save x for later
+         ldx   #1             Sleep for remainder of this tick
+         os9   F$Sleep        Wait for card
+         puls  x              Restore
+
+         clrb                 Number of loops = 256
+CHKRFL2  cmpa  ,y
+         beq   CHKRFG         Got our response
+         decb                 Loop counter
+         bne   CHKRFL2        Keep looping?
+         
+CHKRFB   comb                 Set error state
+         puls  d,pc           Cleanup/Return
+CHKRFG   clrb                 Set no error
+         puls  d,pc           Cleanup/Return
+
+***************************************************************
+* GREAD - New generic read subroutine.  Requires:
+*         MDN,u = drive number
+*         RCMDBLK,u LSN (RCMDBLK+1,RCMDBLK+2,RCMDBLK+3)
+*         SECTPNT,u = location to copy sector to
+*         Y = V.port,u (MMC base port address)
+***************************************************************
+GREAD    
+         lda   MDN,u
+         sta   MMCCRO,y       Select MMC
+
+         lda   ,y             Burn a byte - bug fix
+
+         lda   #$FF           Expected card response
+         bsr   CHKRF          Go check for response byte
+         bcc   RDN1           Is card ready?  If yes continue
+
+         lbsr  INITCRD        Try and initialize the card requested
+         lbcs  ENOTRDY        Not ready - no card found in slot
+
+         lda   MDN,u          Get drive number
+         sta   MMCCRO,y       Write to MMC control register
+
+RDN1     leax  RCMDBLK,u      Read command block
+         lda   #$00           Expected response
+         bsr   SNDCF          Send this command without delay
+         bcc   RDN2           If command did not generate err continue
+
+         lbsr  INITCRD        Try and initialize the card requested
+         lbcs  ENOTRDY        Not ready
+
+         lda   MDN,u          Get drive number again
+         sta   MMCCRO,y       Set card selected at full speed
+
+         leax  RCMDBLK,u      Read command block
+         lda   #$00           Expected response - cmd accepted
+         bsr   SNDCF          Send this command without delay
+         lbcs  ENOTRDY        Not ready
+
+RDN2     lda   #$FE           Expected response start of sector
+         bsr   CHKRF          Check for response
+         lbcs  EREAD          Read Error
+
+         ldx   SECTPNT,u      We need to get the sector buffer to use
+         bsr   RDSEC          Go read the sector
+
+         clrb                 Set no errors
+         rts
+
+***************************************************************
+* RDSEC - Read a single 256 byte sector from the MMC + 2 CRC bytes
+* Entry: Y=MMC data port address
+*        X=Sector location to copy to
+***************************************************************
+         IFNE  SMALLC
+RDSEC    pshs  x              Save x
+         clrb                 Loop counter
+RDLP1    lda   ,y             Get data byte
+         sta   ,x+            Store data byte
+         decb
+         bne   RDLP1          Keep looping?
+*         ldd   ,y             Get CRC bytes
+*         lda   ,y             Get CRC bytes
+         puls  x,pc           Restore/return
+
+         ELSE
+
+* Using a 5 bit offset only adds 1 cycle to each of the STD instructs.
+* incrementing the X index register each time by ++ adds 3 instructions
+* so this saves 2 cycles for every 2 bytes transfered.  2 cycles * 16 
+* STD instructions = 32 saved cycles per loop or 256 cycles per sector
+* read.  This loop uses about 1900 cycles to complete. A simple lda
+* sta single byte move loop takes about 3900 cycles to complete.  This
+* is a more than 50% increase in speed for this loop (this is where
+* the driver uses the most CPU time).  6309 users note! a TFM will not
+* work because you need AT LEAST 4 coco (regardless of the CoCo's actual
+* speed) cycles between data port access for the SPI cycle to complete.  
+* If a write or read occurs during the four cycles
+* after a byte is read/wrote to the SPI data port then the data
+* transfer will be corrupted.  
+
+RDSEC    leax  15,x           Move to the middle of the 32 byte block
+         lda   #8             Number of loops to run
+         pshs  a              Used for loop
+RDLP1    ldd   ,y             Load byte 1
+         ldb   ,y             Load byte 2
+         std   -15,x          Store two bytes
+         ldd   ,y             Load byte 3
+         ldb   ,y             Load byte 4
+         std   -13,x          Store two bytes
+         ldd   ,y             Load byte 5
+         ldb   ,y             Load byte 6
+         std   -11,x          Store two bytes
+         ldd   ,y             Load byte 7
+         ldb   ,y             Load byte 8
+         std   -9,x           Store two bytes
+         ldd   ,y             Load byte 9
+         ldb   ,y             Load byte 10
+         std   -7,x           Store two bytes
+         ldd   ,y             Load byte 11
+         ldb   ,y             Load byte 12
+         std   -5,x           Store two bytes
+         ldd   ,y             Load byte 13
+         ldb   ,y             Load byte 14
+         std   -3,x           Store two bytes
+         ldd   ,y             Load byte 15
+         ldb   ,y             Load byte 16
+         std   -1,x           Store two bytes
+         ldd   ,y             Load byte 17
+         ldb   ,y             Load byte 18
+         std   1,x            Store two bytes
+         ldd   ,y             Load byte 19
+         ldb   ,y             Load byte 20
+         std   3,x            Store two bytes
+         ldd   ,y             Load byte 21
+         ldb   ,y             Load byte 22
+         std   5,x            Store two bytes
+         ldd   ,y             Load byte 23
+         ldb   ,y             Load byte 24
+         std   7,x            Store two bytes
+         ldd   ,y             Load byte 25
+         ldb   ,y             Load byte 26
+         std   9,x            Store two bytes
+         ldd   ,y             Load byte 27
+         ldb   ,y             Load byte 28
+         std   11,x           Store two bytes
+         ldd   ,y             Load byte 29
+         ldb   ,y             Load byte 30
+         std   13,x           Store two bytes
+         ldd   ,y             Load byte 31
+         ldb   ,y             Load byte 32
+         std   15,x           Store two bytes
+         leax  32,x           Add 32 bytes
+         dec   ,s             Loop counter 
+         bne   RDLP1          Loop back and do it again
+
+* Eliminated the code to pull two CRC bytes from the card.
+* The routine that checks for the correct response will 
+* extract these two bytes from the MMC
+
+*         ldd   ,y             Get 1 byte of CRC data from card
+*         ldb   ,y             Get 1 byte of CRC data from card
+
+         puls  a,pc
+
+         ENDC
+
+* End of RDSEC subroutine
+
+ENOTRDY  bsr   ERREXIT
+         comb
+         ldb   #E$NotRdy      Not ready
+         rts
+
+EWRITE   bsr   ERREXIT
+         comb
+         ldb   #E$Write       Write error
+         rts
+
+EREAD    bsr   ERREXIT
+         comb
+         ldb   #E$Read        Read error
+         rts
+
+* Added to handle things that need to occur if an error occurs
+* 1. Select the card (may already be selected)
+* 2. Send command to change sector size back to 256 bytes
+* 3. Clear the LSN0 flag (may already be cleared)
+* 4. Deselect all cards.
+
+ERREXIT  lda   MDN,u          Get drive number
+         sta   MMCCRO,y       Select card (in case not selected)
+         leax  CMD171,pcr     Get command to change sector to 256 bytes
+         lda   #$00           Expected response
+         lbsr  SNDCF          Go send the command (cmd17-1) w/o delay
+
+         clr   lsn0,u         Clear LSN0 flag if set
+         clr   MMCCRO,y       Deselect any cards
+         rts 
+
+         emod
+eom      equ   *
+         end