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