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.63 2006/02/18 13:15:21 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) |
779 |
case wd_error: /* 1: error (r), precomp (w) */ |
case wd_error: /* 1: error (r), precomp (w) */ |
780 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
781 |
odata = d->error; |
odata = d->error; |
782 |
debug("[ wdc: read from ERROR: 0x%02x ]\n", |
debug("[ wdc: read from ERROR: 0x%02x ]\n", (int)odata); |
|
(int)odata); |
|
783 |
/* TODO: is the error value cleared on read? */ |
/* TODO: is the error value cleared on read? */ |
784 |
d->error = 0; |
d->error = 0; |
785 |
} else { |
} else { |
909 |
} |
} |
910 |
|
|
911 |
|
|
912 |
/* |
DEVINIT(wdc) |
|
* devinit_wdc(): |
|
|
*/ |
|
|
int devinit_wdc(struct devinit *devinit) |
|
913 |
{ |
{ |
914 |
struct wdc_data *d; |
struct wdc_data *d; |
915 |
uint64_t alt_status_addr; |
uint64_t alt_status_addr; |
921 |
exit(1); |
exit(1); |
922 |
} |
} |
923 |
memset(d, 0, sizeof(struct wdc_data)); |
memset(d, 0, sizeof(struct wdc_data)); |
924 |
d->irq_nr = devinit->irq_nr; |
d->irq_nr = devinit->irq_nr; |
925 |
|
d->addr_mult = devinit->addr_mult; |
926 |
d->data_debug = 1; |
d->data_debug = 1; |
927 |
|
|
928 |
d->inbuf = zeroed_alloc(WDC_INBUF_SIZE); |
d->inbuf = zeroed_alloc(WDC_INBUF_SIZE); |
934 |
|
|
935 |
alt_status_addr = devinit->addr + 0x206; |
alt_status_addr = devinit->addr + 0x206; |
936 |
|
|
937 |
/* Special hack for pcic/hpcmips: TODO: Fix */ |
/* Special hacks for individual machines: */ |
938 |
if (devinit->addr == 0x14000180) |
switch (devinit->machine->machine_type) { |
939 |
alt_status_addr = 0x14000386; |
case MACHINE_MACPPC: |
940 |
|
alt_status_addr = devinit->addr + 0x160; |
941 |
|
break; |
942 |
|
case MACHINE_HPCMIPS: |
943 |
|
/* TODO: Fix */ |
944 |
|
if (devinit->addr == 0x14000180) |
945 |
|
alt_status_addr = 0x14000386; |
946 |
|
break; |
947 |
|
case MACHINE_IQ80321: |
948 |
|
alt_status_addr = devinit->addr + 0x402; |
949 |
|
break; |
950 |
|
} |
951 |
|
|
952 |
/* Get disk geometries: */ |
/* Get disk geometries: */ |
953 |
for (i=0; i<2; i++) |
for (i=0; i<2; i++) |
960 |
memory_device_register(devinit->machine->memory, "wdc_altstatus", |
memory_device_register(devinit->machine->memory, "wdc_altstatus", |
961 |
alt_status_addr, 2, dev_wdc_altstatus_access, d, DM_DEFAULT, NULL); |
alt_status_addr, 2, dev_wdc_altstatus_access, d, DM_DEFAULT, NULL); |
962 |
memory_device_register(devinit->machine->memory, devinit->name, |
memory_device_register(devinit->machine->memory, devinit->name, |
963 |
devinit->addr, DEV_WDC_LENGTH, dev_wdc_access, d, DM_DEFAULT, |
devinit->addr, DEV_WDC_LENGTH * devinit->addr_mult, dev_wdc_access, |
964 |
NULL); |
d, DM_DEFAULT, NULL); |
965 |
|
|
966 |
if (devinit->machine->machine_type != MACHINE_HPCMIPS && |
if (devinit->machine->machine_type != MACHINE_HPCMIPS && |
967 |
devinit->machine->machine_type != MACHINE_EVBMIPS) |
devinit->machine->machine_type != MACHINE_EVBMIPS) |