1/* 2 * Copyright 2002/03, Thomas Kurschel. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6/* 7 IDE ISA controller driver 8 9 This is a testing-only driver. In reality, you want to use 10 the IDE PCI controller driver, but at least under Bochs, there's not 11 much choice as PCI support is very limited there. 12*/ 13 14 15#include <KernelExport.h> 16#include <stdlib.h> 17#include <string.h> 18 19#include <bus/ISA.h> 20#include <bus/IDE.h> 21#include <ide_types.h> 22#include <device_manager.h> 23 24 25//#define TRACE_IDE_ISA 26#ifdef TRACE_IDE_ISA 27# define TRACE(x...) dprintf("ide_isa: " x) 28#else 29# define TRACE(x...) ; 30#endif 31 32 33#define IDE_ISA_MODULE_NAME "busses/ide/ide_isa/driver_v1" 34 35// private node item: 36// io address of command block 37#define IDE_ISA_COMMAND_BLOCK_BASE "ide_isa/command_block_base" 38// io address of control block 39#define IDE_ISA_CONTROL_BLOCK_BASE "ide_isa/control_block_base" 40// interrupt number 41#define IDE_ISA_INTNUM "ide_isa/irq" 42 43 44ide_for_controller_interface *ide; 45device_manager_info *pnp; 46 47 48// info about one channel 49typedef struct channel_info { 50 isa2_module_info *isa; 51 uint16 command_block_base; // io address command block 52 uint16 control_block_base; // io address control block 53 int intnum; // interrupt number 54 55 uint32 lost; // != 0 if device got removed, i.e. if it must not 56 // be accessed anymore 57 58 ide_channel ide_channel; 59 device_node *node; 60} channel_info; 61 62 63/*! publish node of an ide channel */ 64static status_t 65publish_channel(device_node *parent, uint16 command_block_base, 66 uint16 control_block_base, uint8 intnum, const char *name) 67{ 68 device_attr attrs[] = { 69 { B_DEVICE_FIXED_CHILD, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }}, 70 71 // properties of this controller for ide bus manager 72 { IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: 2 }}, 73 { IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: 0 }}, 74 { IDE_CONTROLLER_CAN_CQ_ITEM, B_UINT8_TYPE, { ui8: 1 }}, 75 { IDE_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE, { string: name }}, 76 77 // DMA properties; the 16 bit alignment is not necessary as 78 // the ide bus manager handles that very efficiently, but why 79 // not use the block device manager for doing that? 80 { B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1 }}, 81 { B_DMA_HIGH_ADDRESS, B_UINT64_TYPE, { ui64: 0x100000000LL }}, 82 83 // private data to identify device 84 { IDE_ISA_COMMAND_BLOCK_BASE, B_UINT16_TYPE, { ui16: command_block_base }}, 85 { IDE_ISA_CONTROL_BLOCK_BASE, B_UINT16_TYPE, { ui16: control_block_base }}, 86 { IDE_ISA_INTNUM, B_UINT8_TYPE, { ui8: intnum }}, 87 { NULL } 88 }; 89 io_resource resources[3] = { 90 { B_IO_PORT, command_block_base, 8 }, 91 { B_IO_PORT, control_block_base, 1 }, 92 {} 93 }; 94 95 TRACE("publishing %s, resources %#x %#x %d\n", 96 name, command_block_base, control_block_base, intnum); 97 98 return pnp->register_node(parent, IDE_ISA_MODULE_NAME, attrs, resources, 99 NULL); 100} 101 102 103// #pragma mark - 104 105 106static void 107set_channel(void *cookie, ide_channel ideChannel) 108{ 109 channel_info *channel = cookie; 110 channel->ide_channel = ideChannel; 111} 112 113 114static status_t 115write_command_block_regs(void *channel_cookie, ide_task_file *tf, 116 ide_reg_mask mask) 117{ 118 channel_info *channel = channel_cookie; 119 uint16 ioaddr = channel->command_block_base; 120 int i; 121 122 if (channel->lost) 123 return B_ERROR; 124 125 for (i = 0; i < 7; i++) { 126 if (((1 << (i-7)) & mask) != 0) { 127 TRACE("write_command_block_regs(): %x->HI(%x)\n", 128 tf->raw.r[i + 7], i); 129 channel->isa->write_io_8(ioaddr + 1 + i, tf->raw.r[i + 7]); 130 } 131 132 if (((1 << i) & mask) != 0 ) { 133 TRACE("write_comamnd_block_regs(): %x->LO(%x)\n", tf->raw.r[i], i); 134 channel->isa->write_io_8(ioaddr + 1 + i, tf->raw.r[i]); 135 } 136 } 137 138 return B_OK; 139} 140 141 142static status_t 143read_command_block_regs(void *channel_cookie, ide_task_file *tf, 144 ide_reg_mask mask) 145{ 146 channel_info *channel = channel_cookie; 147 uint16 ioaddr = channel->command_block_base; 148 int i; 149 150 if (channel->lost) 151 return B_ERROR; 152 153 for (i = 0; i < 7; i++) { 154 if (((1 << i) & mask) != 0) { 155 tf->raw.r[i] = channel->isa->read_io_8(ioaddr + 1 + i); 156 TRACE("read_command_block_regs(%x): %x\n", i, (int)tf->raw.r[i]); 157 } 158 } 159 160 return B_OK; 161} 162 163 164static uint8 165get_altstatus(void *channel_cookie) 166{ 167 channel_info *channel = channel_cookie; 168 uint16 altstatusaddr = channel->control_block_base; 169 170 if (channel->lost) 171 return B_ERROR; 172 173 return channel->isa->read_io_8(altstatusaddr); 174} 175 176 177static status_t 178write_device_control(void *channel_cookie, uint8 val) 179{ 180 channel_info *channel = channel_cookie; 181 uint16 device_control_addr = channel->control_block_base; 182 183 TRACE("write_device_control(%x)\n", (int)val); 184 185 if (channel->lost) 186 return B_ERROR; 187 188 channel->isa->write_io_8(device_control_addr, val); 189 190 return B_OK; 191} 192 193 194static status_t 195write_pio_16(void *channel_cookie, uint16 *data, int count, bool force_16bit) 196{ 197 channel_info *channel = channel_cookie; 198 uint16 ioaddr = channel->command_block_base; 199 200 if (channel->lost) 201 return B_ERROR; 202 203 // Bochs doesn't support 32 bit accesses; 204 // no real performance impact as this driver is for Bochs only anyway 205 force_16bit = true; 206 207 if ((count & 1) != 0 || force_16bit) { 208 for (; count > 0; --count) 209 channel->isa->write_io_16(ioaddr, *(data++)); 210 } else { 211 uint32 *cur_data = (uint32 *)data; 212 213 for (; count > 0; count -= 2) 214 channel->isa->write_io_32(ioaddr, *(cur_data++)); 215 } 216 217 return B_OK; 218} 219 220 221static status_t 222read_pio_16(void *channel_cookie, uint16 *data, int count, bool force_16bit) 223{ 224 channel_info *channel = channel_cookie; 225 uint16 ioaddr = channel->command_block_base; 226 227 if (channel->lost) 228 return B_ERROR; 229 230 force_16bit = true; 231 232 if ((count & 1) != 0 || force_16bit) { 233 for (; count > 0; --count) 234 *(data++) = channel->isa->read_io_16(ioaddr); 235 } else { 236 uint32 *cur_data = (uint32 *)data; 237 238 for (; count > 0; count -= 2) 239 *(cur_data++) = channel->isa->read_io_32(ioaddr); 240 } 241 242 return B_OK; 243} 244 245 246static int32 247inthand(void *arg) 248{ 249 channel_info *channel = (channel_info *)arg; 250 uint8 status; 251 252 TRACE("interrupt handler()\n"); 253 254 if (channel->lost) 255 return B_UNHANDLED_INTERRUPT; 256 257 // acknowledge IRQ 258 status = channel->isa->read_io_8(channel->command_block_base + 7); 259 260 return ide->irq_handler(channel->ide_channel, status); 261} 262 263 264static status_t 265prepare_dma(void *channel_cookie, const physical_entry *sg_list, 266 size_t sg_list_count, bool write) 267{ 268 return B_NOT_ALLOWED; 269} 270 271 272static status_t 273start_dma(void *channel_cookie) 274{ 275 return B_NOT_ALLOWED; 276} 277 278 279static status_t 280finish_dma(void *channel_cookie) 281{ 282 return B_NOT_ALLOWED; 283} 284 285 286// #pragma mark - 287 288 289static float 290supports_device(device_node *parent) 291{ 292 const char *bus; 293 294 // make sure parent is really the ISA bus manager 295 if (pnp->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 296 return B_ERROR; 297 298 if (strcmp(bus, "isa")) 299 return 0.0; 300 301 // we assume that every modern PC has an IDE controller, so no 302 // further testing is done (well - I don't really know how to detect the 303 // controller, but who cares ;) 304 305 return 0.6; 306} 307 308 309static status_t 310init_channel(device_node *node, void **_cookie) 311{ 312 channel_info *channel; 313 device_node *parent; 314 isa2_module_info *isa; 315 uint16 command_block_base, control_block_base; 316 uint8 irq; 317 status_t res; 318 319 TRACE("ISA-IDE: channel init\n"); 320 321 // get device data 322 if (pnp->get_attr_uint16(node, IDE_ISA_COMMAND_BLOCK_BASE, &command_block_base, false) != B_OK 323 || pnp->get_attr_uint16(node, IDE_ISA_CONTROL_BLOCK_BASE, &control_block_base, false) != B_OK 324 || pnp->get_attr_uint8(node, IDE_ISA_INTNUM, &irq, false) != B_OK) 325 return B_ERROR; 326 327 parent = pnp->get_parent_node(node); 328 pnp->get_driver(parent, (driver_module_info **)&isa, NULL); 329 pnp->put_node(parent); 330 331 channel = (channel_info *)malloc(sizeof(channel_info)); 332 if (channel == NULL) 333 return B_NO_MEMORY; 334 335 TRACE("ISA-IDE: channel init, resources %#x %#x %d\n", 336 command_block_base, control_block_base, irq); 337 338 channel->isa = isa; 339 channel->node = node; 340 channel->lost = false; 341 channel->command_block_base = command_block_base; 342 channel->control_block_base = control_block_base; 343 channel->intnum = irq; 344 channel->ide_channel = NULL; 345 346 res = install_io_interrupt_handler(channel->intnum, 347 inthand, channel, 0); 348 349 if (res < 0) { 350 TRACE("ISA-IDE: couldn't install irq handler for int %d\n", irq); 351 goto err; 352 } 353 354 // enable interrupts so the channel is ready to run 355 write_device_control(channel, ide_devctrl_bit3); 356 357 *_cookie = channel; 358 return B_OK; 359 360err: 361 free(channel); 362 return res; 363} 364 365 366static void 367uninit_channel(void *channel_cookie) 368{ 369 channel_info *channel = channel_cookie; 370 371 TRACE("ISA-IDE: channel uninit\n"); 372 373 // disable IRQs 374 write_device_control(channel, ide_devctrl_bit3 | ide_devctrl_nien); 375 376 // catch spurious interrupt 377 // (some controllers generate an IRQ when you _disable_ interrupts, 378 // they are delayed by less then 40 µs, so 1 ms is safe) 379 snooze(1000); 380 381 remove_io_interrupt_handler(channel->intnum, inthand, channel); 382 383 free(channel); 384} 385 386 387static status_t 388register_device(device_node *parent) 389{ 390 status_t primaryStatus; 391 status_t secondaryStatus; 392 TRACE("register_device()\n"); 393 394 // our parent device is the isa bus and all device drivers are Universal, 395 // so the pnp_manager tries each ISA driver in turn 396 primaryStatus = publish_channel(parent, 0x1f0, 0x3f6, 14, 397 "primary IDE channel"); 398 secondaryStatus = publish_channel(parent, 0x170, 0x376, 15, 399 "secondary IDE channel"); 400 401 if (primaryStatus == B_OK || secondaryStatus == B_OK) 402 return B_OK; 403 404 return primaryStatus; 405} 406 407 408static void 409channel_removed(void *cookie) 410{ 411 channel_info *channel = cookie; 412 TRACE("channel_removed()\n"); 413 414 // disable access instantly 415 atomic_or(&channel->lost, 1); 416} 417 418 419module_dependency module_dependencies[] = { 420 { IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide }, 421 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, 422 {} 423}; 424 425// exported interface 426static ide_controller_interface sISAControllerInterface = { 427 { 428 { 429 IDE_ISA_MODULE_NAME, 430 0, 431 NULL 432 }, 433 434 supports_device, 435 register_device, 436 init_channel, 437 uninit_channel, 438 NULL, // register child devices 439 NULL, // rescan 440 channel_removed, 441 }, 442 443 &set_channel, 444 445 &write_command_block_regs, 446 &read_command_block_regs, 447 448 &get_altstatus, 449 &write_device_control, 450 451 &write_pio_16, 452 &read_pio_16, 453 454 &prepare_dma, 455 &start_dma, 456 &finish_dma, 457}; 458 459module_info *modules[] = { 460 (module_info *)&sISAControllerInterface, 461 NULL 462}; 463