/[gxemul]/upstream/0.3.6.1/src/devices/dev_wdc.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /upstream/0.3.6.1/src/devices/dev_wdc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 17 - (hide annotations)
Mon Oct 8 16:19:05 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 17791 byte(s)
0.3.6.1
1 dpavlin 4 /*
2     * Copyright (C) 2004-2005 Anders Gavare. All rights reserved.
3     *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27 dpavlin 14 *
28     * $Id: dev_wdc.c,v 1.39 2005/09/27 23:55:44 debug Exp $
29     *
30     * Standard "wdc" IDE controller.
31 dpavlin 4 */
32    
33     #include <stdio.h>
34     #include <stdlib.h>
35     #include <string.h>
36    
37     #include "console.h"
38     #include "cpu.h"
39 dpavlin 14 #include "device.h"
40 dpavlin 4 #include "diskimage.h"
41     #include "machine.h"
42     #include "memory.h"
43     #include "misc.h"
44    
45     #include "wdcreg.h"
46    
47 dpavlin 14 #define DEV_WDC_LENGTH 8
48 dpavlin 4 #define WDC_TICK_SHIFT 14
49     #define WDC_INBUF_SIZE (512*257)
50    
51 dpavlin 14 /*
52     * INT_DELAY=2 to be safe, 1 is faster but maybe buggy. 0 is fastest.
53     *
54     * The only reason for this delay to exist is because (some versions of)
55     * NetBSD for hpcmips have interrupt problems. These problems are not only
56     * triggered inside the emulator, but also on real hardware. Using the
57     * delay is an ugly (but working) work-around.
58     */
59 dpavlin 4 #define INT_DELAY 1
60    
61 dpavlin 6 extern int quiet_mode;
62    
63 dpavlin 4 /* #define debug fatal */
64    
65     struct wdc_data {
66     int irq_nr;
67     int base_drive;
68 dpavlin 14 int data_debug;
69 dpavlin 4
70 dpavlin 14 /* Cached values: */
71     int cyls[2];
72     int heads[2];
73     int sectors_per_track[2];
74 dpavlin 4
75     unsigned char identify_struct[512];
76    
77     unsigned char inbuf[WDC_INBUF_SIZE];
78     int inbuf_head;
79     int inbuf_tail;
80    
81 dpavlin 14 int delayed_interrupt;
82 dpavlin 4 int write_in_progress;
83     int write_count;
84     int64_t write_offset;
85    
86     int error;
87     int precomp;
88     int seccnt;
89     int sector;
90     int cyl_lo;
91     int cyl_hi;
92     int sectorsize;
93     int lba;
94     int drive;
95     int head;
96     int cur_command;
97     };
98    
99    
100     /*
101     * dev_wdc_tick():
102     */
103     void dev_wdc_tick(struct cpu *cpu, void *extra)
104     {
105     struct wdc_data *d = extra;
106    
107     if (d->delayed_interrupt) {
108     d->delayed_interrupt --;
109    
110     if (d->delayed_interrupt == 0)
111     cpu_interrupt(cpu, d->irq_nr);
112     }
113     }
114    
115    
116     /*
117     * wdc_addtoinbuf():
118     *
119     * Write to the inbuf at its head, read at its tail.
120     */
121     static void wdc_addtoinbuf(struct wdc_data *d, int c)
122     {
123     d->inbuf[d->inbuf_head] = c;
124    
125     d->inbuf_head = (d->inbuf_head + 1) % WDC_INBUF_SIZE;
126     if (d->inbuf_head == d->inbuf_tail)
127 dpavlin 6 fatal("[ wdc_addtoinbuf(): WARNING! wdc inbuf overrun ]\n");
128 dpavlin 4 }
129    
130    
131     /*
132     * wdc_get_inbuf():
133     *
134     * Read from the tail of inbuf.
135     */
136     static uint64_t wdc_get_inbuf(struct wdc_data *d)
137     {
138     int c = d->inbuf[d->inbuf_tail];
139    
140     if (d->inbuf_head == d->inbuf_tail) {
141 dpavlin 6 fatal("[ wdc: WARNING! someone is reading too much from the "
142     "wdc inbuf! ]\n");
143 dpavlin 4 return -1;
144     }
145    
146     d->inbuf_tail = (d->inbuf_tail + 1) % WDC_INBUF_SIZE;
147     return c;
148     }
149    
150    
151     /*
152     * wdc_initialize_identify_struct(d):
153     */
154     static void wdc_initialize_identify_struct(struct cpu *cpu, struct wdc_data *d)
155     {
156 dpavlin 6 uint64_t total_size;
157 dpavlin 14 char namebuf[40];
158 dpavlin 4
159 dpavlin 6 total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive,
160     DISKIMAGE_IDE);
161 dpavlin 4
162     memset(d->identify_struct, 0, sizeof(d->identify_struct));
163    
164     /* Offsets are in 16-bit WORDS! High byte, then low. */
165    
166     /* 0: general flags */
167     d->identify_struct[2 * 0 + 0] = 0;
168     d->identify_struct[2 * 0 + 1] = 1 << 6;
169    
170     /* 1: nr of cylinders */
171 dpavlin 14 d->identify_struct[2 * 1 + 0] = (d->cyls[d->drive] >> 8);
172     d->identify_struct[2 * 1 + 1] = d->cyls[d->drive] & 255;
173 dpavlin 4
174     /* 3: nr of heads */
175 dpavlin 14 d->identify_struct[2 * 3 + 0] = d->heads[d->drive] >> 8;
176     d->identify_struct[2 * 3 + 1] = d->heads[d->drive];
177 dpavlin 4
178     /* 6: sectors per track */
179 dpavlin 14 d->identify_struct[2 * 6 + 0] = d->sectors_per_track[d->drive] >> 8;
180     d->identify_struct[2 * 6 + 1] = d->sectors_per_track[d->drive];
181 dpavlin 4
182     /* 10-19: Serial number */
183     memcpy(&d->identify_struct[2 * 10], "S/N 1234-5678 ", 20);
184    
185     /* 23-26: Firmware version */
186     memcpy(&d->identify_struct[2 * 23], "VER 1.0 ", 8);
187    
188     /* 27-46: Model number */
189 dpavlin 14 if (diskimage_getname(cpu->machine, d->drive + d->base_drive,
190     DISKIMAGE_IDE, namebuf, sizeof(namebuf))) {
191     int i;
192     for (i=0; i<sizeof(namebuf); i++)
193     if (namebuf[i] == 0) {
194     for (; i<sizeof(namebuf); i++)
195     namebuf[i] = ' ';
196     break;
197     }
198     memcpy(&d->identify_struct[2 * 27], namebuf, 40);
199     } else
200     memcpy(&d->identify_struct[2 * 27],
201     "Fake GXemul IDE disk ", 40);
202 dpavlin 4
203     /* 47: max sectors per multitransfer */
204     d->identify_struct[2 * 47 + 0] = 0x80;
205     d->identify_struct[2 * 47 + 1] = 1; /* 1 or 16? */
206    
207     /* 57-58: current capacity in sectors */
208     d->identify_struct[2 * 57 + 0] = ((total_size / 512) >> 24) % 255;
209     d->identify_struct[2 * 57 + 1] = ((total_size / 512) >> 16) % 255;
210     d->identify_struct[2 * 58 + 0] = ((total_size / 512) >> 8) % 255;
211     d->identify_struct[2 * 58 + 1] = (total_size / 512) & 255;
212    
213     /* 60-61: total nr of addresable sectors */
214     d->identify_struct[2 * 60 + 0] = ((total_size / 512) >> 24) % 255;
215     d->identify_struct[2 * 60 + 1] = ((total_size / 512) >> 16) % 255;
216     d->identify_struct[2 * 61 + 0] = ((total_size / 512) >> 8) % 255;
217     d->identify_struct[2 * 61 + 1] = (total_size / 512) & 255;
218    
219     }
220    
221    
222     /*
223 dpavlin 14 * wdc__read():
224     */
225     void wdc__read(struct cpu *cpu, struct wdc_data *d)
226     {
227     unsigned char buf[512];
228     int i, cyl = d->cyl_hi * 256+ d->cyl_lo;
229     int count = d->seccnt? d->seccnt : 256;
230     uint64_t offset = 512 * (d->sector - 1
231     + d->head * d->sectors_per_track[d->drive] +
232     d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl);
233    
234     #if 0
235     /* LBA: */
236     if (d->lba)
237     offset = 512 * (((d->head & 0xf) << 24) + (cyl << 8)
238     + d->sector);
239     printf("WDC read from offset %lli\n", (long long)offset);
240     #endif
241    
242     while (count > 0) {
243     diskimage_access(cpu->machine, d->drive + d->base_drive,
244     DISKIMAGE_IDE, 0, offset, buf, 512);
245     /* TODO: result code */
246     for (i=0; i<512; i++)
247     wdc_addtoinbuf(d, buf[i]);
248     offset += 512;
249     count --;
250     }
251    
252     d->delayed_interrupt = INT_DELAY;
253     }
254    
255    
256     /*
257     * wdc__write():
258     */
259     void wdc__write(struct cpu *cpu, struct wdc_data *d)
260     {
261     int cyl = d->cyl_hi * 256+ d->cyl_lo;
262     int count = d->seccnt? d->seccnt : 256;
263     uint64_t offset = 512 * (d->sector - 1
264     + d->head * d->sectors_per_track[d->drive] +
265     d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl);
266     #if 0
267     /* LBA: */
268     if (d->lba)
269     offset = 512 * (((d->head & 0xf) << 24) +
270     (cyl << 8) + d->sector);
271     printf("WDC write to offset %lli\n", (long long)offset);
272     #endif
273    
274     d->write_in_progress = 1;
275     d->write_count = count;
276     d->write_offset = offset;
277    
278     /* TODO: result code? */
279     }
280    
281    
282     /*
283 dpavlin 4 * status_byte():
284 dpavlin 14 *
285     * Return a reasonable status byte corresponding to the controller's current
286     * state.
287 dpavlin 4 */
288     static int status_byte(struct wdc_data *d, struct cpu *cpu)
289     {
290     int odata = 0;
291    
292 dpavlin 14 /*
293     * Modern versions of OpenBSD wants WDCS_DSC. (Thanks to Alexander
294     * Yurchenko for noticing this.)
295     */
296 dpavlin 6 if (diskimage_exist(cpu->machine, d->drive + d->base_drive,
297     DISKIMAGE_IDE))
298 dpavlin 14 odata |= WDCS_DRDY | WDCS_DSC;
299 dpavlin 4 if (d->inbuf_head != d->inbuf_tail)
300     odata |= WDCS_DRQ;
301     if (d->write_in_progress)
302     odata |= WDCS_DRQ;
303     if (d->error)
304     odata |= WDCS_ERR;
305    
306     return odata;
307     }
308    
309    
310     /*
311     * dev_wdc_altstatus_access():
312     */
313     int dev_wdc_altstatus_access(struct cpu *cpu, struct memory *mem,
314     uint64_t relative_addr, unsigned char *data, size_t len,
315     int writeflag, void *extra)
316     {
317     struct wdc_data *d = extra;
318     uint64_t idata = 0, odata = 0;
319    
320     idata = memory_readmax64(cpu, data, len);
321    
322     /* Same as the normal status byte? */
323     odata = status_byte(d, cpu);
324    
325     if (writeflag==MEM_READ)
326     debug("[ wdc: read from ALTSTATUS: 0x%02x ]\n",
327     (int)odata);
328     else
329     debug("[ wdc: write to ALT. CTRL: 0x%02x ]\n",
330     (int)idata);
331    
332     if (writeflag == MEM_READ)
333     memory_writemax64(cpu, data, len, odata);
334    
335     return 1;
336     }
337    
338    
339     /*
340     * dev_wdc_access():
341     */
342     int dev_wdc_access(struct cpu *cpu, struct memory *mem,
343     uint64_t relative_addr, unsigned char *data, size_t len,
344     int writeflag, void *extra)
345     {
346     struct wdc_data *d = extra;
347     uint64_t idata = 0, odata = 0;
348 dpavlin 14 int i;
349 dpavlin 4
350     idata = memory_readmax64(cpu, data, len);
351    
352     switch (relative_addr) {
353    
354     case wd_data: /* 0: data */
355     if (writeflag==MEM_READ) {
356     odata = 0;
357    
358     /* TODO: This is hardcoded for little-endian? */
359    
360     odata += wdc_get_inbuf(d);
361     if (len >= 2)
362     odata += (wdc_get_inbuf(d) << 8);
363     if (len == 4) {
364     odata += (wdc_get_inbuf(d) << 16);
365     odata += (wdc_get_inbuf(d) << 24);
366     }
367    
368 dpavlin 14 if (d->data_debug)
369     debug("[ wdc: read from DATA: 0x%04x ]\n",
370     (int)odata);
371 dpavlin 4 if (d->inbuf_tail != d->inbuf_head)
372     d->delayed_interrupt = INT_DELAY;
373     } else {
374     int inbuf_len;
375 dpavlin 14 if (d->data_debug)
376     debug("[ wdc: write to DATA (len=%i): "
377     "0x%08lx ]\n", (int)len, (long)idata);
378 dpavlin 4 if (!d->write_in_progress) {
379     fatal("[ wdc: write to DATA, but not "
380     "expecting any? (len=%i): 0x%08lx ]\n",
381     (int)len, (long)idata);
382     }
383    
384     switch (len) {
385     case 4: wdc_addtoinbuf(d, idata & 0xff);
386     wdc_addtoinbuf(d, (idata >> 8) & 0xff);
387     wdc_addtoinbuf(d, (idata >> 16) & 0xff);
388     wdc_addtoinbuf(d, (idata >> 24) & 0xff);
389     break;
390     case 2: wdc_addtoinbuf(d, idata & 0xff);
391     wdc_addtoinbuf(d, (idata >> 8) & 0xff);
392     break;
393     case 1: wdc_addtoinbuf(d, idata); break;
394     default:fatal("wdc: unimplemented write len %i\n", len);
395     exit(1);
396     }
397    
398     inbuf_len = d->inbuf_head - d->inbuf_tail;
399     while (inbuf_len < 0)
400     inbuf_len += WDC_INBUF_SIZE;
401    
402     #if 0
403     if ((inbuf_len % (512 * d->write_count)) == 0) {
404 dpavlin 14 #else
405     if ((inbuf_len % 512) == 0) {
406 dpavlin 4 #endif
407     int count = 1; /* d->write_count; */
408     unsigned char *buf = malloc(count * 512);
409     if (buf == NULL) {
410     fprintf(stderr, "out of memory\n");
411     exit(1);
412     }
413    
414     for (i=0; i<512 * count; i++)
415     buf[i] = wdc_get_inbuf(d);
416    
417     diskimage_access(cpu->machine,
418 dpavlin 6 d->drive + d->base_drive, DISKIMAGE_IDE, 1,
419 dpavlin 4 d->write_offset, buf, 512 * count);
420     free(buf);
421    
422     d->write_count --;
423     d->write_offset += 512;
424    
425     d->delayed_interrupt = INT_DELAY;
426    
427     if (d->write_count == 0)
428     d->write_in_progress = 0;
429     }
430     }
431     break;
432    
433     case wd_error: /* 1: error (r), precomp (w) */
434     if (writeflag==MEM_READ) {
435     odata = d->error;
436 dpavlin 14 debug("[ wdc: read from ERROR: 0x%02x ]\n",
437     (int)odata);
438 dpavlin 4 /* TODO: is the error value cleared on read? */
439     d->error = 0;
440     } else {
441     d->precomp = idata;
442 dpavlin 14 debug("[ wdc: write to PRECOMP: 0x%02x ]\n",(int)idata);
443 dpavlin 4 }
444     break;
445    
446     case wd_seccnt: /* 2: sector count */
447     if (writeflag==MEM_READ) {
448     odata = d->seccnt;
449 dpavlin 14 debug("[ wdc: read from SECCNT: 0x%02x ]\n",(int)odata);
450 dpavlin 4 } else {
451     d->seccnt = idata;
452 dpavlin 14 debug("[ wdc: write to SECCNT: 0x%02x ]\n", (int)idata);
453 dpavlin 4 }
454     break;
455    
456     case wd_sector: /* 3: first sector */
457     if (writeflag==MEM_READ) {
458     odata = d->sector;
459 dpavlin 14 debug("[ wdc: read from SECTOR: 0x%02x ]\n",(int)odata);
460 dpavlin 4 } else {
461     d->sector = idata;
462 dpavlin 14 debug("[ wdc: write to SECTOR: 0x%02x ]\n", (int)idata);
463 dpavlin 4 }
464     break;
465    
466     case wd_cyl_lo: /* 4: cylinder low */
467     if (writeflag==MEM_READ) {
468     odata = d->cyl_lo;
469 dpavlin 14 debug("[ wdc: read from CYL_LO: 0x%02x ]\n",(int)odata);
470 dpavlin 4 } else {
471     d->cyl_lo = idata;
472 dpavlin 14 debug("[ wdc: write to CYL_LO: 0x%02x ]\n", (int)idata);
473 dpavlin 4 }
474     break;
475    
476     case wd_cyl_hi: /* 5: cylinder low */
477     if (writeflag==MEM_READ) {
478     odata = d->cyl_hi;
479 dpavlin 14 debug("[ wdc: read from CYL_HI: 0x%02x ]\n",(int)odata);
480 dpavlin 4 } else {
481     d->cyl_hi = idata;
482 dpavlin 14 debug("[ wdc: write to CYL_HI: 0x%02x ]\n", (int)idata);
483 dpavlin 4 }
484     break;
485    
486     case wd_sdh: /* 6: sectorsize/drive/head */
487     if (writeflag==MEM_READ) {
488     odata = (d->sectorsize << 6) + (d->lba << 5) +
489     (d->drive << 4) + (d->head);
490     debug("[ wdc: read from SDH: 0x%02x (sectorsize %i,"
491     " lba=%i, drive %i, head %i) ]\n", (int)odata,
492     d->sectorsize, d->lba, d->drive, d->head);
493     } else {
494     d->sectorsize = (idata >> 6) & 3;
495     d->lba = (idata >> 5) & 1;
496     d->drive = (idata >> 4) & 1;
497     d->head = idata & 0xf;
498     debug("[ wdc: write to SDH: 0x%02x (sectorsize %i,"
499     " lba=%i, drive %i, head %i) ]\n", (int)idata,
500     d->sectorsize, d->lba, d->drive, d->head);
501     }
502     break;
503    
504     case wd_command: /* 7: command or status */
505     if (writeflag==MEM_READ) {
506     odata = status_byte(d, cpu);
507 dpavlin 6 if (!quiet_mode)
508     debug("[ wdc: read from STATUS: 0x%02x ]\n",
509 dpavlin 14 (int)odata);
510 dpavlin 4 cpu_interrupt_ack(cpu, d->irq_nr);
511     d->delayed_interrupt = 0;
512     } else {
513 dpavlin 14 debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);
514 dpavlin 4 d->cur_command = idata;
515    
516     /* TODO: Is this correct behaviour? */
517     if (!diskimage_exist(cpu->machine,
518 dpavlin 6 d->drive + d->base_drive, DISKIMAGE_IDE)) {
519 dpavlin 4 d->error |= WDCE_ABRT;
520     d->delayed_interrupt = INT_DELAY;
521     break;
522     }
523    
524     /* Handle the command: */
525     switch (d->cur_command) {
526 dpavlin 14
527 dpavlin 4 case WDCC_READ:
528 dpavlin 14 if (!quiet_mode)
529     debug("[ wdc: READ from drive %i, head"
530     " %i, cyl %i, sector %i, nsecs %i "
531     "]\n", d->drive, d->head,
532     d->cyl_hi*256+d->cyl_lo, d->sector,
533     d->seccnt);
534     wdc__read(cpu, d);
535     break;
536 dpavlin 6
537 dpavlin 4 case WDCC_WRITE:
538 dpavlin 14 if (!quiet_mode)
539     debug("[ wdc: WRITE to drive %i, head"
540     " %i, cyl %i, sector %i, nsecs %i"
541     " ]\n", d->drive, d->head,
542     d->cyl_hi*256+d->cyl_lo, d->sector,
543     d->seccnt);
544     wdc__write(cpu, d);
545 dpavlin 4 break;
546    
547     case WDCC_IDP: /* Initialize drive parameters */
548     debug("[ wdc: IDP drive %i (TODO) ]\n",
549     d->drive);
550     /* TODO */
551     d->delayed_interrupt = INT_DELAY;
552     break;
553 dpavlin 14
554 dpavlin 4 case SET_FEATURES:
555     fatal("[ wdc: SET_FEATURES drive %i (TODO), "
556     "feature 0x%02x ]\n", d->drive, d->precomp);
557     /* TODO */
558     switch (d->precomp) {
559     case WDSF_SET_MODE:
560     fatal("[ wdc: WDSF_SET_MODE drive %i, "
561     "pio/dma flags 0x%02x ]\n",
562     d->drive, d->seccnt);
563     break;
564     default:
565     d->error |= WDCE_ABRT;
566     }
567     /* TODO: always interrupt? */
568     d->delayed_interrupt = INT_DELAY;
569     break;
570 dpavlin 14
571 dpavlin 4 case WDCC_RECAL:
572     debug("[ wdc: RECAL drive %i ]\n", d->drive);
573     d->delayed_interrupt = INT_DELAY;
574     break;
575 dpavlin 14
576 dpavlin 4 case WDCC_IDENTIFY:
577     debug("[ wdc: IDENTIFY drive %i ]\n", d->drive);
578     wdc_initialize_identify_struct(cpu, d);
579     /* The IDENTIFY data block is sent out
580     in low/high byte order: */
581     for (i=0; i<sizeof(d->identify_struct); i+=2) {
582     wdc_addtoinbuf(d, d->identify_struct
583     [i+1]);
584     wdc_addtoinbuf(d, d->identify_struct
585     [i+0]);
586     }
587     d->delayed_interrupt = INT_DELAY;
588     break;
589 dpavlin 14
590 dpavlin 4 case WDCC_IDLE_IMMED:
591     debug("[ wdc: IDLE_IMMED drive %i ]\n",
592     d->drive);
593     /* TODO: interrupt here? */
594     d->delayed_interrupt = INT_DELAY;
595     break;
596 dpavlin 14
597     /* Unsupported commands, without warning: */
598     case ATAPI_IDENTIFY_DEVICE:
599     case WDCC_SEC_SET_PASSWORD:
600     case WDCC_SEC_UNLOCK:
601     case WDCC_SEC_ERASE_PREPARE:
602     case WDCC_SEC_ERASE_UNIT:
603     case WDCC_SEC_FREEZE_LOCK:
604     case WDCC_SEC_DISABLE_PASSWORD:
605     d->error |= WDCE_ABRT;
606     break;
607    
608 dpavlin 4 default:
609     /* TODO */
610     d->error |= WDCE_ABRT;
611    
612 dpavlin 14 fatal("[ wdc: WARNING! Unimplemented command "
613     "0x%02x (drive %i, head %i, cyl %i, sector"
614     " %i, nsecs %i) ]\n", d->cur_command,
615     d->drive, d->head, d->cyl_hi*256+d->cyl_lo,
616 dpavlin 4 d->sector, d->seccnt);
617     }
618     }
619     break;
620    
621     default:
622     if (writeflag==MEM_READ)
623     debug("[ wdc: read from 0x%02x ]\n",
624     (int)relative_addr);
625     else
626     debug("[ wdc: write to 0x%02x: 0x%02x ]\n",
627     (int)relative_addr, (int)idata);
628     }
629    
630     if (writeflag == MEM_READ)
631     memory_writemax64(cpu, data, len, odata);
632    
633     return 1;
634     }
635    
636    
637     /*
638 dpavlin 14 * devinit_wdc():
639 dpavlin 4 */
640 dpavlin 14 int devinit_wdc(struct devinit *devinit)
641 dpavlin 4 {
642     struct wdc_data *d;
643     uint64_t alt_status_addr;
644 dpavlin 14 int i;
645 dpavlin 4
646     d = malloc(sizeof(struct wdc_data));
647     if (d == NULL) {
648     fprintf(stderr, "out of memory\n");
649     exit(1);
650     }
651     memset(d, 0, sizeof(struct wdc_data));
652 dpavlin 14 d->irq_nr = devinit->irq_nr;
653 dpavlin 4
654 dpavlin 14 /* base_drive = 0 for the primary controller, 2 for the secondary. */
655     d->base_drive = 0;
656     if ((devinit->addr & 0xfff) == 0x170)
657     d->base_drive = 2;
658 dpavlin 4
659 dpavlin 14 alt_status_addr = devinit->addr + 0x206;
660    
661 dpavlin 4 /* Special hack for pcic/hpcmips: TODO: Fix */
662 dpavlin 14 if (devinit->addr == 0x14000180)
663 dpavlin 4 alt_status_addr = 0x14000386;
664    
665 dpavlin 14 /* Get disk geometries: */
666     for (i=0; i<2; i++)
667     if (diskimage_exist(devinit->machine, d->base_drive +i,
668     DISKIMAGE_IDE))
669     diskimage_getchs(devinit->machine, d->base_drive + i,
670     DISKIMAGE_IDE, &d->cyls[i], &d->heads[i],
671     &d->sectors_per_track[i]);
672 dpavlin 4
673 dpavlin 14 memory_device_register(devinit->machine->memory, "wdc_altstatus",
674     alt_status_addr, 2, dev_wdc_altstatus_access, d, MEM_DEFAULT, NULL);
675     memory_device_register(devinit->machine->memory, devinit->name,
676     devinit->addr, DEV_WDC_LENGTH, dev_wdc_access, d, MEM_DEFAULT,
677     NULL);
678    
679     machine_add_tickfunction(devinit->machine, dev_wdc_tick,
680 dpavlin 4 d, WDC_TICK_SHIFT);
681 dpavlin 14
682     return 1;
683 dpavlin 4 }
684    

  ViewVC Help
Powered by ViewVC 1.1.26