1 |
/* |
/* |
2 |
* Copyright (C) 2004-2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2004-2007 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_wdc.c,v 1.56 2005/11/23 23:31:36 debug Exp $ |
* $Id: dev_wdc.c,v 1.76 2007/06/15 19:57:34 debug Exp $ |
29 |
* |
* |
30 |
* Standard "wdc" IDE controller. |
* COMMENT: Standard "wdc" IDE controller |
31 |
*/ |
*/ |
32 |
|
|
33 |
#include <stdio.h> |
#include <stdio.h> |
48 |
#define WDC_MAX_SECTORS 512 |
#define WDC_MAX_SECTORS 512 |
49 |
#define WDC_INBUF_SIZE (512*(WDC_MAX_SECTORS+1)) |
#define WDC_INBUF_SIZE (512*(WDC_MAX_SECTORS+1)) |
50 |
|
|
|
/* |
|
|
* INT_DELAY: This is an old hack which only exists because (some versions of) |
|
|
* NetBSD for hpcmips have interrupt problems. These problems are probably not |
|
|
* specific to GXemul, but are also triggered on real hardware. |
|
|
* |
|
|
* See the following URL for more info: |
|
|
* http://mail-index.netbsd.org/port-hpcmips/2004/12/30/0003.html |
|
|
* |
|
|
* NetBSD/malta also bugs out if wdc interrupts come too quickly. Hm. |
|
|
*/ |
|
|
#define INT_DELAY 1 |
|
|
|
|
51 |
extern int quiet_mode; |
extern int quiet_mode; |
52 |
|
|
53 |
/* #define debug fatal */ |
/* #define debug fatal */ |
54 |
|
|
55 |
struct wdc_data { |
struct wdc_data { |
56 |
int irq_nr; |
struct interrupt irq; |
57 |
|
int addr_mult; |
58 |
int base_drive; |
int base_drive; |
59 |
int data_debug; |
int data_debug; |
60 |
|
int io_enabled; |
61 |
|
|
62 |
/* Cached values: */ |
/* Cached values: */ |
63 |
int cyls[2]; |
int cyls[2]; |
68 |
int inbuf_head; |
int inbuf_head; |
69 |
int inbuf_tail; |
int inbuf_tail; |
70 |
|
|
71 |
int delayed_interrupt; |
int int_assert; |
|
int int_asserted; |
|
72 |
|
|
73 |
int write_in_progress; |
int write_in_progress; |
74 |
int write_count; |
int write_count; |
90 |
int atapi_phase; |
int atapi_phase; |
91 |
struct scsi_transfer *atapi_st; |
struct scsi_transfer *atapi_st; |
92 |
int atapi_len; |
int atapi_len; |
93 |
int atapi_received; |
size_t atapi_received; |
94 |
|
|
95 |
unsigned char identify_struct[512]; |
unsigned char identify_struct[512]; |
96 |
}; |
}; |
99 |
#define COMMAND_RESET 0x100 |
#define COMMAND_RESET 0x100 |
100 |
|
|
101 |
|
|
102 |
/* |
DEVICE_TICK(wdc) |
|
* dev_wdc_tick(): |
|
|
*/ |
|
|
void dev_wdc_tick(struct cpu *cpu, void *extra) |
|
103 |
{ |
{ |
104 |
struct wdc_data *d = extra; |
struct wdc_data *d = extra; |
|
int old_di = d->delayed_interrupt; |
|
105 |
|
|
106 |
if (d->delayed_interrupt) |
if (d->int_assert) |
107 |
d->delayed_interrupt --; |
INTERRUPT_ASSERT(d->irq); |
108 |
|
} |
109 |
|
|
110 |
if (old_di == 1 || d->int_asserted) { |
|
111 |
cpu_interrupt(cpu, d->irq_nr); |
/* |
112 |
d->int_asserted = 1; |
* wdc_set_io_enabled(): |
113 |
} |
* |
114 |
|
* Set io_enabled to zero to disable the I/O registers temporarily (e.g. |
115 |
|
* used by PCI code in NetBSD to detect whether multiple controllers collide |
116 |
|
* in I/O space). |
117 |
|
* |
118 |
|
* Return value is old contents of the io_enabled variable. |
119 |
|
*/ |
120 |
|
int wdc_set_io_enabled(struct wdc_data *d, int io_enabled) |
121 |
|
{ |
122 |
|
int old = d->io_enabled; |
123 |
|
d->io_enabled = io_enabled; |
124 |
|
return old; |
125 |
} |
} |
126 |
|
|
127 |
|
|
208 |
/* 27-46: Model number */ |
/* 27-46: Model number */ |
209 |
if (diskimage_getname(cpu->machine, d->drive + d->base_drive, |
if (diskimage_getname(cpu->machine, d->drive + d->base_drive, |
210 |
DISKIMAGE_IDE, namebuf, sizeof(namebuf))) { |
DISKIMAGE_IDE, namebuf, sizeof(namebuf))) { |
211 |
int i; |
size_t i; |
212 |
for (i=0; i<sizeof(namebuf); i++) |
for (i=0; i<sizeof(namebuf); i++) |
213 |
if (namebuf[i] == 0) { |
if (namebuf[i] == 0) { |
214 |
for (; i<sizeof(namebuf); i++) |
for (; i<sizeof(namebuf); i++) |
272 |
int i, cyl = d->cyl_hi * 256+ d->cyl_lo; |
int i, cyl = d->cyl_hi * 256+ d->cyl_lo; |
273 |
int count = d->seccnt? d->seccnt : 256; |
int count = d->seccnt? d->seccnt : 256; |
274 |
uint64_t offset = 512 * (d->sector - 1 |
uint64_t offset = 512 * (d->sector - 1 |
275 |
+ d->head * d->sectors_per_track[d->drive] + |
+ (int64_t)d->head * d->sectors_per_track[d->drive] + |
276 |
d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl); |
(int64_t)d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl); |
277 |
|
|
278 |
#if 0 |
#if 0 |
279 |
/* LBA: */ |
/* LBA: */ |
307 |
count -= to_read; |
count -= to_read; |
308 |
} |
} |
309 |
|
|
310 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
311 |
} |
} |
312 |
|
|
313 |
|
|
319 |
int cyl = d->cyl_hi * 256+ d->cyl_lo; |
int cyl = d->cyl_hi * 256+ d->cyl_lo; |
320 |
int count = d->seccnt? d->seccnt : 256; |
int count = d->seccnt? d->seccnt : 256; |
321 |
uint64_t offset = 512 * (d->sector - 1 |
uint64_t offset = 512 * (d->sector - 1 |
322 |
+ d->head * d->sectors_per_track[d->drive] + |
+ (int64_t)d->head * d->sectors_per_track[d->drive] + |
323 |
d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl); |
(int64_t)d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl); |
324 |
#if 0 |
#if 0 |
325 |
/* LBA: */ |
/* LBA: */ |
326 |
if (d->lba) |
if (d->lba) |
362 |
} |
} |
363 |
|
|
364 |
|
|
365 |
/* |
DEVICE_ACCESS(wdc_altstatus) |
|
* dev_wdc_altstatus_access(): |
|
|
*/ |
|
|
int dev_wdc_altstatus_access(struct cpu *cpu, struct memory *mem, |
|
|
uint64_t relative_addr, unsigned char *data, size_t len, |
|
|
int writeflag, void *extra) |
|
366 |
{ |
{ |
367 |
struct wdc_data *d = extra; |
struct wdc_data *d = extra; |
368 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
394 |
*/ |
*/ |
395 |
void wdc_command(struct cpu *cpu, struct wdc_data *d, int idata) |
void wdc_command(struct cpu *cpu, struct wdc_data *d, int idata) |
396 |
{ |
{ |
397 |
int i; |
size_t i; |
398 |
|
|
399 |
d->cur_command = idata; |
d->cur_command = idata; |
400 |
d->atapi_cmd_in_progress = 0; |
d->atapi_cmd_in_progress = 0; |
412 |
debug("[ wdc: command 0x%02x drive %i, but no disk image ]\n", |
debug("[ wdc: command 0x%02x drive %i, but no disk image ]\n", |
413 |
d->cur_command, d->drive + d->base_drive); |
d->cur_command, d->drive + d->base_drive); |
414 |
d->error |= WDCE_ABRT; |
d->error |= WDCE_ABRT; |
415 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
416 |
return; |
return; |
417 |
} |
} |
418 |
if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive, |
if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive, |
420 |
debug("[ wdc: IDENTIFY drive %i, but it is an ATAPI " |
debug("[ wdc: IDENTIFY drive %i, but it is an ATAPI " |
421 |
"drive ]\n", d->drive + d->base_drive); |
"drive ]\n", d->drive + d->base_drive); |
422 |
d->error |= WDCE_ABRT; |
d->error |= WDCE_ABRT; |
423 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
424 |
return; |
return; |
425 |
} |
} |
426 |
|
|
448 |
case WDCC_IDP: /* Initialize drive parameters */ |
case WDCC_IDP: /* Initialize drive parameters */ |
449 |
debug("[ wdc: IDP drive %i (TODO) ]\n", d->drive); |
debug("[ wdc: IDP drive %i (TODO) ]\n", d->drive); |
450 |
/* TODO */ |
/* TODO */ |
451 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
452 |
break; |
break; |
453 |
|
|
454 |
case SET_FEATURES: |
case SET_FEATURES: |
463 |
default:d->error |= WDCE_ABRT; |
default:d->error |= WDCE_ABRT; |
464 |
} |
} |
465 |
/* TODO: always interrupt? */ |
/* TODO: always interrupt? */ |
466 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
467 |
break; |
break; |
468 |
|
|
469 |
case WDCC_RECAL: |
case WDCC_RECAL: |
470 |
debug("[ wdc: RECAL drive %i ]\n", d->drive); |
debug("[ wdc: RECAL drive %i ]\n", d->drive); |
471 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
472 |
break; |
break; |
473 |
|
|
474 |
case WDCC_IDENTIFY: |
case WDCC_IDENTIFY: |
481 |
wdc_addtoinbuf(d, d->identify_struct[i+1]); |
wdc_addtoinbuf(d, d->identify_struct[i+1]); |
482 |
wdc_addtoinbuf(d, d->identify_struct[i+0]); |
wdc_addtoinbuf(d, d->identify_struct[i+0]); |
483 |
} |
} |
484 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
485 |
break; |
break; |
486 |
|
|
487 |
case WDCC_IDLE_IMMED: |
case WDCC_IDLE_IMMED: |
488 |
debug("[ wdc: IDLE_IMMED drive %i ]\n", d->drive); |
debug("[ wdc: IDLE_IMMED drive %i ]\n", d->drive); |
489 |
/* TODO: interrupt here? */ |
/* TODO: interrupt here? */ |
490 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
491 |
break; |
break; |
492 |
|
|
493 |
case WDCC_SETMULTI: |
case WDCC_SETMULTI: |
494 |
debug("[ wdc: SETMULTI drive %i ]\n", d->drive); |
debug("[ wdc: SETMULTI drive %i ]\n", d->drive); |
495 |
/* TODO: interrupt here? */ |
/* TODO: interrupt here? */ |
496 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
497 |
break; |
break; |
498 |
|
|
499 |
case ATAPI_SOFT_RESET: |
case ATAPI_SOFT_RESET: |
500 |
debug("[ wdc: ATAPI_SOFT_RESET drive %i ]\n", d->drive); |
debug("[ wdc: ATAPI_SOFT_RESET drive %i ]\n", d->drive); |
501 |
/* TODO: interrupt here? */ |
/* TODO: interrupt here? */ |
502 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
503 |
break; |
break; |
504 |
|
|
505 |
case ATAPI_PKT_CMD: |
case ATAPI_PKT_CMD: |
506 |
debug("[ wdc: ATAPI_PKT_CMD drive %i ]\n", d->drive); |
debug("[ wdc: ATAPI_PKT_CMD drive %i ]\n", d->drive); |
507 |
/* TODO: interrupt here? */ |
/* TODO: interrupt here? */ |
508 |
/* d->delayed_interrupt = INT_DELAY; */ |
/* d->int_assert = 1; */ |
509 |
d->atapi_cmd_in_progress = 1; |
d->atapi_cmd_in_progress = 1; |
510 |
d->atapi_phase = PHASE_CMDOUT; |
d->atapi_phase = PHASE_CMDOUT; |
511 |
break; |
break; |
512 |
|
|
513 |
|
case WDCC_DIAGNOSE: |
514 |
|
debug("[ wdc: WDCC_DIAGNOSE drive %i: TODO ]\n", d->drive); |
515 |
|
/* TODO: interrupt here? */ |
516 |
|
d->int_assert = 1; |
517 |
|
d->error = 1; /* No error? */ |
518 |
|
break; |
519 |
|
|
520 |
/* Unsupported commands, without warning: */ |
/* Unsupported commands, without warning: */ |
521 |
case WDCC_SEC_SET_PASSWORD: |
case WDCC_SEC_SET_PASSWORD: |
522 |
case WDCC_SEC_UNLOCK: |
case WDCC_SEC_UNLOCK: |
537 |
} |
} |
538 |
|
|
539 |
|
|
540 |
/* |
DEVICE_ACCESS(wdc) |
|
* dev_wdc_access(): |
|
|
*/ |
|
|
int dev_wdc_access(struct cpu *cpu, struct memory *mem, |
|
|
uint64_t relative_addr, unsigned char *data, size_t len, |
|
|
int writeflag, void *extra) |
|
541 |
{ |
{ |
542 |
struct wdc_data *d = extra; |
struct wdc_data *d = extra; |
543 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
544 |
int i; |
int i; |
545 |
|
|
546 |
|
relative_addr /= d->addr_mult; |
547 |
|
|
548 |
|
if (!d->io_enabled) |
549 |
|
goto ret; |
550 |
|
|
551 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
552 |
if (relative_addr == wd_data) |
if (relative_addr == wd_data) |
553 |
idata = memory_readmax64(cpu, data, len); |
idata = memory_readmax64(cpu, data, len); |
562 |
|
|
563 |
case wd_data: /* 0: data */ |
case wd_data: /* 0: data */ |
564 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
565 |
odata = 0; |
odata = wdc_get_inbuf(d); |
|
|
|
|
odata += wdc_get_inbuf(d); |
|
566 |
|
|
567 |
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
568 |
if (len >= 2) |
if (len >= 2) |
581 |
} |
} |
582 |
|
|
583 |
if (d->data_debug) { |
if (d->data_debug) { |
584 |
char *s = "0x%04llx ]\n"; |
char *s = "0x%04"PRIx64" ]\n"; |
585 |
if (len == 1) |
if (len == 1) |
586 |
s = "0x%02llx ]\n"; |
s = "0x%02"PRIx64" ]\n"; |
587 |
if (len == 4) |
if (len == 4) |
588 |
s = "0x%08llx ]\n"; |
s = "0x%08"PRIx64" ]\n"; |
589 |
if (len == 8) |
if (len == 8) |
590 |
s = "0x%016llx ]\n"; |
s = "0x%016"PRIx64" ]\n"; |
591 |
debug("[ wdc: read from DATA: "); |
debug("[ wdc: read from DATA: "); |
592 |
debug(s, (long long)odata); |
debug(s, (uint64_t) odata); |
593 |
} |
} |
594 |
|
|
595 |
if (d->atapi_cmd_in_progress) { |
if (d->atapi_cmd_in_progress) { |
607 |
} else |
} else |
608 |
d->atapi_phase = |
d->atapi_phase = |
609 |
PHASE_COMPLETED; |
PHASE_COMPLETED; |
610 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
611 |
} |
} |
612 |
} else { |
} else { |
613 |
#if 0 |
#if 0 |
617 |
((d->inbuf_tail - d->inbuf_head) % 512) |
((d->inbuf_tail - d->inbuf_head) % 512) |
618 |
== 0) |
== 0) |
619 |
#endif |
#endif |
620 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
621 |
} |
} |
622 |
} else { |
} else { |
623 |
int inbuf_len; |
int inbuf_len; |
624 |
if (d->data_debug) { |
if (d->data_debug) { |
625 |
char *s = "0x%04llx ]\n"; |
char *s = "0x%04"PRIx64" ]\n"; |
626 |
if (len == 1) |
if (len == 1) |
627 |
s = "0x%02llx ]\n"; |
s = "0x%02"PRIx64" ]\n"; |
628 |
if (len == 4) |
if (len == 4) |
629 |
s = "0x%08llx ]\n"; |
s = "0x%08"PRIx64" ]\n"; |
630 |
if (len == 8) |
if (len == 8) |
631 |
s = "0x%016llx ]\n"; |
s = "0x%016"PRIx64" ]\n"; |
632 |
debug("[ wdc: write to DATA: "); |
debug("[ wdc: write to DATA: "); |
633 |
debug(s, (long long)idata); |
debug(s, (uint64_t) idata); |
634 |
} |
} |
635 |
if (!d->write_in_progress && |
if (!d->write_in_progress && |
636 |
!d->atapi_cmd_in_progress) { |
!d->atapi_cmd_in_progress) { |
676 |
inbuf_len += WDC_INBUF_SIZE; |
inbuf_len += WDC_INBUF_SIZE; |
677 |
|
|
678 |
if (d->atapi_cmd_in_progress && inbuf_len == 12) { |
if (d->atapi_cmd_in_progress && inbuf_len == 12) { |
679 |
unsigned char *scsi_cmd = malloc(12); |
unsigned char *scsi_cmd; |
680 |
int x = 0, res; |
int x = 0, res; |
681 |
|
|
682 |
|
CHECK_ALLOCATION(scsi_cmd = malloc(12)); |
683 |
|
|
684 |
if (d->atapi_st != NULL) |
if (d->atapi_st != NULL) |
685 |
scsi_transfer_free(d->atapi_st); |
scsi_transfer_free(d->atapi_st); |
686 |
d->atapi_st = scsi_transfer_alloc(); |
d->atapi_st = scsi_transfer_alloc(); |
734 |
exit(1); |
exit(1); |
735 |
} |
} |
736 |
|
|
737 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
738 |
} |
} |
739 |
|
|
740 |
if (( d->write_in_progress == WDCC_WRITEMULTI && |
if (( d->write_in_progress == WDCC_WRITEMULTI && |
744 |
inbuf_len % 512 == 0) ) { |
inbuf_len % 512 == 0) ) { |
745 |
int count = (d->write_in_progress == |
int count = (d->write_in_progress == |
746 |
WDCC_WRITEMULTI)? d->write_count : 1; |
WDCC_WRITEMULTI)? d->write_count : 1; |
747 |
unsigned char buf[512 * count]; |
unsigned char *buf, *b; |
748 |
unsigned char *b = buf; |
|
749 |
|
CHECK_ALLOCATION(buf = malloc(512 * count)); |
750 |
|
b = buf; |
751 |
|
|
752 |
if (d->inbuf_tail+512*count <= WDC_INBUF_SIZE) { |
if (d->inbuf_tail+512*count <= WDC_INBUF_SIZE) { |
753 |
b = d->inbuf + d->inbuf_tail; |
b = d->inbuf + d->inbuf_tail; |
765 |
d->write_count -= count; |
d->write_count -= count; |
766 |
d->write_offset += 512 * count; |
d->write_offset += 512 * count; |
767 |
|
|
768 |
d->delayed_interrupt = INT_DELAY; |
d->int_assert = 1; |
769 |
|
|
770 |
if (d->write_count == 0) |
if (d->write_count == 0) |
771 |
d->write_in_progress = 0; |
d->write_in_progress = 0; |
772 |
|
|
773 |
|
free(buf); |
774 |
} |
} |
775 |
} |
} |
776 |
break; |
break; |
778 |
case wd_error: /* 1: error (r), precomp (w) */ |
case wd_error: /* 1: error (r), precomp (w) */ |
779 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
780 |
odata = d->error; |
odata = d->error; |
781 |
debug("[ wdc: read from ERROR: 0x%02x ]\n", |
debug("[ wdc: read from ERROR: 0x%02x ]\n", (int)odata); |
|
(int)odata); |
|
782 |
/* TODO: is the error value cleared on read? */ |
/* TODO: is the error value cleared on read? */ |
783 |
d->error = 0; |
d->error = 0; |
784 |
} else { |
} else { |
874 |
if (!quiet_mode) |
if (!quiet_mode) |
875 |
debug("[ wdc: read from STATUS: 0x%02x ]\n", |
debug("[ wdc: read from STATUS: 0x%02x ]\n", |
876 |
(int)odata); |
(int)odata); |
877 |
cpu_interrupt_ack(cpu, d->irq_nr); |
INTERRUPT_DEASSERT(d->irq); |
878 |
d->int_asserted = 0; |
d->int_assert = 0; |
|
d->delayed_interrupt = 0; |
|
879 |
} else { |
} else { |
880 |
debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata); |
debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata); |
881 |
wdc_command(cpu, d, idata); |
wdc_command(cpu, d, idata); |
891 |
(int)relative_addr, (int)idata); |
(int)relative_addr, (int)idata); |
892 |
} |
} |
893 |
|
|
894 |
if (cpu->machine->machine_type != MACHINE_HPCMIPS && |
/* Assert interrupt, if necessary: */ |
895 |
cpu->machine->machine_type != MACHINE_EVBMIPS && |
dev_wdc_tick(cpu, extra); |
|
cpu->machine->machine_type != MACHINE_BEBOX) |
|
|
dev_wdc_tick(cpu, extra); |
|
896 |
|
|
897 |
|
ret: |
898 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
899 |
if (relative_addr == wd_data) |
if (relative_addr == wd_data) |
900 |
memory_writemax64(cpu, data, len, odata); |
memory_writemax64(cpu, data, len, odata); |
906 |
} |
} |
907 |
|
|
908 |
|
|
909 |
/* |
DEVINIT(wdc) |
|
* devinit_wdc(): |
|
|
*/ |
|
|
int devinit_wdc(struct devinit *devinit) |
|
910 |
{ |
{ |
911 |
struct wdc_data *d; |
struct wdc_data *d; |
912 |
uint64_t alt_status_addr; |
uint64_t alt_status_addr; |
913 |
int i, tick_shift = WDC_TICK_SHIFT; |
int i, tick_shift = WDC_TICK_SHIFT; |
914 |
|
|
915 |
d = malloc(sizeof(struct wdc_data)); |
CHECK_ALLOCATION(d = malloc(sizeof(struct wdc_data))); |
|
if (d == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
916 |
memset(d, 0, sizeof(struct wdc_data)); |
memset(d, 0, sizeof(struct wdc_data)); |
|
d->irq_nr = devinit->irq_nr; |
|
917 |
|
|
918 |
|
INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); |
919 |
|
d->addr_mult = devinit->addr_mult; |
920 |
d->data_debug = 1; |
d->data_debug = 1; |
921 |
|
d->io_enabled = 1; |
922 |
|
|
923 |
d->inbuf = zeroed_alloc(WDC_INBUF_SIZE); |
d->inbuf = zeroed_alloc(WDC_INBUF_SIZE); |
924 |
|
|
929 |
|
|
930 |
alt_status_addr = devinit->addr + 0x206; |
alt_status_addr = devinit->addr + 0x206; |
931 |
|
|
932 |
/* Special hack for pcic/hpcmips: TODO: Fix */ |
/* Special hacks for individual machines: */ |
933 |
if (devinit->addr == 0x14000180) |
switch (devinit->machine->machine_type) { |
934 |
alt_status_addr = 0x14000386; |
case MACHINE_MACPPC: |
935 |
|
alt_status_addr = devinit->addr + 0x160; |
936 |
|
break; |
937 |
|
case MACHINE_HPCMIPS: |
938 |
|
/* TODO: Fix */ |
939 |
|
if (devinit->addr == 0x14000180) |
940 |
|
alt_status_addr = 0x14000386; |
941 |
|
break; |
942 |
|
case MACHINE_IQ80321: |
943 |
|
alt_status_addr = devinit->addr + 0x402; |
944 |
|
break; |
945 |
|
} |
946 |
|
|
947 |
/* Get disk geometries: */ |
/* Get disk geometries: */ |
948 |
for (i=0; i<2; i++) |
for (i=0; i<2; i++) |
955 |
memory_device_register(devinit->machine->memory, "wdc_altstatus", |
memory_device_register(devinit->machine->memory, "wdc_altstatus", |
956 |
alt_status_addr, 2, dev_wdc_altstatus_access, d, DM_DEFAULT, NULL); |
alt_status_addr, 2, dev_wdc_altstatus_access, d, DM_DEFAULT, NULL); |
957 |
memory_device_register(devinit->machine->memory, devinit->name, |
memory_device_register(devinit->machine->memory, devinit->name, |
958 |
devinit->addr, DEV_WDC_LENGTH, dev_wdc_access, d, DM_DEFAULT, |
devinit->addr, DEV_WDC_LENGTH * devinit->addr_mult, dev_wdc_access, |
959 |
NULL); |
d, DM_DEFAULT, NULL); |
|
|
|
|
if (devinit->machine->machine_type != MACHINE_HPCMIPS && |
|
|
devinit->machine->machine_type != MACHINE_EVBMIPS) |
|
|
tick_shift += 1; |
|
960 |
|
|
961 |
machine_add_tickfunction(devinit->machine, dev_wdc_tick, |
machine_add_tickfunction(devinit->machine, dev_wdc_tick, |
962 |
d, tick_shift); |
d, tick_shift); |
963 |
|
|
964 |
|
devinit->return_ptr = d; |
965 |
|
|
966 |
return 1; |
return 1; |
967 |
} |
} |
968 |
|
|