/[gxemul]/trunk/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

Contents of /trunk/src/devices/dev_wdc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 16043 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.2  ==============


1 /*
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 *
28 * $Id: dev_wdc.c,v 1.33 2005/04/14 20:55:23 debug Exp $
29 *
30 * Standard IDE controller.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "console.h"
38 #include "cop0.h"
39 #include "cpu.h"
40 #include "devices.h"
41 #include "diskimage.h"
42 #include "machine.h"
43 #include "memory.h"
44 #include "misc.h"
45
46 #include "wdcreg.h"
47
48
49 #define WDC_TICK_SHIFT 14
50 #define WDC_INBUF_SIZE (512*257)
51
52 /* INT_DELAY=2 to be safe, 1 is faster but maybe buggy. */
53 #define INT_DELAY 1
54
55 /* #define debug fatal */
56 /* #define DATA_DEBUG */
57
58 struct wdc_data {
59 int irq_nr;
60 int base_drive;
61
62 int delayed_interrupt;
63
64 unsigned char identify_struct[512];
65
66 unsigned char inbuf[WDC_INBUF_SIZE];
67 int inbuf_head;
68 int inbuf_tail;
69
70 int write_in_progress;
71 int write_count;
72 int64_t write_offset;
73
74 int error;
75 int precomp;
76 int seccnt;
77 int sector;
78 int cyl_lo;
79 int cyl_hi;
80 int sectorsize;
81 int lba;
82 int drive;
83 int head;
84 int cur_command;
85 };
86
87
88 /*
89 * dev_wdc_tick():
90 */
91 void dev_wdc_tick(struct cpu *cpu, void *extra)
92 {
93 struct wdc_data *d = extra;
94
95 if (d->delayed_interrupt) {
96 d->delayed_interrupt --;
97
98 if (d->delayed_interrupt == 0)
99 cpu_interrupt(cpu, d->irq_nr);
100 }
101 }
102
103
104 /*
105 * wdc_addtoinbuf():
106 *
107 * Write to the inbuf at its head, read at its tail.
108 */
109 static void wdc_addtoinbuf(struct wdc_data *d, int c)
110 {
111 d->inbuf[d->inbuf_head] = c;
112
113 d->inbuf_head = (d->inbuf_head + 1) % WDC_INBUF_SIZE;
114 if (d->inbuf_head == d->inbuf_tail)
115 fatal("WARNING! wdc inbuf overrun\n");
116 }
117
118
119 /*
120 * wdc_get_inbuf():
121 *
122 * Read from the tail of inbuf.
123 */
124 static uint64_t wdc_get_inbuf(struct wdc_data *d)
125 {
126 int c = d->inbuf[d->inbuf_tail];
127
128 if (d->inbuf_head == d->inbuf_tail) {
129 fatal("WARNING! someone is reading too much from the "
130 "wdc inbuf!\n");
131 return -1;
132 }
133
134 d->inbuf_tail = (d->inbuf_tail + 1) % WDC_INBUF_SIZE;
135 return c;
136 }
137
138
139 /*
140 * wdc_initialize_identify_struct(d):
141 */
142 static void wdc_initialize_identify_struct(struct cpu *cpu, struct wdc_data *d)
143 {
144 uint64_t total_size, cyls;
145
146 total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive);
147
148 memset(d->identify_struct, 0, sizeof(d->identify_struct));
149
150 cyls = total_size / (63 * 16 * 512);
151 if (cyls * 63*16*512 < total_size)
152 cyls ++;
153
154 /* Offsets are in 16-bit WORDS! High byte, then low. */
155
156 /* 0: general flags */
157 d->identify_struct[2 * 0 + 0] = 0;
158 d->identify_struct[2 * 0 + 1] = 1 << 6;
159
160 /* 1: nr of cylinders */
161 d->identify_struct[2 * 1 + 0] = (cyls >> 8);
162 d->identify_struct[2 * 1 + 1] = cyls & 255;
163
164 /* 3: nr of heads */
165 d->identify_struct[2 * 3 + 0] = 0;
166 d->identify_struct[2 * 3 + 1] = 16;
167
168 /* 6: sectors per track */
169 d->identify_struct[2 * 6 + 0] = 0;
170 d->identify_struct[2 * 6 + 1] = 63;
171
172 /* 10-19: Serial number */
173 memcpy(&d->identify_struct[2 * 10], "S/N 1234-5678 ", 20);
174
175 /* 23-26: Firmware version */
176 memcpy(&d->identify_struct[2 * 23], "VER 1.0 ", 8);
177
178 /* 27-46: Model number */
179 memcpy(&d->identify_struct[2 * 27],
180 "Fake GXemul IDE disk ", 40);
181 /* TODO: Use the diskimage's filename instead? */
182
183 /* 47: max sectors per multitransfer */
184 d->identify_struct[2 * 47 + 0] = 0x80;
185 d->identify_struct[2 * 47 + 1] = 1; /* 1 or 16? */
186
187 /* 57-58: current capacity in sectors */
188 d->identify_struct[2 * 57 + 0] = ((total_size / 512) >> 24) % 255;
189 d->identify_struct[2 * 57 + 1] = ((total_size / 512) >> 16) % 255;
190 d->identify_struct[2 * 58 + 0] = ((total_size / 512) >> 8) % 255;
191 d->identify_struct[2 * 58 + 1] = (total_size / 512) & 255;
192
193 /* 60-61: total nr of addresable sectors */
194 d->identify_struct[2 * 60 + 0] = ((total_size / 512) >> 24) % 255;
195 d->identify_struct[2 * 60 + 1] = ((total_size / 512) >> 16) % 255;
196 d->identify_struct[2 * 61 + 0] = ((total_size / 512) >> 8) % 255;
197 d->identify_struct[2 * 61 + 1] = (total_size / 512) & 255;
198
199 }
200
201
202 /*
203 * status_byte():
204 */
205 static int status_byte(struct wdc_data *d, struct cpu *cpu)
206 {
207 int odata = 0;
208
209 if (diskimage_exist(cpu->machine,
210 d->drive + d->base_drive))
211 odata |= WDCS_DRDY;
212 if (d->inbuf_head != d->inbuf_tail)
213 odata |= WDCS_DRQ;
214 if (d->write_in_progress)
215 odata |= WDCS_DRQ;
216 if (d->error)
217 odata |= WDCS_ERR;
218
219 #if 0
220 /*
221 * TODO: Is this correct behaviour?
222 *
223 * NetBSD/cobalt seems to want it, but Linux on MobilePro does not.
224 */
225 if (!diskimage_exist(cpu->machine,
226 d->drive + d->base_drive))
227 odata = 0xff;
228 #endif
229
230 return odata;
231 }
232
233
234 /*
235 * dev_wdc_altstatus_access():
236 */
237 int dev_wdc_altstatus_access(struct cpu *cpu, struct memory *mem,
238 uint64_t relative_addr, unsigned char *data, size_t len,
239 int writeflag, void *extra)
240 {
241 struct wdc_data *d = extra;
242 uint64_t idata = 0, odata = 0;
243
244 idata = memory_readmax64(cpu, data, len);
245
246 /* Same as the normal status byte? */
247 odata = status_byte(d, cpu);
248
249 if (writeflag==MEM_READ)
250 debug("[ wdc: read from ALTSTATUS: 0x%02x ]\n",
251 (int)odata);
252 else
253 debug("[ wdc: write to ALT. CTRL: 0x%02x ]\n",
254 (int)idata);
255
256 if (writeflag == MEM_READ)
257 memory_writemax64(cpu, data, len, odata);
258
259 return 1;
260 }
261
262
263 /*
264 * dev_wdc_access():
265 */
266 int dev_wdc_access(struct cpu *cpu, struct memory *mem,
267 uint64_t relative_addr, unsigned char *data, size_t len,
268 int writeflag, void *extra)
269 {
270 struct wdc_data *d = extra;
271 uint64_t idata = 0, odata = 0;
272 int i;
273
274 idata = memory_readmax64(cpu, data, len);
275
276 switch (relative_addr) {
277
278 case wd_data: /* 0: data */
279 if (writeflag==MEM_READ) {
280 odata = 0;
281
282 /* TODO: This is hardcoded for little-endian? */
283
284 odata += wdc_get_inbuf(d);
285 if (len >= 2)
286 odata += (wdc_get_inbuf(d) << 8);
287 if (len == 4) {
288 odata += (wdc_get_inbuf(d) << 16);
289 odata += (wdc_get_inbuf(d) << 24);
290 }
291
292 #ifdef DATA_DEBUG
293 debug("[ wdc: read from DATA: 0x%04x ]\n", odata);
294 #endif
295
296 if (d->inbuf_tail != d->inbuf_head)
297 d->delayed_interrupt = INT_DELAY;
298
299 } else {
300 int inbuf_len;
301 #ifdef DATA_DEBUG
302 debug("[ wdc: write to DATA (len=%i): 0x%08lx ]\n",
303 (int)len, (long)idata);
304 #endif
305 if (!d->write_in_progress) {
306 fatal("[ wdc: write to DATA, but not "
307 "expecting any? (len=%i): 0x%08lx ]\n",
308 (int)len, (long)idata);
309 }
310
311 switch (len) {
312 case 4: wdc_addtoinbuf(d, idata & 0xff);
313 wdc_addtoinbuf(d, (idata >> 8) & 0xff);
314 wdc_addtoinbuf(d, (idata >> 16) & 0xff);
315 wdc_addtoinbuf(d, (idata >> 24) & 0xff);
316 break;
317 case 2: wdc_addtoinbuf(d, idata & 0xff);
318 wdc_addtoinbuf(d, (idata >> 8) & 0xff);
319 break;
320 case 1: wdc_addtoinbuf(d, idata); break;
321 default:fatal("wdc: unimplemented write len %i\n", len);
322 exit(1);
323 }
324
325 inbuf_len = d->inbuf_head - d->inbuf_tail;
326 while (inbuf_len < 0)
327 inbuf_len += WDC_INBUF_SIZE;
328
329 #if 0
330 if ((inbuf_len % (512 * d->write_count)) == 0) {
331 #endif
332 if ((inbuf_len % 512) == 0) {
333 int count = 1; /* d->write_count; */
334 unsigned char *buf = malloc(count * 512);
335 if (buf == NULL) {
336 fprintf(stderr, "out of memory\n");
337 exit(1);
338 }
339
340 for (i=0; i<512 * count; i++)
341 buf[i] = wdc_get_inbuf(d);
342
343 diskimage_access(cpu->machine,
344 d->drive + d->base_drive, 1,
345 d->write_offset, buf, 512 * count);
346 free(buf);
347
348 d->write_count --;
349 d->write_offset += 512;
350
351 d->delayed_interrupt = INT_DELAY;
352
353 if (d->write_count == 0)
354 d->write_in_progress = 0;
355 }
356 }
357 break;
358
359 case wd_error: /* 1: error (r), precomp (w) */
360 if (writeflag==MEM_READ) {
361 odata = d->error;
362 debug("[ wdc: read from ERROR: 0x%02x ]\n", odata);
363 /* TODO: is the error value cleared on read? */
364 d->error = 0;
365 } else {
366 d->precomp = idata;
367 debug("[ wdc: write to PRECOMP: 0x%02x ]\n", idata);
368 }
369 break;
370
371 case wd_seccnt: /* 2: sector count */
372 if (writeflag==MEM_READ) {
373 odata = d->seccnt;
374 debug("[ wdc: read from SECCNT: 0x%02x ]\n", odata);
375 } else {
376 d->seccnt = idata;
377 debug("[ wdc: write to SECCNT: 0x%02x ]\n", idata);
378 }
379 break;
380
381 case wd_sector: /* 3: first sector */
382 if (writeflag==MEM_READ) {
383 odata = d->sector;
384 debug("[ wdc: read from SECTOR: 0x%02x ]\n", odata);
385 } else {
386 d->sector = idata;
387 debug("[ wdc: write to SECTOR: 0x%02x ]\n", idata);
388 }
389 break;
390
391 case wd_cyl_lo: /* 4: cylinder low */
392 if (writeflag==MEM_READ) {
393 odata = d->cyl_lo;
394 debug("[ wdc: read from CYL_LO: 0x%02x ]\n", odata);
395 } else {
396 d->cyl_lo = idata;
397 debug("[ wdc: write to CYL_LO: 0x%02x ]\n", idata);
398 }
399 break;
400
401 case wd_cyl_hi: /* 5: cylinder low */
402 if (writeflag==MEM_READ) {
403 odata = d->cyl_hi;
404 debug("[ wdc: read from CYL_HI: 0x%02x ]\n", odata);
405 } else {
406 d->cyl_hi = idata;
407 debug("[ wdc: write to CYL_HI: 0x%02x ]\n", idata);
408 }
409 break;
410
411 case wd_sdh: /* 6: sectorsize/drive/head */
412 if (writeflag==MEM_READ) {
413 odata = (d->sectorsize << 6) + (d->lba << 5) +
414 (d->drive << 4) + (d->head);
415 debug("[ wdc: read from SDH: 0x%02x (sectorsize %i,"
416 " lba=%i, drive %i, head %i) ]\n", (int)odata,
417 d->sectorsize, d->lba, d->drive, d->head);
418 } else {
419 d->sectorsize = (idata >> 6) & 3;
420 d->lba = (idata >> 5) & 1;
421 d->drive = (idata >> 4) & 1;
422 d->head = idata & 0xf;
423 debug("[ wdc: write to SDH: 0x%02x (sectorsize %i,"
424 " lba=%i, drive %i, head %i) ]\n", (int)idata,
425 d->sectorsize, d->lba, d->drive, d->head);
426 }
427 break;
428
429 case wd_command: /* 7: command or status */
430 if (writeflag==MEM_READ) {
431 odata = status_byte(d, cpu);
432 #if 1
433 debug("[ wdc: read from STATUS: 0x%02x ]\n", odata);
434 #endif
435
436 cpu_interrupt_ack(cpu, d->irq_nr);
437 d->delayed_interrupt = 0;
438 } else {
439 debug("[ wdc: write to COMMAND: 0x%02x ]\n", idata);
440 d->cur_command = idata;
441
442 /* TODO: Is this correct behaviour? */
443 if (!diskimage_exist(cpu->machine,
444 d->drive + d->base_drive)) {
445 d->error |= WDCE_ABRT;
446 d->delayed_interrupt = INT_DELAY;
447 break;
448 }
449
450 /* Handle the command: */
451 switch (d->cur_command) {
452 case WDCC_READ:
453 debug("[ wdc: READ from drive %i, head %i, "
454 "cylinder %i, sector %i, nsecs %i ]\n",
455 d->drive, d->head, d->cyl_hi*256+d->cyl_lo,
456 d->sector, d->seccnt);
457 /* TODO: HAHA! This should be removed
458 quickly */
459 {
460 unsigned char buf[512*256];
461 int cyl = d->cyl_hi * 256+ d->cyl_lo;
462 int count = d->seccnt? d->seccnt : 256;
463 uint64_t offset = 512 * (d->sector - 1
464 + d->head * 63 + 16*63*cyl);
465
466 #if 0
467 /* LBA: */
468 if (d->lba)
469 offset = 512 * (((d->head & 0xf) << 24) + (cyl << 8) + d->sector);
470 printf("WDC read from offset %lli\n", (long long)offset);
471 #endif
472 diskimage_access(cpu->machine,
473 d->drive + d->base_drive, 0,
474 offset, buf, 512 * count);
475 /* TODO: result code */
476 for (i=0; i<512 * count; i++)
477 wdc_addtoinbuf(d, buf[i]);
478 }
479 d->delayed_interrupt = INT_DELAY;
480 break;
481 case WDCC_WRITE:
482 debug("[ wdc: WRITE to drive %i, head %i, "
483 "cylinder %i, sector %i, nsecs %i ]\n",
484 d->drive, d->head, d->cyl_hi*256+d->cyl_lo,
485 d->sector, d->seccnt);
486 /* TODO: HAHA! This should be removed
487 quickly */
488 {
489 int cyl = d->cyl_hi * 256+ d->cyl_lo;
490 int count = d->seccnt? d->seccnt : 256;
491 uint64_t offset = 512 * (d->sector - 1
492 + d->head * 63 + 16*63*cyl);
493
494 #if 0
495 /* LBA: */
496 if (d->lba)
497 offset = 512 * (((d->head & 0xf) << 24) + (cyl << 8) + d->sector);
498 printf("WDC write to offset %lli\n", (long long)offset);
499 #endif
500
501 d->write_in_progress = 1;
502 d->write_count = count;
503 d->write_offset = offset;
504
505 /* TODO: result code */
506 }
507 /* TODO: Really interrupt here? */
508 #if 0
509 d->delayed_interrupt = INT_DELAY;
510 #endif
511 break;
512
513 case WDCC_IDP: /* Initialize drive parameters */
514 debug("[ wdc: IDP drive %i (TODO) ]\n",
515 d->drive);
516 /* TODO */
517 d->delayed_interrupt = INT_DELAY;
518 break;
519 case SET_FEATURES:
520 fatal("[ wdc: SET_FEATURES drive %i (TODO), "
521 "feature 0x%02x ]\n", d->drive, d->precomp);
522 /* TODO */
523 switch (d->precomp) {
524 case WDSF_SET_MODE:
525 fatal("[ wdc: WDSF_SET_MODE drive %i, "
526 "pio/dma flags 0x%02x ]\n",
527 d->drive, d->seccnt);
528 break;
529 default:
530 d->error |= WDCE_ABRT;
531 }
532 /* TODO: always interrupt? */
533 d->delayed_interrupt = INT_DELAY;
534 break;
535 case WDCC_RECAL:
536 debug("[ wdc: RECAL drive %i ]\n", d->drive);
537 d->delayed_interrupt = INT_DELAY;
538 break;
539 case WDCC_IDENTIFY:
540 debug("[ wdc: IDENTIFY drive %i ]\n", d->drive);
541 wdc_initialize_identify_struct(cpu, d);
542 /* The IDENTIFY data block is sent out
543 in low/high byte order: */
544 for (i=0; i<sizeof(d->identify_struct); i+=2) {
545 wdc_addtoinbuf(d, d->identify_struct
546 [i+1]);
547 wdc_addtoinbuf(d, d->identify_struct
548 [i+0]);
549 }
550 d->delayed_interrupt = INT_DELAY;
551 break;
552 case WDCC_IDLE_IMMED:
553 debug("[ wdc: IDLE_IMMED drive %i ]\n",
554 d->drive);
555 /* TODO: interrupt here? */
556 d->delayed_interrupt = INT_DELAY;
557 break;
558 default:
559 /* TODO */
560 d->error |= WDCE_ABRT;
561
562 fatal("[ wdc: unknown command 0x%02x ("
563 "drive %i, head %i, cylinder %i, sector %i,"
564 " nsecs %i) ]\n", d->cur_command, d->drive,
565 d->head, d->cyl_hi*256+d->cyl_lo,
566 d->sector, d->seccnt);
567 exit(1);
568 }
569 }
570 break;
571
572 default:
573 if (writeflag==MEM_READ)
574 debug("[ wdc: read from 0x%02x ]\n",
575 (int)relative_addr);
576 else
577 debug("[ wdc: write to 0x%02x: 0x%02x ]\n",
578 (int)relative_addr, (int)idata);
579 }
580
581 if (writeflag == MEM_READ)
582 memory_writemax64(cpu, data, len, odata);
583
584 return 1;
585 }
586
587
588 /*
589 * dev_wdc_init():
590 *
591 * base_drive should be 0 for the primary device, and 2 for the secondary.
592 */
593 void dev_wdc_init(struct machine *machine, struct memory *mem,
594 uint64_t baseaddr, int irq_nr, int base_drive)
595 {
596 struct wdc_data *d;
597 uint64_t alt_status_addr;
598
599 d = malloc(sizeof(struct wdc_data));
600 if (d == NULL) {
601 fprintf(stderr, "out of memory\n");
602 exit(1);
603 }
604 memset(d, 0, sizeof(struct wdc_data));
605 d->irq_nr = irq_nr;
606 d->base_drive = base_drive;
607
608 alt_status_addr = baseaddr + 0x206;
609
610 /* Special hack for pcic/hpcmips: TODO: Fix */
611 if (baseaddr == 0x14000180)
612 alt_status_addr = 0x14000386;
613
614 memory_device_register(mem, "wdc_altstatus", alt_status_addr, 2,
615 dev_wdc_altstatus_access, d, MEM_DEFAULT, NULL);
616 memory_device_register(mem, "wdc", baseaddr, DEV_WDC_LENGTH,
617 dev_wdc_access, d, MEM_DEFAULT, NULL);
618
619 machine_add_tickfunction(machine, dev_wdc_tick,
620 d, WDC_TICK_SHIFT);
621 }
622

  ViewVC Help
Powered by ViewVC 1.1.26