NOLIST ; This file is part of picide, ATA(PI) interface to PIC18 family MCUs. ; Copyright (C) 2004-5 Toby Thain, toby@telegraphics.com.au ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA LIST TITLE picide SUBTITLE "ATAPI module" ;; Version history ;; 21-Oct-2004: 0.1 - started by Toby ;; 23-Feb-2005: 1.0 - public release under GPL ; contents of this module: global atapipkt ; data block for 12 byte ATAPI command packet global atapi_zeropkt ; initialise ATAPI command packet to zeroes ; before calling the following routines, ; set up parameters in atapipkt (LBA0/8/16/24 and LEN0/8) global atapi_read10 ; ATAPI READ(10) command global atapi_readcd ; ATAPI READCD command global atapi_modesense ; ATAPI MODE SENSE command global atapi_reqsense ; ATAPI REQUEST SENSE command global atapi_readcapacity ; ATAPI READ CAPACITY command ; check error in last command global atapi_checkerr #include "defs.inc" #include "idecmd.inc" #include "idedefs.inc" #include "atapidefs.inc" ;#define ATAPI_DEBUG extern datasetup,ide_rdata,ide_wdata,wdcnt,ide_atapipacket extern longwaitbsy,seccnt extern rdreg,wrreg,ide_rblk,delay2ms,delay1500ms extern putdec16,dec16,putch,puthex,dumpsec udata_acs wcnt res 2 errsave res 1 atapipkt res 12 ; command packet code ; handle read-data phase of ATAPI command atapi_rdata: ;call delay2ms ; FIXME call datasetup ; wait for data ready (!BSY & DRQ) _returniferr ; check timeout ;call delay2ms ; FIXME moredata: ; device indicates how many bytes are to be transferred _rdreg ATAPI_REG_BYTECNTHI movwf wcnt+1 _rdreg ATAPI_REG_BYTECNTLO movwf wcnt #ifdef ATAPI_DEBUG _puts "bytecnt=\0" movff wcnt+1,dec16+1 movff wcnt,dec16 call putdec16 _crlf #endif bcf STATUS,C ; clear carry rrcf wcnt+1 ; divide bytes by 2, leaving sector count in wcnt+1 rrcf wcnt ; and remaining # of words in wcnt #ifdef ATAPI_DEBUG _puts " =\0" movf wcnt+1,w call puthex _puts "sec+\0" movf wcnt,w call puthex _puts "wds\r\n\0" #endif ; now do transfer, 256 words at a time lfsr 0,secbuf ; point indirection reg at sector buffer movf wcnt+1,w movwf seccnt bz part ; <1 sector whole: ; do whole sectors #ifdef ATAPI_DEBUG _putchar 'W' #endif clrf wdcnt ; do 256 words call ide_rblk ; PIO transfer decfsz seccnt bra whole part: #ifdef ATAPI_DEBUG _putchar 'P' #endif movf wcnt,w ; check if there is a partial sector remaining bz done ; nothing left movwf wdcnt ; loop counter used by ide_rdata call ide_rblk done: call longwaitbsy ;call delay2ms ; FIXME why is this needed??? _rdreg IDE_REG_STATUS movwf errsave andlw IDE_STATUS_DRQ bnz moredata #ifdef ATAPI_DEBUG _puts " data done\r\n\0" #endif movf errsave,w andlw ATAPI_STATUS_CHECK return ;--------------------------------------------------------- atapi_checkerr: ; first see if STATUS indicates an error condition (CHECK) call longwaitbsy _rdreg IDE_REG_STATUS #ifdef ATAPI_DEBUG movwf errsave _puts "ATAPI Status\0" movf errsave,w _putstrbits " BSY\000 DRDY\000 DF\000 DSC\000 DRQ\000 CORR\000 1\000 CHECK\000" _crlf movf errsave,w #endif andlw ATAPI_STATUS_CHECK bnz err _puts "atapi_checkerr: No Error\r\n\0" retlw NO_ERR ; no error err: ; error condition exists, examine Sense Key _rdreg IDE_REG_ERROR movwf errsave #ifdef ATAPI_DEBUG _puts " Error \0" movf errsave,w _putstrbits "\000\000\000\000 MCR\000 ABRT\000 EOM\000 ILI\000" _crlf #endif swapf errsave,f movlw 0x0f andwf errsave,f ;#ifdef ATAPI_DEBUG _puts " *** Sense \0" movf errsave,w call puthex _putchar '=' movf errsave,w _putstrlist "No Sense\000Recov Err\000Not Ready\000Medium Err\000Hw Err\000Illegal Req\000Unit Attn\000Data Protect\000Blank Check\0009\000A\000Aborted Cmd\000C\000D\000Miscompare\000F\000" _crlf ;#endif movlw ATAPI_SENSE_UNITATTN cpfseq errsave ; is it UNIT ATTENTION? bra notattn ; UNIT ATTENTION - issue Request Sense to clear it #ifdef ATAPI_DEBUG _puts "== Unit Attn; Req Sense...\r\n\0" #endif rcall atapi_reqsense _returniferr retlw ATAPI_RETRY ; tell caller to retry notattn: movlw ATAPI_SENSE_NOTREADY cpfseq errsave retlw ABORT_ERR ; give up. #ifdef ATAPI_DEBUG _puts "== Not Ready; retry\r\n\0" #endif ; device reports NOT READY call delay1500ms ; wait a bit... retlw ATAPI_RETRY ; and suggest caller retries. ; interpretation of status bits if dma/overlapped ; dw " BSY\000 DRDY\000 DMAREADY\000 SERVICE\000 DRQ\000 CORR\000 1\000 CHECK\000" ;--------------------------------------------------------- atapi_reqsense: rcall atapi_zeropkt setf ATAPI_LBA8 ; allocation length = 255 movlw ATAPI_CMD_REQSENSE rcall atapi_cmd _returniferr BANKSEL secbuf _puts "Sense Data: \0" btfss secbuf+0,7,1 bra notvalid _puts "Info(LBA)=\0" movf secbuf+3,w,1 call puthex movf secbuf+4,w,1 call puthex movf secbuf+5,w,1 call puthex movf secbuf+6,w,1 call puthex notvalid: _puts " Key=\0" movlw 0x0f andwf secbuf+2,w,1 call puthex _puts " ASC=\0" movf secbuf+12,w,1 call puthex _puts " ASCQ=\0" movf secbuf+13,w,1 call puthex _crlf #ifdef ATAPI_DEBUG movlw 2 call dumpsec #endif retlw NO_ERR ;--------------------------------------------------------- atapi_read10: movlw ATAPI_CMD_READ10 atapi_cmd:movwf ATAPI_OPCODE ; caller must have set up LBA0/8/16/24 and LEN0/8 call ide_atapipacket ; issue command _returniferr ; only timeout? rcall atapi_rdata ; handle data phase tstfsz WREG rcall atapi_checkerr return ;--------------------------------------------------------- atapi_modesense: movlw ATAPI_CMD_MODESENSE bra atapi_cmd ;--------------------------------------------------------- atapi_readcd: movlw ATAPI_CMD_READCD bra atapi_cmd ;--------------------------------------------------------- retryreadcap: _puts "Retry Read Capacity: \0" atapi_readcapacity: rcall atapi_zeropkt movlw ATAPI_CMD_READCAPACITY rcall atapi_cmd addlw 0 ; set flags on W bz readcok xorlw ATAPI_RETRY bz retryreadcap xorlw ATAPI_RETRY ; restore error code return ; not retry, we must give up readcok: ;movlw 1 ;call dumpsec _puts "Capacity: LBA=0x\0" lfsr 1,secbuf movf POSTINC1,w call puthex movf POSTINC1,w movwf dec16+1 call puthex movf POSTINC1,w movwf dec16 call puthex movf POSTINC1,w call puthex ; compute megabytes **assuming 2K blocks** ; bytes = cap << 11 ; megabytes = (cap << 11) >> 20 ; = cap >> 9, so eliminate the lsbyte, and shift 1 bit right _putchar '=' bcf STATUS,C rrcf dec16+1 rrcf dec16 call putdec16 ; this uses FSR0!! _puts "MB Blk len=\0" movf POSTINC1,w ;call puthex movf POSTINC1,w ;call puthex movf POSTINC1,w movwf dec16+1 ;call puthex movf POSTINC1,w movwf dec16 ;call puthex call putdec16 _crlf retlw NO_ERR ;--------------------------------------------------------- atapi_zeropkt: ; zero 12 bytes of command packet lfsr 0,atapipkt movlw 12 loop: clrf POSTINC0 decfsz WREG bra loop return ;--------------------------------------------------------- end