/* atadevice.c -- ATA Device simulation. Simulates a harddisk, using a local
|
/* atadevice.c -- ATA Device simulation. Simulates a harddisk, using a local
|
streams.
|
streams.
|
|
|
Copyright (C) 2002 Richard Herveille, rherveille@opencores.org
|
Copyright (C) 2002 Richard Herveille, rherveille@opencores.org
|
Copyright (C) 2008 Embecosm Limited
|
Copyright (C) 2008 Embecosm Limited
|
|
|
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
|
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
|
|
|
This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
|
This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
|
|
|
This program is free software; you can redistribute it and/or modify it
|
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
|
under the terms of the GNU General Public License as published by the Free
|
Software Foundation; either version 3 of the License, or (at your option)
|
Software Foundation; either version 3 of the License, or (at your option)
|
any later version.
|
any later version.
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
more details.
|
more details.
|
|
|
You should have received a copy of the GNU General Public License along
|
You should have received a copy of the GNU General Public License along
|
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
/* This program is commented throughout in a fashion suitable for processing
|
/* This program is commented throughout in a fashion suitable for processing
|
with Doxygen. */
|
with Doxygen. */
|
|
|
|
|
/* Autoconf and/or portability configuration */
|
/* Autoconf and/or portability configuration */
|
#include "config.h"
|
#include "config.h"
|
#include "port.h"
|
#include "port.h"
|
|
|
/* System includes */
|
/* System includes */
|
#ifdef __APPLE__
|
#ifdef __APPLE__
|
#include <libkern/OSByteOrder.h>
|
#include <libkern/OSByteOrder.h>
|
#define bswap_16(x) OSSwapInt16(x)
|
#define bswap_16(x) OSSwapInt16(x)
|
#define bswap_32(x) OSSwapInt32(x)
|
#define bswap_32(x) OSSwapInt32(x)
|
#define bswap_64(x) OSSwapInt64(x)
|
#define bswap_64(x) OSSwapInt64(x)
|
#else
|
#else
|
#include <byteswap.h>
|
#include <byteswap.h>
|
#endif
|
#endif
|
|
|
/* Package includes */
|
/* Package includes */
|
#include "atadevice.h"
|
#include "atadevice.h"
|
#include "atadevice-cmdi.h"
|
#include "atadevice-cmdi.h"
|
#include "atacmd.h"
|
#include "atacmd.h"
|
#include "abstract.h"
|
#include "abstract.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
|
*/
|
*/
|
|
|
|
|
/* Use a file to simulate a hard-disk */
|
/* Use a file to simulate a hard-disk */
|
static FILE *
|
static FILE *
|
open_file (uint32_t * size, const char *filename)
|
open_file (uint32_t * 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+")))
|
{
|
{
|
fprintf (stderr, "Warning: ata_open_file, cannot open hd-file %s\n",
|
fprintf (stderr, "Warning: ata_open_file, cannot open hd-file %s\n",
|
filename);
|
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 */
|
for (n = 0; n < *size; n++)
|
for (n = 0; n < *size; 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",
|
fprintf (stderr, "file %s already exists. Using existing file.\n",
|
filename);
|
filename);
|
|
|
/* 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);
|
|
|
return fp;
|
return fp;
|
}
|
}
|
|
|
|
|
/* Use a the local filesystem as a hard-disk */
|
/* Use a the local filesystem as a hard-disk */
|
static FILE *
|
static FILE *
|
open_local (void)
|
open_local (void)
|
{
|
{
|
// TODO:
|
// TODO:
|
fprintf (stderr, "Warning: Device type LOCAL is not yet supported: "
|
fprintf (stderr, "Warning: Device type LOCAL is not yet supported: "
|
"Defaulting to device type NO_CONNECT.");
|
"Defaulting to device type NO_CONNECT.");
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
static void
|
static void
|
ata_device_init (struct ata_device * device, int dev)
|
ata_device_init (struct 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->conf.type)
|
switch (device->conf.type)
|
{
|
{
|
case TYPE_NO_CONNECT:
|
case TYPE_NO_CONNECT:
|
device->conf.stream = NULL;
|
device->conf.stream = NULL;
|
break;
|
break;
|
|
|
case TYPE_FILE:
|
case TYPE_FILE:
|
device->conf.stream = open_file (&device->conf.size, device->conf.file);
|
device->conf.stream = open_file (&device->conf.size, device->conf.file);
|
break;
|
break;
|
|
|
case TYPE_LOCAL:
|
case TYPE_LOCAL:
|
device->conf.stream = open_local ();
|
device->conf.stream = open_local ();
|
break;
|
break;
|
|
|
default:
|
default:
|
fprintf (stderr, "Warning: Illegal device-type %d: "
|
fprintf (stderr, "Warning: Illegal device-type %d: "
|
"Defaulting to type NO_CONNECT.\n", device->conf.type);
|
"Defaulting to type NO_CONNECT.\n", device->conf.type);
|
device->conf.stream = NULL;
|
device->conf.stream = NULL;
|
break;
|
break;
|
}
|
}
|
|
|
device->conf.size_sect = device->conf.size / BYTES_PER_SECTOR;
|
device->conf.size_sect = device->conf.size / BYTES_PER_SECTOR;
|
}
|
}
|
|
|
/*
|
/*
|
D E V I C E S _ I N I T
|
D E V I C E S _ I N I T
|
*/
|
*/
|
void
|
void
|
ata_devices_init (struct ata_devices * devices)
|
ata_devices_init (struct ata_devices * devices)
|
{
|
{
|
ata_device_init (&devices->device[0], 0);
|
ata_device_init (&devices->device[0], 0);
|
|
|
if (devices->device[0].conf.type)
|
if (devices->device[0].conf.type)
|
ata_device_init (&devices->device[1], ATA_DHR_DEV);
|
ata_device_init (&devices->device[1], ATA_DHR_DEV);
|
else
|
else
|
ata_device_init (&devices->device[1], 0);
|
ata_device_init (&devices->device[1], 0);
|
}
|
}
|
|
|
/*
|
/*
|
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
|
*/
|
*/
|
static void
|
static void
|
ata_device_hw_reset (struct ata_device * device, int reset_signal,
|
ata_device_hw_reset (struct 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 = device->conf.sectors;
|
device->internals.sectors_per_track = device->conf.sectors;
|
device->internals.heads_per_cylinder = device->conf.heads;
|
device->internals.heads_per_cylinder = device->conf.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->conf.packet)
|
if (!device->conf.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 if (reset_signal)
|
else 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;
|
|
|
/* set new state */
|
/* set new state */
|
device->internals.state = ATA_STATE_HW_RST;
|
device->internals.state = ATA_STATE_HW_RST;
|
}
|
}
|
}
|
}
|
|
|
/* power-on and hardware reset */
|
/* power-on and hardware reset */
|
void
|
void
|
ata_devices_hw_reset (struct ata_devices * devices, int reset_signal)
|
ata_devices_hw_reset (struct ata_devices * devices, int reset_signal)
|
{
|
{
|
/* find device 0 */
|
/* find device 0 */
|
if ((devices->device[0].conf.stream) && (devices->device[1].conf.stream))
|
if ((devices->device[0].conf.stream) && (devices->device[1].conf.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->device[1], reset_signal, 1, /* assert dasp, this is device1 */
|
ata_device_hw_reset (&devices->device[1], reset_signal, 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->device[0], reset_signal,
|
ata_device_hw_reset (&devices->device[0], reset_signal,
|
0,
|
0,
|
devices->device[1].sigs.pdiago,
|
devices->device[1].sigs.pdiago,
|
devices->device[1].sigs.daspo);
|
devices->device[1].sigs.daspo);
|
}
|
}
|
else if (devices->device[0].conf.stream)
|
else if (devices->device[0].conf.stream)
|
{
|
{
|
/* device0 is device0, there's no device1 */
|
/* device0 is device0, there's no device1 */
|
ata_device_hw_reset (&devices->device[0], reset_signal, 0, /* negate dasp, this is device0 */
|
ata_device_hw_reset (&devices->device[0], reset_signal, 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->device[1].conf.stream)
|
else if (devices->device[1].conf.stream)
|
{
|
{
|
/* device1 is (logical) device0, there's no (physical) device0 */
|
/* device1 is (logical) device0, there's no (physical) device0 */
|
ata_device_hw_reset (&devices->device[1], reset_signal, 0, /* negate dasp, this is device0 */
|
ata_device_hw_reset (&devices->device[1], reset_signal, 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 */
|
}
|
}
|
}
|
}
|
|
|
|
|
/*
|
/*
|
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
|
*/
|
*/
|
static void
|
static void
|
ata_device_do_control_register (struct ata_device * device)
|
ata_device_do_control_register (struct 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;
|
}
|
}
|
}
|
}
|
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->conf.packet)
|
if (!device->conf.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> 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
|
*/
|
*/
|
static void
|
static void
|
ata_device_do_command_register (struct ata_device * device)
|
ata_device_do_command_register (struct ata_device * device)
|
{
|
{
|
/* check BSY & DRQ */
|
/* check BSY & DRQ */
|
if ((device->regs.status & ATA_SR_BSY)
|
if ((device->regs.status & ATA_SR_BSY)
|
|| (device->regs.status & ATA_SR_DRQ))
|
|| (device->regs.status & ATA_SR_DRQ))
|
{
|
{
|
if (device->regs.command != DEVICE_RESET)
|
if (device->regs.command != DEVICE_RESET)
|
{
|
{
|
fprintf (stderr, "Warning: ata_device_write, writing a command "
|
fprintf (stderr, "Warning: ata_device_write, writing a command "
|
"while BSY or DRQ asserted.\n");
|
"while BSY or DRQ asserted.\n");
|
}
|
}
|
}
|
}
|
|
|
/* 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
|
short
|
ata_devices_read (struct ata_devices * devices, char adr)
|
ata_devices_read (struct ata_devices * devices, char adr)
|
{
|
{
|
struct ata_device *device;
|
struct ata_device *device;
|
|
|
/* check for no connected devices */
|
/* check for no connected devices */
|
if ((!devices->device[0].conf.stream) && (!devices->device[1].conf.stream))
|
if ((!devices->device[0].conf.stream) && (!devices->device[1].conf.stream))
|
{
|
{
|
fprintf (stderr, "Warning: ata_devices_read, no ata devices "
|
fprintf (stderr, "Warning: ata_devices_read, no ata devices "
|
"connected.\n");
|
"connected.\n");
|
}
|
}
|
else
|
else
|
{
|
{
|
/* check if both device0 and device1 are connected */
|
/* check if both device0 and device1 are connected */
|
if ((devices->device[0].conf.stream)
|
if ((devices->device[0].conf.stream)
|
&& (devices->device[1].conf.stream))
|
&& (devices->device[1].conf.stream))
|
{
|
{
|
/* get the current active device */
|
/* get the current active device */
|
if (devices->device[1].regs.device_head & ATA_DHR_DEV)
|
if (devices->device[1].regs.device_head & ATA_DHR_DEV)
|
device = &devices->device[1];
|
device = &devices->device[1];
|
else
|
else
|
device = &devices->device[0];
|
device = &devices->device[0];
|
}
|
}
|
else
|
else
|
{
|
{
|
/* only one device connected */
|
/* only one device connected */
|
if (devices->device[1].conf.stream)
|
if (devices->device[1].conf.stream)
|
device = &devices->device[1];
|
device = &devices->device[1];
|
else
|
else
|
device = &devices->device[0];
|
device = &devices->device[0];
|
}
|
}
|
|
|
/* return data provided by selected device */
|
/* return data provided by selected device */
|
switch (adr)
|
switch (adr)
|
{
|
{
|
case ATA_ASR:
|
case ATA_ASR:
|
if ((device->regs.device_head & ATA_DHR_DEV) ==
|
if ((device->regs.device_head & ATA_DHR_DEV) ==
|
device->internals.dev)
|
device->internals.dev)
|
return device->regs.status;
|
return device->regs.status;
|
else
|
else
|
{
|
{
|
return 0; // return 0 when device0 responds for device1
|
return 0; // return 0 when device0 responds for device1
|
}
|
}
|
|
|
case ATA_CHR:
|
case ATA_CHR:
|
return device->regs.cylinder_high;
|
return device->regs.cylinder_high;
|
|
|
case ATA_CLR:
|
case ATA_CLR:
|
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))
|
{
|
{
|
return 0;
|
return 0;
|
}
|
}
|
else
|
else
|
{
|
{
|
uint16_t val = LE16 (*device->internals.dbuf_ptr++);
|
uint16_t val = LE16 (*device->internals.dbuf_ptr++);
|
if (!--device->internals.dbuf_cnt)
|
if (!--device->internals.dbuf_cnt)
|
{
|
{
|
device->regs.status &= ~ATA_SR_DRQ;
|
device->regs.status &= ~ATA_SR_DRQ;
|
if (device->internals.end_t_func)
|
if (device->internals.end_t_func)
|
device->internals.end_t_func (device);
|
device->internals.end_t_func (device);
|
}
|
}
|
return val;
|
return val;
|
}
|
}
|
|
|
case ATA_DHR:
|
case ATA_DHR:
|
return device->regs.device_head;
|
return device->regs.device_head;
|
|
|
case ATA_ERR:
|
case ATA_ERR:
|
return device->regs.error;
|
return device->regs.error;
|
|
|
case ATA_SCR:
|
case ATA_SCR:
|
return device->regs.sector_count;
|
return device->regs.sector_count;
|
|
|
case ATA_SNR:
|
case ATA_SNR:
|
return device->regs.sector_number;
|
return device->regs.sector_number;
|
|
|
case ATA_SR:
|
case ATA_SR:
|
if ((device->regs.device_head & ATA_DHR_DEV) ==
|
if ((device->regs.device_head & ATA_DHR_DEV) ==
|
device->internals.dev)
|
device->internals.dev)
|
{
|
{
|
device->sigs.intrq = 0;
|
device->sigs.intrq = 0;
|
return device->regs.status;
|
return device->regs.status;
|
}
|
}
|
|
|
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;
|
}
|
}
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
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 a single device */
|
/* write to a single device */
|
static void
|
static void
|
ata_device_write (struct ata_device * device, char adr, short value)
|
ata_device_write (struct ata_device * device, char adr, short value)
|
{
|
{
|
switch (adr)
|
switch (adr)
|
{
|
{
|
case ATA_CR:
|
case ATA_CR:
|
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:
|
device->regs.cylinder_high = value;
|
device->regs.cylinder_high = value;
|
break;
|
break;
|
|
|
case ATA_CLR:
|
case ATA_CLR:
|
device->regs.cylinder_low = value;
|
device->regs.cylinder_low = value;
|
break;
|
break;
|
|
|
case ATA_DR:
|
case ATA_DR:
|
if (!device->regs.status & ATA_SR_DRQ)
|
if (!(device->regs.status & ATA_SR_DRQ))
|
{
|
{
|
break;
|
break;
|
}
|
}
|
else
|
else
|
{
|
{
|
*device->internals.dbuf_ptr++ = LE16 (value);
|
*device->internals.dbuf_ptr++ = LE16 (value);
|
if (!--device->internals.dbuf_cnt)
|
if (!--device->internals.dbuf_cnt)
|
{
|
{
|
device->regs.status &= ~ATA_SR_DRQ;
|
device->regs.status &= ~ATA_SR_DRQ;
|
if (device->internals.end_t_func)
|
if (device->internals.end_t_func)
|
device->internals.end_t_func (device);
|
device->internals.end_t_func (device);
|
}
|
}
|
}
|
}
|
device->regs.dataport_i = value;
|
device->regs.dataport_i = value;
|
break;
|
break;
|
|
|
case ATA_DCR:
|
case ATA_DCR:
|
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:
|
device->regs.device_head = value;
|
device->regs.device_head = value;
|
break;
|
break;
|
|
|
case ATA_FR:
|
case ATA_FR:
|
device->regs.features = value;
|
device->regs.features = value;
|
break;
|
break;
|
|
|
case ATA_SCR:
|
case ATA_SCR:
|
device->regs.sector_count = value;
|
device->regs.sector_count = value;
|
break;
|
break;
|
|
|
case ATA_SNR:
|
case ATA_SNR:
|
device->regs.sector_number = value;
|
device->regs.sector_number = value;
|
break;
|
break;
|
|
|
} //endcase
|
} //endcase
|
}
|
}
|
|
|
/* Write to devices */
|
/* Write to devices */
|
void
|
void
|
ata_devices_write (struct ata_devices * devices, char adr, short value)
|
ata_devices_write (struct ata_devices * devices, char adr, short value)
|
{
|
{
|
/* check for no connected devices */
|
/* check for no connected devices */
|
if (!devices->device[0].conf.stream && !devices->device[1].conf.stream)
|
if (!devices->device[0].conf.stream && !devices->device[1].conf.stream)
|
{
|
{
|
fprintf (stderr, "Warning: ata_devices_write, no ata devices "
|
fprintf (stderr, "Warning: ata_devices_write, no ata devices "
|
"connected.\n");
|
"connected.\n");
|
}
|
}
|
else
|
else
|
{
|
{
|
/* first device */
|
/* first device */
|
if (devices->device[0].conf.stream)
|
if (devices->device[0].conf.stream)
|
ata_device_write (&devices->device[0], adr, value);
|
ata_device_write (&devices->device[0], adr, value);
|
|
|
/* second device */
|
/* second device */
|
if (devices->device[1].conf.stream)
|
if (devices->device[1].conf.stream)
|
ata_device_write (&devices->device[1], adr, value);
|
ata_device_write (&devices->device[1], adr, value);
|
}
|
}
|
}
|
}
|
|
|