1 |
/* |
/* |
2 |
* Copyright (C) 2004-2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2004-2006 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.66 2006/04/20 16:59:05 debug Exp $ |
29 |
* |
* |
30 |
* Standard "wdc" IDE controller. |
* Standard "wdc" IDE controller. |
31 |
*/ |
*/ |
66 |
|
|
67 |
struct wdc_data { |
struct wdc_data { |
68 |
int irq_nr; |
int irq_nr; |
69 |
|
int addr_mult; |
70 |
int base_drive; |
int base_drive; |
71 |
int data_debug; |
int data_debug; |
72 |
|
|
102 |
int atapi_phase; |
int atapi_phase; |
103 |
struct scsi_transfer *atapi_st; |
struct scsi_transfer *atapi_st; |
104 |
int atapi_len; |
int atapi_len; |
105 |
int atapi_received; |
size_t atapi_received; |
106 |
|
|
107 |
unsigned char identify_struct[512]; |
unsigned char identify_struct[512]; |
108 |
}; |
}; |
212 |
/* 27-46: Model number */ |
/* 27-46: Model number */ |
213 |
if (diskimage_getname(cpu->machine, d->drive + d->base_drive, |
if (diskimage_getname(cpu->machine, d->drive + d->base_drive, |
214 |
DISKIMAGE_IDE, namebuf, sizeof(namebuf))) { |
DISKIMAGE_IDE, namebuf, sizeof(namebuf))) { |
215 |
int i; |
size_t i; |
216 |
for (i=0; i<sizeof(namebuf); i++) |
for (i=0; i<sizeof(namebuf); i++) |
217 |
if (namebuf[i] == 0) { |
if (namebuf[i] == 0) { |
218 |
for (; i<sizeof(namebuf); i++) |
for (; i<sizeof(namebuf); i++) |
369 |
/* |
/* |
370 |
* dev_wdc_altstatus_access(): |
* dev_wdc_altstatus_access(): |
371 |
*/ |
*/ |
372 |
int dev_wdc_altstatus_access(struct cpu *cpu, struct memory *mem, |
DEVICE_ACCESS(wdc_altstatus) |
|
uint64_t relative_addr, unsigned char *data, size_t len, |
|
|
int writeflag, void *extra) |
|
373 |
{ |
{ |
374 |
struct wdc_data *d = extra; |
struct wdc_data *d = extra; |
375 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
401 |
*/ |
*/ |
402 |
void wdc_command(struct cpu *cpu, struct wdc_data *d, int idata) |
void wdc_command(struct cpu *cpu, struct wdc_data *d, int idata) |
403 |
{ |
{ |
404 |
int i; |
size_t i; |
405 |
|
|
406 |
d->cur_command = idata; |
d->cur_command = idata; |
407 |
d->atapi_cmd_in_progress = 0; |
d->atapi_cmd_in_progress = 0; |
517 |
d->atapi_phase = PHASE_CMDOUT; |
d->atapi_phase = PHASE_CMDOUT; |
518 |
break; |
break; |
519 |
|
|
520 |
|
case WDCC_DIAGNOSE: |
521 |
|
debug("[ wdc: WDCC_DIAGNOSE drive %i: TODO ]\n", d->drive); |
522 |
|
/* TODO: interrupt here? */ |
523 |
|
d->delayed_interrupt = INT_DELAY; |
524 |
|
d->error = 1; /* No error? */ |
525 |
|
break; |
526 |
|
|
527 |
/* Unsupported commands, without warning: */ |
/* Unsupported commands, without warning: */ |
528 |
case WDCC_SEC_SET_PASSWORD: |
case WDCC_SEC_SET_PASSWORD: |
529 |
case WDCC_SEC_UNLOCK: |
case WDCC_SEC_UNLOCK: |
547 |
/* |
/* |
548 |
* dev_wdc_access(): |
* dev_wdc_access(): |
549 |
*/ |
*/ |
550 |
int dev_wdc_access(struct cpu *cpu, struct memory *mem, |
DEVICE_ACCESS(wdc) |
|
uint64_t relative_addr, unsigned char *data, size_t len, |
|
|
int writeflag, void *extra) |
|
551 |
{ |
{ |
552 |
struct wdc_data *d = extra; |
struct wdc_data *d = extra; |
553 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
554 |
int i; |
int i; |
555 |
|
|
556 |
|
relative_addr /= d->addr_mult; |
557 |
|
|
558 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
559 |
if (relative_addr == wd_data) |
if (relative_addr == wd_data) |
560 |
idata = memory_readmax64(cpu, data, len); |
idata = memory_readmax64(cpu, data, len); |
569 |
|
|
570 |
case wd_data: /* 0: data */ |
case wd_data: /* 0: data */ |
571 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
572 |
odata = 0; |
odata = wdc_get_inbuf(d); |
|
|
|
|
odata += wdc_get_inbuf(d); |
|
573 |
|
|
574 |
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
575 |
if (len >= 2) |
if (len >= 2) |
588 |
} |
} |
589 |
|
|
590 |
if (d->data_debug) { |
if (d->data_debug) { |
591 |
char *s = "0x%04llx ]\n"; |
char *s = "0x%04"PRIx64" ]\n"; |
592 |
if (len == 1) |
if (len == 1) |
593 |
s = "0x%02llx ]\n"; |
s = "0x%02"PRIx64" ]\n"; |
594 |
if (len == 4) |
if (len == 4) |
595 |
s = "0x%08llx ]\n"; |
s = "0x%08"PRIx64" ]\n"; |
596 |
if (len == 8) |
if (len == 8) |
597 |
s = "0x%016llx ]\n"; |
s = "0x%016"PRIx64" ]\n"; |
598 |
debug("[ wdc: read from DATA: "); |
debug("[ wdc: read from DATA: "); |
599 |
debug(s, (long long)odata); |
debug(s, (uint64_t) odata); |
600 |
} |
} |
601 |
|
|
602 |
if (d->atapi_cmd_in_progress) { |
if (d->atapi_cmd_in_progress) { |
629 |
} else { |
} else { |
630 |
int inbuf_len; |
int inbuf_len; |
631 |
if (d->data_debug) { |
if (d->data_debug) { |
632 |
char *s = "0x%04llx ]\n"; |
char *s = "0x%04"PRIx64" ]\n"; |
633 |
if (len == 1) |
if (len == 1) |
634 |
s = "0x%02llx ]\n"; |
s = "0x%02"PRIx64" ]\n"; |
635 |
if (len == 4) |
if (len == 4) |
636 |
s = "0x%08llx ]\n"; |
s = "0x%08"PRIx64" ]\n"; |
637 |
if (len == 8) |
if (len == 8) |
638 |
s = "0x%016llx ]\n"; |
s = "0x%016"PRIx64" ]\n"; |
639 |
debug("[ wdc: write to DATA: "); |
debug("[ wdc: write to DATA: "); |
640 |
debug(s, (long long)idata); |
debug(s, (uint64_t) idata); |
641 |
} |
} |
642 |
if (!d->write_in_progress && |
if (!d->write_in_progress && |
643 |
!d->atapi_cmd_in_progress) { |
!d->atapi_cmd_in_progress) { |
749 |
inbuf_len % 512 == 0) ) { |
inbuf_len % 512 == 0) ) { |
750 |
int count = (d->write_in_progress == |
int count = (d->write_in_progress == |
751 |
WDCC_WRITEMULTI)? d->write_count : 1; |
WDCC_WRITEMULTI)? d->write_count : 1; |
752 |
unsigned char buf[512 * count]; |
unsigned char *buf = malloc(512 * count); |
753 |
unsigned char *b = buf; |
unsigned char *b = buf; |
754 |
|
|
755 |
|
if (buf == NULL) { |
756 |
|
fprintf(stderr, "out of memory\n"); |
757 |
|
exit(1); |
758 |
|
} |
759 |
|
|
760 |
if (d->inbuf_tail+512*count <= WDC_INBUF_SIZE) { |
if (d->inbuf_tail+512*count <= WDC_INBUF_SIZE) { |
761 |
b = d->inbuf + d->inbuf_tail; |
b = d->inbuf + d->inbuf_tail; |
762 |
d->inbuf_tail = (d->inbuf_tail + 512 |
d->inbuf_tail = (d->inbuf_tail + 512 |
777 |
|
|
778 |
if (d->write_count == 0) |
if (d->write_count == 0) |
779 |
d->write_in_progress = 0; |
d->write_in_progress = 0; |
780 |
|
|
781 |
|
free(buf); |
782 |
} |
} |
783 |
} |
} |
784 |
break; |
break; |
786 |
case wd_error: /* 1: error (r), precomp (w) */ |
case wd_error: /* 1: error (r), precomp (w) */ |
787 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
788 |
odata = d->error; |
odata = d->error; |
789 |
debug("[ wdc: read from ERROR: 0x%02x ]\n", |
debug("[ wdc: read from ERROR: 0x%02x ]\n", (int)odata); |
|
(int)odata); |
|
790 |
/* TODO: is the error value cleared on read? */ |
/* TODO: is the error value cleared on read? */ |
791 |
d->error = 0; |
d->error = 0; |
792 |
} else { |
} else { |
916 |
} |
} |
917 |
|
|
918 |
|
|
919 |
/* |
DEVINIT(wdc) |
|
* devinit_wdc(): |
|
|
*/ |
|
|
int devinit_wdc(struct devinit *devinit) |
|
920 |
{ |
{ |
921 |
struct wdc_data *d; |
struct wdc_data *d; |
922 |
uint64_t alt_status_addr; |
uint64_t alt_status_addr; |
928 |
exit(1); |
exit(1); |
929 |
} |
} |
930 |
memset(d, 0, sizeof(struct wdc_data)); |
memset(d, 0, sizeof(struct wdc_data)); |
931 |
d->irq_nr = devinit->irq_nr; |
d->irq_nr = devinit->irq_nr; |
932 |
|
d->addr_mult = devinit->addr_mult; |
933 |
d->data_debug = 1; |
d->data_debug = 1; |
934 |
|
|
935 |
d->inbuf = zeroed_alloc(WDC_INBUF_SIZE); |
d->inbuf = zeroed_alloc(WDC_INBUF_SIZE); |
941 |
|
|
942 |
alt_status_addr = devinit->addr + 0x206; |
alt_status_addr = devinit->addr + 0x206; |
943 |
|
|
944 |
/* Special hack for pcic/hpcmips: TODO: Fix */ |
/* Special hacks for individual machines: */ |
945 |
if (devinit->addr == 0x14000180) |
switch (devinit->machine->machine_type) { |
946 |
alt_status_addr = 0x14000386; |
case MACHINE_MACPPC: |
947 |
|
alt_status_addr = devinit->addr + 0x160; |
948 |
|
break; |
949 |
|
case MACHINE_HPCMIPS: |
950 |
|
/* TODO: Fix */ |
951 |
|
if (devinit->addr == 0x14000180) |
952 |
|
alt_status_addr = 0x14000386; |
953 |
|
break; |
954 |
|
case MACHINE_IQ80321: |
955 |
|
alt_status_addr = devinit->addr + 0x402; |
956 |
|
break; |
957 |
|
} |
958 |
|
|
959 |
/* Get disk geometries: */ |
/* Get disk geometries: */ |
960 |
for (i=0; i<2; i++) |
for (i=0; i<2; i++) |
967 |
memory_device_register(devinit->machine->memory, "wdc_altstatus", |
memory_device_register(devinit->machine->memory, "wdc_altstatus", |
968 |
alt_status_addr, 2, dev_wdc_altstatus_access, d, DM_DEFAULT, NULL); |
alt_status_addr, 2, dev_wdc_altstatus_access, d, DM_DEFAULT, NULL); |
969 |
memory_device_register(devinit->machine->memory, devinit->name, |
memory_device_register(devinit->machine->memory, devinit->name, |
970 |
devinit->addr, DEV_WDC_LENGTH, dev_wdc_access, d, DM_DEFAULT, |
devinit->addr, DEV_WDC_LENGTH * devinit->addr_mult, dev_wdc_access, |
971 |
NULL); |
d, DM_DEFAULT, NULL); |
972 |
|
|
973 |
if (devinit->machine->machine_type != MACHINE_HPCMIPS && |
if (devinit->machine->machine_type != MACHINE_HPCMIPS && |
974 |
devinit->machine->machine_type != MACHINE_EVBMIPS) |
devinit->machine->machine_type != MACHINE_EVBMIPS) |
975 |
tick_shift += 1; |
tick_shift += 1; |
976 |
|
|
977 |
machine_add_tickfunction(devinit->machine, dev_wdc_tick, |
machine_add_tickfunction(devinit->machine, dev_wdc_tick, |
978 |
d, tick_shift); |
d, tick_shift, 0.0); |
979 |
|
|
980 |
return 1; |
return 1; |
981 |
} |
} |