2 * Copyright 2002/03, Thomas Kurschel. All rights reserved.
3 * Distributed under the terms of the MIT License.
7 IDE ISA controller driver
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.
15 #include <KernelExport.h>
21 #include <ide_types.h>
22 #include <device_manager.h>
25 //#define TRACE_IDE_ISA
27 # define TRACE(x...) dprintf("ide_isa: " x)
29 # define TRACE(x...) ;
33 #define IDE_ISA_MODULE_NAME "busses/ide/ide_isa/driver_v1"
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"
41 #define IDE_ISA_INTNUM "ide_isa/irq"
44 ide_for_controller_interface
*ide
;
45 device_manager_info
*pnp
;
48 // info about one channel
49 typedef 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
55 uint32 lost
; // != 0 if device got removed, i.e. if it must not
56 // be accessed anymore
58 ide_channel ide_channel
;
63 /*! publish node of an ide channel */
65 publish_channel(device_node
*parent
, uint16 command_block_base
,
66 uint16 control_block_base
, uint8 intnum
, const char *name
)
68 device_attr attrs
[] = {
69 { B_DEVICE_FIXED_CHILD
, B_STRING_TYPE
, { string
: IDE_FOR_CONTROLLER_MODULE_NAME
}},
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
}},
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
}},
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
}},
89 io_resource resources
[3] = {
90 { B_IO_PORT
, command_block_base
, 8 },
91 { B_IO_PORT
, control_block_base
, 1 },
95 TRACE("publishing %s, resources %#x %#x %d\n",
96 name
, command_block_base
, control_block_base
, intnum
);
98 return pnp
->register_node(parent
, IDE_ISA_MODULE_NAME
, attrs
, resources
,
107 set_channel(void *cookie
, ide_channel ideChannel
)
109 channel_info
*channel
= cookie
;
110 channel
->ide_channel
= ideChannel
;
115 write_command_block_regs(void *channel_cookie
, ide_task_file
*tf
,
118 channel_info
*channel
= channel_cookie
;
119 uint16 ioaddr
= channel
->command_block_base
;
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]);
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
]);
143 read_command_block_regs(void *channel_cookie
, ide_task_file
*tf
,
146 channel_info
*channel
= channel_cookie
;
147 uint16 ioaddr
= channel
->command_block_base
;
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
]);
165 get_altstatus(void *channel_cookie
)
167 channel_info
*channel
= channel_cookie
;
168 uint16 altstatusaddr
= channel
->control_block_base
;
173 return channel
->isa
->read_io_8(altstatusaddr
);
178 write_device_control(void *channel_cookie
, uint8 val
)
180 channel_info
*channel
= channel_cookie
;
181 uint16 device_control_addr
= channel
->control_block_base
;
183 TRACE("write_device_control(%x)\n", (int)val
);
188 channel
->isa
->write_io_8(device_control_addr
, val
);
195 write_pio_16(void *channel_cookie
, uint16
*data
, int count
, bool force_16bit
)
197 channel_info
*channel
= channel_cookie
;
198 uint16 ioaddr
= channel
->command_block_base
;
203 // Bochs doesn't support 32 bit accesses;
204 // no real performance impact as this driver is for Bochs only anyway
207 if ((count
& 1) != 0 || force_16bit
) {
208 for (; count
> 0; --count
)
209 channel
->isa
->write_io_16(ioaddr
, *(data
++));
211 uint32
*cur_data
= (uint32
*)data
;
213 for (; count
> 0; count
-= 2)
214 channel
->isa
->write_io_32(ioaddr
, *(cur_data
++));
222 read_pio_16(void *channel_cookie
, uint16
*data
, int count
, bool force_16bit
)
224 channel_info
*channel
= channel_cookie
;
225 uint16 ioaddr
= channel
->command_block_base
;
232 if ((count
& 1) != 0 || force_16bit
) {
233 for (; count
> 0; --count
)
234 *(data
++) = channel
->isa
->read_io_16(ioaddr
);
236 uint32
*cur_data
= (uint32
*)data
;
238 for (; count
> 0; count
-= 2)
239 *(cur_data
++) = channel
->isa
->read_io_32(ioaddr
);
249 channel_info
*channel
= (channel_info
*)arg
;
252 TRACE("interrupt handler()\n");
255 return B_UNHANDLED_INTERRUPT
;
258 status
= channel
->isa
->read_io_8(channel
->command_block_base
+ 7);
260 return ide
->irq_handler(channel
->ide_channel
, status
);
265 prepare_dma(void *channel_cookie
, const physical_entry
*sg_list
,
266 size_t sg_list_count
, bool write
)
268 return B_NOT_ALLOWED
;
273 start_dma(void *channel_cookie
)
275 return B_NOT_ALLOWED
;
280 finish_dma(void *channel_cookie
)
282 return B_NOT_ALLOWED
;
290 supports_device(device_node
*parent
)
294 // make sure parent is really the ISA bus manager
295 if (pnp
->get_attr_string(parent
, B_DEVICE_BUS
, &bus
, false))
298 if (strcmp(bus
, "isa"))
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 ;)
310 init_channel(device_node
*node
, void **_cookie
)
312 channel_info
*channel
;
314 isa2_module_info
*isa
;
315 uint16 command_block_base
, control_block_base
;
319 TRACE("ISA-IDE: channel init\n");
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
)
327 parent
= pnp
->get_parent_node(node
);
328 pnp
->get_driver(parent
, (driver_module_info
**)&isa
, NULL
);
329 pnp
->put_node(parent
);
331 channel
= (channel_info
*)malloc(sizeof(channel_info
));
335 TRACE("ISA-IDE: channel init, resources %#x %#x %d\n",
336 command_block_base
, control_block_base
, irq
);
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
;
346 res
= install_io_interrupt_handler(channel
->intnum
,
347 inthand
, channel
, 0);
350 TRACE("ISA-IDE: couldn't install irq handler for int %d\n", irq
);
354 // enable interrupts so the channel is ready to run
355 write_device_control(channel
, ide_devctrl_bit3
);
367 uninit_channel(void *channel_cookie
)
369 channel_info
*channel
= channel_cookie
;
371 TRACE("ISA-IDE: channel uninit\n");
374 write_device_control(channel
, ide_devctrl_bit3
| ide_devctrl_nien
);
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)
381 remove_io_interrupt_handler(channel
->intnum
, inthand
, channel
);
388 register_device(device_node
*parent
)
390 status_t primaryStatus
;
391 status_t secondaryStatus
;
392 TRACE("register_device()\n");
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");
401 if (primaryStatus
== B_OK
|| secondaryStatus
== B_OK
)
404 return primaryStatus
;
409 channel_removed(void *cookie
)
411 channel_info
*channel
= cookie
;
412 TRACE("channel_removed()\n");
414 // disable access instantly
415 atomic_or(&channel
->lost
, 1);
419 module_dependency module_dependencies
[] = {
420 { IDE_FOR_CONTROLLER_MODULE_NAME
, (module_info
**)&ide
},
421 { B_DEVICE_MANAGER_MODULE_NAME
, (module_info
**)&pnp
},
425 // exported interface
426 static ide_controller_interface sISAControllerInterface
= {
438 NULL
, // register child devices
445 &write_command_block_regs
,
446 &read_command_block_regs
,
449 &write_device_control
,
459 module_info
*modules
[] = {
460 (module_info
*)&sISAControllerInterface
,