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
publish_channel(device_node * parent,uint16 command_block_base,uint16 control_block_base,uint8 intnum,const char * name)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 { 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
103 static void
set_channel(void * cookie,ata_channel ataChannel)104 set_channel(void *cookie, ata_channel ataChannel)
105 {
106 channel_info *channel = cookie;
107 channel->ataChannel = ataChannel;
108 }
109
110
111 static status_t
write_command_block_regs(void * channel_cookie,ata_task_file * tf,ata_reg_mask mask)112 write_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
139 static status_t
read_command_block_regs(void * channel_cookie,ata_task_file * tf,ata_reg_mask mask)140 read_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
161 static uint8
get_altstatus(void * channel_cookie)162 get_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
174 static status_t
write_device_control(void * channel_cookie,uint8 val)175 write_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
191 static status_t
write_pio_16(void * channel_cookie,uint16 * data,int count,bool force_16bit)192 write_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
218 static status_t
read_pio_16(void * channel_cookie,uint16 * data,int count,bool force_16bit)219 read_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
243 static int32
inthand(void * arg)244 inthand(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
261 static status_t
prepare_dma(void * channel_cookie,const physical_entry * sg_list,size_t sg_list_count,bool write)262 prepare_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
269 static status_t
start_dma(void * channel_cookie)270 start_dma(void *channel_cookie)
271 {
272 return B_NOT_ALLOWED;
273 }
274
275
276 static status_t
finish_dma(void * channel_cookie)277 finish_dma(void *channel_cookie)
278 {
279 return B_NOT_ALLOWED;
280 }
281
282
283 // #pragma mark -
284
285
286 static float
supports_device(device_node * parent)287 supports_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
306 static status_t
init_channel(device_node * node,void ** _cookie)307 init_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
357 err:
358 free(channel);
359 return res;
360 }
361
362
363 static void
uninit_channel(void * channel_cookie)364 uninit_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
384 static status_t
register_device(device_node * parent)385 register_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
405 static void
channel_removed(void * cookie)406 channel_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
416 module_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
423 static 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
456 module_info *modules[] = {
457 (module_info *)&sISAControllerInterface,
458 NULL
459 };
460