;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Onhold Revision 5.1 ; Modify Version By Leo Lau ; leo8597@yahoo.com.hk ; ; 25 Sep 2006 ; more a little function... ; When pause CD, allow using Eject Key, Stop Key to Eject or Stop CD ; ; 24 Sep 2006 ; Fix a little bug again... ; Add Mode Sense Function to check CD-Rom tray status open or close ; and modify LCD display to reduce flashing when connect VFD Module ; ; Onhold Revision 5 ; Modify Version By Leo Lau ; leo8597@yahoo.com.hk ; ; 29 Jan 2005 ; Fix a little bug Open CD-Rom Tray & Change TOC Total Time ; ; Remove 74LS164, BC559, 7 x 1K 1 x & 5.6K Resistor, 1 x LED, ; Redraw PCB Board (Single Side), ; Change 4 x Keys function + IR Receive or 5 x Keys Function ; Open, Stop, Play, Previous, Next & Pause Key ; high to low (remove 4 x 1K Resistor) ; using 4 bit to control LCD ; ; Onhold Revision 3 ; Modify Version By Leo Lau ; leo8597@yahoo.com.hk ; 22 Dec 2003 ; ; Add More Key for Open, Close, Previous, Stop and Play Key. Change LCD ; Display like a Audio CD Player... ; ; Normal Function is work such as Open CD-Rom Tray, Stop, ; Play, Next & Previous. But some bug may be found...I'm still debug... ; ; onhold (final at89c51 target), with 16x2 character LCD display ; Revision 2 ; A Simple 8051 based ATAPI CDROM audio controller ; Copyright (C) 2000,2002 Jason Nunn ; August 2000 ; ; This software comes under the GNU public license agreement. See the COPYING ; file in this distribution. ; ; If you use this code (or parts) of it, then please credit me. ; ; 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. ; ; WWW: http//jsno.arafuraconnect.com.au ; ; If you use this code (or parts) of it, then please credit me. ; ; coded to parse by LA51 assembler (ASM51) ; current target: - DARMICON development board (SAB80C537 @ 12Mhz) ; (by Felino MOLINA & Howard PULLEN- www.ntu.edu.au) ; - 16x2 LM016L compatable LCD display ; ; ==================================================================== ; ; designed for one device only (set to master) ; ; design references: ; ; - ATA/ATAPI-5 (T13/1321D R3) (www.t10.org) ; - ATA packet interface for CDROM's (SFF-8020i) (fission.dt.wdc.com) ; ; other references used: ; ; - linux 2.2.x source code (/usr/src/linux/drivers/ide*) ; (had to be referred to seens that the SFF-8020i spec is so shitty) ; ; - ATAPI references & Black magic in ATA/ATAPI ; by Constantine Sapuntzakis ; http://www.stanford.edu/~csapuntz/ide.html ; http://www.stanford.edu/~csapuntz/blackmagic.html ; ; - 8052 Basic project page (IDE logger section) ; by Sergey Zorin ; http://www.nomad.ee/micros/8052bas.html ; (nb/ very very helpful) ; ; - General ATAPI info (including some source code) ; Hale Landis's ATAPI pages http://www.ata-atapi.com ; (a good introduction to it all, as i knew nothing when i first started ; this project) ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CODE_BASE equ 0000h STACK_START equ 3fh ;ctrl bus ; ; 7 6 5 4 3 2 1 0 ;+DA2+DA1+DA0+CS1+CS0+---+---+---+ ;| X | X | X | X | X | | | | ;+---+---+---+---+---+---+---+---+ ; ATA_ADDR data p2 ; ; LCD ctrl and data lines ; ; nb/ some of the lines on by development board have had the ; "smoke let out of them" (ie- blown up)... hence the uncontingious ; choice of lines used ;) LCD_RS bit P2.3 ; LCD RS pin LCD_EN bit P2.0 ; LCD EN pin LCD_DATA data P2 ; LCD Data ATA_nReset bit p3.0 ; ATA Reset ATA_nDIOW bit p3.1 ATA_nDIOR bit p3.2 ATA_INTRQ bit p2.2 ;** ; ; p3.3 Reserve for IR input or other function key ; EJECT_Key bit p3.3 ;open cd-rom tray STOP_KEY bit p3.4 ;stop cd-rom PREVIOUS_TRK bit p3.5 ;previous track NEXT_TRK bit p3.6 ;next track PLAY_KEY bit p3.7 ;play audio cd PAUSE_KEY bit p3.7 ;pause cd-rom ; ;data bus ATA_DATA_LS data p1 ATA_DATA_MS data p0 ; variable data ; packet_size data 08h start_track data 09h end_track data 0ah current_track data 0bh next_track data 0ch toc_track data 0dh toc_M data 0eh toc_S data 0fh toc_F data 10h toc_M_next data 11h toc_S_next data 12h toc_F_next data 13h start_M data 14h start_S data 15h start_F data 16h end_M data 17h end_S data 18h end_F data 19h next_M data 1ah next_S data 1bh next_F data 1ch audio_status data 1dh over_track data 1eh packet_tab data 70h packet_cmd data 70h packet_1 data 71h packet_2 data 72h packet_3 data 73h packet_4 data 74h packet_5 data 75h packet_6 data 76h packet_7 data 77h packet_8 data 78h packet_9 data 79h packet_10 data 7ah packet_11 data 7bh packet_12 data 7ch packet_13 data 7dh packet_14 data 7eh packet_15 data 7fh ; Position data 35H mediatype data 3ch ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org CODE_BASE ljmp start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; delay routines ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; delay_100000us: mov r7,#0c8h delay_100000us_l0: mov r6,#0f8h delay_100000us_l1: djnz r6,delay_100000us_l1 nop djnz r7,delay_100000us_l0 ret ;r5 = seconds delay: acall delay_100000us acall delay_100000us acall delay_100000us acall delay_100000us acall delay_100000us acall delay_100000us acall delay_100000us acall delay_100000us acall delay_100000us acall delay_100000us djnz r5,delay ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; New LCD routines ; ; Remove 74LS164, Change 4 bit ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SET_LCD: MOV R5,#1 CALL DELAY CLR LCD_EN CALL INIT_LCD MOV R5,#10 CALL LCD_DELAY MOV DPTR,#LMESS1 ; CD-Rom Player MOV A,#1 CALL LCD_PRINT MOV DPTR,#LMESS2 ; Version 5.0 MOV A,#2 CALL LCD_PRINT MOV R5,#2 CALL DELAY Ret INIT_LCD: MOV LCD_DATA,#30H CALL EN1 MOV LCD_DATA,#30H CALL EN1 MOV LCD_DATA,#30H CALL EN1 MOV LCD_DATA,#20H CALL EN1 CALL INIT_LCD1 Ret EN1: SETB LCD_EN CALL DE CLR LCD_EN CALL DE Ret DE: MOV R7,#5 DJNZ R7,$ Ret WCOM: ; Write Hi 4 Bit MOV LCD_DATA,A CLR LCD_RS CALL EN1 RLC A RLC A RLC A RLC A ; Write Low 4 Bit MOV LCD_DATA,A CLR LCD_RS CALL EN1 Ret WDATA: ; Write Hi 4 Bit MOV LCD_DATA,A SETB LCD_RS CALL EN1 RLC A RLC A RLC A RLC A ; Write Low 4 Bit MOV LCD_DATA,A SETB LCD_RS CALL EN1 Ret INIT_LCD1: MOV A,#28H CALL WCOM MOV A,#0CH ; Cursor On = 0EH Off = 0CH CALL WCOM MOV A,#06H CALL WCOM CLR_SCREEN: MOV A,#01H CALL WCOM Ret LCD_PRINT: CJNE A,#1,LINE2 LINE1:MOV A,#80H CALL WCOM CALL CLR_LINE MOV A,#80H CALL WCOM JMP FILL LINE2:MOV A,#0C0H CALL WCOM CALL CLR_LINE MOV A,#0C0H CALL WCOM FILL: CLR A MOVC A,@A+DPTR CJNE A,#0,L1 Ret L1: CALL WDATA INC DPTR JMP FILL Ret ; CLR_LINE: MOV R0,#24 C1: MOV A,#' ' CALL WDATA DJNZ R0,C1 Ret LCD_CLEAR: ; CLEAR LINE 1 MOV A,#80H CALL WCOM MOV R0,#24 AA: MOV A,#' ' CALL WDATA DJNZ R0,AA ; CLEAR LINE2 MOV A,#0C0H CALL WCOM MOV R0,#24 BB: MOV A,#' ' DJNZ R0,AA Ret CLR_LINE1: MOV A,#80H CALL WCOM MOV R0,#24 CC: MOV A,#' ' CALL WDATA DJNZ R0,CC Ret CLR_LINE2: MOV A,#0C0H CALL WCOM MOV R0,#24 CC2: MOV A,#' ' CALL WDATA DJNZ R0,CC2 Ret LCD_DELAY: MOV R6,#50 DD: MOV R7,#100 DJNZ R7,$ DJNZ R6,DD DJNZ R5,LCD_DELAY Ret LCDP1: PUSH ACC MOV A,B ADD A,#80H CALL WCOM POP ACC CALL WDATA Ret ; LCDP2: PUSH ACC MOV A,B ADD A,#0C0H CALL WCOM POP ACC CALL WDATA Ret SHOW_DIG1: MOV B,#10 DIV AB ADD A,#30H PUSH B MOV B,POSITION CALL LCDP1 ; POP B MOV A,B ADD A,#30H INC POSITION MOV B,POSITION CALL LCDP1 Ret SHOW_DIG2: MOV B,#10 DIV AB ADD A,#30H PUSH B MOV B,POSITION CALL LCDP2 ; POP B MOV A,B ADD A,#30H INC POSITION MOV B,POSITION CALL LCDP2 Ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; atomic routines ; ; Nb/ code assumes 1us clock cycle (12Mhz xtal clock) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; read_cycle: mov ATA_DATA_LS,#0ffh mov ATA_DATA_MS,#0ffh clr ATA_nDIOR mov a,ATA_DATA_LS mov b,ATA_DATA_MS setb ATA_nDIOR ret read_cycle_ls: mov ATA_DATA_LS,#0ffh clr ATA_nDIOR mov a,ATA_DATA_LS setb ATA_nDIOR ret write_cycle: mov ATA_DATA_LS,a mov ATA_DATA_MS,b clr ATA_nDIOW nop setb ATA_nDIOW ret write_cycle_ls: mov ATA_DATA_LS,a clr ATA_nDIOW nop setb ATA_nDIOW ret wait_irq: ; mov r5,#1 ; acall delay setb ATA_INTRQ jnb ATA_INTRQ,wait_irq ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; cylinder register ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; get_cyl_high_register: mov ATA_ADDR,#10110000b acall read_cycle_ls ret get_cyl_low_register: mov ATA_ADDR,#10010000b acall read_cycle_ls ret set_cyl_high_register: mov ATA_ADDR,#10110000b acall write_cycle_ls ret set_cyl_low_register: mov ATA_ADDR,#10010000b acall write_cycle_ls ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; a = cmd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set_cmd_register: mov ATA_ADDR,#11110000b acall write_cycle_ls ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; data register ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ret: a = ls b = ms get_data: mov ATA_ADDR,#00010000b acall read_cycle ret ; a = ls b = ms set_data: mov ATA_ADDR,#00010000b acall write_cycle ret ; a = ls set_data_ls: mov ATA_ADDR,#00010000b acall write_cycle_ls ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; device/head register ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; get_devhead_register: mov ATA_ADDR,#11010000b acall read_cycle_ls ret set_devhead_register: mov ATA_ADDR,#11010000b acall write_cycle_ls ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; error register ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ERROR_REG_AMNF bit acc.0 ERROR_REG_TK0NF bit acc.1 ERROR_REG_ABRT bit acc.2 ERROR_REG_MCR bit acc.3 ERROR_REG_IDNF bit acc.4 ERROR_REG_MC bit acc.5 ERROR_REG_UNC bit acc.6 ERROR_REG_RES bit acc.7 get_error_register: mov ATA_ADDR,#00110000b acall read_cycle_ls ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; sector register's ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; get_sector_c_register: mov ATA_ADDR,#01010000b acall read_cycle_ls ret get_sector_n_register: mov ATA_ADDR,#01110000b acall read_cycle_ls ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; status register ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; STATUS_REG_ERR bit acc.0 STATUS_REG_IDX bit acc.1 STATUS_REG_CORR bit acc.2 STATUS_REG_DRQ bit acc.3 STATUS_REG_DSC bit acc.4 STATUS_REG_DF bit acc.5 STATUS_REG_DRDY bit acc.6 STATUS_REG_BSY bit acc.7 get_status_register: mov ATA_ADDR,#11110000b acall read_cycle_ls ret bsy_wait: nop nop nop nop acall get_status_register jb STATUS_REG_BSY,bsy_wait ret bsy_drdy_wait: nop nop nop nop acall delay_100000us acall get_status_register jb STATUS_REG_BSY,bsy_drdy_wait jnb STATUS_REG_DRDY,bsy_drdy_wait ret drq_wait: nop nop nop nop acall get_status_register jb STATUS_REG_BSY,drq_wait jnb STATUS_REG_DRQ,drq_wait ret ndrq_wait: nop nop nop nop acall get_status_register jb STATUS_REG_BSY,drq_wait jb STATUS_REG_DRQ,drq_wait ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; main routines ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; misc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; skip_device_fields: acall get_data djnz r7,skip_device_fields ret ; clocks data out of buffer until all done (DRQ goes low) ; skip_rest_of_packet: acall get_status_register jnb STATUS_REG_DRQ,skip_rest_of_packet_d acall get_data sjmp skip_rest_of_packet skip_rest_of_packet_d: ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; MSF routines ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; get_MSF_field: acall get_data mov toc_M,b acall get_data mov toc_S,a mov toc_F,b ret print_MSF_field_lcd: ; MOV DPTR,#LMESS5 ; Time ; MOV A,#2 ; CALL LCD_PRINT ;Print_MSF_field_lcd: mov a,toc_M MOV POSITION,#5 CALL SHOW_DIG2 mov a,#':' Mov b,#7 Call LCDP2 MOV A,toc_S MOV POSITION,#8 CALL SHOW_DIG2 ret ;print_MSF_field_lcd: ; MOV DPTR,#LMESS5 ; Time ; MOV A,#2 ; CALL LCD_PRINT ;Print_MSF_field_lcd: ; mov a,toc_M ; MOV POSITION,#5 ; CALL SHOW_DIG2 ; MOV A,toc_S ; MOV POSITION,#8 ; CALL SHOW_DIG2 ; ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; init ATA device routines.. ; ; also detects the device during the process of initing it. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; init_ata_device: acall CLR_SCREEN MOV R5,#10 CALL LCD_DELAY MOV DPTR,#LMESS3 ; Initing MOV A,#1 CALL LCD_PRINT ; do hard reset.. ; ; nb/ you have a wait a bit after pulling the reset back high. if you ; don't, then bsy flag will falsey pass. i haven't figured out a way ; yet to determine when the device controller is busy during hard reset ; clr ATA_nRESET acall delay_100000us setb ATA_nRESET mov r5,#2 acall delay acall bsy_wait ;select device 0 ; ;the device will now respond to commands now ; acall get_devhead_register ; setb acc.4 clr acc.4 ;set device to 0 acall set_devhead_register ; test for device signature to determine if it's 'packet command' device ; if it's not a packet command, then it's probably a harddisk or ; something, and we can't continue. ; ; we have to check this inorder to know if we can issue the 'identify ; packet device' ATA command. ; acall bsy_wait acall get_cyl_low_register cjne a,#14h,init_device_s_error acall get_cyl_high_register cjne a,#0ebh,init_device_s_error sjmp init_device_s_done init_device_s_error: sjmp $ init_device_s_done: ; running self diagonistics.. ; nb/ this is the first ATA command we send ; mov a,#90h acall set_cmd_register acall bsy_wait acall get_error_register jb acc.0,init_device_c1 sjmp $ init_device_c1: ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ATAPI identify packet device ; ; this ATA/ATAPI command is mandatory for CDROM (and like) devices, as it ; will enable the DRDY flag. without this command, we won't be able to ; issue any commands (ATA or packet). ; ; nb/ older ATA standards, DRDY goes high immediately after BSY goes low ; during reset. .. not so for CDROM devices ;) ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; print_device_ansi_lcd: acall get_data xch a,b acall wdata mov a,b acall wdata djnz r6,print_device_ansi_lcd ret identify_packet_device: Call CLR_SCREEN MOV R5,#10 CALL LCD_DELAY MOV DPTR,#LMESS6 ; Identifying MOV A,#1 CALL LCD_PRINT MOV A,#0C0H CALL WCOM mov a,#2h ;set byte count registers acall set_cyl_high_register ;maximum transfer length = 0200h clr a ;nb/ on the few devices i've tested, this acall set_cyl_low_register ;cmd automatically sets these registers. ;but i'll set it for consistency ;) mov a,#0a1h acall set_cmd_register acall wait_irq ; get general config word ; acall get_data jb acc.0,identify_packet_device_c2 jb acc.1,identify_packet_device_c2 mov packet_size,#6 sjmp identify_packet_device_c3 identify_packet_device_c2: jb acc.0,identify_packet_device_c3 jnb acc.1,identify_packet_device_c3 mov packet_size,#8 identify_packet_device_c3: ; skip next 26 words ; mov r7,#26 acall skip_device_fields ; get model number ; mov r6,#20 acall print_device_ansi_lcd acall skip_rest_of_packet acall bsy_drdy_wait ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; do_packet_cmd: ; clr packet table ; mov r0,#packet_tab mov r7,#16 init_pck_l: mov @r0,#0 inc r0 djnz r7,init_pck_l ; send packet command ; acall ndrq_wait mov a,#0a0h acall set_cmd_register ret send_packet: acall drq_wait mov r0,#packet_tab mov r7,packet_size send_packet_l: mov a,@r0 inc r0 push acc mov a,@r0 inc r0 mov b,a pop acc acall set_data djnz r7,send_packet_l acall wait_irq acall get_status_register ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; test unit ready ATAPI command ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; test_unit_ready_cmd: acall do_packet_cmd mov packet_cmd,#00h acall send_packet clr c jnb STATUS_REG_ERR,test_unit_ready_d ret test_unit_ready_d: setb c ret ; wait_for_ready_state: Reading_CD: call CLR_SCREEN MOV R5,#10 CALL LCD_DELAY MOV DPTR,#LMESS9 ; Insert Audio CD MOV A,#1 CALL LCD_PRINT MOV DPTR,#LMESS10 ; Waiting....... MOV A,#2 CALL LCD_PRINT wait_for_ready_state_restart: jnb EJECT_Key,Check_Tray_Status mov r2,#1 ; wait_for_ready_state_l: acall delay_100000us acall delay_100000us acall delay_100000us acall test_unit_ready_cmd jnc wait_for_ready_state_restart dec r2 cjne r2,#0,wait_for_ready_state_l ret Check_Tray_Status: lcall mode_sense_cmd mov a,mediatype cjne a,#71h,open_tray MOV R5,#10 CALL LCD_DELAY MOV DPTR,#LMESS7 ; Close MOV A,#1 CALL LCD_PRINT MOV DPTR,#LMESS8 ; MOV A,#2 CALL LCD_PRINT acall do_packet_cmd mov packet_cmd,#11011b mov packet_4,#03h mov packet_8,#00h acall send_packet jmp Reading_CD Open_Tray: MOV R5,#10 CALL LCD_DELAY MOV DPTR,#LMESS11 ; Open MOV A,#1 CALL LCD_PRINT MOV DPTR,#LMESS12 ; Wait.... MOV A,#2 CALL LCD_PRINT acall do_packet_cmd mov packet_cmd,#11011b mov packet_4,#02h mov packet_8,#00h acall send_packet mov next_track,#1 jmp wait_for_ready_state ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; read sub channel cmd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; read_subchan_cmd: mov a,#0ffh ;set byte counter register acall set_cyl_low_register ;(set it to full on.. it doesn't matter coz acall set_cyl_high_register ;DRQ controls the feed) acall do_packet_cmd mov packet_cmd,#42h mov packet_1,#00000010b ;MSF=1 mov packet_2,#01000000b ;SubQ=1 mov packet_3,#01h ;format=01 (current position) mov packet_7,#0ffh ;allocation length mov packet_8,#0ffh ;(set it to full on) acall send_packet jb STATUS_REG_ERR,read_subchan_cmd_e jb STATUS_REG_DRQ,read_subchan_cmd_r ret read_subchan_cmd_e: mov audio_status,#0ffh ret ; ;read sub-channel header ; read_subchan_cmd_r: acall get_data ;get audio status mov audio_status,b acall get_data ;sub channel data length (will be zero).. ignore acall get_data ;format code, ADR, cntl (ignore) acall get_data mov current_track,a read_cmd: cjne a,end_track,calc_next_track_1 sjmp calc_next_track_2 calc_next_track_1: jc calc_next_track_2 mov a,start_track calc_next_track_2: mov next_track,a ; MOV R5,#10 ; CALL LCD_DELAY ; MOV DPTR,#LMESS13 ; Playing Track ; MOV A,#1 ; CALL LCD_PRINT mov a,current_track MOV POSITION,#14 CALL SHOW_DIG1 ; skip absolute address pos acall get_MSF_field ; CALL LCD_PRINT MOV A,#0C0H CALL WCOM ; acall lcd_home2 acall get_MSF_field acall print_MSF_field_lcd acall skip_rest_of_packet ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Table of Contents command ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; read_toc_cmd: CALL CLR_SCREEN ; MOV R5,#10 ; CALL LCD_DELAY ; MOV DPTR,#LMESS15 ; Reading TOC ; MOV A,#1 ; CALL LCD_PRINT mov a,#0ffh ;set byte counter register acall set_cyl_low_register ;(set it to full on.. it doesn't matter coz acall set_cyl_high_register ;DRQ controls the feed) acall do_packet_cmd mov packet_cmd,#43h mov packet_1,#00000010b ;MSF=1 mov packet_7,#0ffh ;allocation length mov packet_8,#0ffh ;(again, set it to full on) acall send_packet jb STATUS_REG_ERR,read_toc_cmd_e jb STATUS_REG_DRQ,read_toc_cmd_r setb c ret read_toc_cmd_e: clr c ret ; read header ; read_toc_cmd_r: acall get_data ;data length acall get_data ;get track limits mov start_track,a mov end_track,b MOV R5,#10 CALL LCD_DELAY MOV DPTR,#LMESS14 ; Track Range MOV A,#1 CALL LCD_PRINT MOV DPTR,#LMESS14A ; Total Time MOV A,#2 CALL LCD_PRINT mov a,start_track MOV POSITION,#11 CALL SHOW_DIG1 mov a,end_track MOV POSITION,#14 CALL SHOW_DIG1 MOV a,end_track ; inc a ; Save Last Track & Plus One mov over_track,a ; ; ; read track descriptors ; read_toc_cmd_l2: acall get_data ;skip ADR and control fields acall get_data ;get track number mov toc_track,a acall get_MSF_field ; mov a,toc_m ; Display Total Min MOV POSITION,#11 CALL SHOW_DIG2 mov a,toc_S ; Display Total Sec MOV POSITION,#14 CALL SHOW_DIG2 ; if start track, then record start position ; mov a,toc_track cjne a,start_track,read_toc_cmd_i0 mov start_M,toc_M mov start_S,toc_S mov start_F,toc_F read_toc_cmd_i0: ;if the last track, then record as end position ; cjne a,#0aah,read_toc_cmd_i1 mov end_M,toc_M mov end_S,toc_S mov end_F,toc_F read_toc_cmd_i1: ;if next track, then record next position ; cjne a,next_track,read_toc_cmd_i2 mov next_M,toc_M mov next_S,toc_S mov next_F,toc_F read_toc_cmd_i2: acall bsy_wait jb STATUS_REG_DRQ,read_toc_cmd_l2 setb c ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; stop/play command ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; stop_play_cmd: acall do_packet_cmd mov packet_cmd,#4eh acall send_packet ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; play MSF cd cmd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; play_entire_cd_cmd: ; call CLR_SCREEN MOV R5,#10 CALL LCD_DELAY MOV DPTR,#LMESS13 ; Playing Track MOV A,#1 CALL LCD_PRINT mov a,next_track MOV POSITION,#14 CALL SHOW_DIG1 MOV DPTR,#LMESS5 ; Time MOV A,#2 CALL LCD_PRINT acall do_packet_cmd mov packet_cmd,#47h mov packet_3,start_M mov packet_4,start_S mov packet_5,start_F mov packet_6,end_M mov packet_7,end_S mov packet_8,end_F acall send_packet jnb STATUS_REG_ERR,play_audio_cmd_d clr c ret play_audio_cmd_d: setb c ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; program entry point ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; start: mov sp,#STACK_START CLR LCD_EN mov next_track,#1 mov toc_M_next,#0 mov toc_S_next,#0 mov toc_F_next,#0 acall set_LCD ; Init & Set LCD to 4bit start_over: acall init_ata_device acall identify_packet_device mov r5,#1 acall delay main_loop: acall wait_for_ready_state acall read_toc_cmd jnc main_loop play_cd: jnb PLAY_KEY,main_play jnb EJECT_Key,unload_cd jmp play_cd main_play: CALL CLR_SCREEN acall play_entire_cd_cmd ;orignal play cd jnc main_loop mov r5,#1 acall delay play_loop: acall read_subchan_cmd mov a,audio_status cjne a,#11h,play_stopped ;if at end then loop mov a,toc_M cjne a,toc_M_next,play_loop_end_cmp mov a,toc_S cjne a,toc_S_next,play_loop_end_cmp mov a,toc_F cjne a,toc_F_next,play_loop_end_cmp sjmp play_stopped play_loop_end_cmp: mov toc_M_next,toc_M mov toc_S_next,toc_S mov toc_F_next,toc_F acall delay_100000us ; jnb NEXT_TRK,play_next_track ; jnb EJECT_Key,unload_cd ; jnb Pause_key,Pause_cd jnb STOP_KEY,stop_cd jnb PREVIOUS_TRK,play_previous_track ; sjmp play_loop stop_cd: acall stop_play_cmd mov next_track,#1 sjmp main_loop play_stopped: mov next_track,#1 sjmp play_normal play_previous_track: mov a,next_track dec a cjne a,#0,play_track_a mov next_track,end_track sjmp play_normal play_normal: acall stop_play_cmd acall read_toc_cmd jnc main_loop mov start_M,next_M mov start_S,next_S mov start_F,next_F sjmp main_play play_track_a: mov next_track,a sjmp play_normal play_next_track: mov a,next_track inc a cjne a,over_track,play_track_a mov next_track,#1 sjmp play_normal unload_cd: acall stop_play_cmd MOV R5,#10 CALL LCD_DELAY MOV DPTR,#LMESS11 ; Open Door MOV A,#1 CALL LCD_PRINT MOV DPTR,#LMESS12 ; Wait.... MOV A,#2 CALL LCD_PRINT acall do_packet_cmd mov packet_cmd,#11011b mov packet_4,#02h acall send_packet mov next_track,#1 jmp main_loop Pause_cd: mov r5,#10 CALL LCD_DELAY MOV DPTR,#LMESS13A ; Pause CD MOV A,#1 CALL LCD_PRINT mov a,next_track MOV POSITION,#12 CALL SHOW_DIG1 acall do_packet_cmd mov packet_cmd,#4bh mov packet_8,#00h acall send_packet acall delay_100000us acall delay_100000us acall delay_100000us Pause_Loop: jnb Stop_Key,Stop_cd jnb Pause_key,resume_cd jnb Eject_key,unload_cd acall delay_100000us jmp Pause_loop Resume_cd: mov r5,#10 CALL LCD_DELAY MOV DPTR,#LMESS13 ; Playing Track MOV A,#1 CALL LCD_PRINT acall delay_100000us acall delay_100000us acall delay_100000us acall do_packet_cmd mov packet_cmd,#4bh mov packet_8,#01h acall send_packet jmp Play_loop_end_cmp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; mode sense cmd;CD-ROM ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mode_sense_cmd: mov a,#16h ;set byte counter register call set_cyl_low_register ;= 16 bytes call set_cyl_high_register ; call do_packet_cmd mov packet_cmd,#5ah mov packet_1,#00H ; mov packet_2,#01H ;PC and page Code mov packet_7,#0ffh ;allocation length mov packet_8,#0ffh ;allocation length call send_packet jb STATUS_REG_DRQ,mode_sense_cmd_r mode_sense_cmd_e: jmp mode_sense_cmd ret mode_sense_cmd_r: call get_data ;mode Data length call get_data ;Medium Type mov mediatype,a call skip_rest_of_packet ret ; 0123456789012345 LMESS1: DB " CD-Rom Player ",0 LMESS2: DB " Version 5.1 ",0 ; LMESS3: DB "Initing ",0 LMESS4: DB " ",0 ; LMESS5: DB "Time ",0 ; LMESS6: DB " Identifying ",0 ; LMESS7: DB " Close Door ",0 LMESS8: DB " Waiting... ",0 ; LMESS9: DB " Reading CD ",0 LMESS10: DB " Waiting... ",0 ; LMESS11: DB " Open Door ",0 LMESS12: DB " Waiting... ",0 ; LMESS13: DB "Playing Track ",0 ; LMESS13A: DB "Pause Track ",0 ; LMESS14: DB "TrackRange - ",0 LMESS14A: Db "Total Time : ",0 ; LMESS15: DB "Reading TOC ",0 ; LMESS16: DB " Please Insert ",0 LMESS17: DB " Audio CD ",0 end