/** * CD.c By: Paul Jensen * * ATA driver with ATAPI extensions for Atmel 8515 * * CONNECTIONS TO CD-ROM: * 40-pin cable: Connects to: * 1 (RESET-) PB0 (out) * 2 (GND) GND * 3 (DD7) PE7 (in/out) * 4 (DD8) PA0 (in/out) * 5 (DD6) PE6 (in/out) * 6 (DD9) PA1 (in/out) * 7 (DD5) PE5 (in/out) * 8 (DD10) PA2 (in/out) * 9 (DD4) PE4 (in/out) * 10 (DD11) PA3 (in/out) * 11 (DD3) PE3 (in/out) * 12 (DD12) PA4 (in/out) * 13 (DD2) PE2 (in/out) * 14 (DD13) PA5 (in/out) * 15 (DD1) PE1 (in/out) * 16 (DD14) PA6 (in/out) * 17 (DD0) PE0 (in/out) * 18 (DD15) PA7 (in/out) * 19 (GND) GND * 20 keypin * 21 (DMA REQUEST) * 22 (GND) GND * 23 (DIOW-) PB7 (out) * 24 (GND) GND * 25 (DIOR-) PB6 (out) * 26 (GND) GND * 27 (IORDY) * 28 (SPSYNC:CSEL) * 29 (DMA ACK-) * 30 (GND) GND * 31 (INTRQ) * 32 (IOCS16-) * 33 (DA1) PC1 (out) * 34 (PDIAG-) * 35 (DA0) PC0 (out) * 36 (DA2) PC2 (out) * 37 (CS1FX-) PC3 (out) * 38 (CS3FX-) PC4 (out) * 39 (DASP-) * 40 (GND) GND */ #include /* void SIO_puts(char flash *c); void SIO_sendchar(BYTE c); void SIO_dumpbin(BYTE c); void SIO_dumphex(BYTE c); void SIO_dump(WORD count); void ATA_hardware_reset(); */ void ATA_software_reset(); //software reset for ATA void ATAPI_software_reset(); //software reset for ATAPI BOOL ATAPI_ReadTOC(); //read table of contents /** * ATA driver with ATAPI extensions */ void ATA_out_byte(BYTE address, BYTE data) { DISABLE_XRAM; PORTC = address; //set register address DDRE = 0xFF; //set data to output PORTE = data; //put data on bus DIOW(0); //set DIOW and delay DIOW(0); DIOW(0); DIOW(0); DIOW(0); delay_us(ATAPI_DELAY); DIOW(1); //clear DIOW delay_us(ATAPI_DELAY); ENABLE_XRAM; } BYTE ATA_in_byte(BYTE address) { BYTE toRet; DISABLE_XRAM; PORTC = address; //set register address DDRE = DDRA = 0x00; //set data to input DIOR(0); //set DIOR and delay DIOR(0); DIOR(0); DIOR(0); DIOR(0); delay_us(ATAPI_DELAY); toRet = PINE; //save data DIOR(1); //clear DIOR delay_us(ATAPI_DELAY); ENABLE_XRAM; return toRet; } void ATA_out_word(WORD data) { DISABLE_XRAM; PORTC = ATA_DATA; //set register address to 0 DDRE = DDRA = 0xFF; //set data to output PORTE = (BYTE)data; //put data on bus PORTA = (BYTE)(data >> 8); //put data on bus DIOW(0); //set DIOW and delay DIOW(0); DIOW(0); DIOW(0); DIOW(0); delay_us(ATAPI_DELAY); DIOW(1); //clear DIOW delay_us(ATAPI_DELAY); ENABLE_XRAM; } WORD ATA_in_word() { WORD toRet; DISABLE_XRAM; PORTC = ATA_DATA; //set register address to 0 DDRA = DDRE = 0x00; //set data to input DIOR(0); //set DIOR and delay DIOR(0); DIOR(0); DIOR(0); DIOR(0); delay_us(ATAPI_DELAY); toRet = ((WORD)PINE) | (((WORD)PINA) << 8); DIOR(1); //clear DIOR delay_us(ATAPI_DELAY); ENABLE_XRAM; return toRet; } void ATA_init() { DIOW(1); DIOR(1); //lcd_clear(); //lcd_putsf("reset1"); // SIO_puts("A"); // // ATA_hardware_reset(); // // SIO_puts("B"); delay_ms(10); //lcd_clear(); //lcd_putsf("reset2"); ATA_software_reset(); // SIO_puts("C"); delay_ms(10); //lcd_clear(); //lcd_putsf("reset3"); ATAPI_software_reset(); // SIO_puts("D"); delay_ms(10); //lcd_clear(); //lcd_putsf("reset4"); while(!ATAPI_ReadTOC()) delay_ms(10); // SIO_puts("EF"); //lcd_clear(); //lcd_putsf("reset5"); delay_ms(10); } /* void ATA_hardware_reset() { DDRD.0 = 1; PORTD.0 = 0; delay_ms(1000); PORTD.0 = 1; delay_ms(1000); while(ATA_in_byte(ATA_STATUS) & 0x80); } */ void ATA_software_reset() { //1. Host sets SRST bit to one. ATA_out_byte(ATA_DEVCRL, 0x0C); //2. Device 0 sets BSY within 400 nsec. delay_ms(1000); //3. Device 0 Posts diagnostic results in the Error Register. //4. Device 0 waits for the Host to clear SRST to zero. ATA_out_byte(ATA_DEVCRL, 0x08); //5. If Device 0 detected that Device 1 is present during the most recent power on or hardware reset sequence, then // Device 0 waits up to 31 seconds from the time that SRST bit became zero for Device 1 to assert PDIAG-. If PDI-AG- // is asserted within 31 seconds, Device 0 clears bit 7 of the Error Register to zero, else Device 0 sets bit 7 equal // to one in the Error Register. If Device 1 was not detected in the most recent power up or hardware reset sequence, // then Device 0 clears bit 7 of the Error Register to zero. delay_ms(1000); //6. Device 0 loads the ATAPI Signature into the Task File Registers. //7. Device 0 Clears the BSY bit to zero when ready to accept commands within 31 seconds after the SRST bit was // cleared to zero. while(ATA_in_byte(ATA_STATUS) & 0x80); } void ATAPI_software_reset() { int i; ATA_out_byte(ATA_CMD, 0x08); // ATAPI soft-reset command delay_ms(500); while(ATA_in_byte(ATA_STATUS) & 0x80); ATA_out_byte(ATA_DRVSEL, 0xa0); ATA_out_byte(ATA_CMD, 0xa1); //ATAPI request info while(ATA_in_byte(ATA_STATUS) & 0x80); delay_ms(500); if(!(ATA_in_byte(ATA_STATUS) & 8)) { // SIO_puts("DRQ not set, won't give info data!\n\r"); // err = ERR_CANT_READ_SECTOR; return; } if((ATA_in_byte(ATA_BCNTH)!=2) || (ATA_in_byte(ATA_BCNTL)!=0)) { // SIO_puts("incorrect sense data length!\n\r"); return; } for(i=0; i<256; i++) ATA_in_word(); } void ATAPI_sense() { WORD temp; again: while(ATA_in_byte(ATA_STATUS) & 0x80); ATA_out_byte(ATA_FEAT, 0x00); ATA_out_byte(ATA_BCNTL, 0x00); ATA_out_byte(ATA_BCNTH, 0x06); ATA_out_byte(ATA_DRVSEL, 0xA0); //2. The host writes the Packet Command code (A0h) to the Command Register. ATA_out_byte(ATA_CMD, 0xA0); //3. The Device sets BSY, before the next system read of the status register, and prepares for Command Packet trans-fer. //4. When the Device is ready to accept the Command Packet, the Device sets CoD and clears IO. DRQ shall then be // asserted simultaneous or prior to the de-assertion of BSY. Some Devices will assert INTRQ following the asser-tion // of DRQ. See section 7.1.7.1, "General Configuration Word (0)", on page 63 for command packet DRQ types // and other related timing information. while(ATA_in_byte(ATA_STATUS) & 0x80); //check status of DRQ if(!(ATA_in_byte(ATA_STATUS) & 8)) { // SIO_puts("DRQ not set, won't accept command!\n\r"); // err = ERR_WONT_ACCEPT_COMMAND; CDerror = TRUE; return; } //5. After detecting DRQ, the host writes the 12 bytes (6 words) of Command to the Data Register. ATA_out_word(0x0003); ATA_out_word(0x0000); ATA_out_word(0x0012); ATA_out_word(0x0000); ATA_out_word(0x0000); ATA_out_word(0x0000); while(ATA_in_byte(ATA_STATUS) & 0x80); //check status of DRQ if(!(ATA_in_byte(ATA_STATUS) & 8)) { // SIO_puts("DRQ not set, won't sense data!\n\r"); // err = ERR_CANT_READ_SECTOR; CDerror = TRUE; return; } if((ATA_in_byte(ATA_BCNTH)!=0) || (ATA_in_byte(ATA_BCNTL)!=20)) { // SIO_puts("incorrect sense data length!\n\r"); CDerror = TRUE; return; } ATA_in_word(); ATA_in_word(); ATA_in_word(); ATA_in_word(); ATA_in_word(); temp = ATA_in_word(); ATA_in_word(); ATA_in_word(); ATA_in_word(); ATA_in_word(); if(temp) goto again; } BOOL ATAPI_ReadTOC() { int i; while(ATA_in_byte(ATA_STATUS) & 0x80); ATA_out_byte(ATA_FEAT, 0x00); ATA_out_byte(ATA_BCNTL, 0x00); ATA_out_byte(ATA_BCNTH, 0x06); ATA_out_byte(ATA_DRVSEL, 0xA0); //2. The host writes the Packet Command code (A0h) to the Command Register. ATA_out_byte(ATA_CMD, 0xA0); //3. The Device sets BSY, before the next system read of the status register, and prepares for Command Packet trans-fer. //4. When the Device is ready to accept the Command Packet, the Device sets CoD and clears IO. DRQ shall then be // asserted simultaneous or prior to the de-assertion of BSY. Some Devices will assert INTRQ following the asser-tion // of DRQ. See section 7.1.7.1, "General Configuration Word (0)", on page 63 for command packet DRQ types // and other related timing information. while(ATA_in_byte(ATA_STATUS) & 0x80); //check status of DRQ if(!(ATA_in_byte(ATA_STATUS) & 8)) { // SIO_puts("DRQ not set, won't accept command!\n\r"); // err = ERR_WONT_ACCEPT_COMMAND; CDerror = TRUE; return FALSE; } //5. After detecting DRQ, the host writes the 12 bytes (6 words) of Command to the Data Register. ATA_out_word(0x0243); ATA_out_word(0x0000); ATA_out_word(0x0000); ATA_out_word(0x0400); ATA_out_word(0x8050); ATA_out_word(0x0000); while(ATA_in_byte(ATA_STATUS) & 0x80); //check status of DRQ if(!(ATA_in_byte(ATA_STATUS) & 8)) { // err = ERR_CANT_READ_SECTOR; return FALSE; } if((ATA_in_byte(ATA_BCNTH)!=0) || (ATA_in_byte(ATA_BCNTL)!=48)) { // SIO_puts("incorrect TOC data length!\n\r"); return FALSE; } for(i=0; i<24; i++) ATA_in_word(); return TRUE; } // // NOTE: after using this command the code must read the status register and check for errors // then read in the sector data // void ATAPI_prep_sector1() { while(ATA_in_byte(ATA_STATUS)&0x1) ATAPI_sense(); //1. The host Polls for BSY=0, DRQ=0 then initializes the task file by writing the required parameters to the Features, // Byte Count, and Drive/Head registers. while(ATA_in_byte(ATA_STATUS) & 0x80); ATA_out_byte(ATA_FEAT, 0x00); ATA_out_byte(ATA_BCNTL, 0x00); ATA_out_byte(ATA_BCNTH, 0x06); ATA_out_byte(ATA_DRVSEL, 0xA0); //2. The host writes the Packet Command code (A0h) to the Command Register. ATA_out_byte(ATA_CMD, 0xA0); //3. The Device sets BSY, before the next system read of the status register, and prepares for Command Packet trans-fer. //4. When the Device is ready to accept the Command Packet, the Device sets CoD and clears IO. DRQ shall then be // asserted simultaneous or prior to the de-assertion of BSY. Some Devices will assert INTRQ following the asser-tion // of DRQ. See section 7.1.7.1, "General Configuration Word (0)", on page 63 for command packet DRQ types // and other related timing information. } BOOL ATAPI_prep_sector2(DWRD sector) { BYTE s0; BYTE s1; BYTE s2; BYTE s3; if(ATA_in_byte(ATA_STATUS) & 0x80) return FALSE; s3 = (BYTE)(sector >> 24); s2 = (BYTE)(sector >> 16); s1 = (BYTE)(sector >> 8); s0 = (BYTE)(sector); // while(ATA_in_byte(ATA_STATUS) & 0x80); //check status of DRQ if(!(ATA_in_byte(ATA_STATUS) & 8)) { CDerror = TRUE; // SIO_puts("DRQ not set, won't accept command!\n\r"); // err = ERR_WONT_ACCEPT_COMMAND; return FALSE; } //5. After detecting DRQ, the host writes the 12 bytes (6 words) of Command to the Data Register. ATA_out_word(0x0028); ATA_out_word(((WORD)s3) | (((WORD)s2)<<8)); ATA_out_word(((WORD)s1) | (((WORD)s0)<<8)); ATA_out_word(0x0000); ATA_out_word(0x0001); ATA_out_word(0x0000); //6. The Device(1) clears DRQ (when the 12th byte is written), (2) sets BSY, (3) reads Features and Byte Count re-quested // by the host system, (4) prepares for data transfer. return TRUE; } void ATAPI_prep_sector(DWRD sector) { ATAPI_prep_sector1(); while(!ATAPI_prep_sector2(sector)); } BOOL ATAPI_sect_ready() { if(ATA_in_byte(ATA_STATUS) & 0x80) return FALSE; if(!(ATA_in_byte(ATA_STATUS) & 8)) { CDerror = TRUE; return FALSE; } if((ATA_in_byte(ATA_BCNTH)!=8) || (ATA_in_byte(ATA_BCNTL)!=0)) { CDerror = TRUE; return FALSE; } return TRUE; } void ATAPI_wait_for_sect() { //7. When ready to transfer data, the Device:(1) sets the byte count (Cylinder High and Low Registers) to the amount // of data that the Device wishes to be sent, (2) clears IO and CoD, (3) sets DRQ and clears BSY, (4) sets INTRQ. // The Byte Count would normally be set to the number of bytes requested by the contents of the register at the re-ceipt // of the command, but may be any amount that the Device can accommodate in its buffers at this time. //8. After detecting INTRQ, the host reads the DRQ bit in the Status Register to determine how it shall proceed with // the command. If DRQ= 0 then the device has terminated the command. If DRQ=1 then the host shall write the // data (number of bytes specified in the Cylinder High/Low Registers) via the Data Register. In response to the Sta-tus // Register being read, the Device negates INTRQ for both cases. while(ATA_in_byte(ATA_STATUS) & 0x80); //check status of DRQ if(!(ATA_in_byte(ATA_STATUS) & 8)) { // SIO_puts("DRQ not set, won't give sector data!\n\r"); // err = ERR_CANT_READ_SECTOR; CDerror = TRUE; return; } // SIO_dumpbin(ATA_in_byte(ATA_BCNTH)); // SIO_sendchar('-'); // SIO_dumpbin(ATA_in_byte(ATA_BCNTL)); // SIO_puts(" bytes of data prepared for reading!\n\r"); if((ATA_in_byte(ATA_BCNTH)!=8) || (ATA_in_byte(ATA_BCNTL)!=0)) { // SIO_puts("incorrect sector data length!\n\r"); // err = ERR_CANT_READ_SECTOR; CDerror = TRUE; return; } //9. The Device clears DRQ and sets BSY. If transfer of more data is required, the above sequence is repeated from 7. //10.When the Device is ready to present the status, the Device places the completion status into the Status Register, // sets CoD, IO, DRDY and clears BSY, DRQ, prior to asserting INTRQ. //11.After detecting INTRQ & DRQ=0 the host reads the Status Register and if necessary, the Error Register for the // command completion status. //check status // if(ATA_in_byte(ATA_STATUS) & 1) // { // err = ERR_CANT_READ_SECTOR; // return; // } } /** * Serial port link */ /* void SIO_init() { UCR = 0x18; //enable SIO TX, RX //UBRR = 0; //set 4 Mhz / 16 = 250,000 baud rate UBRR = 25; //set to 19200 baud rate to start with } void SIO_sendchar(BYTE c) { while(!(USR & 32)); UDR = c; //put out char } void SIO_dumpbin(BYTE c) { SIO_sendchar((c&128)?'1':'0'); SIO_sendchar((c&64)?'1':'0'); SIO_sendchar((c&32)?'1':'0'); SIO_sendchar((c&16)?'1':'0'); SIO_sendchar((c&8)?'1':'0'); SIO_sendchar((c&4)?'1':'0'); SIO_sendchar((c&2)?'1':'0'); SIO_sendchar((c&1)?'1':'0'); } void SIO_dumphex(BYTE c) { BYTE low, high; low = c&0xF; high = c>>4; SIO_sendchar(high+(high>9?'A'-10:'0')); SIO_sendchar(low+(low>9?'A'-10:'0')); } void SIO_puts(char flash *c) { while(*c) SIO_sendchar(*(c++)); } /* prints: STAT:01234567 ERR:01234567 BCNT:01234567-01234567 INTRE:01234567 */ /* void SIO_dumpregs() { SIO_puts("STAT:"); SIO_dumpbin(ATA_in_byte(ATA_STATUS)); SIO_puts(" ERR:"); SIO_dumpbin(ATA_in_byte(ATA_ERROR)); SIO_puts(" BCNT:"); SIO_dumpbin(ATA_in_byte(ATA_BCNTH)); SIO_sendchar('-'); SIO_dumpbin(ATA_in_byte(ATA_BCNTL)); SIO_puts(" INTRE:"); SIO_dumpbin(ATA_in_byte(ATA_INTRE)); SIO_puts("\n\r"); } //dump count *WORDs* from CDROM to SIO link /* void SIO_dump(WORD count) { //init port PORTD = ATA_DATA; //set register address to 0 DDRA = DDRC = 0x00; //set data to input while(count--) { delay_us(ATAPI_DELAY); PORTB.1 = 0; delay_us(ATAPI_DELAY); // SIO_sendchar('('); // SIO_dumpbin(PINA); SIO_sendchar(PINA); // SIO_dumphex(PINA); // SIO_sendchar('-'); // while(!(USR & 32)); // UDR = PORTA; //put out low half of word // while(!(USR & 32)); // UDR = PORTC; //put out high half of word SIO_sendchar(PINC); // SIO_dumphex(PINC); // SIO_sendchar('-'); // SIO_dumpbin(PINC); // SIO_sendchar(')'); PORTB.1 = 1; } }*/ void xfer_data(BYTE *buf, WORD words) { int pos = 0; DISABLE_XRAM; PORTC = ATA_DATA; //set register address to 0 DDRA = DDRE = 0x00; //set data to input while(words--) { delay_us(ATAPI_DELAY); DIOR(0); delay_us(ATAPI_DELAY); buf[pos++] = PINE; buf[pos++] = PINA; DIOR(1); } ENABLE_XRAM; } /* int load_sector(DWRD sector, BYTE *buf) { while(ATA_in_byte(ATA_STATUS)&0x1) ATAPI_sense(); ATAPI_prep_sector(sector); if(err) { SIO_puts("error #"); SIO_sendchar(err+'0'); SIO_puts("\n\r"); err = 0; sector = 0; continue; } //SIO_dump(1024); }*/ /* void main() { DWRD sector = 0; BYTE buf; WORD bigbuf; err = ERR_NONE; SIO_init(); ATA_init(); while(TRUE) { if(ATA_in_byte(ATA_STATUS)&0x1) ATAPI_sense(); if(USR & 0x80) { buf = UDR; if(buf=='r') { ATAPI_ReadTOC(); continue; } if(buf=='s') { ATAPI_sense(); continue; } if(buf=='d') { bigbuf = ATA_in_word(); SIO_dumpbin((BYTE)(bigbuf>>8)); SIO_dumpbin((BYTE)bigbuf); continue; } if(buf==13) { // if(sector==0) // { // SIO_dumpregs(); // continue; // } // SIO_puts("Preparing sector for read...\n\r"); err = 0; ATAPI_prep_sector(sector); if(err) { SIO_puts("error #"); SIO_sendchar(err+'0'); SIO_puts("\n\r"); err = 0; sector = 0; continue; } // SIO_puts("dump:\n\r"); SIO_dump(1024); sector = 0; continue; } if( !((buf>='0') && (buf<='9')) ) continue; sector = sector*10 + (UDR - '0'); } } } */