xref: /netbsd-src/external/gpl3/gdb/dist/sim/ppc/hw_ide.c (revision 6de51c519f1b899da63c1bf576f478920b89083f)
1 /*  This file is part of the program psim.
2 
3     Copyright (C) 1996, Andrew Cagney <cagney@highland.com.au>
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 
19     */
20 
21 
22 #ifndef _HW_IDE_C_
23 #define _HW_IDE_C_
24 
25 #include "device_table.h"
26 
27 
28 
29 /* DEVICE
30 
31 
32    ide - Integrated Disk Electronics
33 
34 
35    DESCRIPTION
36 
37 
38    This device models the primary/secondary <<ide>> controller
39    described in the [CHRPIO] document.
40 
41    The controller has separate independant interrupt outputs for each
42    <<ide>> bus.
43 
44 
45    PROPERTIES
46 
47 
48    reg = ...  (required)
49 
50    The <<reg>> property is described in the document [CHRPIO].
51 
52 
53    ready-delay = <integer>  (optional)
54 
55    If present, this specifies the time that the <<ide>> device takes
56    to complete an I/O operation.
57 
58 
59    disk@?/ide-byte-count = <integer>  (optional)
60 
61    disk@?/ide-sector-count = <integer>  (optional)
62 
63    disk@?/ide-head-count = <integer>  (optional)
64 
65    The <<ide>> device checks each child (disk device) node to see if
66    it has the above properties.  If present, these values will be used
67    to compute the <<LBA>> address in <<CHS>> addressing mode.
68 
69 
70    EXAMPLES
71 
72 
73    Enable tracing:
74 
75    |  -t ide-device \
76 
77 
78    Attach the <<ide>> device to the <<pci>> bus at slot one.  Specify
79    legacy I/O addresses:
80 
81    |  -o '/phb/ide@1/assigned-addresses \
82    |        ni0,0,10,1f0 8 \
83    |        ni0,0,14,3f8 8 \
84    |        ni0,0,18,170 8 \
85    |        ni0,0,1c,378 8 \
86    |        ni0,0,20,200 8' \
87    |  -o '/phb@0x80000000/ide@1/reg \
88    |        1 0 \
89    |        i0,0,10,0 8 \
90    |        i0,0,18,0 8 \
91    |        i0,0,14,6 1 \
92    |        i0,0,1c,6 1 \
93    |        i0,0,20,0 8' \
94 
95    Note: the fouth and fifth reg entries specify that the register is
96    at an offset into the address specified by the base register
97    (<<assigned-addresses>>); Apart from restrictions placed by the
98    <<pci>> specification, no restrictions are placed on the number of
99    base registers specified by the <<assigned-addresses>> property.
100 
101    Attach a <<disk>> to the primary and a <<cdrom>> to the secondary
102    <<ide>> controller.
103 
104    |  -o '/phb@0x80000000/ide@1/disk@0/file "zero' \
105    |  -o '/phb@0x80000000/ide@1/cdrom@2/file "/dev/cdrom"' \
106 
107    Connect the two interrupt outputs (a and b) to a <<glue>> device to
108    allow testing of the interrupt port. In a real simulation they
109    would be wired to the interrupt controller.
110 
111    |  -o '/phb@0x80000000/glue@2/reg 2 0 ni0,0,0,0 8' \
112    |  -o '/phb@0x80000000/ide@1 > a 0 /phb@0x80000000/glue@2' \
113    |  -o '/phb@0x80000000/ide@1 > b 1 /phb@0x80000000/glue@2'
114 
115 
116    BUGS
117 
118 
119    While the DMA registers are present, DMA support has not yet been
120    implemented.
121 
122    The number of supported commands is very limited.
123 
124    The standards documents appear to be vague on how to specify the
125    <<unit-address>> of disk devices devices being attached to the
126    <<ide>> controller.  I've chosen to use integers with devices zero
127    and one going to the primary controller while two and three are
128    connected to the secondary controller.
129 
130 
131    REFERENCES
132 
133 
134    [CHRPIO] PowerPC(tm) Microprocessor Common Hardware Reference
135    Platform: I/O Device Reference.  http://chrp.apple.com/???.
136 
137    [SCHMIDT] The SCSI Bus and IDE Interface - Protocols, Applications
138    and Programming.  Friedhelm Schmidt (translated by Michael
139    Schultz).  ISBN 0-201-42284-0.  Addison-Wesley Publishing Company.
140 
141 
142    */
143 
144 
145 
146 typedef enum _io_direction {
147   is_read,
148   is_write,
149 } io_direction;
150 
151 
152 enum {
153   nr_ide_controllers = 2,
154   nr_ide_drives_per_controller = 2,
155   nr_fifo_entries = 8192,
156 };
157 
158 enum {
159   /* command register block - read */
160   ide_data_reg,
161   ide_error_reg, /*ide_feature_reg*/
162   ide_sector_count_reg,
163   ide_sector_number_reg,
164   ide_cylinder_reg0,
165   ide_cylinder_reg1,
166   ide_drive_head_reg,
167   ide_status_reg, /*ide_command_reg*/
168   /* command register block - write */
169   ide_feature_reg, /*ide_error_reg*/
170   ide_command_reg, /*ide_status_reg*/
171   /* control register block - read */
172   ide_alternate_status_reg, /*ide_control_reg*/
173   ide_control_reg, /*ide_alternate_status_reg*/
174   /* dma register block */
175   ide_dma_command_reg,
176   ide_dma_unused_1_reg,
177   ide_dma_status_reg,
178   ide_dma_unused_3_reg,
179   ide_dma_prd_table_address_reg0,
180   ide_dma_prd_table_address_reg1,
181   ide_dma_prd_table_address_reg2,
182   ide_dma_prd_table_address_reg3,
183   nr_ide_registers,
184 };
185 
186 
187 typedef enum _ide_states {
188   idle_state,
189   busy_loaded_state,
190   busy_drained_state,
191   busy_dma_state,
192   busy_command_state,
193   loading_state,
194   draining_state,
195 } ide_states;
196 
197 static const char *
198 ide_state_name(ide_states state)
199 {
200   switch (state) {
201   case idle_state: return "idle";
202   case busy_loaded_state: return "busy_loaded_state";
203   case busy_drained_state: return "busy_drained_state";
204   case busy_dma_state: return "busy_dma_state";
205   case busy_command_state: return "busy_command_state";
206   case loading_state: return "loading_state";
207   case draining_state: return "draining_state";
208   default: return "illegal-state";
209   }
210 }
211 
212 typedef struct _ide_geometry {
213   int head;
214   int sector;
215   int byte;
216 } ide_geometry;
217 
218 typedef struct _ide_drive {
219   int nr;
220   device *device;
221   ide_geometry geometry;
222   ide_geometry default_geometry;
223 } ide_drive;
224 
225 typedef struct _ide_controller {
226   int nr;
227   ide_states state;
228   unsigned8 reg[nr_ide_registers];
229   unsigned8 fifo[nr_fifo_entries];
230   int fifo_pos;
231   int fifo_size;
232   ide_drive *current_drive;
233   int current_byte;
234   int current_transfer;
235   ide_drive drive[nr_ide_drives_per_controller];
236   device *me;
237   event_entry_tag event_tag;
238   int is_interrupting;
239   signed64 ready_delay;
240 } ide_controller;
241 
242 
243 
244 static void
245 set_interrupt(device *me,
246 	      ide_controller *controller)
247 {
248   if ((controller->reg[ide_control_reg] & 0x2) == 0) {
249     DTRACE(ide, ("controller %d - interrupt set\n", controller->nr));
250     device_interrupt_event(me, controller->nr, 1, NULL, 0);
251     controller->is_interrupting = 1;
252   }
253 }
254 
255 
256 static void
257 clear_interrupt(device *me,
258 		ide_controller *controller)
259 {
260   if (controller->is_interrupting) {
261     DTRACE(ide, ("controller %d - interrupt clear\n", controller->nr));
262     device_interrupt_event(me, controller->nr, 0, NULL, 0);
263     controller->is_interrupting = 0;
264   }
265 }
266 
267 
268 static void
269 do_event(void *data)
270 {
271   ide_controller *controller = data;
272   device *me = controller->me;
273   controller->event_tag = 0;
274   switch (controller->state) {
275   case busy_loaded_state:
276   case busy_drained_state:
277     if (controller->current_transfer > 0) {
278       controller->state = (controller->state == busy_loaded_state
279 			   ? loading_state : draining_state);
280     }
281     else {
282       controller->state = idle_state;
283     }
284     set_interrupt(me, controller);
285     break;
286   default:
287     device_error(me, "controller %d - unexpected event", controller->nr);
288     break;
289   }
290 }
291 
292 
293 static void
294 schedule_ready_event(device *me,
295 		     ide_controller *controller)
296 {
297   if (controller->event_tag != 0)
298     device_error(me, "controller %d - attempting to schedule multiple events",
299 		 controller->nr);
300   controller->event_tag =
301     device_event_queue_schedule(me, controller->ready_delay,
302 				do_event, controller);
303 }
304 
305 
306 static void
307 do_fifo_read(device *me,
308 	     ide_controller *controller,
309 	     void *dest,
310 	     int nr_bytes)
311 {
312   if (controller->state != draining_state)
313     device_error(me, "controller %d - reading fifo when not ready (%s)",
314 		 controller->nr,
315 		 ide_state_name(controller->state));
316   if (controller->fifo_pos + nr_bytes > controller->fifo_size)
317     device_error(me, "controller %d - fifo underflow", controller->nr);
318   if (nr_bytes > 0) {
319     memcpy(dest, &controller->fifo[controller->fifo_pos], nr_bytes);
320     controller->fifo_pos += nr_bytes;
321   }
322   if (controller->fifo_pos == controller->fifo_size) {
323     controller->current_transfer -= 1;
324     if (controller->current_transfer > 0
325 	&& controller->current_drive != NULL) {
326       DTRACE(ide, ("controller %d:%d - reading %d byte block at 0x%x\n",
327 		   controller->nr,
328 		   controller->current_drive->nr,
329 		   controller->fifo_size,
330 		   controller->current_byte));
331       if (device_io_read_buffer(controller->current_drive->device,
332 				controller->fifo,
333 				0, controller->current_byte,
334 				controller->fifo_size,
335 				NULL, 0)
336 	  != controller->fifo_size)
337 	device_error(me, "controller %d - disk %s io read error",
338 		     controller->nr,
339 		     device_path(controller->current_drive->device));
340     }
341     controller->state = busy_drained_state;
342     controller->fifo_pos = 0;
343     controller->current_byte += controller->fifo_size;
344     schedule_ready_event(me, controller);
345   }
346 }
347 
348 
349 static void
350 do_fifo_write(device *me,
351 	      ide_controller *controller,
352 	      const void *source,
353 	      int nr_bytes)
354 {
355   if (controller->state != loading_state)
356     device_error(me, "controller %d - writing fifo when not ready (%s)",
357 		 controller->nr,
358 		 ide_state_name(controller->state));
359   if (controller->fifo_pos + nr_bytes > controller->fifo_size)
360     device_error(me, "controller %d - fifo overflow", controller->nr);
361   if (nr_bytes > 0) {
362     memcpy(&controller->fifo[controller->fifo_pos], source, nr_bytes);
363     controller->fifo_pos += nr_bytes;
364   }
365   if (controller->fifo_pos == controller->fifo_size) {
366     if (controller->current_transfer > 0
367 	&& controller->current_drive != NULL) {
368       DTRACE(ide, ("controller %d:%d - writing %d byte block at 0x%x\n",
369 		   controller->nr,
370 		   controller->current_drive->nr,
371 		   controller->fifo_size,
372 		   controller->current_byte));
373       if (device_io_write_buffer(controller->current_drive->device,
374 				 controller->fifo,
375 				 0, controller->current_byte,
376 				 controller->fifo_size,
377 				 NULL, 0)
378 	  != controller->fifo_size)
379 	device_error(me, "controller %d - disk %s io write error",
380 		     controller->nr,
381 		     device_path(controller->current_drive->device));
382     }
383     controller->current_transfer -= 1;
384     controller->fifo_pos = 0;
385     controller->current_byte += controller->fifo_size;
386     controller->state = busy_loaded_state;
387     schedule_ready_event(me, controller);
388   }
389 }
390 
391 
392 static void
393 setup_fifo(device *me,
394 	   ide_controller *controller,
395 	   int is_simple,
396 	   int is_with_disk,
397 	   io_direction direction)
398 {
399   /* find the disk */
400   if (is_with_disk) {
401     int drive_nr = (controller->reg[ide_drive_head_reg] & 0x10) != 0;
402     controller->current_drive = &controller->drive[drive_nr];
403   }
404   else {
405     controller->current_drive = NULL;
406   }
407 
408   /* number of transfers */
409   if (is_simple)
410     controller->current_transfer = 1;
411   else {
412     int sector_count = controller->reg[ide_sector_count_reg];
413     if (sector_count == 0)
414       controller->current_transfer = 256;
415     else
416       controller->current_transfer = sector_count;
417   }
418 
419   /* the transfer size */
420   if (controller->current_drive == NULL)
421     controller->fifo_size = 512;
422   else
423     controller->fifo_size = controller->current_drive->geometry.byte;
424 
425   /* empty the fifo */
426   controller->fifo_pos = 0;
427 
428   /* the starting address */
429   if (controller->current_drive == NULL)
430     controller->current_byte = 0;
431   else if (controller->reg[ide_drive_head_reg] & 0x40) {
432     /* LBA addressing mode */
433     controller->current_byte = controller->fifo_size
434       * (((controller->reg[ide_drive_head_reg] & 0xf) << 24)
435 	 | (controller->reg[ide_cylinder_reg1] << 16)
436 	 | (controller->reg[ide_cylinder_reg0] << 8)
437 	 | (controller->reg[ide_sector_number_reg]));
438   }
439   else if (controller->current_drive->geometry.head != 0
440 	   && controller->current_drive->geometry.sector != 0) {
441     /* CHS addressing mode */
442     int head_nr = controller->reg[ide_drive_head_reg] & 0xf;
443     int cylinder_nr = ((controller->reg[ide_cylinder_reg1] << 8)
444 		    | controller->reg[ide_cylinder_reg0]);
445     int sector_nr = controller->reg[ide_sector_number_reg];
446     controller->current_byte = controller->fifo_size
447       * ((cylinder_nr * controller->current_drive->geometry.head + head_nr)
448 	 * controller->current_drive->geometry.sector + sector_nr - 1);
449   }
450   else
451     device_error(me, "controller %d:%d - CHS addressing disabled",
452 		 controller->nr, controller->current_drive->nr);
453   DTRACE(ide, ("controller %ld:%ld - transfer (%s) %ld blocks of %ld bytes from 0x%lx\n",
454 	       (long)controller->nr,
455 	       controller->current_drive == NULL ? -1L : (long)controller->current_drive->nr,
456 	       direction == is_read ? "read" : "write",
457 	       (long)controller->current_transfer,
458 	       (long)controller->fifo_size,
459 	       (unsigned long)controller->current_byte));
460   switch (direction) {
461   case is_read:
462     /* force a primeing read */
463     controller->current_transfer += 1;
464     controller->state = draining_state;
465     controller->fifo_pos = controller->fifo_size;
466     do_fifo_read(me, controller, NULL, 0);
467     break;
468   case is_write:
469     controller->state = loading_state;
470     break;
471   }
472 }
473 
474 
475 static void
476 do_command(device *me,
477 	   ide_controller *controller,
478 	   int command)
479 {
480   if (controller->state != idle_state)
481     device_error(me, "controller %d - command when not idle", controller->nr);
482   switch (command) {
483   case 0x20: case 0x21: /* read-sectors */
484     setup_fifo(me, controller, 0/*is_simple*/, 1/*is_with_disk*/, is_read);
485     break;
486   case 0x30: case 0x31: /* write */
487     setup_fifo(me, controller, 0/*is_simple*/, 1/*is_with_disk*/, is_write);
488     break;
489   }
490 }
491 
492 static unsigned8
493 get_status(device *me,
494 	   ide_controller *controller)
495 {
496   switch (controller->state) {
497   case loading_state:
498   case draining_state:
499     return 0x08; /* data req */
500   case busy_loaded_state:
501   case busy_drained_state:
502     return 0x80; /* busy */
503   case idle_state:
504     return 0x40; /* drive ready */
505   default:
506     device_error(me, "internal error");
507     return 0;
508   }
509 }
510 
511 
512 /* The address presented to the IDE controler is decoded and then
513    mapped onto a controller:reg pair */
514 
515 enum {
516   nr_address_blocks = 6,
517 };
518 
519 typedef struct _address_block {
520   int space;
521   unsigned_word base_addr;
522   unsigned_word bound_addr;
523   int controller;
524   int base_reg;
525 } address_block;
526 
527 typedef struct _address_decoder {
528   address_block block[nr_address_blocks];
529 } address_decoder;
530 
531 static void
532 decode_address(device *me,
533 	       address_decoder *decoder,
534 	       int space,
535 	       unsigned_word address,
536 	       int *controller,
537 	       int *reg,
538 	       io_direction direction)
539 {
540   int i;
541   for (i = 0; i < nr_address_blocks; i++) {
542     if (space == decoder->block[i].space
543 	&& address >= decoder->block[i].base_addr
544 	&& address <= decoder->block[i].bound_addr) {
545       *controller = decoder->block[i].controller;
546       *reg = (address
547 	      - decoder->block[i].base_addr
548 	      + decoder->block[i].base_reg);
549       if (direction == is_write) {
550 	switch (*reg) {
551 	case ide_error_reg: *reg = ide_feature_reg; break;
552 	case ide_status_reg: *reg = ide_command_reg; break;
553 	case ide_alternate_status_reg: *reg = ide_control_reg; break;
554 	default: break;
555 	}
556       }
557       return;
558     }
559   }
560   device_error(me, "address %d:0x%lx invalid",
561 	       space, (unsigned long)address);
562 }
563 
564 
565 static void
566 build_address_decoder(device *me,
567 		      address_decoder *decoder)
568 {
569   int reg;
570   for (reg = 1; reg < 6; reg++) {
571     reg_property_spec unit;
572     int space;
573     unsigned_word address;
574     unsigned size;
575     /* find and decode the reg property */
576     if (!device_find_reg_array_property(me, "reg", reg, &unit))
577       device_error(me, "missing or invalid reg entry %d", reg);
578     device_address_to_attach_address(device_parent(me), &unit.address,
579 				     &space, &address, me);
580     device_size_to_attach_size(device_parent(me), &unit.size, &size, me);
581     /* insert it into the address decoder */
582     switch (reg) {
583     case 1:
584     case 2:
585       /* command register block */
586       if (size != 8)
587 	device_error(me, "reg entry %d must have a size of 8", reg);
588       decoder->block[reg-1].space = space;
589       decoder->block[reg-1].base_addr = address;
590       decoder->block[reg-1].bound_addr = address + size - 1;
591       decoder->block[reg-1].controller = (reg + 1) % nr_ide_controllers;
592       decoder->block[reg-1].base_reg = ide_data_reg;
593       DTRACE(ide, ("controller %d command register block at %d:0x%lx..0x%lx\n",
594 		   decoder->block[reg-1].controller,
595 		   decoder->block[reg-1].space,
596 		   (unsigned long)decoder->block[reg-1].base_addr,
597 		   (unsigned long)decoder->block[reg-1].bound_addr));
598       break;
599     case 3:
600     case 4:
601       /* control register block */
602       if (size != 1)
603 	device_error(me, "reg entry %d must have a size of 1", reg);
604       decoder->block[reg-1].space = space;
605       decoder->block[reg-1].base_addr = address;
606       decoder->block[reg-1].bound_addr = address + size - 1;
607       decoder->block[reg-1].controller = (reg + 1) % nr_ide_controllers;
608       decoder->block[reg-1].base_reg = ide_alternate_status_reg;
609       DTRACE(ide, ("controller %d control register block at %d:0x%lx..0x%lx\n",
610 		   decoder->block[reg-1].controller,
611 		   decoder->block[reg-1].space,
612 		   (unsigned long)decoder->block[reg-1].base_addr,
613 		   (unsigned long)decoder->block[reg-1].bound_addr));
614       break;
615     case 5:
616       /* dma register block */
617       if (size != 8)
618 	device_error(me, "reg entry %d must have a size of 8", reg);
619       decoder->block[reg-1].space = space;
620       decoder->block[reg-1].base_addr = address;
621       decoder->block[reg-1].bound_addr = address + 4 - 1;
622       decoder->block[reg-1].base_reg = ide_dma_command_reg;
623       decoder->block[reg-1].controller = 0;
624       DTRACE(ide, ("controller %d dma register block at %d:0x%lx..0x%lx\n",
625 		   decoder->block[reg-1].controller,
626 		   decoder->block[reg-1].space,
627 		   (unsigned long)decoder->block[reg-1].base_addr,
628 		   (unsigned long)decoder->block[reg-1].bound_addr));
629       decoder->block[reg].space = space;
630       decoder->block[reg].base_addr = address + 4;
631       decoder->block[reg].bound_addr = address + 8 - 1;
632       decoder->block[reg].controller = 1;
633       decoder->block[reg].base_reg = ide_dma_command_reg;
634       DTRACE(ide, ("controller %d dma register block at %d:0x%lx..0x%lx\n",
635 		   decoder->block[reg].controller,
636 		   decoder->block[reg-1].space,
637 		   (unsigned long)decoder->block[reg].base_addr,
638 		   (unsigned long)decoder->block[reg].bound_addr));
639       break;
640     default:
641       device_error(me, "internal error - bad switch");
642       break;
643     }
644   }
645 }
646 
647 
648 
649 typedef struct _hw_ide_device {
650   ide_controller controller[nr_ide_controllers];
651   address_decoder decoder;
652 } hw_ide_device;
653 
654 
655 static void
656 hw_ide_init_address(device *me)
657 {
658   hw_ide_device *ide = device_data(me);
659   int controller;
660   int drive;
661 
662   /* zero some things */
663   for (controller = 0; controller < nr_ide_controllers; controller++) {
664     memset(&ide->controller[controller], 0, sizeof(ide_controller));
665     for (drive = 0; drive < nr_ide_drives_per_controller; drive++) {
666       ide->controller[controller].drive[drive].nr = drive;
667     }
668     ide->controller[controller].me = me;
669     if (device_find_property(me, "ready-delay") != NULL)
670       ide->controller[controller].ready_delay =
671 	device_find_integer_property(me, "ready-delay");
672   }
673 
674   /* attach this device to its parent */
675   generic_device_init_address(me);
676 
677   /* determine our own address map */
678   build_address_decoder(me, &ide->decoder);
679 
680 }
681 
682 
683 static void
684 hw_ide_attach_address(device *me,
685 		      attach_type type,
686 		      int space,
687 		      unsigned_word addr,
688 		      unsigned nr_bytes,
689 		      access_type access,
690 		      device *client) /*callback/default*/
691 {
692   hw_ide_device *ide = (hw_ide_device*)device_data(me);
693   int controller_nr = addr / nr_ide_drives_per_controller;
694   int drive_nr = addr % nr_ide_drives_per_controller;
695   ide_controller *controller;
696   ide_drive *drive;
697   if (controller_nr >= nr_ide_controllers)
698     device_error(me, "no controller for disk %s",
699 		 device_path(client));
700 
701   controller = &ide->controller[controller_nr];
702   drive = &controller->drive[drive_nr];
703   drive->device = client;
704   if (device_find_property(client, "ide-byte-count") != NULL)
705     drive->geometry.byte = device_find_integer_property(client, "ide-byte-count");
706   else
707     drive->geometry.byte = 512;
708   if (device_find_property(client, "ide-sector-count") != NULL)
709     drive->geometry.sector = device_find_integer_property(client, "ide-sector-count");
710   if (device_find_property(client, "ide-head-count") != NULL)
711     drive->geometry.head = device_find_integer_property(client, "ide-head-count");
712   drive->default_geometry = drive->geometry;
713   DTRACE(ide, ("controller %d:%d %s byte-count %d, sector-count %d, head-count %d\n",
714 	       controller_nr,
715 	       drive->nr,
716 	       device_path(client),
717 	       drive->geometry.byte,
718 	       drive->geometry.sector,
719 	       drive->geometry.head));
720 }
721 
722 
723 static unsigned
724 hw_ide_io_read_buffer(device *me,
725 		      void *dest,
726 		      int space,
727 		      unsigned_word addr,
728 		      unsigned nr_bytes,
729 		      cpu *processor,
730 		      unsigned_word cia)
731 {
732   hw_ide_device *ide = (hw_ide_device *)device_data(me);
733   int control_nr;
734   int reg;
735   ide_controller *controller;
736 
737   /* find the interface */
738   decode_address(me, &ide->decoder, space, addr, &control_nr, &reg, is_read);
739   controller = & ide->controller[control_nr];
740 
741   /* process the transfer */
742   memset(dest, 0, nr_bytes);
743   switch (reg) {
744   case ide_data_reg:
745     do_fifo_read(me, controller, dest, nr_bytes);
746     break;
747   case ide_status_reg:
748     *(unsigned8*)dest = get_status(me, controller);
749     clear_interrupt(me, controller);
750     break;
751   case ide_alternate_status_reg:
752     *(unsigned8*)dest = get_status(me, controller);
753     break;
754   case ide_error_reg:
755   case ide_sector_count_reg:
756   case ide_sector_number_reg:
757   case ide_cylinder_reg0:
758   case ide_cylinder_reg1:
759   case ide_drive_head_reg:
760   case ide_control_reg:
761   case ide_dma_command_reg:
762   case ide_dma_status_reg:
763   case ide_dma_prd_table_address_reg0:
764   case ide_dma_prd_table_address_reg1:
765   case ide_dma_prd_table_address_reg2:
766   case ide_dma_prd_table_address_reg3:
767     *(unsigned8*)dest = controller->reg[reg];
768     break;
769   default:
770     device_error(me, "bus-error at address 0x%lx", addr);
771     break;
772   }
773   return nr_bytes;
774 }
775 
776 
777 static unsigned
778 hw_ide_io_write_buffer(device *me,
779 		       const void *source,
780 		       int space,
781 		       unsigned_word addr,
782 		       unsigned nr_bytes,
783 		       cpu *processor,
784 		       unsigned_word cia)
785 {
786   hw_ide_device *ide = (hw_ide_device *)device_data(me);
787   int control_nr;
788   int reg;
789   ide_controller *controller;
790 
791   /* find the interface */
792   decode_address(me, &ide->decoder, space, addr, &control_nr, &reg, is_write);
793   controller = &ide->controller[control_nr];
794 
795   /* process the access */
796   switch (reg) {
797   case ide_data_reg:
798     do_fifo_write(me, controller, source, nr_bytes);
799     break;
800   case ide_command_reg:
801     do_command(me, controller, *(unsigned8*)source);
802     break;
803   case ide_control_reg:
804     controller->reg[reg] = *(unsigned8*)source;
805     /* possibly cancel interrupts */
806     if ((controller->reg[reg] & 0x02) == 0x02)
807       clear_interrupt(me, controller);
808     break;
809   case ide_feature_reg:
810   case ide_sector_count_reg:
811   case ide_sector_number_reg:
812   case ide_cylinder_reg0:
813   case ide_cylinder_reg1:
814   case ide_drive_head_reg:
815   case ide_dma_command_reg:
816   case ide_dma_status_reg:
817   case ide_dma_prd_table_address_reg0:
818   case ide_dma_prd_table_address_reg1:
819   case ide_dma_prd_table_address_reg2:
820   case ide_dma_prd_table_address_reg3:
821     controller->reg[reg] = *(unsigned8*)source;
822     break;
823   default:
824     device_error(me, "bus-error at 0x%lx", addr);
825     break;
826   }
827   return nr_bytes;
828 }
829 
830 
831 static const device_interrupt_port_descriptor hw_ide_interrupt_ports[] = {
832   { "a", 0, 0 },
833   { "b", 1, 0 },
834   { "c", 2, 0 },
835   { "d", 3, 0 },
836   { NULL }
837 };
838 
839 
840 
841 static device_callbacks const hw_ide_callbacks = {
842   { hw_ide_init_address, },
843   { hw_ide_attach_address, }, /* attach */
844   { hw_ide_io_read_buffer, hw_ide_io_write_buffer, },
845   { NULL, }, /* DMA */
846   { NULL, NULL, hw_ide_interrupt_ports }, /* interrupt */
847   { generic_device_unit_decode,
848     generic_device_unit_encode,
849     generic_device_address_to_attach_address,
850     generic_device_size_to_attach_size },
851 };
852 
853 
854 static void *
855 hw_ide_create(const char *name,
856 	      const device_unit *unit_address,
857 	      const char *args)
858 {
859   hw_ide_device *ide = ZALLOC(hw_ide_device);
860   return ide;
861 }
862 
863 
864 const device_descriptor hw_ide_device_descriptor[] = {
865   { "ide", hw_ide_create, &hw_ide_callbacks },
866   { NULL, },
867 };
868 
869 #endif /* _HW_IDE_ */
870