Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


updates to ATAPI packet command support
[palacios.git] / palacios / src / devices / ide.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <devices/ide.h>
22 #include "ide-types.h"
23 #include "atapi-types.h"
24
25 #define PRI_DEFAULT_IRQ 14
26 #define SEC_DEFAULT_IRQ 15
27
28
29 #define PRI_DATA_PORT         0x1f0
30 #define PRI_FEATURES_PORT     0x1f1
31 #define PRI_SECT_CNT_PORT     0x1f2
32 #define PRI_SECT_NUM_PORT     0x1f3
33 #define PRI_CYL_LOW_PORT      0x1f4
34 #define PRI_CYL_HIGH_PORT     0x1f5
35 #define PRI_DRV_SEL_PORT      0x1f6
36 #define PRI_CMD_PORT          0x1f7
37 #define PRI_CTRL_PORT         0x3f6
38 #define PRI_ADDR_REG_PORT     0x3f7
39
40 #define SEC_DATA_PORT         0x170
41 #define SEC_FEATURES_PORT     0x171
42 #define SEC_SECT_CNT_PORT     0x172
43 #define SEC_SECT_NUM_PORT     0x173
44 #define SEC_CYL_LOW_PORT      0x174
45 #define SEC_CYL_HIGH_PORT     0x175
46 #define SEC_DRV_SEL_PORT      0x176
47 #define SEC_CMD_PORT          0x177
48 #define SEC_CTRL_PORT         0x376
49 #define SEC_ADDR_REG_PORT     0x377
50
51
52 #define DATA_BUFFER_SIZE 2048
53
54 static const char * ide_dev_type_strs[] = {"HARDDISK", "CDROM", "NONE"};
55
56
57 static inline const char * device_type_to_str(v3_ide_dev_type_t type) {
58     if (type > 2) {
59         return NULL;
60     }
61
62     return ide_dev_type_strs[type];
63 }
64
65
66
67 struct ide_cd_state {
68     struct atapi_sense_data sense;
69     uint_t current_lba;
70     uint8_t atapi_cmd;
71     struct atapi_error_recovery err_recovery;
72 };
73
74 struct ide_hd_state {
75
76 };
77
78 struct ide_drive {
79     // Command Registers
80
81     v3_ide_dev_type_t drive_type;
82
83     union {
84         struct v3_ide_cd_ops * cd_ops;
85         struct v3_ide_hd_ops * hd_ops;
86     };
87
88
89     union {
90         struct ide_cd_state cd_state;
91         struct ide_hd_state hd_state;
92     };
93
94     char model[41];
95
96     // Where we are in the data transfer
97     uint_t transfer_index;
98
99     // the length of a transfer
100     // calculated for easy access
101     uint_t transfer_length;
102
103
104     // We have a local data buffer that we use for IO port accesses
105     uint8_t data_buf[DATA_BUFFER_SIZE];
106
107
108     void * private_data;
109     
110     union {
111         uint8_t sector_count;             // 0x1f2,0x172
112         struct atapi_irq_flags irq_flags;
113     } __attribute__((packed));
114
115     uint8_t sector_num;               // 0x1f3,0x173
116
117     union {
118         uint16_t cylinder;
119
120         struct {
121             uint8_t cylinder_low;       // 0x1f4,0x174
122             uint8_t cylinder_high;      // 0x1f5,0x175
123         } __attribute__((packed));
124
125         // The transfer length requested by the CPU 
126         uint16_t req_len;
127     } __attribute__((packed));
128
129
130 };
131
132
133
134 struct ide_channel {
135     struct ide_drive drives[2];
136
137     // Command Registers
138     struct ide_error_reg error_reg;     // [read] 0x1f1,0x171
139
140     struct ide_features_reg features;
141
142     struct ide_drive_head_reg drive_head; // 0x1f6,0x176
143
144     struct ide_status_reg status;       // [read] 0x1f7,0x177
145     uint8_t cmd_reg;                // [write] 0x1f7,0x177
146
147     int irq; // this is temporary until we add PCI support
148
149     // Control Registers
150     struct ide_ctrl_reg ctrl_reg; // [write] 0x3f6,0x376
151 };
152
153
154
155 struct ide_internal {
156     struct ide_channel channels[2];
157 };
158
159
160
161 static inline uint16_t be_to_le_16(const uint16_t val) {
162     uint8_t * buf = (uint8_t *)&val;
163     return (buf[0] << 8) | (buf[1]) ;
164 }
165
166 static inline uint16_t le_to_be_16(const uint16_t val) {
167     return be_to_le_16(val);
168 }
169
170
171 static inline uint32_t be_to_le_32(const uint32_t val) {
172     uint8_t * buf = (uint8_t *)&val;
173     return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
174 }
175
176 static inline uint32_t le_to_be_32(const uint32_t val) {
177     return be_to_le_32(val);
178 }
179
180
181 static inline int get_channel_index(ushort_t port) {
182     if (((port & 0xfff8) == 0x1f0) ||
183         ((port & 0xfffe) == 0x3f6)) {
184         return 0;
185     } else if (((port & 0xfff8) == 0x170) ||
186                ((port & 0xfffe) == 0x376)) {
187         return 1;
188     }
189
190     return -1;
191 }
192
193 static inline struct ide_channel * get_selected_channel(struct ide_internal * ide, ushort_t port) {
194     int channel_idx = get_channel_index(port);    
195     return &(ide->channels[channel_idx]);
196 }
197
198 static inline struct ide_drive * get_selected_drive(struct ide_channel * channel) {
199     return &(channel->drives[channel->drive_head.drive_sel]);
200 }
201
202
203 static inline int is_lba_enabled(struct ide_channel * channel) {
204     return channel->drive_head.lba_mode;
205 }
206
207
208 static void ide_raise_irq(struct vm_device * dev, struct ide_channel * channel) {
209     if (channel->ctrl_reg.irq_disable == 0) {
210         v3_raise_irq(dev->vm, channel->irq);
211     }
212 }
213
214
215 static void drive_reset(struct ide_drive * drive) {
216     drive->sector_count = 0x01;
217     drive->sector_num = 0x01;
218     
219     if (drive->drive_type == IDE_CDROM) {
220         drive->cylinder = 0xeb14;
221     } else {
222         drive->cylinder = 0x0000;
223     }
224
225
226     memset(drive->data_buf, 0, sizeof(drive->data_buf));
227     drive->transfer_index = 0;
228
229     // Send the reset signal to the connected device callbacks
230     //     channel->drives[0].reset();
231     //    channel->drives[1].reset();
232 }
233
234 static void channel_reset(struct ide_channel * channel) {
235     
236     // set busy and seek complete flags
237     channel->status.val = 0x90;
238
239     // Clear errors
240     channel->error_reg.val = 0x01;
241
242     // clear commands
243     channel->cmd_reg = 0x00;
244
245     channel->ctrl_reg.irq_disable = 0;
246 }
247
248 static void channel_reset_complete(struct ide_channel * channel) {
249     channel->status.busy = 0;
250     channel->status.ready = 1;
251
252     channel->drive_head.head_num = 0;    
253     
254     drive_reset(&(channel->drives[0]));
255     drive_reset(&(channel->drives[1]));
256 }
257
258
259 static void ide_abort_command(struct vm_device * dev, struct ide_channel * channel) {
260     channel->status.val = 0x41; // Error + ready
261     channel->error_reg.val = 0x04; // No idea...
262
263     ide_raise_irq(dev, channel);
264 }
265
266
267 // Include the ATAPI interface handlers
268 #include "atapi.h"
269
270
271 static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
272     struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
273     struct ide_channel * channel = get_selected_channel(ide, port);
274     struct ide_drive * drive = get_selected_drive(channel);
275
276     if (length != 1) {
277         PrintError("Invalid Write Length on IDE command Port %x\n", port);
278         return -1;
279     }
280
281     PrintDebug("IDE: Writing Command Port %x (val=%x)\n", port, *(uint8_t *)src);
282     
283     channel->cmd_reg = *(uint8_t *)src;
284     
285     switch (channel->cmd_reg) {
286         
287         case 0xa0: // ATAPI Command Packet
288             if (drive->drive_type != IDE_CDROM) {
289                 ide_abort_command(dev, channel);
290             }
291             
292             drive->sector_count = 1;
293
294             channel->status.busy = 0;
295             channel->status.write_fault = 0;
296             channel->status.data_req = 1;
297             channel->status.error = 0;
298
299             // reset the data buffer...
300             drive->transfer_length = ATAPI_PACKET_SIZE;
301             drive->transfer_index = 0;
302
303             break;
304         case 0xa1: // ATAPI Identify Device Packet
305             atapi_identify_device(drive);
306
307             channel->error_reg.val = 0;
308             channel->status.val = 0x58; // ready, data_req, seek_complete
309             
310             ide_raise_irq(dev, channel);
311             break;
312         case 0xec: // Identify Device
313             if (drive->drive_type != IDE_DISK) {
314                 drive_reset(drive);
315
316                 // JRL: Should we abort here?
317                 ide_abort_command(dev, channel);
318             } else {
319                 PrintError("IDE Disks currently not implemented\n");
320                 return -1;
321             }
322             break;
323         default:
324             PrintError("Unimplemented IDE command (%x)\n", channel->cmd_reg);
325             return -1;
326     }
327
328     return length;
329 }
330
331
332 static int write_data_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
333     struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
334     struct ide_channel * channel = get_selected_channel(ide, port);
335     struct ide_drive * drive = get_selected_drive(channel);
336
337     //    PrintDebug("IDE: Writing Data Port %x (val=%x, len=%d)\n", 
338     //         port, *(uint32_t *)src, length);
339     
340     memcpy(drive->data_buf + drive->transfer_index, src, length);    
341     drive->transfer_index += length;
342
343     // Transfer is complete, dispatch the command
344     if (drive->transfer_index >= drive->transfer_length) {
345         switch (channel->cmd_reg) {
346             case 0x30: // Write Sectors
347                 PrintError("Writing Data not yet implemented\n");
348                 return -1;
349                 
350             case 0xa0: // ATAPI packet command
351                 if (atapi_handle_packet(dev, channel) == -1) {
352                     PrintError("Error handling ATAPI packet\n");
353                     return -1;
354                 }
355                 break;
356             default:
357                 PrintError("Unhandld IDE Command %x\n", channel->cmd_reg);
358                 return -1;
359         }
360     }
361
362     return length;
363 }
364
365
366 static int read_hd_data(uint8_t * dst, uint_t length, struct vm_device * dev, struct ide_channel * channel) {
367     PrintError("Harddrive data port read not implemented\n");
368     return -1;
369 }
370
371
372
373 static int read_cd_data(uint8_t * dst, uint_t length, struct vm_device * dev, struct ide_channel * channel) {
374     struct ide_drive * drive = get_selected_drive(channel);
375     int data_offset = drive->transfer_index % DATA_BUFFER_SIZE;
376     int req_offset = drive->transfer_index % drive->req_len;
377     
378     if (drive->cd_state.atapi_cmd != 0x28) {
379         PrintDebug("IDE: Reading CD Data (len=%d) (req_len=%d)\n", length, drive->req_len);
380     }
381
382     if (drive->transfer_index >= drive->transfer_length) {
383         PrintError("Buffer Overrun... (xfer_len=%d) (cur_idx=%d) (post_idx=%d)\n", 
384                    drive->transfer_length, drive->transfer_index, 
385                    drive->transfer_index + length);
386         return -1;
387     }
388
389
390
391     if ((data_offset == 0) && (drive->transfer_index > 0)) {
392         
393         if (drive->drive_type == IDE_CDROM) {
394             if (atapi_update_data_buf(dev, channel) == -1) {
395                 PrintError("Could not update CDROM data buffer\n");
396                 return -1;
397             } 
398         } else {
399             PrintError("IDE Harddrives not implemented\n");
400             return -1;
401         }
402     }
403
404     memcpy(dst, drive->data_buf + data_offset, length);
405     
406     drive->transfer_index += length;
407
408     if ((req_offset == 0) && (drive->transfer_index > 0)) {
409         if (drive->transfer_index < drive->transfer_length) {
410             // An increment is complete, but there is still more data to be transferred...
411             
412             channel->status.data_req = 1;
413
414             drive->irq_flags.c_d = 0;
415
416             // Update the request length in the cylinder regs
417             if (atapi_update_req_len(dev, channel, drive->transfer_length - drive->transfer_index) == -1) {
418                 PrintError("Could not update request length after completed increment\n");
419                 return -1;
420             }
421         } else {
422             // This was the final read of the request
423             channel->status.data_req = 0;
424             channel->status.ready = 1;
425             
426             drive->irq_flags.c_d = 1;
427             drive->irq_flags.rel = 0;
428         }
429
430         drive->irq_flags.io_dir = 1;
431         channel->status.busy = 0;
432
433         ide_raise_irq(dev, channel);
434     }
435
436     return length;
437 }
438
439
440 static int read_drive_id(uint8_t * dst, uint_t length, struct vm_device * dev, struct ide_channel * channel) {
441     struct ide_drive * drive = get_selected_drive(channel);
442
443     channel->status.busy = 0;
444     channel->status.ready = 1;
445     channel->status.write_fault = 0;
446     channel->status.seek_complete = 1;
447     channel->status.corrected = 0;
448     channel->status.error = 0;
449                 
450     
451     memcpy(dst, drive->data_buf + drive->transfer_index, length);
452     drive->transfer_index += length;
453     
454     if (drive->transfer_index >= drive->transfer_length) {
455         channel->status.data_req = 0;
456     }
457     
458     return length;
459 }
460
461
462 static int ide_read_data_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
463     struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
464     struct ide_channel * channel = get_selected_channel(ide, port);
465     struct ide_drive * drive = get_selected_drive(channel);
466
467     //    PrintDebug("IDE: Reading Data Port %x (len=%d)\n", port, length);
468
469     if ((channel->cmd_reg == 0xec) ||
470         (channel->cmd_reg == 0xa1)) {
471         return read_drive_id((uint8_t *)dst, length, dev, channel);
472     }
473
474     if (drive->drive_type == IDE_CDROM) {
475         if (read_cd_data((uint8_t *)dst, length, dev, channel) == -1) {
476             PrintError("IDE: Could not read CD Data\n");
477             return -1;
478         }
479     } else if (drive->drive_type == IDE_DISK) {
480         if (read_hd_data((uint8_t *)dst, length, dev, channel) == -1) {
481             PrintError("IDE: Could not read HD Data\n");
482             return -1;
483         }
484     } else {
485         memset((uint8_t *)dst, 0, length);
486     }
487
488     return length;
489 }
490
491 static int write_port_std(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
492     struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
493     struct ide_channel * channel = get_selected_channel(ide, port);
494     struct ide_drive * drive = get_selected_drive(channel);
495             
496     if (length != 1) {
497         PrintError("Invalid Write length on IDE port %x\n", port);
498         return -1;
499     }
500
501     PrintDebug("IDE: Writing Standard Port %x (val=%x)\n", port, *(uint8_t *)src);
502
503
504     switch (port) {
505         // reset and interrupt enable
506         case PRI_CTRL_PORT:
507         case SEC_CTRL_PORT: {
508             struct ide_ctrl_reg * tmp_ctrl = (struct ide_ctrl_reg *)src;
509
510             // only reset channel on a 0->1 reset bit transition
511             if ((!channel->ctrl_reg.soft_reset) && (tmp_ctrl->soft_reset)) {
512                 channel_reset(channel);
513             } else if ((channel->ctrl_reg.soft_reset) && (!tmp_ctrl->soft_reset)) {
514                 channel_reset_complete(channel);
515             }
516
517             channel->ctrl_reg.val = tmp_ctrl->val;          
518             break;
519         }
520         case PRI_FEATURES_PORT:
521         case SEC_FEATURES_PORT:
522             channel->features.val = *(uint8_t *)src;
523             break;
524
525         case PRI_SECT_CNT_PORT:
526         case SEC_SECT_CNT_PORT:
527             drive->sector_count = *(uint8_t *)src;
528             break;
529
530         case PRI_SECT_NUM_PORT:
531         case SEC_SECT_NUM_PORT:
532             drive->sector_num = *(uint8_t *)src;
533
534         case PRI_CYL_LOW_PORT:
535         case SEC_CYL_LOW_PORT:
536             drive->cylinder_low = *(uint8_t *)src;
537             break;
538
539         case PRI_CYL_HIGH_PORT:
540         case SEC_CYL_HIGH_PORT:
541             drive->cylinder_high = *(uint8_t *)src;
542             break;
543
544         case PRI_DRV_SEL_PORT:
545         case SEC_DRV_SEL_PORT: {
546             channel->drive_head.val = *(uint8_t *)src;
547             
548             // make sure the reserved bits are ok..
549             // JRL TODO: check with new ramdisk to make sure this is right...
550             channel->drive_head.val |= 0xa0;
551
552             drive = get_selected_drive(channel);
553
554             // Selecting a non-present device is a no-no
555             if (drive->drive_type == IDE_NONE) {
556                 PrintDebug("Attempting to select a non-present drive\n");
557                 channel->error_reg.abort = 1;
558                 channel->status.error = 1;
559             }
560
561             break;
562         }
563         default:
564             PrintError("IDE: Write to unknown Port %x\n", port);
565             return -1;
566     }
567     return length;
568 }
569
570
571 static int read_port_std(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
572     struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
573     struct ide_channel * channel = get_selected_channel(ide, port);
574     struct ide_drive * drive = get_selected_drive(channel);
575     
576     if (length != 1) {
577         PrintError("Invalid Read length on IDE port %x\n", port);
578         return -1;
579     }
580
581     PrintDebug("IDE: Reading Standard Port %x\n", port);
582
583
584     if ((port == PRI_ADDR_REG_PORT) ||
585         (port == SEC_ADDR_REG_PORT)) {
586         // unused, return 0xff
587         *(uint8_t *)dst = 0xff;
588         return length;
589     }
590
591
592     // if no drive is present just return 0 + reserved bits
593     if (drive->drive_type == IDE_NONE) {
594         if ((port == PRI_DRV_SEL_PORT) ||
595             (port == SEC_DRV_SEL_PORT)) {
596             *(uint8_t *)dst = 0xa0;
597         } else {
598             *(uint8_t *)dst = 0;
599         }
600
601         return length;
602     }
603
604     switch (port) {
605
606         // This is really the error register.
607         case PRI_FEATURES_PORT:
608         case SEC_FEATURES_PORT:
609             *(uint8_t *)dst = channel->error_reg.val;
610             break;
611             
612         case PRI_SECT_CNT_PORT:
613         case SEC_SECT_CNT_PORT:
614             *(uint8_t *)dst = drive->sector_count;
615             break;
616
617         case PRI_SECT_NUM_PORT:
618         case SEC_SECT_NUM_PORT:
619             *(uint8_t *)dst = drive->sector_num;
620             break;
621
622         case PRI_CYL_LOW_PORT:
623         case SEC_CYL_LOW_PORT:
624             *(uint8_t *)dst = drive->cylinder_low;
625             break;
626
627
628         case PRI_CYL_HIGH_PORT:
629         case SEC_CYL_HIGH_PORT:
630             *(uint8_t *)dst = drive->cylinder_high;
631             break;
632
633         case PRI_DRV_SEL_PORT:
634         case SEC_DRV_SEL_PORT:  // hard disk drive and head register 0x1f6
635             *(uint8_t *)dst = channel->drive_head.val;
636             break;
637
638         case PRI_CTRL_PORT:
639         case SEC_CTRL_PORT:
640         case PRI_CMD_PORT:
641         case SEC_CMD_PORT:
642             // Something about lowering interrupts here....
643             *(uint8_t *)dst = channel->status.val;
644             break;
645
646         default:
647             PrintError("Invalid Port: %x\n", port);
648             return -1;
649     }
650
651     PrintDebug("\tVal=%x\n", *(uint8_t *)dst);
652
653     return length;
654 }
655
656
657
658 static void init_drive(struct ide_drive * drive) {
659
660     drive->sector_count = 0x01;
661     drive->sector_num = 0x01;
662     drive->cylinder = 0x0000;
663
664     drive->drive_type = IDE_NONE;
665
666     memset(drive->model, 0, sizeof(drive->model));
667
668     drive->transfer_index = 0;
669     drive->transfer_length = 0;
670     memset(drive->data_buf, 0, sizeof(drive->data_buf));
671
672     drive->private_data = NULL;
673     drive->cd_ops = NULL;
674 }
675
676 static void init_channel(struct ide_channel * channel) {
677     int i = 0;
678
679     channel->error_reg.val = 0x01;
680     channel->drive_head.val = 0x00;
681     channel->status.val = 0x00;
682     channel->cmd_reg = 0x00;
683     channel->ctrl_reg.val = 0x08;
684
685
686     for (i = 0; i < 2; i++) {
687         init_drive(&(channel->drives[i]));
688     }
689
690 }
691
692 static void init_ide_state(struct ide_internal * ide) {
693     int i;
694
695     for (i = 0; i < 2; i++) {
696         init_channel(&(ide->channels[i]));
697
698         // JRL: this is a terrible hack...
699         ide->channels[i].irq = PRI_DEFAULT_IRQ + i;
700     }
701 }
702
703
704
705 static int init_ide(struct vm_device * dev) {
706     struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
707
708     PrintDebug("IDE: Initializing IDE\n");
709
710     init_ide_state(ide);
711
712
713     v3_dev_hook_io(dev, PRI_CTRL_PORT, 
714                    &read_port_std, &write_port_std);
715
716     v3_dev_hook_io(dev, PRI_DATA_PORT, 
717                    &ide_read_data_port, &write_data_port);
718     v3_dev_hook_io(dev, PRI_FEATURES_PORT, 
719                    &read_port_std, &write_port_std);
720     v3_dev_hook_io(dev, PRI_SECT_CNT_PORT, 
721                    &read_port_std, &write_port_std);
722     v3_dev_hook_io(dev, PRI_SECT_NUM_PORT, 
723                    &read_port_std, &write_port_std);
724     v3_dev_hook_io(dev, PRI_CYL_LOW_PORT, 
725                    &read_port_std, &write_port_std);
726     v3_dev_hook_io(dev, PRI_CYL_HIGH_PORT, 
727                    &read_port_std, &write_port_std);
728     v3_dev_hook_io(dev, PRI_DRV_SEL_PORT, 
729                    &read_port_std, &write_port_std);
730     v3_dev_hook_io(dev, PRI_CMD_PORT, 
731                    &read_port_std, &write_cmd_port);
732
733
734     v3_dev_hook_io(dev, SEC_CTRL_PORT, 
735                    &read_port_std, &write_port_std);
736
737     v3_dev_hook_io(dev, SEC_DATA_PORT, 
738                    &ide_read_data_port, &write_data_port);
739     v3_dev_hook_io(dev, SEC_FEATURES_PORT, 
740                    &read_port_std, &write_port_std);
741     v3_dev_hook_io(dev, SEC_SECT_CNT_PORT, 
742                    &read_port_std, &write_port_std);
743     v3_dev_hook_io(dev, SEC_SECT_NUM_PORT, 
744                    &read_port_std, &write_port_std);
745     v3_dev_hook_io(dev, SEC_CYL_LOW_PORT, 
746                    &read_port_std, &write_port_std);
747     v3_dev_hook_io(dev, SEC_CYL_HIGH_PORT, 
748                    &read_port_std, &write_port_std);
749     v3_dev_hook_io(dev, SEC_DRV_SEL_PORT, 
750                    &read_port_std, &write_port_std);
751     v3_dev_hook_io(dev, SEC_CMD_PORT, 
752                    &read_port_std, &write_cmd_port);
753   
754   
755
756     v3_dev_hook_io(dev, SEC_ADDR_REG_PORT, 
757                    &read_port_std, &write_port_std);
758
759     v3_dev_hook_io(dev, PRI_ADDR_REG_PORT, 
760                    &read_port_std, &write_port_std);
761
762     return 0;
763 }
764
765
766 static int deinit_ide(struct vm_device * dev) {
767     // unhook io ports....
768     // deregister from PCI?
769     return 0;
770 }
771
772
773 static struct vm_device_ops dev_ops = {
774     .init = init_ide,
775     .deinit = deinit_ide,
776     .reset = NULL,
777     .start = NULL,
778     .stop = NULL,
779 };
780
781
782 struct vm_device *  v3_create_ide() {
783     struct ide_internal * ide  = (struct ide_internal *)V3_Malloc(sizeof(struct ide_internal));  
784     struct vm_device * device = v3_create_device("IDE", &dev_ops, ide);
785
786     //    ide->pci = pci;
787
788     PrintDebug("IDE: Creating IDE bus x 2\n");
789
790     return device;
791 }
792
793
794
795
796
797 int v3_ide_register_cdrom(struct vm_device * ide_dev, 
798                           uint_t bus_num, 
799                           uint_t drive_num,
800                           char * dev_name, 
801                           struct v3_ide_cd_ops * ops, 
802                           void * private_data) {
803
804     struct ide_internal * ide  = (struct ide_internal *)(ide_dev->private_data);  
805     struct ide_channel * channel = NULL;
806     struct ide_drive * drive = NULL;
807
808     V3_ASSERT((bus_num >= 0) && (bus_num < 2));
809     V3_ASSERT((drive_num >= 0) && (drive_num < 2));
810
811     channel = &(ide->channels[bus_num]);
812     drive = &(channel->drives[drive_num]);
813     
814     if (drive->drive_type != IDE_NONE) {
815         PrintError("Device slot (bus=%d, drive=%d) already occupied\n", bus_num, drive_num);
816         return -1;
817     }
818
819     strncpy(drive->model, dev_name, sizeof(drive->model) - 1);
820
821     while (strlen((char *)(drive->model)) < 40) {
822         strcat((char*)(drive->model), " ");
823     }
824
825
826     drive->drive_type = IDE_CDROM;
827
828     drive->cd_ops = ops;
829
830     drive->private_data = private_data;
831
832     return 0;
833 }
834
835
836 int v3_ide_register_harddisk(struct vm_device * ide_dev, 
837                              uint_t bus_num, 
838                              uint_t drive_num, 
839                              char * dev_name, 
840                              struct v3_ide_hd_ops * ops, 
841                              void * private_data) {
842
843     struct ide_internal * ide  = (struct ide_internal *)(ide_dev->private_data);  
844     struct ide_channel * channel = NULL;
845     struct ide_drive * drive = NULL;
846
847     V3_ASSERT((bus_num >= 0) && (bus_num < 2));
848     V3_ASSERT((drive_num >= 0) && (drive_num < 2));
849
850     channel = &(ide->channels[bus_num]);
851     drive = &(channel->drives[drive_num]);
852     
853     if (drive->drive_type != IDE_NONE) {
854         PrintError("Device slot (bus=%d, drive=%d) already occupied\n", bus_num, drive_num);
855         return -1;
856     }
857
858     strncpy(drive->model, dev_name, sizeof(drive->model) - 1);
859
860     drive->drive_type = IDE_DISK;
861
862     drive->hd_ops = ops;
863
864     drive->private_data = private_data;
865
866     return 0;
867 }