123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869 |
- /* This file is part of the program psim.
- Copyright (C) 1996, Andrew Cagney <cagney@highland.com.au>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-
- */
- #ifndef _HW_IDE_C_
- #define _HW_IDE_C_
- #include "device_table.h"
- /* DEVICE
- ide - Integrated Disk Electronics
- DESCRIPTION
- This device models the primary/secondary <<ide>> controller
- described in the [CHRPIO] document.
- The controller has separate independant interrupt outputs for each
- <<ide>> bus.
- PROPERTIES
- reg = ... (required)
- The <<reg>> property is described in the document [CHRPIO].
- ready-delay = <integer> (optional)
- If present, this specifies the time that the <<ide>> device takes
- to complete an I/O operation.
- disk@?/ide-byte-count = <integer> (optional)
- disk@?/ide-sector-count = <integer> (optional)
- disk@?/ide-head-count = <integer> (optional)
- The <<ide>> device checks each child (disk device) node to see if
- it has the above properties. If present, these values will be used
- to compute the <<LBA>> address in <<CHS>> addressing mode.
- EXAMPLES
- Enable tracing:
- | -t ide-device \
- Attach the <<ide>> device to the <<pci>> bus at slot one. Specify
- legacy I/O addresses:
- | -o '/phb/ide@1/assigned-addresses \
- | ni0,0,10,1f0 8 \
- | ni0,0,14,3f8 8 \
- | ni0,0,18,170 8 \
- | ni0,0,1c,378 8 \
- | ni0,0,20,200 8' \
- | -o '/phb@0x80000000/ide@1/reg \
- | 1 0 \
- | i0,0,10,0 8 \
- | i0,0,18,0 8 \
- | i0,0,14,6 1 \
- | i0,0,1c,6 1 \
- | i0,0,20,0 8' \
- Note: the fouth and fifth reg entries specify that the register is
- at an offset into the address specified by the base register
- (<<assigned-addresses>>); Apart from restrictions placed by the
- <<pci>> specification, no restrictions are placed on the number of
- base registers specified by the <<assigned-addresses>> property.
-
- Attach a <<disk>> to the primary and a <<cdrom>> to the secondary
- <<ide>> controller.
- | -o '/phb@0x80000000/ide@1/disk@0/file "zero' \
- | -o '/phb@0x80000000/ide@1/cdrom@2/file "/dev/cdrom"' \
- Connect the two interrupt outputs (a and b) to a <<glue>> device to
- allow testing of the interrupt port. In a real simulation they
- would be wired to the interrupt controller.
- | -o '/phb@0x80000000/glue@2/reg 2 0 ni0,0,0,0 8' \
- | -o '/phb@0x80000000/ide@1 > a 0 /phb@0x80000000/glue@2' \
- | -o '/phb@0x80000000/ide@1 > b 1 /phb@0x80000000/glue@2'
-
- BUGS
-
- While the DMA registers are present, DMA support has not yet been
- implemented.
- The number of supported commands is very limited.
- The standards documents appear to be vague on how to specify the
- <<unit-address>> of disk devices devices being attached to the
- <<ide>> controller. I've chosen to use integers with devices zero
- and one going to the primary controller while two and three are
- connected to the secondary controller.
- REFERENCES
- [CHRPIO] PowerPC(tm) Microprocessor Common Hardware Reference
- Platform: I/O Device Reference. http://chrp.apple.com/???.
- [SCHMIDT] The SCSI Bus and IDE Interface - Protocols, Applications
- and Programming. Friedhelm Schmidt (translated by Michael
- Schultz). ISBN 0-201-42284-0. Addison-Wesley Publishing Company.
- */
-
- typedef enum _io_direction {
- is_read,
- is_write,
- } io_direction;
- enum {
- nr_ide_controllers = 2,
- nr_ide_drives_per_controller = 2,
- nr_fifo_entries = 8192,
- };
- enum {
- /* command register block - read */
- ide_data_reg,
- ide_error_reg, /*ide_feature_reg*/
- ide_sector_count_reg,
- ide_sector_number_reg,
- ide_cylinder_reg0,
- ide_cylinder_reg1,
- ide_drive_head_reg,
- ide_status_reg, /*ide_command_reg*/
- /* command register block - write */
- ide_feature_reg, /*ide_error_reg*/
- ide_command_reg, /*ide_status_reg*/
- /* control register block - read */
- ide_alternate_status_reg, /*ide_control_reg*/
- ide_control_reg, /*ide_alternate_status_reg*/
- /* dma register block */
- ide_dma_command_reg,
- ide_dma_unused_1_reg,
- ide_dma_status_reg,
- ide_dma_unused_3_reg,
- ide_dma_prd_table_address_reg0,
- ide_dma_prd_table_address_reg1,
- ide_dma_prd_table_address_reg2,
- ide_dma_prd_table_address_reg3,
- nr_ide_registers,
- };
- typedef enum _ide_states {
- idle_state,
- busy_loaded_state,
- busy_drained_state,
- busy_dma_state,
- busy_command_state,
- loading_state,
- draining_state,
- } ide_states;
- static const char *
- ide_state_name(ide_states state)
- {
- switch (state) {
- case idle_state: return "idle";
- case busy_loaded_state: return "busy_loaded_state";
- case busy_drained_state: return "busy_drained_state";
- case busy_dma_state: return "busy_dma_state";
- case busy_command_state: return "busy_command_state";
- case loading_state: return "loading_state";
- case draining_state: return "draining_state";
- default: return "illegal-state";
- }
- }
- typedef struct _ide_geometry {
- int head;
- int sector;
- int byte;
- } ide_geometry;
- typedef struct _ide_drive {
- int nr;
- device *device;
- ide_geometry geometry;
- ide_geometry default_geometry;
- } ide_drive;
- typedef struct _ide_controller {
- int nr;
- ide_states state;
- unsigned8 reg[nr_ide_registers];
- unsigned8 fifo[nr_fifo_entries];
- int fifo_pos;
- int fifo_size;
- ide_drive *current_drive;
- int current_byte;
- int current_transfer;
- ide_drive drive[nr_ide_drives_per_controller];
- device *me;
- event_entry_tag event_tag;
- int is_interrupting;
- signed64 ready_delay;
- } ide_controller;
- static void
- set_interrupt(device *me,
- ide_controller *controller)
- {
- if ((controller->reg[ide_control_reg] & 0x2) == 0) {
- DTRACE(ide, ("controller %d - interrupt set\n", controller->nr));
- device_interrupt_event(me, controller->nr, 1, NULL, 0);
- controller->is_interrupting = 1;
- }
- }
- static void
- clear_interrupt(device *me,
- ide_controller *controller)
- {
- if (controller->is_interrupting) {
- DTRACE(ide, ("controller %d - interrupt clear\n", controller->nr));
- device_interrupt_event(me, controller->nr, 0, NULL, 0);
- controller->is_interrupting = 0;
- }
- }
- static void
- do_event(void *data)
- {
- ide_controller *controller = data;
- device *me = controller->me;
- controller->event_tag = 0;
- switch (controller->state) {
- case busy_loaded_state:
- case busy_drained_state:
- if (controller->current_transfer > 0) {
- controller->state = (controller->state == busy_loaded_state
- ? loading_state : draining_state);
- }
- else {
- controller->state = idle_state;
- }
- set_interrupt(me, controller);
- break;
- default:
- device_error(me, "controller %d - unexpected event", controller->nr);
- break;
- }
- }
- static void
- schedule_ready_event(device *me,
- ide_controller *controller)
- {
- if (controller->event_tag != 0)
- device_error(me, "controller %d - attempting to schedule multiple events",
- controller->nr);
- controller->event_tag =
- device_event_queue_schedule(me, controller->ready_delay,
- do_event, controller);
- }
- static void
- do_fifo_read(device *me,
- ide_controller *controller,
- void *dest,
- int nr_bytes)
- {
- if (controller->state != draining_state)
- device_error(me, "controller %d - reading fifo when not ready (%s)",
- controller->nr,
- ide_state_name(controller->state));
- if (controller->fifo_pos + nr_bytes > controller->fifo_size)
- device_error(me, "controller %d - fifo underflow", controller->nr);
- if (nr_bytes > 0) {
- memcpy(dest, &controller->fifo[controller->fifo_pos], nr_bytes);
- controller->fifo_pos += nr_bytes;
- }
- if (controller->fifo_pos == controller->fifo_size) {
- controller->current_transfer -= 1;
- if (controller->current_transfer > 0
- && controller->current_drive != NULL) {
- DTRACE(ide, ("controller %d:%d - reading %d byte block at 0x%x\n",
- controller->nr,
- controller->current_drive->nr,
- controller->fifo_size,
- controller->current_byte));
- if (device_io_read_buffer(controller->current_drive->device,
- controller->fifo,
- 0, controller->current_byte,
- controller->fifo_size,
- NULL, 0)
- != controller->fifo_size)
- device_error(me, "controller %d - disk %s io read error",
- controller->nr,
- device_path(controller->current_drive->device));
- }
- controller->state = busy_drained_state;
- controller->fifo_pos = 0;
- controller->current_byte += controller->fifo_size;
- schedule_ready_event(me, controller);
- }
- }
- static void
- do_fifo_write(device *me,
- ide_controller *controller,
- const void *source,
- int nr_bytes)
- {
- if (controller->state != loading_state)
- device_error(me, "controller %d - writing fifo when not ready (%s)",
- controller->nr,
- ide_state_name(controller->state));
- if (controller->fifo_pos + nr_bytes > controller->fifo_size)
- device_error(me, "controller %d - fifo overflow", controller->nr);
- if (nr_bytes > 0) {
- memcpy(&controller->fifo[controller->fifo_pos], source, nr_bytes);
- controller->fifo_pos += nr_bytes;
- }
- if (controller->fifo_pos == controller->fifo_size) {
- if (controller->current_transfer > 0
- && controller->current_drive != NULL) {
- DTRACE(ide, ("controller %d:%d - writing %d byte block at 0x%x\n",
- controller->nr,
- controller->current_drive->nr,
- controller->fifo_size,
- controller->current_byte));
- if (device_io_write_buffer(controller->current_drive->device,
- controller->fifo,
- 0, controller->current_byte,
- controller->fifo_size,
- NULL, 0)
- != controller->fifo_size)
- device_error(me, "controller %d - disk %s io write error",
- controller->nr,
- device_path(controller->current_drive->device));
- }
- controller->current_transfer -= 1;
- controller->fifo_pos = 0;
- controller->current_byte += controller->fifo_size;
- controller->state = busy_loaded_state;
- schedule_ready_event(me, controller);
- }
- }
- static void
- setup_fifo(device *me,
- ide_controller *controller,
- int is_simple,
- int is_with_disk,
- io_direction direction)
- {
- /* find the disk */
- if (is_with_disk) {
- int drive_nr = (controller->reg[ide_drive_head_reg] & 0x10) != 0;
- controller->current_drive = &controller->drive[drive_nr];
- }
- else {
- controller->current_drive = NULL;
- }
- /* number of transfers */
- if (is_simple)
- controller->current_transfer = 1;
- else {
- int sector_count = controller->reg[ide_sector_count_reg];
- if (sector_count == 0)
- controller->current_transfer = 256;
- else
- controller->current_transfer = sector_count;
- }
- /* the transfer size */
- if (controller->current_drive == NULL)
- controller->fifo_size = 512;
- else
- controller->fifo_size = controller->current_drive->geometry.byte;
- /* empty the fifo */
- controller->fifo_pos = 0;
- /* the starting address */
- if (controller->current_drive == NULL)
- controller->current_byte = 0;
- else if (controller->reg[ide_drive_head_reg] & 0x40) {
- /* LBA addressing mode */
- controller->current_byte = controller->fifo_size
- * (((controller->reg[ide_drive_head_reg] & 0xf) << 24)
- | (controller->reg[ide_cylinder_reg1] << 16)
- | (controller->reg[ide_cylinder_reg0] << 8)
- | (controller->reg[ide_sector_number_reg]));
- }
- else if (controller->current_drive->geometry.head != 0
- && controller->current_drive->geometry.sector != 0) {
- /* CHS addressing mode */
- int head_nr = controller->reg[ide_drive_head_reg] & 0xf;
- int cylinder_nr = ((controller->reg[ide_cylinder_reg1] << 8)
- | controller->reg[ide_cylinder_reg0]);
- int sector_nr = controller->reg[ide_sector_number_reg];
- controller->current_byte = controller->fifo_size
- * ((cylinder_nr * controller->current_drive->geometry.head + head_nr)
- * controller->current_drive->geometry.sector + sector_nr - 1);
- }
- else
- device_error(me, "controller %d:%d - CHS addressing disabled",
- controller->nr, controller->current_drive->nr);
- DTRACE(ide, ("controller %ld:%ld - transfer (%s) %ld blocks of %ld bytes from 0x%lx\n",
- (long)controller->nr,
- controller->current_drive == NULL ? -1L : (long)controller->current_drive->nr,
- direction == is_read ? "read" : "write",
- (long)controller->current_transfer,
- (long)controller->fifo_size,
- (unsigned long)controller->current_byte));
- switch (direction) {
- case is_read:
- /* force a primeing read */
- controller->current_transfer += 1;
- controller->state = draining_state;
- controller->fifo_pos = controller->fifo_size;
- do_fifo_read(me, controller, NULL, 0);
- break;
- case is_write:
- controller->state = loading_state;
- break;
- }
- }
- static void
- do_command(device *me,
- ide_controller *controller,
- int command)
- {
- if (controller->state != idle_state)
- device_error(me, "controller %d - command when not idle", controller->nr);
- switch (command) {
- case 0x20: case 0x21: /* read-sectors */
- setup_fifo(me, controller, 0/*is_simple*/, 1/*is_with_disk*/, is_read);
- break;
- case 0x30: case 0x31: /* write */
- setup_fifo(me, controller, 0/*is_simple*/, 1/*is_with_disk*/, is_write);
- break;
- }
- }
- static unsigned8
- get_status(device *me,
- ide_controller *controller)
- {
- switch (controller->state) {
- case loading_state:
- case draining_state:
- return 0x08; /* data req */
- case busy_loaded_state:
- case busy_drained_state:
- return 0x80; /* busy */
- case idle_state:
- return 0x40; /* drive ready */
- default:
- device_error(me, "internal error");
- return 0;
- }
- }
-
- /* The address presented to the IDE controler is decoded and then
- mapped onto a controller:reg pair */
- enum {
- nr_address_blocks = 6,
- };
- typedef struct _address_block {
- int space;
- unsigned_word base_addr;
- unsigned_word bound_addr;
- int controller;
- int base_reg;
- } address_block;
- typedef struct _address_decoder {
- address_block block[nr_address_blocks];
- } address_decoder;
- static void
- decode_address(device *me,
- address_decoder *decoder,
- int space,
- unsigned_word address,
- int *controller,
- int *reg,
- io_direction direction)
- {
- int i;
- for (i = 0; i < nr_address_blocks; i++) {
- if (space == decoder->block[i].space
- && address >= decoder->block[i].base_addr
- && address <= decoder->block[i].bound_addr) {
- *controller = decoder->block[i].controller;
- *reg = (address
- - decoder->block[i].base_addr
- + decoder->block[i].base_reg);
- if (direction == is_write) {
- switch (*reg) {
- case ide_error_reg: *reg = ide_feature_reg; break;
- case ide_status_reg: *reg = ide_command_reg; break;
- case ide_alternate_status_reg: *reg = ide_control_reg; break;
- default: break;
- }
- }
- return;
- }
- }
- device_error(me, "address %d:0x%lx invalid",
- space, (unsigned long)address);
- }
- static void
- build_address_decoder(device *me,
- address_decoder *decoder)
- {
- int reg;
- for (reg = 1; reg < 6; reg++) {
- reg_property_spec unit;
- int space;
- unsigned_word address;
- unsigned size;
- /* find and decode the reg property */
- if (!device_find_reg_array_property(me, "reg", reg, &unit))
- device_error(me, "missing or invalid reg entry %d", reg);
- device_address_to_attach_address(device_parent(me), &unit.address,
- &space, &address, me);
- device_size_to_attach_size(device_parent(me), &unit.size, &size, me);
- /* insert it into the address decoder */
- switch (reg) {
- case 1:
- case 2:
- /* command register block */
- if (size != 8)
- device_error(me, "reg entry %d must have a size of 8", reg);
- decoder->block[reg-1].space = space;
- decoder->block[reg-1].base_addr = address;
- decoder->block[reg-1].bound_addr = address + size - 1;
- decoder->block[reg-1].controller = (reg + 1) % nr_ide_controllers;
- decoder->block[reg-1].base_reg = ide_data_reg;
- DTRACE(ide, ("controller %d command register block at %d:0x%lx..0x%lx\n",
- decoder->block[reg-1].controller,
- decoder->block[reg-1].space,
- (unsigned long)decoder->block[reg-1].base_addr,
- (unsigned long)decoder->block[reg-1].bound_addr));
- break;
- case 3:
- case 4:
- /* control register block */
- if (size != 1)
- device_error(me, "reg entry %d must have a size of 1", reg);
- decoder->block[reg-1].space = space;
- decoder->block[reg-1].base_addr = address;
- decoder->block[reg-1].bound_addr = address + size - 1;
- decoder->block[reg-1].controller = (reg + 1) % nr_ide_controllers;
- decoder->block[reg-1].base_reg = ide_alternate_status_reg;
- DTRACE(ide, ("controller %d control register block at %d:0x%lx..0x%lx\n",
- decoder->block[reg-1].controller,
- decoder->block[reg-1].space,
- (unsigned long)decoder->block[reg-1].base_addr,
- (unsigned long)decoder->block[reg-1].bound_addr));
- break;
- case 5:
- /* dma register block */
- if (size != 8)
- device_error(me, "reg entry %d must have a size of 8", reg);
- decoder->block[reg-1].space = space;
- decoder->block[reg-1].base_addr = address;
- decoder->block[reg-1].bound_addr = address + 4 - 1;
- decoder->block[reg-1].base_reg = ide_dma_command_reg;
- decoder->block[reg-1].controller = 0;
- DTRACE(ide, ("controller %d dma register block at %d:0x%lx..0x%lx\n",
- decoder->block[reg-1].controller,
- decoder->block[reg-1].space,
- (unsigned long)decoder->block[reg-1].base_addr,
- (unsigned long)decoder->block[reg-1].bound_addr));
- decoder->block[reg].space = space;
- decoder->block[reg].base_addr = address + 4;
- decoder->block[reg].bound_addr = address + 8 - 1;
- decoder->block[reg].controller = 1;
- decoder->block[reg].base_reg = ide_dma_command_reg;
- DTRACE(ide, ("controller %d dma register block at %d:0x%lx..0x%lx\n",
- decoder->block[reg].controller,
- decoder->block[reg-1].space,
- (unsigned long)decoder->block[reg].base_addr,
- (unsigned long)decoder->block[reg].bound_addr));
- break;
- default:
- device_error(me, "internal error - bad switch");
- break;
- }
- }
- }
-
- typedef struct _hw_ide_device {
- ide_controller controller[nr_ide_controllers];
- address_decoder decoder;
- } hw_ide_device;
- static void
- hw_ide_init_address(device *me)
- {
- hw_ide_device *ide = device_data(me);
- int controller;
- int drive;
-
- /* zero some things */
- for (controller = 0; controller < nr_ide_controllers; controller++) {
- memset(&ide->controller[controller], 0, sizeof(ide_controller));
- for (drive = 0; drive < nr_ide_drives_per_controller; drive++) {
- ide->controller[controller].drive[drive].nr = drive;
- }
- ide->controller[controller].me = me;
- if (device_find_property(me, "ready-delay") != NULL)
- ide->controller[controller].ready_delay =
- device_find_integer_property(me, "ready-delay");
- }
- /* attach this device to its parent */
- generic_device_init_address(me);
- /* determine our own address map */
- build_address_decoder(me, &ide->decoder);
- }
- static void
- hw_ide_attach_address(device *me,
- attach_type type,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- access_type access,
- device *client) /*callback/default*/
- {
- hw_ide_device *ide = (hw_ide_device*)device_data(me);
- int controller_nr = addr / nr_ide_drives_per_controller;
- int drive_nr = addr % nr_ide_drives_per_controller;
- ide_controller *controller;
- ide_drive *drive;
- if (controller_nr >= nr_ide_controllers)
- device_error(me, "no controller for disk %s",
- device_path(client));
- controller = &ide->controller[controller_nr];
- drive = &controller->drive[drive_nr];
- drive->device = client;
- if (device_find_property(client, "ide-byte-count") != NULL)
- drive->geometry.byte = device_find_integer_property(client, "ide-byte-count");
- else
- drive->geometry.byte = 512;
- if (device_find_property(client, "ide-sector-count") != NULL)
- drive->geometry.sector = device_find_integer_property(client, "ide-sector-count");
- if (device_find_property(client, "ide-head-count") != NULL)
- drive->geometry.head = device_find_integer_property(client, "ide-head-count");
- drive->default_geometry = drive->geometry;
- DTRACE(ide, ("controller %d:%d %s byte-count %d, sector-count %d, head-count %d\n",
- controller_nr,
- drive->nr,
- device_path(client),
- drive->geometry.byte,
- drive->geometry.sector,
- drive->geometry.head));
- }
- static unsigned
- hw_ide_io_read_buffer(device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
- {
- hw_ide_device *ide = (hw_ide_device *)device_data(me);
- int control_nr;
- int reg;
- ide_controller *controller;
- /* find the interface */
- decode_address(me, &ide->decoder, space, addr, &control_nr, ®, is_read);
- controller = & ide->controller[control_nr];
- /* process the transfer */
- memset(dest, 0, nr_bytes);
- switch (reg) {
- case ide_data_reg:
- do_fifo_read(me, controller, dest, nr_bytes);
- break;
- case ide_status_reg:
- *(unsigned8*)dest = get_status(me, controller);
- clear_interrupt(me, controller);
- break;
- case ide_alternate_status_reg:
- *(unsigned8*)dest = get_status(me, controller);
- break;
- case ide_error_reg:
- case ide_sector_count_reg:
- case ide_sector_number_reg:
- case ide_cylinder_reg0:
- case ide_cylinder_reg1:
- case ide_drive_head_reg:
- case ide_control_reg:
- case ide_dma_command_reg:
- case ide_dma_status_reg:
- case ide_dma_prd_table_address_reg0:
- case ide_dma_prd_table_address_reg1:
- case ide_dma_prd_table_address_reg2:
- case ide_dma_prd_table_address_reg3:
- *(unsigned8*)dest = controller->reg[reg];
- break;
- default:
- device_error(me, "bus-error at address 0x%lx", addr);
- break;
- }
- return nr_bytes;
- }
- static unsigned
- hw_ide_io_write_buffer(device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
- {
- hw_ide_device *ide = (hw_ide_device *)device_data(me);
- int control_nr;
- int reg;
- ide_controller *controller;
- /* find the interface */
- decode_address(me, &ide->decoder, space, addr, &control_nr, ®, is_write);
- controller = &ide->controller[control_nr];
- /* process the access */
- switch (reg) {
- case ide_data_reg:
- do_fifo_write(me, controller, source, nr_bytes);
- break;
- case ide_command_reg:
- do_command(me, controller, *(unsigned8*)source);
- break;
- case ide_control_reg:
- controller->reg[reg] = *(unsigned8*)source;
- /* possibly cancel interrupts */
- if ((controller->reg[reg] & 0x02) == 0x02)
- clear_interrupt(me, controller);
- break;
- case ide_feature_reg:
- case ide_sector_count_reg:
- case ide_sector_number_reg:
- case ide_cylinder_reg0:
- case ide_cylinder_reg1:
- case ide_drive_head_reg:
- case ide_dma_command_reg:
- case ide_dma_status_reg:
- case ide_dma_prd_table_address_reg0:
- case ide_dma_prd_table_address_reg1:
- case ide_dma_prd_table_address_reg2:
- case ide_dma_prd_table_address_reg3:
- controller->reg[reg] = *(unsigned8*)source;
- break;
- default:
- device_error(me, "bus-error at 0x%lx", addr);
- break;
- }
- return nr_bytes;
- }
- static const device_interrupt_port_descriptor hw_ide_interrupt_ports[] = {
- { "a", 0, 0 },
- { "b", 1, 0 },
- { "c", 2, 0 },
- { "d", 3, 0 },
- { NULL }
- };
- static device_callbacks const hw_ide_callbacks = {
- { hw_ide_init_address, },
- { hw_ide_attach_address, }, /* attach */
- { hw_ide_io_read_buffer, hw_ide_io_write_buffer, },
- { NULL, }, /* DMA */
- { NULL, NULL, hw_ide_interrupt_ports }, /* interrupt */
- { generic_device_unit_decode,
- generic_device_unit_encode,
- generic_device_address_to_attach_address,
- generic_device_size_to_attach_size },
- };
- static void *
- hw_ide_create(const char *name,
- const device_unit *unit_address,
- const char *args)
- {
- hw_ide_device *ide = ZALLOC(hw_ide_device);
- return ide;
- }
- const device_descriptor hw_ide_device_descriptor[] = {
- { "ide", hw_ide_create, &hw_ide_callbacks },
- { NULL, },
- };
- #endif /* _HW_IDE_ */
|