📄 hw_ide.c
字号:
| (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 voiddo_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 unsigned8get_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 voiddecode_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 voidbuild_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 voidhw_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 voidhw_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 unsignedhw_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 unsignedhw_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_ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -