/*
|
/*
|
atadevice.c -- ATA Device simulation
|
atadevice.c -- ATA Device simulation
|
Simulates a harddisk, using a local streams.
|
Simulates a harddisk, using a local streams.
|
Copyright (C) 2002 Richard Herveille, rherveille@opencores.org
|
Copyright (C) 2002 Richard Herveille, rherveille@opencores.org
|
|
|
This file is part of OpenRISC 1000 Architectural Simulator
|
This file is part of OpenRISC 1000 Architectural Simulator
|
|
|
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
(at your option) any later version
|
(at your option) any later version
|
|
|
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GNU General Public License for more details.
|
GNU General Public License for more details.
|
|
|
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
*/
|
*/
|
|
|
#include <string.h>
|
#include <string.h>
|
#include <stdarg.h>
|
#include <stdarg.h>
|
|
|
#include "config.h"
|
#include "config.h"
|
|
|
#ifdef HAVE_INTTYPES_H
|
#ifdef HAVE_INTTYPES_H
|
#include <inttypes.h>
|
#include <inttypes.h>
|
#endif
|
#endif
|
|
|
#include "port.h"
|
#include "port.h"
|
#include "arch.h"
|
#include "arch.h"
|
#include "abstract.h"
|
#include "abstract.h"
|
|
|
#include "messages.h"
|
#include "messages.h"
|
#include "atadevice.h"
|
#include "atadevice.h"
|
#include "atacmd.h"
|
#include "atacmd.h"
|
#include "sim-config.h"
|
#include "sim-config.h"
|
#include "atadevice_cmdi.h"
|
#include "atadevice_cmdi.h"
|
|
|
/*
|
/*
|
mandatory commands:
|
mandatory commands:
|
- execute device diagnostics (done)
|
- execute device diagnostics (done)
|
- flush cache
|
- flush cache
|
- identify device (done)
|
- identify device (done)
|
- initialize device parameters (done)
|
- initialize device parameters (done)
|
- read dma
|
- read dma
|
- read multiple
|
- read multiple
|
- read sector(s) (done)
|
- read sector(s) (done)
|
- read verify sector(s)
|
- read verify sector(s)
|
- seek
|
- seek
|
- set features
|
- set features
|
- set multiple mode
|
- set multiple mode
|
- write dma
|
- write dma
|
- write multiple
|
- write multiple
|
- write sector(s)
|
- write sector(s)
|
|
|
|
|
optional commands:
|
optional commands:
|
- download microcode
|
- download microcode
|
- nop
|
- nop
|
- read buffer
|
- read buffer
|
- write buffer
|
- write buffer
|
|
|
|
|
prohibited commands:
|
prohibited commands:
|
- device reset
|
- device reset
|
*/
|
*/
|
|
|
|
|
/*
|
/*
|
D E V I C E S _ I N I T
|
D E V I C E S _ I N I T
|
*/
|
*/
|
void ata_devices_init(ata_devices *devices)
|
void ata_devices_init(ata_devices *devices)
|
{
|
{
|
ata_device_init(&devices->device0, 0);
|
ata_device_init(&devices->device0, 0);
|
|
|
if (devices->device0.type)
|
if (devices->device0.type)
|
ata_device_init(&devices->device1, ATA_DHR_DEV);
|
ata_device_init(&devices->device1, ATA_DHR_DEV);
|
else
|
else
|
ata_device_init(&devices->device1, 0);
|
ata_device_init(&devices->device1, 0);
|
}
|
}
|
|
|
|
|
void ata_device_init(ata_device *device, int dev)
|
void ata_device_init(ata_device *device, int dev)
|
{
|
{
|
/* set DeviceID */
|
/* set DeviceID */
|
device->internals.dev = dev;
|
device->internals.dev = dev;
|
|
|
/* generate stream for hd_simulation */
|
/* generate stream for hd_simulation */
|
switch(device->type)
|
switch(device->type)
|
{
|
{
|
case TYPE_NO_CONNECT:
|
case TYPE_NO_CONNECT:
|
MSG_NOTE("ata_device, using type NO_CONNECT.");
|
MSG_NOTE("ata_device, using type NO_CONNECT.");
|
device->stream = NULL;
|
device->stream = NULL;
|
break;
|
break;
|
|
|
case TYPE_FILE:
|
case TYPE_FILE:
|
MSG_NOTE("ata_device, using device type FILE.");
|
MSG_NOTE("ata_device, using device type FILE.");
|
device->stream = open_file(&device->size, device->file);
|
device->stream = open_file(&device->size, device->file);
|
break;
|
break;
|
|
|
case TYPE_LOCAL:
|
case TYPE_LOCAL:
|
MSG_NOTE("ata_device, using device type LOCAL.");
|
MSG_NOTE("ata_device, using device type LOCAL.");
|
device->stream = open_local();
|
device->stream = open_local();
|
break;
|
break;
|
|
|
default:
|
default:
|
MSG_FATAL("ata_device, illegal device-type.");
|
MSG_FATAL("ata_device, illegal device-type.");
|
MSG_EMPTY("defaulting to type NO_CONNECT.");
|
MSG_EMPTY("defaulting to type NO_CONNECT.");
|
device->stream = NULL;
|
device->stream = NULL;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
/* Use a file to simulate a hard-disk */
|
/* Use a file to simulate a hard-disk */
|
FILE *open_file(unsigned long *size, const char *filename)
|
FILE *open_file(unsigned long *size, const char *filename)
|
{
|
{
|
FILE *fp;
|
FILE *fp;
|
unsigned long n;
|
unsigned long n;
|
|
|
// TODO:
|
// TODO:
|
|
|
/* check if a file with name 'filename' already exists */
|
/* check if a file with name 'filename' already exists */
|
if ( !(fp = fopen(filename, "rb+")) )
|
if ( !(fp = fopen(filename, "rb+")) )
|
if ( !(fp = fopen(filename, "wb+")) )
|
if ( !(fp = fopen(filename, "wb+")) )
|
{
|
{
|
MSG_FATAL( strcat("ata_open_file, cannot open hd-file ", filename) );
|
MSG_FATAL( strcat("ata_open_file, cannot open hd-file ", filename) );
|
return NULL;
|
return NULL;
|
}
|
}
|
else
|
else
|
{
|
{
|
/* TODO create a file 'size' large */
|
/* TODO create a file 'size' large */
|
/* create a file 'size' large */
|
/* create a file 'size' large */
|
MSG_NOTE("ata_device; generating a new hard disk file.");
|
MSG_NOTE("ata_device; generating a new hard disk file.");
|
MSG_EMPTY("This may take a while, depending on the requested size.");
|
MSG_EMPTY("This may take a while, depending on the requested size.");
|
for (n=0; n < (*size << 20); n++)
|
for (n=0; n < (*size << 20); n++)
|
fputc(0, fp);
|
fputc(0, fp);
|
}
|
}
|
else /* file already exist */
|
else /* file already exist */
|
fprintf(stderr, "file %s already exists. Using existing file.\n", filename);
|
fprintf(stderr, "file %s already exists. Using existing file.\n", filename);
|
|
|
|
|
ata_device_debug(1, "requested filesize was: %d (MBytes).\n", *size);
|
ata_device_debug(1, "requested filesize was: %d (MBytes).\n", *size);
|
|
|
/* get the size of the file. This is also the size of the harddisk*/
|
/* get the size of the file. This is also the size of the harddisk*/
|
fseek(fp, 0, SEEK_END);
|
fseek(fp, 0, SEEK_END);
|
*size = ftell(fp);
|
*size = ftell(fp);
|
|
|
ata_device_debug(1, "actual filesize is: %d (MBytes).\n", *size >> 20);
|
ata_device_debug(1, "actual filesize is: %d (MBytes).\n", *size >> 20);
|
|
|
return fp;
|
return fp;
|
}
|
}
|
|
|
|
|
/* Use a the local filesystem as a hard-disk */
|
/* Use a the local filesystem as a hard-disk */
|
FILE *open_local(void)
|
FILE *open_local(void)
|
{
|
{
|
// TODO:
|
// TODO:
|
MSG_WARNING("ata_device; device type LOCAL is not supported yet.");
|
MSG_WARNING("ata_device; device type LOCAL is not supported yet.");
|
MSG_EMPTY("defaulting to device type NO_CONNECT.");
|
MSG_EMPTY("defaulting to device type NO_CONNECT.");
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
|
|
|
|
|
|
/*
|
/*
|
D E V I C E S _ H W _ R E S E T
|
D E V I C E S _ H W _ R E S E T
|
*/
|
*/
|
/* power-on and hardware reset */
|
/* power-on and hardware reset */
|
void ata_devices_hw_reset(ata_devices *devices, int reset_signal)
|
void ata_devices_hw_reset(ata_devices *devices, int reset_signal)
|
{
|
{
|
/* display debug information */
|
/* display debug information */
|
ata_device_debug(2, "ata_devices_hw_reset.\n");
|
ata_device_debug(2, "ata_devices_hw_reset.\n");
|
|
|
/* find device 0 */
|
/* find device 0 */
|
if ( (devices->device0.stream) && (devices->device1.stream) )
|
if ( (devices->device0.stream) && (devices->device1.stream) )
|
{
|
{
|
/* this one is simple, device0 is device0 */
|
/* this one is simple, device0 is device0 */
|
|
|
/* 1) handle device1 first */
|
/* 1) handle device1 first */
|
ata_device_hw_reset(&devices->device1, reset_signal,
|
ata_device_hw_reset(&devices->device1, reset_signal,
|
1, /* assert dasp, this is device1 */
|
1, /* assert dasp, this is device1 */
|
0, /* negate pdiag input, no more devices */
|
0, /* negate pdiag input, no more devices */
|
0); /* negate dasp input, no more devices */
|
0); /* negate dasp input, no more devices */
|
|
|
/* 2) Then handle device0 */
|
/* 2) Then handle device0 */
|
ata_device_hw_reset(&devices->device0, reset_signal,
|
ata_device_hw_reset(&devices->device0, reset_signal,
|
0,
|
0,
|
devices->device1.sigs.pdiago,
|
devices->device1.sigs.pdiago,
|
devices->device1.sigs.daspo);
|
devices->device1.sigs.daspo);
|
}
|
}
|
else if (devices->device0.stream)
|
else if (devices->device0.stream)
|
{
|
{
|
/* device0 is device0, there's no device1 */
|
/* device0 is device0, there's no device1 */
|
ata_device_hw_reset(&devices->device0, reset_signal,
|
ata_device_hw_reset(&devices->device0, reset_signal,
|
0, /* negate dasp, this is device0 */
|
0, /* negate dasp, this is device0 */
|
0, /* negate pdiag input, there's no device1*/
|
0, /* negate pdiag input, there's no device1*/
|
0); /* negate dasp input, there's no device1 */
|
0); /* negate dasp input, there's no device1 */
|
}
|
}
|
else if (devices->device1.stream)
|
else if (devices->device1.stream)
|
{
|
{
|
/* device1 is (logical) device0, there's no (physical) device0 */
|
/* device1 is (logical) device0, there's no (physical) device0 */
|
ata_device_hw_reset(&devices->device1, reset_signal,
|
ata_device_hw_reset(&devices->device1, reset_signal,
|
0, /* negate dasp, this is device0 */
|
0, /* negate dasp, this is device0 */
|
0, /* negate pdiag input, there's no device1*/
|
0, /* negate pdiag input, there's no device1*/
|
0); /* negate dasp input, there's no device1 */
|
0); /* negate dasp input, there's no device1 */
|
}
|
}
|
else
|
else
|
{
|
{
|
/* no devices connected */
|
/* no devices connected */
|
ata_device_debug(1, "ata_device_hw_reset, no devices connected.\n");
|
ata_device_debug(1, "ata_device_hw_reset, no devices connected.\n");
|
}
|
}
|
}
|
}
|
|
|
void ata_device_hw_reset(ata_device *device, int reset_signal,
|
void ata_device_hw_reset(ata_device *device, int reset_signal,
|
int daspo, int pdiagi, int daspi)
|
int daspo, int pdiagi, int daspi)
|
{
|
{
|
/* check ata-device state */
|
/* check ata-device state */
|
if (device->internals.state == ATA_STATE_HW_RST)
|
if (device->internals.state == ATA_STATE_HW_RST)
|
{
|
{
|
if (!reset_signal)
|
if (!reset_signal)
|
{
|
{
|
/* hardware reset finished */
|
/* hardware reset finished */
|
|
|
/* set sectors_per_track & heads_per_cylinders */
|
/* set sectors_per_track & heads_per_cylinders */
|
device->internals.sectors_per_track = SECTORS;
|
device->internals.sectors_per_track = SECTORS;
|
device->internals.heads_per_cylinder = HEADS;
|
device->internals.heads_per_cylinder = HEADS;
|
|
|
/* set device1 input signals */
|
/* set device1 input signals */
|
device->sigs.pdiagi = pdiagi;
|
device->sigs.pdiagi = pdiagi;
|
device->sigs.daspi = daspi;
|
device->sigs.daspi = daspi;
|
|
|
ata_execute_device_diagnostics_cmd(device);
|
ata_execute_device_diagnostics_cmd(device);
|
|
|
/* clear busy bit */
|
/* clear busy bit */
|
device->regs.status &= ~ATA_SR_BSY;
|
device->regs.status &= ~ATA_SR_BSY;
|
|
|
/* set DRDY bit, when not a PACKET device */
|
/* set DRDY bit, when not a PACKET device */
|
if (!device->packet)
|
if (!device->packet)
|
device->regs.status |= ATA_SR_DRDY;
|
device->regs.status |= ATA_SR_DRDY;
|
|
|
/* set new state */
|
/* set new state */
|
device->internals.state = ATA_STATE_IDLE;
|
device->internals.state = ATA_STATE_IDLE;
|
}
|
}
|
}
|
}
|
else
|
else
|
if (reset_signal)
|
if (reset_signal)
|
{
|
{
|
/* hardware reset signal asserted, stop what we are doing */
|
/* hardware reset signal asserted, stop what we are doing */
|
|
|
/* negate bus signals */
|
/* negate bus signals */
|
device->sigs.iordy = 0;
|
device->sigs.iordy = 0;
|
device->sigs.intrq = 0;
|
device->sigs.intrq = 0;
|
device->sigs.dmarq = 0;
|
device->sigs.dmarq = 0;
|
device->sigs.pdiago = 0;
|
device->sigs.pdiago = 0;
|
device->sigs.daspo = daspo;
|
device->sigs.daspo = daspo;
|
|
|
/* set busy bit */
|
/* set busy bit */
|
device->regs.status |= ATA_SR_BSY;
|
device->regs.status |= ATA_SR_BSY;
|
PRINTF("setting status register BSY 0x%2X\n", device->regs.status);
|
PRINTF("setting status register BSY 0x%2X\n", device->regs.status);
|
|
|
/* set new state */
|
/* set new state */
|
device->internals.state = ATA_STATE_HW_RST;
|
device->internals.state = ATA_STATE_HW_RST;
|
}
|
}
|
}
|
}
|
|
|
|
|
/*
|
/*
|
D E V I C E S _ D O _ C O N T R O L _ R E G I S T E R
|
D E V I C E S _ D O _ C O N T R O L _ R E G I S T E R
|
|
|
Handles - software reset
|
Handles - software reset
|
- Interrupt enable bit
|
- Interrupt enable bit
|
*/
|
*/
|
void ata_device_do_control_register(ata_device *device)
|
void ata_device_do_control_register(ata_device *device)
|
{
|
{
|
/* TODO respond to new values of nIEN */
|
/* TODO respond to new values of nIEN */
|
/* if device not selected, respond to new values of nIEN & SRST */
|
/* if device not selected, respond to new values of nIEN & SRST */
|
|
|
/* check if SRST bit is set */
|
/* check if SRST bit is set */
|
if (device->regs.device_control & ATA_DCR_RST)
|
if (device->regs.device_control & ATA_DCR_RST)
|
{
|
{
|
if (device->internals.state == ATA_STATE_IDLE)
|
if (device->internals.state == ATA_STATE_IDLE)
|
{ /* start software reset */
|
{ /* start software reset */
|
/* negate bus signals */
|
/* negate bus signals */
|
device->sigs.pdiago = 0;
|
device->sigs.pdiago = 0;
|
device->sigs.intrq = 0;
|
device->sigs.intrq = 0;
|
device->sigs.iordy = 0;
|
device->sigs.iordy = 0;
|
device->sigs.dmarq = 0;
|
device->sigs.dmarq = 0;
|
|
|
/* set busy bit */
|
/* set busy bit */
|
device->regs.status |= ATA_SR_BSY;
|
device->regs.status |= ATA_SR_BSY;
|
|
|
/* set new state */
|
/* set new state */
|
device->internals.state = ATA_STATE_SW_RST;
|
device->internals.state = ATA_STATE_SW_RST;
|
|
|
/* display debug information */
|
/* display debug information */
|
ata_device_debug(2, "ata_device_sw_reset initiated.\n");
|
ata_device_debug(2, "ata_device_sw_reset initiated.\n");
|
}
|
}
|
}
|
}
|
else if (device->internals.state == ATA_STATE_SW_RST)
|
else if (device->internals.state == ATA_STATE_SW_RST)
|
{ /* are we doing a software reset ?? */
|
{ /* are we doing a software reset ?? */
|
/* SRST bit cleared, end of software reset */
|
/* SRST bit cleared, end of software reset */
|
|
|
/*execute device diagnostics */
|
/*execute device diagnostics */
|
ata_execute_device_diagnostics_cmd(device);
|
ata_execute_device_diagnostics_cmd(device);
|
|
|
/* clear busy bit */
|
/* clear busy bit */
|
device->regs.status &= ~ATA_SR_BSY;
|
device->regs.status &= ~ATA_SR_BSY;
|
|
|
/* set DRDY bit, when not a PACKET device */
|
/* set DRDY bit, when not a PACKET device */
|
if (!device->packet)
|
if (!device->packet)
|
device->regs.status |= ATA_SR_DRDY;
|
device->regs.status |= ATA_SR_DRDY;
|
|
|
/* set new state */
|
/* set new state */
|
device->internals.state = ATA_STATE_IDLE;
|
device->internals.state = ATA_STATE_IDLE;
|
|
|
/* display debug information */
|
/* display debug information */
|
ata_device_debug(2, "ata_device_sw_reset done.\n");
|
ata_device_debug(2, "ata_device_sw_reset done.\n");
|
}
|
}
|
/*
|
/*
|
<else> We are doing a hardware reset (or similar)
|
<else> We are doing a hardware reset (or similar)
|
ignore command
|
ignore command
|
*/
|
*/
|
}
|
}
|
|
|
|
|
/*
|
/*
|
D E V I C E S _ D O _ C O M M A N D _ R E G I S T E R
|
D E V I C E S _ D O _ C O M M A N D _ R E G I S T E R
|
*/
|
*/
|
void ata_device_do_command_register(ata_device *device)
|
void ata_device_do_command_register(ata_device *device)
|
{
|
{
|
/* check BSY & DRQ */
|
/* check BSY & DRQ */
|
if ( (device->regs.status & ATA_SR_BSY) || (device->regs.status & ATA_SR_DRQ) )
|
if ( (device->regs.status & ATA_SR_BSY) || (device->regs.status & ATA_SR_DRQ) )
|
if (device->regs.command != DEVICE_RESET)
|
if (device->regs.command != DEVICE_RESET)
|
MSG_WARNING("ata_device_write, writing a command while BSY or DRQ asserted.");
|
MSG_WARNING("ata_device_write, writing a command while BSY or DRQ asserted.");
|
|
|
/* check if device selected */
|
/* check if device selected */
|
if ( (device->regs.device_head & ATA_DHR_DEV) == device->internals.dev )
|
if ( (device->regs.device_head & ATA_DHR_DEV) == device->internals.dev )
|
ata_device_execute_cmd(device);
|
ata_device_execute_cmd(device);
|
else
|
else
|
{
|
{
|
/* if not selected, only respond to EXECUTE DEVICE DIAGNOSTICS */
|
/* if not selected, only respond to EXECUTE DEVICE DIAGNOSTICS */
|
if (device->regs.command == EXECUTE_DEVICE_DIAGNOSTICS)
|
if (device->regs.command == EXECUTE_DEVICE_DIAGNOSTICS)
|
ata_device_execute_cmd(device);
|
ata_device_execute_cmd(device);
|
}
|
}
|
}
|
}
|
|
|
|
|
/*
|
/*
|
D E V I C E S _ R E A D
|
D E V I C E S _ R E A D
|
*/
|
*/
|
/* Read from devices */
|
/* Read from devices */
|
short ata_devices_read(ata_devices *devices, char adr)
|
short ata_devices_read(ata_devices *devices, char adr)
|
{
|
{
|
ata_device *device;
|
ata_device *device;
|
|
|
/* check for no connected devices */
|
/* check for no connected devices */
|
if ( (!devices->device0.stream) && (!devices->device1.stream) )
|
if ( (!devices->device0.stream) && (!devices->device1.stream) )
|
MSG_ERROR("ata_devices_read, no ata devices connected.");
|
MSG_ERROR("ata_devices_read, no ata devices connected.");
|
else
|
else
|
{
|
{
|
/* check if both device0 and device1 are connected */
|
/* check if both device0 and device1 are connected */
|
if ( (devices->device0.stream) && (devices->device1.stream) )
|
if ( (devices->device0.stream) && (devices->device1.stream) )
|
{
|
{
|
/* get the current active device */
|
/* get the current active device */
|
if (devices->device1.regs.device_head & ATA_DHR_DEV)
|
if (devices->device1.regs.device_head & ATA_DHR_DEV)
|
device = &devices->device1;
|
device = &devices->device1;
|
else
|
else
|
device = &devices->device0;
|
device = &devices->device0;
|
}
|
}
|
else
|
else
|
{
|
{
|
/* only one device connected */
|
/* only one device connected */
|
if (devices->device1.stream)
|
if (devices->device1.stream)
|
device = &devices->device1;
|
device = &devices->device1;
|
else
|
else
|
device = &devices->device0;
|
device = &devices->device0;
|
}
|
}
|
|
|
/* return data provided by selected device */
|
/* return data provided by selected device */
|
switch (adr) {
|
switch (adr) {
|
case ATA_ASR :
|
case ATA_ASR :
|
ata_device_debug(4, "alternate_status register read\n");
|
ata_device_debug(4, "alternate_status register read\n");
|
if ( (device->regs.device_head & ATA_DHR_DEV) == device->internals.dev )
|
if ( (device->regs.device_head & ATA_DHR_DEV) == device->internals.dev )
|
return device -> regs.status;
|
return device -> regs.status;
|
else
|
else
|
{
|
{
|
ata_device_debug(2, "device0 responds for device1, asr = 0x00\n");
|
ata_device_debug(2, "device0 responds for device1, asr = 0x00\n");
|
return 0; // return 0 when device0 responds for device1
|
return 0; // return 0 when device0 responds for device1
|
}
|
}
|
|
|
case ATA_CHR :
|
case ATA_CHR :
|
ata_device_debug(4, "cylinder_high register read, value = 0x%02X\n",
|
ata_device_debug(4, "cylinder_high register read, value = 0x%02X\n",
|
device->regs.cylinder_high);
|
device->regs.cylinder_high);
|
return device -> regs.cylinder_high;
|
return device -> regs.cylinder_high;
|
|
|
case ATA_CLR :
|
case ATA_CLR :
|
ata_device_debug(4, "cylinder_low register read, value = 0x%02X\n",
|
ata_device_debug(4, "cylinder_low register read, value = 0x%02X\n",
|
device->regs.cylinder_low);
|
device->regs.cylinder_low);
|
return device -> regs.cylinder_low;
|
return device -> regs.cylinder_low;
|
|
|
case ATA_DR :
|
case ATA_DR :
|
if (!device->regs.status & ATA_SR_DRQ)
|
if (!device->regs.status & ATA_SR_DRQ)
|
{
|
{
|
ata_device_debug(1, "data register read, while DRQ bit negated\n" );
|
ata_device_debug(1, "data register read, while DRQ bit negated\n" );
|
return 0;
|
return 0;
|
}
|
}
|
else
|
else
|
{
|
{
|
ata_device_debug(4, "data register read, value = 0x%04X, cnt = %3d\n",
|
ata_device_debug(4, "data register read, value = 0x%04X, cnt = %3d\n",
|
*device->internals.dbuf_ptr, device->internals.dbuf_cnt);
|
*device->internals.dbuf_ptr, device->internals.dbuf_cnt);
|
if (!--device->internals.dbuf_cnt)
|
if (!--device->internals.dbuf_cnt)
|
device->regs.status &= ~ATA_SR_DRQ;
|
device->regs.status &= ~ATA_SR_DRQ;
|
return *device -> internals.dbuf_ptr++;
|
return *device -> internals.dbuf_ptr++;
|
}
|
}
|
|
|
case ATA_DHR :
|
case ATA_DHR :
|
ata_device_debug(4, "device_head register read, value = 0x%02X\n",
|
ata_device_debug(4, "device_head register read, value = 0x%02X\n",
|
device->regs.device_head);
|
device->regs.device_head);
|
return device -> regs.device_head;
|
return device -> regs.device_head;
|
|
|
case ATA_ERR :
|
case ATA_ERR :
|
ata_device_debug(4, "error register read, value = 0x%02X\n",
|
ata_device_debug(4, "error register read, value = 0x%02X\n",
|
device->regs.error);
|
device->regs.error);
|
return device -> regs.error;
|
return device -> regs.error;
|
|
|
case ATA_SCR :
|
case ATA_SCR :
|
ata_device_debug(4, "sectorcount register read, value = 0x%02X\n",
|
ata_device_debug(4, "sectorcount register read, value = 0x%02X\n",
|
device->regs.sector_count);
|
device->regs.sector_count);
|
return device -> regs.sector_count;
|
return device -> regs.sector_count;
|
|
|
case ATA_SNR :
|
case ATA_SNR :
|
ata_device_debug(4, "sectornumber register read, value = 0x%02X\n",
|
ata_device_debug(4, "sectornumber register read, value = 0x%02X\n",
|
device->regs.sector_number);
|
device->regs.sector_number);
|
return device -> regs.sector_number;
|
return device -> regs.sector_number;
|
|
|
case ATA_SR :
|
case ATA_SR :
|
ata_device_debug(4, "status register read\n");
|
ata_device_debug(4, "status register read\n");
|
if ( (device->regs.device_head & ATA_DHR_DEV) == device->internals.dev)
|
if ( (device->regs.device_head & ATA_DHR_DEV) == device->internals.dev)
|
return device -> regs.status;
|
return device -> regs.status;
|
else
|
else
|
{
|
{
|
ata_device_debug(2, "device0 responds for device1, sr = 0x00\n");
|
ata_device_debug(2, "device0 responds for device1, sr = 0x00\n");
|
return 0; // return 0 when device0 responds for device1
|
return 0; // return 0 when device0 responds for device1
|
}
|
}
|
|
|
// case ATA_DA :
|
// case ATA_DA :
|
// return device -> regs.status;
|
// return device -> regs.status;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
/*
|
/*
|
D E V I C E S _ W R I T E
|
D E V I C E S _ W R I T E
|
*/
|
*/
|
/* Write to devices */
|
/* Write to devices */
|
void ata_devices_write(ata_devices *devices, char adr, short value)
|
void ata_devices_write(ata_devices *devices, char adr, short value)
|
{
|
{
|
/* check for no connected devices */
|
/* check for no connected devices */
|
if (!devices->device0.stream && !devices->device1.stream)
|
if (!devices->device0.stream && !devices->device1.stream)
|
MSG_ERROR("ata_devices_write, no ata devices connected.");
|
MSG_ERROR("ata_devices_write, no ata devices connected.");
|
else
|
else
|
{
|
{
|
/* first device */
|
/* first device */
|
if (devices->device0.stream)
|
if (devices->device0.stream)
|
ata_device_write(&devices->device0, adr, value);
|
ata_device_write(&devices->device0, adr, value);
|
|
|
/* second device */
|
/* second device */
|
if (devices->device1.stream)
|
if (devices->device1.stream)
|
ata_device_write(&devices->device1, adr, value);
|
ata_device_write(&devices->device1, adr, value);
|
}
|
}
|
}
|
}
|
|
|
/* write to a single device */
|
/* write to a single device */
|
void ata_device_write(ata_device *device, char adr, short value)
|
void ata_device_write(ata_device *device, char adr, short value)
|
{
|
{
|
switch (adr) {
|
switch (adr) {
|
case ATA_CR :
|
case ATA_CR :
|
/*display debug information */
|
/*display debug information */
|
ata_device_debug(4, "command register written, value = 0x%02X\n", value);
|
ata_device_debug(4, "command register written, value = 0x%02X\n", value);
|
|
|
device->regs.command = value;
|
device->regs.command = value;
|
|
|
/* check command register settings and execute command */
|
/* check command register settings and execute command */
|
ata_device_do_command_register(device);
|
ata_device_do_command_register(device);
|
break;
|
break;
|
|
|
|
|
case ATA_CHR :
|
case ATA_CHR :
|
/*display debug information */
|
/*display debug information */
|
ata_device_debug(4, "cylinder high register written, value = 0x%02X\n", value);
|
ata_device_debug(4, "cylinder high register written, value = 0x%02X\n", value);
|
|
|
device->regs.cylinder_high = value;
|
device->regs.cylinder_high = value;
|
break;
|
break;
|
|
|
case ATA_CLR :
|
case ATA_CLR :
|
/*display debug information */
|
/*display debug information */
|
ata_device_debug(4, "cylinder low register written, value = 0x%02X\n", value);
|
ata_device_debug(4, "cylinder low register written, value = 0x%02X\n", value);
|
|
|
device->regs.cylinder_low = value;
|
device->regs.cylinder_low = value;
|
break;
|
break;
|
|
|
case ATA_DR :
|
case ATA_DR :
|
/*display debug information */
|
/*display debug information */
|
ata_device_debug(4, "data register written, value = 0x%04X\n", value);
|
ata_device_debug(4, "data register written, value = 0x%04X\n", value);
|
|
|
device->regs.dataport_i = value;
|
device->regs.dataport_i = value;
|
break;
|
break;
|
|
|
case ATA_DCR :
|
case ATA_DCR :
|
/*display debug information */
|
/*display debug information */
|
ata_device_debug(4, "device control register written, value = 0x%02X\n", value);
|
ata_device_debug(4, "device control register written, value = 0x%02X\n", value);
|
|
|
device->regs.device_control = value;
|
device->regs.device_control = value;
|
ata_device_do_control_register(device);
|
ata_device_do_control_register(device);
|
break;
|
break;
|
|
|
case ATA_DHR :
|
case ATA_DHR :
|
/*display debug information */
|
/*display debug information */
|
ata_device_debug(4, "device head register written, value = 0x%02X\n", value);
|
ata_device_debug(4, "device head register written, value = 0x%02X\n", value);
|
|
|
device->regs.device_head = value;
|
device->regs.device_head = value;
|
break;
|
break;
|
|
|
case ATA_FR :
|
case ATA_FR :
|
/*display debug information */
|
/*display debug information */
|
ata_device_debug(4, "features register written, value = 0x%02X\n", value);
|
ata_device_debug(4, "features register written, value = 0x%02X\n", value);
|
|
|
device->regs.features = value;
|
device->regs.features = value;
|
break;
|
break;
|
|
|
case ATA_SCR :
|
case ATA_SCR :
|
/*display debug information */
|
/*display debug information */
|
ata_device_debug(4, "sectorcount register written, value = 0x%02X\n", value);
|
ata_device_debug(4, "sectorcount register written, value = 0x%02X\n", value);
|
|
|
device->regs.sector_count = value;
|
device->regs.sector_count = value;
|
break;
|
break;
|
|
|
case ATA_SNR :
|
case ATA_SNR :
|
/*display debug information */
|
/*display debug information */
|
ata_device_debug(4, "sectornumber register written, value = 0x%02X\n", value);
|
ata_device_debug(4, "sectornumber register written, value = 0x%02X\n", value);
|
|
|
device->regs.sector_number = value;
|
device->regs.sector_number = value;
|
break;
|
break;
|
|
|
} //endcase
|
} //endcase
|
}
|
}
|
|
|
|
|
/* -------------------------- */
|
/* -------------------------- */
|
/* -- print debug messages -- */
|
/* -- print debug messages -- */
|
/* -------------------------- */
|
/* -------------------------- */
|
int ata_device_debug(int lvl, char *format, ...)
|
int ata_device_debug(int lvl, char *format, ...)
|
{
|
{
|
va_list ap;
|
va_list ap;
|
|
|
va_start(ap, format);
|
va_start(ap, format);
|
|
|
if (ATA_DEVICE_DEBUG_LVL >= lvl)
|
if (ATA_DEVICE_DEBUG_LVL >= lvl)
|
{
|
{
|
fprintf(stderr, "ata_device_debug: ");
|
fprintf(stderr, "ata_device_debug: ");
|
vfprintf(stderr, format, ap);
|
vfprintf(stderr, format, ap);
|
}
|
}
|
|
|
va_end(ap);
|
va_end(ap);
|
return 0;
|
return 0;
|
}
|
}
|
|
|