Minor spelling fix in ChangeLog.
[external/binutils.git] / sim / ppc / hw_ide.c
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_ */