BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / busses / ide / ide_isa / ide_isa.c
bloba846496456584fc2516d40719bbdf7bfd52a371c
1 /*
2 * Copyright 2002/03, Thomas Kurschel. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
6 /*
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>
16 #include <stdlib.h>
17 #include <string.h>
19 #include <bus/ISA.h>
20 #include <bus/IDE.h>
21 #include <ide_types.h>
22 #include <device_manager.h>
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
33 #define IDE_ISA_MODULE_NAME "busses/ide/ide_isa/driver_v1"
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"
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;
59 device_node *node;
60 } channel_info;
63 /*! publish node of an ide channel */
64 static status_t
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 }},
87 { NULL }
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,
99 NULL);
103 // #pragma mark -
106 static void
107 set_channel(void *cookie, ide_channel ideChannel)
109 channel_info *channel = cookie;
110 channel->ide_channel = ideChannel;
114 static status_t
115 write_command_block_regs(void *channel_cookie, ide_task_file *tf,
116 ide_reg_mask mask)
118 channel_info *channel = channel_cookie;
119 uint16 ioaddr = channel->command_block_base;
120 int i;
122 if (channel->lost)
123 return B_ERROR;
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]);
138 return B_OK;
142 static status_t
143 read_command_block_regs(void *channel_cookie, ide_task_file *tf,
144 ide_reg_mask mask)
146 channel_info *channel = channel_cookie;
147 uint16 ioaddr = channel->command_block_base;
148 int i;
150 if (channel->lost)
151 return B_ERROR;
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]);
160 return B_OK;
164 static uint8
165 get_altstatus(void *channel_cookie)
167 channel_info *channel = channel_cookie;
168 uint16 altstatusaddr = channel->control_block_base;
170 if (channel->lost)
171 return B_ERROR;
173 return channel->isa->read_io_8(altstatusaddr);
177 static status_t
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);
185 if (channel->lost)
186 return B_ERROR;
188 channel->isa->write_io_8(device_control_addr, val);
190 return B_OK;
194 static status_t
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;
200 if (channel->lost)
201 return B_ERROR;
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;
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;
213 for (; count > 0; count -= 2)
214 channel->isa->write_io_32(ioaddr, *(cur_data++));
217 return B_OK;
221 static status_t
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;
227 if (channel->lost)
228 return B_ERROR;
230 force_16bit = true;
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;
238 for (; count > 0; count -= 2)
239 *(cur_data++) = channel->isa->read_io_32(ioaddr);
242 return B_OK;
246 static int32
247 inthand(void *arg)
249 channel_info *channel = (channel_info *)arg;
250 uint8 status;
252 TRACE("interrupt handler()\n");
254 if (channel->lost)
255 return B_UNHANDLED_INTERRUPT;
257 // acknowledge IRQ
258 status = channel->isa->read_io_8(channel->command_block_base + 7);
260 return ide->irq_handler(channel->ide_channel, status);
264 static status_t
265 prepare_dma(void *channel_cookie, const physical_entry *sg_list,
266 size_t sg_list_count, bool write)
268 return B_NOT_ALLOWED;
272 static status_t
273 start_dma(void *channel_cookie)
275 return B_NOT_ALLOWED;
279 static status_t
280 finish_dma(void *channel_cookie)
282 return B_NOT_ALLOWED;
286 // #pragma mark -
289 static float
290 supports_device(device_node *parent)
292 const char *bus;
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;
298 if (strcmp(bus, "isa"))
299 return 0.0;
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 ;)
305 return 0.6;
309 static status_t
310 init_channel(device_node *node, void **_cookie)
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;
319 TRACE("ISA-IDE: channel init\n");
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;
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));
332 if (channel == NULL)
333 return B_NO_MEMORY;
335 TRACE("ISA-IDE: channel init, resources %#x %#x %d\n",
336 command_block_base, control_block_base, irq);
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;
346 res = install_io_interrupt_handler(channel->intnum,
347 inthand, channel, 0);
349 if (res < 0) {
350 TRACE("ISA-IDE: couldn't install irq handler for int %d\n", irq);
351 goto err;
354 // enable interrupts so the channel is ready to run
355 write_device_control(channel, ide_devctrl_bit3);
357 *_cookie = channel;
358 return B_OK;
360 err:
361 free(channel);
362 return res;
366 static void
367 uninit_channel(void *channel_cookie)
369 channel_info *channel = channel_cookie;
371 TRACE("ISA-IDE: channel uninit\n");
373 // disable IRQs
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)
379 snooze(1000);
381 remove_io_interrupt_handler(channel->intnum, inthand, channel);
383 free(channel);
387 static status_t
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)
402 return B_OK;
404 return primaryStatus;
408 static void
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 = {
429 IDE_ISA_MODULE_NAME,
431 NULL
434 supports_device,
435 register_device,
436 init_channel,
437 uninit_channel,
438 NULL, // register child devices
439 NULL, // rescan
440 channel_removed,
443 &set_channel,
445 &write_command_block_regs,
446 &read_command_block_regs,
448 &get_altstatus,
449 &write_device_control,
451 &write_pio_16,
452 &read_pio_16,
454 &prepare_dma,
455 &start_dma,
456 &finish_dma,
459 module_info *modules[] = {
460 (module_info *)&sISAControllerInterface,
461 NULL