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