/[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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 14 by dpavlin, Mon Oct 8 16:18:51 2007 UTC revision 24 by dpavlin, Mon Oct 8 16:19:56 2007 UTC
# Line 1  Line 1 
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:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: dev_wdc.c,v 1.39 2005/09/27 23:55:44 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   */   */
# Line 34  Line 34 
34  #include <stdlib.h>  #include <stdlib.h>
35  #include <string.h>  #include <string.h>
36    
 #include "console.h"  
37  #include "cpu.h"  #include "cpu.h"
38  #include "device.h"  #include "device.h"
39  #include "diskimage.h"  #include "diskimage.h"
# Line 46  Line 45 
45    
46  #define DEV_WDC_LENGTH          8  #define DEV_WDC_LENGTH          8
47  #define WDC_TICK_SHIFT          14  #define WDC_TICK_SHIFT          14
48  #define WDC_INBUF_SIZE          (512*257)  #define WDC_MAX_SECTORS         512
49    #define WDC_INBUF_SIZE          (512*(WDC_MAX_SECTORS+1))
50    
51  /*  /*
52   *  INT_DELAY=2 to be safe, 1 is faster but maybe buggy. 0 is fastest.   *  INT_DELAY: This is an old hack which only exists because (some versions of)
53     *  NetBSD for hpcmips have interrupt problems. These problems are probably not
54     *  specific to GXemul, but are also triggered on real hardware.
55   *   *
56   *  The only reason for this delay to exist is because (some versions of)   *  See the following URL for more info:
57   *  NetBSD for hpcmips have interrupt problems. These problems are not only   *  http://mail-index.netbsd.org/port-hpcmips/2004/12/30/0003.html
58   *  triggered inside the emulator, but also on real hardware. Using the   *
59   *  delay is an ugly (but working) work-around.   *  NetBSD/malta also bugs out if wdc interrupts come too quickly. Hm.
60   */   */
61  #define INT_DELAY               1  #define INT_DELAY               1
62    
# Line 64  extern int quiet_mode; Line 66  extern int quiet_mode;
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    
# Line 72  struct wdc_data { Line 75  struct wdc_data {
75          int             heads[2];          int             heads[2];
76          int             sectors_per_track[2];          int             sectors_per_track[2];
77    
78          unsigned char   identify_struct[512];          unsigned char   *inbuf;
   
         unsigned char   inbuf[WDC_INBUF_SIZE];  
79          int             inbuf_head;          int             inbuf_head;
80          int             inbuf_tail;          int             inbuf_tail;
81    
82          int             delayed_interrupt;          int             delayed_interrupt;
83            int             int_asserted;
84    
85          int             write_in_progress;          int             write_in_progress;
86          int             write_count;          int             write_count;
87          int64_t         write_offset;          int64_t         write_offset;
# Line 94  struct wdc_data { Line 97  struct wdc_data {
97          int             drive;          int             drive;
98          int             head;          int             head;
99          int             cur_command;          int             cur_command;
100    
101            int             atapi_cmd_in_progress;
102            int             atapi_phase;
103            struct scsi_transfer *atapi_st;
104            int             atapi_len;
105            size_t          atapi_received;
106    
107            unsigned char   identify_struct[512];
108  };  };
109    
110    
111    #define COMMAND_RESET   0x100
112    
113    
114  /*  /*
115   *  dev_wdc_tick():   *  dev_wdc_tick():
116   */   */
117  void dev_wdc_tick(struct cpu *cpu, void *extra)  void dev_wdc_tick(struct cpu *cpu, void *extra)
118  {  {
119          struct wdc_data *d = extra;          struct wdc_data *d = extra;
120            int old_di = d->delayed_interrupt;
121    
122          if (d->delayed_interrupt) {          if (d->delayed_interrupt)
123                  d->delayed_interrupt --;                  d->delayed_interrupt --;
124    
125                  if (d->delayed_interrupt == 0)          if (old_di == 1 || d->int_asserted) {
126                          cpu_interrupt(cpu, d->irq_nr);                  cpu_interrupt(cpu, d->irq_nr);
127                    d->int_asserted = 1;
128          }          }
129  }  }
130    
# Line 124  static void wdc_addtoinbuf(struct wdc_da Line 140  static void wdc_addtoinbuf(struct wdc_da
140    
141          d->inbuf_head = (d->inbuf_head + 1) % WDC_INBUF_SIZE;          d->inbuf_head = (d->inbuf_head + 1) % WDC_INBUF_SIZE;
142          if (d->inbuf_head == d->inbuf_tail)          if (d->inbuf_head == d->inbuf_tail)
143                  fatal("[ wdc_addtoinbuf(): WARNING! wdc inbuf overrun ]\n");                  fatal("[ wdc_addtoinbuf(): WARNING! wdc inbuf overrun!"
144                        " Increase WDC_MAX_SECTORS. ]\n");
145  }  }
146    
147    
# Line 149  static uint64_t wdc_get_inbuf(struct wdc Line 166  static uint64_t wdc_get_inbuf(struct wdc
166    
167    
168  /*  /*
169   *  wdc_initialize_identify_struct(d):   *  wdc_initialize_identify_struct():
170   */   */
171  static void wdc_initialize_identify_struct(struct cpu *cpu, struct wdc_data *d)  static void wdc_initialize_identify_struct(struct cpu *cpu, struct wdc_data *d)
172  {  {
173          uint64_t total_size;          uint64_t total_size;
174            int flags, cdrom = 0;
175          char namebuf[40];          char namebuf[40];
176    
177          total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive,          total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive,
178              DISKIMAGE_IDE);              DISKIMAGE_IDE);
179            if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive,
180                DISKIMAGE_IDE))
181                    cdrom = 1;
182    
183          memset(d->identify_struct, 0, sizeof(d->identify_struct));          memset(d->identify_struct, 0, sizeof(d->identify_struct));
184    
185          /*  Offsets are in 16-bit WORDS!  High byte, then low.  */          /*  Offsets are in 16-bit WORDS!  High byte, then low.  */
186    
187          /*  0: general flags  */          /*  0: general flags  */
188          d->identify_struct[2 * 0 + 0] = 0;          flags = 1 << 6; /*  Fixed  */
189          d->identify_struct[2 * 0 + 1] = 1 << 6;          if (cdrom)
190                    flags = 0x8580;         /*  ATAPI, CDROM, removable  */
191            d->identify_struct[2 * 0 + 0] = flags >> 8;
192            d->identify_struct[2 * 0 + 1] = flags;
193    
194          /*  1: nr of cylinders  */          /*  1: nr of cylinders  */
195          d->identify_struct[2 * 1 + 0] = (d->cyls[d->drive] >> 8);          d->identify_struct[2 * 1 + 0] = d->cyls[d->drive] >> 8;
196          d->identify_struct[2 * 1 + 1] = d->cyls[d->drive] & 255;          d->identify_struct[2 * 1 + 1] = d->cyls[d->drive];
197    
198          /*  3: nr of heads  */          /*  3: nr of heads  */
199          d->identify_struct[2 * 3 + 0] = d->heads[d->drive] >> 8;          d->identify_struct[2 * 3 + 0] = d->heads[d->drive] >> 8;
# Line 180  static void wdc_initialize_identify_stru Line 204  static void wdc_initialize_identify_stru
204          d->identify_struct[2 * 6 + 1] = d->sectors_per_track[d->drive];          d->identify_struct[2 * 6 + 1] = d->sectors_per_track[d->drive];
205    
206          /*  10-19: Serial number  */          /*  10-19: Serial number  */
207          memcpy(&d->identify_struct[2 * 10], "S/N 1234-5678       ", 20);          memcpy(&d->identify_struct[2 * 10], "#0                  ", 20);
208    
209          /*  23-26: Firmware version  */          /*  23-26: Firmware version  */
210          memcpy(&d->identify_struct[2 * 23], "VER 1.0 ", 8);          memcpy(&d->identify_struct[2 * 23], "1.0     ", 8);
211    
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++)
# Line 202  static void wdc_initialize_identify_stru Line 226  static void wdc_initialize_identify_stru
226    
227          /*  47: max sectors per multitransfer  */          /*  47: max sectors per multitransfer  */
228          d->identify_struct[2 * 47 + 0] = 0x80;          d->identify_struct[2 * 47 + 0] = 0x80;
229          d->identify_struct[2 * 47 + 1] = 1;     /*  1 or 16?  */          d->identify_struct[2 * 47 + 1] = 128;
230    
231            /*  49: capabilities:  */
232            /*  (0x200 = LBA, 0x100 = DMA support.)  */
233            d->identify_struct[2 * 49 + 0] = 0;
234            d->identify_struct[2 * 49 + 1] = 0;
235    
236            /*  51: PIO timing mode.  */
237            d->identify_struct[2 * 51 + 0] = 0x00;  /*  ?  */
238            d->identify_struct[2 * 51 + 1] = 0x00;
239    
240            /*  53: 0x02 = fields 64-70 valid, 0x01 = fields 54-58 valid  */
241            d->identify_struct[2 * 53 + 0] = 0x00;
242            d->identify_struct[2 * 53 + 1] = 0x02;
243    
244          /*  57-58: current capacity in sectors  */          /*  57-58: current capacity in sectors  */
245          d->identify_struct[2 * 57 + 0] = ((total_size / 512) >> 24) % 255;          d->identify_struct[2 * 57 + 0] = ((total_size / 512) >> 24) % 255;
# Line 210  static void wdc_initialize_identify_stru Line 247  static void wdc_initialize_identify_stru
247          d->identify_struct[2 * 58 + 0] = ((total_size / 512) >> 8) % 255;          d->identify_struct[2 * 58 + 0] = ((total_size / 512) >> 8) % 255;
248          d->identify_struct[2 * 58 + 1] = (total_size / 512) & 255;          d->identify_struct[2 * 58 + 1] = (total_size / 512) & 255;
249    
250          /*  60-61: total nr of addresable sectors  */          /*  60-61: total nr of addressable sectors  */
251          d->identify_struct[2 * 60 + 0] = ((total_size / 512) >> 24) % 255;          d->identify_struct[2 * 60 + 0] = ((total_size / 512) >> 24) % 255;
252          d->identify_struct[2 * 60 + 1] = ((total_size / 512) >> 16) % 255;          d->identify_struct[2 * 60 + 1] = ((total_size / 512) >> 16) % 255;
253          d->identify_struct[2 * 61 + 0] = ((total_size / 512) >> 8) % 255;          d->identify_struct[2 * 61 + 0] = ((total_size / 512) >> 8) % 255;
254          d->identify_struct[2 * 61 + 1] = (total_size / 512) & 255;          d->identify_struct[2 * 61 + 1] = (total_size / 512) & 255;
255    
256            /*  64: Advanced PIO mode support. 0x02 = mode4, 0x01 = mode3  */
257            d->identify_struct[2 * 64 + 0] = 0x00;
258            d->identify_struct[2 * 64 + 1] = 0x03;
259    
260            /*  67, 68: PIO timing  */
261            d->identify_struct[2 * 67 + 0] = 0;
262            d->identify_struct[2 * 67 + 1] = 120;
263            d->identify_struct[2 * 68 + 0] = 0;
264            d->identify_struct[2 * 68 + 1] = 120;
265  }  }
266    
267    
# Line 224  static void wdc_initialize_identify_stru Line 270  static void wdc_initialize_identify_stru
270   */   */
271  void wdc__read(struct cpu *cpu, struct wdc_data *d)  void wdc__read(struct cpu *cpu, struct wdc_data *d)
272  {  {
273          unsigned char buf[512];  #define MAX_SECTORS_PER_CHUNK   64
274            const int max_sectors_per_chunk = MAX_SECTORS_PER_CHUNK;
275            unsigned char buf[512 * MAX_SECTORS_PER_CHUNK];
276          int i, cyl = d->cyl_hi * 256+ d->cyl_lo;          int i, cyl = d->cyl_hi * 256+ d->cyl_lo;
277          int count = d->seccnt? d->seccnt : 256;          int count = d->seccnt? d->seccnt : 256;
278          uint64_t offset = 512 * (d->sector - 1          uint64_t offset = 512 * (d->sector - 1
# Line 240  void wdc__read(struct cpu *cpu, struct w Line 288  void wdc__read(struct cpu *cpu, struct w
288  #endif  #endif
289    
290          while (count > 0) {          while (count > 0) {
291                  diskimage_access(cpu->machine, d->drive + d->base_drive,                  int to_read = count > max_sectors_per_chunk?
292                      DISKIMAGE_IDE, 0, offset, buf, 512);                      max_sectors_per_chunk : count;
293                  /*  TODO: result code  */  
294                  for (i=0; i<512; i++)                  /*  TODO: result code from the read?  */
295                          wdc_addtoinbuf(d, buf[i]);  
296                  offset += 512;                  if (d->inbuf_head + 512 * to_read <= WDC_INBUF_SIZE) {
297                  count --;                          diskimage_access(cpu->machine, d->drive + d->base_drive,
298                                DISKIMAGE_IDE, 0, offset,
299                                d->inbuf + d->inbuf_head, 512 * to_read);
300                            d->inbuf_head += 512 * to_read;
301                            if (d->inbuf_head == WDC_INBUF_SIZE)
302                                    d->inbuf_head = 0;
303                    } else {
304                            diskimage_access(cpu->machine, d->drive + d->base_drive,
305                                DISKIMAGE_IDE, 0, offset, buf, 512 * to_read);
306                            for (i=0; i<512 * to_read; i++)
307                                    wdc_addtoinbuf(d, buf[i]);
308                    }
309    
310                    offset += 512 * to_read;
311                    count -= to_read;
312          }          }
313    
314          d->delayed_interrupt = INT_DELAY;          d->delayed_interrupt = INT_DELAY;
# Line 271  void wdc__write(struct cpu *cpu, struct Line 333  void wdc__write(struct cpu *cpu, struct
333          printf("WDC write to offset %lli\n", (long long)offset);          printf("WDC write to offset %lli\n", (long long)offset);
334  #endif  #endif
335    
336          d->write_in_progress = 1;          d->write_in_progress = d->cur_command;
337          d->write_count = count;          d->write_count = count;
338          d->write_offset = offset;          d->write_offset = offset;
339    
# Line 288  void wdc__write(struct cpu *cpu, struct Line 350  void wdc__write(struct cpu *cpu, struct
350  static int status_byte(struct wdc_data *d, struct cpu *cpu)  static int status_byte(struct wdc_data *d, struct cpu *cpu)
351  {  {
352          int odata = 0;          int odata = 0;
   
         /*  
          *  Modern versions of OpenBSD wants WDCS_DSC. (Thanks to Alexander  
          *  Yurchenko for noticing this.)  
          */  
353          if (diskimage_exist(cpu->machine, d->drive + d->base_drive,          if (diskimage_exist(cpu->machine, d->drive + d->base_drive,
354              DISKIMAGE_IDE))              DISKIMAGE_IDE))
355                  odata |= WDCS_DRDY | WDCS_DSC;                  odata |= WDCS_DRDY | WDCS_DSC;
# Line 302  static int status_byte(struct wdc_data * Line 359  static int status_byte(struct wdc_data *
359                  odata |= WDCS_DRQ;                  odata |= WDCS_DRQ;
360          if (d->error)          if (d->error)
361                  odata |= WDCS_ERR;                  odata |= WDCS_ERR;
362            if (d->atapi_cmd_in_progress && (d->atapi_phase & WDCS_DRQ)) {
363                    odata |= WDCS_DRQ;
364            }
365          return odata;          return odata;
366  }  }
367    
# Line 310  static int status_byte(struct wdc_data * Line 369  static int status_byte(struct wdc_data *
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;
376    
377          idata = memory_readmax64(cpu, data, len);          idata = data[0];
378    
379          /*  Same as the normal status byte?  */          /*  Same as the normal status byte:  */
380          odata = status_byte(d, cpu);          odata = status_byte(d, cpu);
381    
382          if (writeflag==MEM_READ)          if (writeflag==MEM_READ)
383                  debug("[ wdc: read from ALTSTATUS: 0x%02x ]\n",                  debug("[ wdc: read from ALTSTATUS: 0x%02x ]\n",
384                      (int)odata);                      (int)odata);
385          else          else {
386                  debug("[ wdc: write to ALT. CTRL: 0x%02x ]\n",                  debug("[ wdc: write to ALT. CTRL: 0x%02x ]\n",
387                      (int)idata);                      (int)idata);
388                    if (idata & WDCTL_4BIT)
389                            d->cur_command = COMMAND_RESET;
390            }
391    
392          if (writeflag == MEM_READ)          if (writeflag == MEM_READ)
393                  memory_writemax64(cpu, data, len, odata);                  data[0] = odata;
394    
395          return 1;          return 1;
396  }  }
397    
398    
399  /*  /*
400     *  wdc_command():
401     */
402    void wdc_command(struct cpu *cpu, struct wdc_data *d, int idata)
403    {
404            size_t i;
405    
406            d->cur_command = idata;
407            d->atapi_cmd_in_progress = 0;
408            d->error = 0;
409    
410            /*
411             *  Disk images that do not exist return an ABORT error.  This also
412             *  happens with CDROM images with the WDCC_IDENTIFY command; CDROM
413             *  images must be detected with ATAPI_IDENTIFY_DEVICE instead.
414             *
415             *  TODO:  Is this correct/good behaviour?
416             */
417            if (!diskimage_exist(cpu->machine, d->drive + d->base_drive,
418                DISKIMAGE_IDE)) {
419                    debug("[ wdc: command 0x%02x drive %i, but no disk image ]\n",
420                        d->cur_command, d->drive + d->base_drive);
421                    d->error |= WDCE_ABRT;
422                    d->delayed_interrupt = INT_DELAY;
423                    return;
424            }
425            if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive,
426                DISKIMAGE_IDE) && d->cur_command == WDCC_IDENTIFY) {
427                    debug("[ wdc: IDENTIFY drive %i, but it is an ATAPI "
428                        "drive ]\n", d->drive + d->base_drive);
429                    d->error |= WDCE_ABRT;
430                    d->delayed_interrupt = INT_DELAY;
431                    return;
432            }
433    
434            /*  Handle the command:  */
435            switch (d->cur_command) {
436    
437            case WDCC_READ:
438            case WDCC_READMULTI:
439                    if (!quiet_mode)
440                            debug("[ wdc: READ from drive %i, head %i, cyl %i, "
441                                "sector %i, nsecs %i ]\n", d->drive, d->head,
442                                d->cyl_hi*256+d->cyl_lo, d->sector, d->seccnt);
443                    wdc__read(cpu, d);
444                    break;
445    
446            case WDCC_WRITE:
447            case WDCC_WRITEMULTI:
448                    if (!quiet_mode)
449                            debug("[ wdc: WRITE to drive %i, head %i, cyl %i, "
450                                "sector %i, nsecs %i ]\n", d->drive, d->head,
451                                d->cyl_hi*256+d->cyl_lo, d->sector, d->seccnt);
452                    wdc__write(cpu, d);
453                    break;
454    
455            case WDCC_IDP:  /*  Initialize drive parameters  */
456                    debug("[ wdc: IDP drive %i (TODO) ]\n", d->drive);
457                    /*  TODO  */
458                    d->delayed_interrupt = INT_DELAY;
459                    break;
460    
461            case SET_FEATURES:
462                    debug("[ wdc: SET_FEATURES drive %i (TODO), feature 0x%02x ]\n",
463                        d->drive, d->precomp);
464                    /*  TODO  */
465                    switch (d->precomp) {
466                    case WDSF_SET_MODE:
467                            debug("[ wdc: WDSF_SET_MODE drive %i, pio/dma flags "
468                                "0x%02x ]\n", d->drive, d->seccnt);
469                            break;
470                    default:d->error |= WDCE_ABRT;
471                    }
472                    /*  TODO: always interrupt?  */
473                    d->delayed_interrupt = INT_DELAY;
474                    break;
475    
476            case WDCC_RECAL:
477                    debug("[ wdc: RECAL drive %i ]\n", d->drive);
478                    d->delayed_interrupt = INT_DELAY;
479                    break;
480    
481            case WDCC_IDENTIFY:
482            case ATAPI_IDENTIFY_DEVICE:
483                    debug("[ wdc: %sIDENTIFY drive %i ]\n", d->cur_command ==
484                        ATAPI_IDENTIFY_DEVICE? "ATAPI " : "", d->drive);
485                    wdc_initialize_identify_struct(cpu, d);
486                    /*  The IDENTIFY data is sent out in low/high byte order:  */
487                    for (i=0; i<sizeof(d->identify_struct); i+=2) {
488                            wdc_addtoinbuf(d, d->identify_struct[i+1]);
489                            wdc_addtoinbuf(d, d->identify_struct[i+0]);
490                    }
491                    d->delayed_interrupt = INT_DELAY;
492                    break;
493    
494            case WDCC_IDLE_IMMED:
495                    debug("[ wdc: IDLE_IMMED drive %i ]\n", d->drive);
496                    /*  TODO: interrupt here?  */
497                    d->delayed_interrupt = INT_DELAY;
498                    break;
499    
500            case WDCC_SETMULTI:
501                    debug("[ wdc: SETMULTI drive %i ]\n", d->drive);
502                    /*  TODO: interrupt here?  */
503                    d->delayed_interrupt = INT_DELAY;
504                    break;
505    
506            case ATAPI_SOFT_RESET:
507                    debug("[ wdc: ATAPI_SOFT_RESET drive %i ]\n", d->drive);
508                    /*  TODO: interrupt here?  */
509                    d->delayed_interrupt = INT_DELAY;
510                    break;
511    
512            case ATAPI_PKT_CMD:
513                    debug("[ wdc: ATAPI_PKT_CMD drive %i ]\n", d->drive);
514                    /*  TODO: interrupt here?  */
515                    /*  d->delayed_interrupt = INT_DELAY;  */
516                    d->atapi_cmd_in_progress = 1;
517                    d->atapi_phase = PHASE_CMDOUT;
518                    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:  */
528            case WDCC_SEC_SET_PASSWORD:
529            case WDCC_SEC_UNLOCK:
530            case WDCC_SEC_ERASE_PREPARE:
531            case WDCC_SEC_ERASE_UNIT:
532            case WDCC_SEC_FREEZE_LOCK:
533            case WDCC_SEC_DISABLE_PASSWORD:
534                    d->error |= WDCE_ABRT;
535                    break;
536    
537            default:/*  TODO  */
538                    d->error |= WDCE_ABRT;
539                    fatal("[ wdc: WARNING! Unimplemented command 0x%02x (drive %i,"
540                        " head %i, cyl %i, sector %i, nsecs %i) ]\n",
541                        d->cur_command, d->drive, d->head, d->cyl_hi*256+d->cyl_lo,
542                        d->sector, d->seccnt);
543            }
544    }
545    
546    
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          idata = memory_readmax64(cpu, data, len);          relative_addr /= d->addr_mult;
557    
558            if (writeflag == MEM_WRITE) {
559                    if (relative_addr == wd_data)
560                            idata = memory_readmax64(cpu, data, len);
561                    else {
562                            if (len != 1)
563                                    fatal("[ wdc: WARNING! non-8-bit access! ]\n");
564                            idata = data[0];
565                    }
566            }
567    
568          switch (relative_addr) {          switch (relative_addr) {
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);
573    
574                          /*  TODO: This is hardcoded for little-endian?  */                          if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
575                                    if (len >= 2)
576                                            odata += (wdc_get_inbuf(d) << 8);
577                                    if (len == 4) {
578                                            odata += (wdc_get_inbuf(d) << 16);
579                                            odata += (wdc_get_inbuf(d) << 24);
580                                    }
581                            } else {
582                                    if (len >= 2)
583                                            odata = (odata << 8) + wdc_get_inbuf(d);
584                                    if (len == 4) {
585                                            odata = (odata << 8) + wdc_get_inbuf(d);
586                                            odata = (odata << 8) + wdc_get_inbuf(d);
587                                    }
588                            }
589    
590                          odata += wdc_get_inbuf(d);                          if (d->data_debug) {
591                          if (len >= 2)                                  char *s = "0x%04"PRIx64" ]\n";
592                                  odata += (wdc_get_inbuf(d) << 8);                                  if (len == 1)
593                          if (len == 4) {                                          s = "0x%02"PRIx64" ]\n";
594                                  odata += (wdc_get_inbuf(d) << 16);                                  if (len == 4)
595                                  odata += (wdc_get_inbuf(d) << 24);                                          s = "0x%08"PRIx64" ]\n";
596                                    if (len == 8)
597                                            s = "0x%016"PRIx64" ]\n";
598                                    debug("[ wdc: read from DATA: ");
599                                    debug(s, (uint64_t) odata);
600                          }                          }
601    
602                          if (d->data_debug)                          if (d->atapi_cmd_in_progress) {
603                                  debug("[ wdc: read from DATA: 0x%04x ]\n",                                  d->atapi_len -= len;
604                                      (int)odata);                                  d->atapi_received += len;
605                          if (d->inbuf_tail != d->inbuf_head)                                  if (d->atapi_len == 0) {
606                                  d->delayed_interrupt = INT_DELAY;                                          if (d->atapi_received < d->atapi_st->
607                                                data_in_len) {
608                                                    d->atapi_phase = PHASE_DATAIN;
609                                                    d->atapi_len = d->atapi_st->
610                                                        data_in_len -
611                                                        d->atapi_received;
612                                                    if (d->atapi_len > 32768)
613                                                            d->atapi_len = 0;
614                                            } else
615                                                    d->atapi_phase =
616                                                        PHASE_COMPLETED;
617                                            d->delayed_interrupt = INT_DELAY;
618                                    }
619                            } else {
620    #if 0
621                                    if (d->inbuf_tail != d->inbuf_head)
622    #else
623                                    if (d->inbuf_tail != d->inbuf_head &&
624                                        ((d->inbuf_tail - d->inbuf_head) % 512)
625                                        == 0)
626    #endif
627                                            d->delayed_interrupt = INT_DELAY;
628                            }
629                  } else {                  } else {
630                          int inbuf_len;                          int inbuf_len;
631                          if (d->data_debug)                          if (d->data_debug) {
632                                  debug("[ wdc: write to DATA (len=%i): "                                  char *s = "0x%04"PRIx64" ]\n";
633                                      "0x%08lx ]\n", (int)len, (long)idata);                                  if (len == 1)
634                          if (!d->write_in_progress) {                                          s = "0x%02"PRIx64" ]\n";
635                                    if (len == 4)
636                                            s = "0x%08"PRIx64" ]\n";
637                                    if (len == 8)
638                                            s = "0x%016"PRIx64" ]\n";
639                                    debug("[ wdc: write to DATA: ");
640                                    debug(s, (uint64_t) idata);
641                            }
642                            if (!d->write_in_progress &&
643                                !d->atapi_cmd_in_progress) {
644                                  fatal("[ wdc: write to DATA, but not "                                  fatal("[ wdc: write to DATA, but not "
645                                      "expecting any? (len=%i): 0x%08lx ]\n",                                      "expecting any? (len=%i): 0x%08lx ]\n",
646                                      (int)len, (long)idata);                                      (int)len, (long)idata);
647                          }                          }
648    
649                          switch (len) {                          if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
650                          case 4: wdc_addtoinbuf(d, idata & 0xff);                                  switch (len) {
651                                  wdc_addtoinbuf(d, (idata >> 8) & 0xff);                                  case 4: wdc_addtoinbuf(d, idata & 0xff);
652                                  wdc_addtoinbuf(d, (idata >> 16) & 0xff);                                          wdc_addtoinbuf(d, (idata >> 8) & 0xff);
653                                  wdc_addtoinbuf(d, (idata >> 24) & 0xff);                                          wdc_addtoinbuf(d, (idata >> 16) & 0xff);
654                                  break;                                          wdc_addtoinbuf(d, (idata >> 24) & 0xff);
655                          case 2: wdc_addtoinbuf(d, idata & 0xff);                                          break;
656                                  wdc_addtoinbuf(d, (idata >> 8) & 0xff);                                  case 2: wdc_addtoinbuf(d, idata & 0xff);
657                                  break;                                          wdc_addtoinbuf(d, (idata >> 8) & 0xff);
658                          case 1: wdc_addtoinbuf(d, idata); break;                                          break;
659                          default:fatal("wdc: unimplemented write len %i\n", len);                                  case 1: wdc_addtoinbuf(d, idata); break;
660                                  exit(1);                                  default:fatal("wdc: unimplemented write "
661                                                "len %i\n", len);
662                                            exit(1);
663                                    }
664                            } else {
665                                    switch (len) {
666                                    case 4: wdc_addtoinbuf(d, (idata >> 24) & 0xff);
667                                            wdc_addtoinbuf(d, (idata >> 16) & 0xff);
668                                            wdc_addtoinbuf(d, (idata >> 8) & 0xff);
669                                            wdc_addtoinbuf(d, idata & 0xff);
670                                            break;
671                                    case 2: wdc_addtoinbuf(d, (idata >> 8) & 0xff);
672                                            wdc_addtoinbuf(d, idata & 0xff);
673                                            break;
674                                    case 1: wdc_addtoinbuf(d, idata); break;
675                                    default:fatal("wdc: unimplemented write "
676                                                "len %i\n", len);
677                                            exit(1);
678                                    }
679                          }                          }
680    
681                          inbuf_len = d->inbuf_head - d->inbuf_tail;                          inbuf_len = d->inbuf_head - d->inbuf_tail;
682                          while (inbuf_len < 0)                          while (inbuf_len < 0)
683                                  inbuf_len += WDC_INBUF_SIZE;                                  inbuf_len += WDC_INBUF_SIZE;
684    
685  #if 0                          if (d->atapi_cmd_in_progress && inbuf_len == 12) {
686                          if ((inbuf_len % (512 * d->write_count)) == 0) {                                  unsigned char *scsi_cmd = malloc(12);
687  #else                                  int x = 0, res;
688                          if ((inbuf_len % 512) == 0) {  
689  #endif                                  if (d->atapi_st != NULL)
690                                  int count = 1;  /*  d->write_count;  */                                          scsi_transfer_free(d->atapi_st);
691                                  unsigned char *buf = malloc(count * 512);                                  d->atapi_st = scsi_transfer_alloc();
692    
693                                    debug("[ wdc: ATAPI command ]\n");
694    
695                                    while (inbuf_len > 0) {
696                                            scsi_cmd[x++] = wdc_get_inbuf(d);
697                                            inbuf_len --;
698                                    }
699    
700                                    d->atapi_st->cmd = scsi_cmd;
701                                    d->atapi_st->cmd_len = 12;
702    
703                                    if (scsi_cmd[0] == SCSIBLOCKCMD_READ_CAPACITY
704                                        || scsi_cmd[0] == SCSICMD_READ_10
705                                        || scsi_cmd[0] == SCSICMD_MODE_SENSE10)
706                                            d->atapi_st->cmd_len = 10;
707    
708                                    res = diskimage_scsicommand(cpu,
709                                        d->drive + d->base_drive, DISKIMAGE_IDE,
710                                        d->atapi_st);
711    
712                                    if (res == 0) {
713                                            fatal("WDC: ATAPI scsi error?\n");
714                                            exit(1);
715                                    }
716    
717                                    d->atapi_len = 0;
718                                    d->atapi_received = 0;
719    
720                                    if (res == 1) {
721                                            if (d->atapi_st->data_in != NULL) {
722                                                    int i;
723                                                    d->atapi_phase = PHASE_DATAIN;
724                                                    d->atapi_len = d->atapi_st->
725                                                        data_in_len;
726                                                    for (i=0; i<d->atapi_len; i++)
727                                                            wdc_addtoinbuf(d,
728                                                                d->atapi_st->
729                                                                data_in[i]);
730                                                    if (d->atapi_len > 32768)
731                                                            d->atapi_len = 32768;
732                                            } else {
733                                                    d->atapi_phase =
734                                                        PHASE_COMPLETED;
735                                            }
736                                    } else {
737                                            fatal("wdc atapi Dataout? TODO\n");
738                                            d->atapi_phase = PHASE_DATAOUT;
739                                            exit(1);
740                                    }
741    
742                                    d->delayed_interrupt = INT_DELAY;
743                            }
744    
745                            if (( d->write_in_progress == WDCC_WRITEMULTI &&
746                                inbuf_len % (512 * d->write_count) == 0)
747                                ||
748                                ( d->write_in_progress == WDCC_WRITE &&
749                                inbuf_len % 512 == 0) ) {
750                                    int count = (d->write_in_progress ==
751                                        WDCC_WRITEMULTI)? d->write_count : 1;
752                                    unsigned char *buf = malloc(512 * count);
753                                    unsigned char *b = buf;
754    
755                                  if (buf == NULL) {                                  if (buf == NULL) {
756                                          fprintf(stderr, "out of memory\n");                                          fprintf(stderr, "out of memory\n");
757                                          exit(1);                                          exit(1);
758                                  }                                  }
759    
760                                  for (i=0; i<512 * count; i++)                                  if (d->inbuf_tail+512*count <= WDC_INBUF_SIZE) {
761                                          buf[i] = wdc_get_inbuf(d);                                          b = d->inbuf + d->inbuf_tail;
762                                            d->inbuf_tail = (d->inbuf_tail + 512
763                                                * count) % WDC_INBUF_SIZE;
764                                    } else {
765                                            for (i=0; i<512 * count; i++)
766                                                    buf[i] = wdc_get_inbuf(d);
767                                    }
768    
769                                  diskimage_access(cpu->machine,                                  diskimage_access(cpu->machine,
770                                      d->drive + d->base_drive, DISKIMAGE_IDE, 1,                                      d->drive + d->base_drive, DISKIMAGE_IDE, 1,
771                                      d->write_offset, buf, 512 * count);                                      d->write_offset, b, 512 * count);
                                 free(buf);  
772    
773                                  d->write_count --;                                  d->write_count -= count;
774                                  d->write_offset += 512;                                  d->write_offset += 512 * count;
775    
776                                  d->delayed_interrupt = INT_DELAY;                                  d->delayed_interrupt = INT_DELAY;
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;
785    
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 {
# Line 443  int dev_wdc_access(struct cpu *cpu, stru Line 795  int dev_wdc_access(struct cpu *cpu, stru
795                  }                  }
796                  break;                  break;
797    
798          case wd_seccnt: /*  2: sector count  */          case wd_seccnt: /*  2: sector count (or "ireason" for ATAPI)  */
799                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
800                          odata = d->seccnt;                          odata = d->seccnt;
801                            if (d->atapi_cmd_in_progress) {
802                                    odata = d->atapi_phase & (WDCI_CMD | WDCI_IN);
803                            }
804                          debug("[ wdc: read from SECCNT: 0x%02x ]\n",(int)odata);                          debug("[ wdc: read from SECCNT: 0x%02x ]\n",(int)odata);
805                  } else {                  } else {
806                          d->seccnt = idata;                          d->seccnt = idata;
# Line 454  int dev_wdc_access(struct cpu *cpu, stru Line 809  int dev_wdc_access(struct cpu *cpu, stru
809                  break;                  break;
810    
811          case wd_sector: /*  3: first sector  */          case wd_sector: /*  3: first sector  */
812                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
813                          odata = d->sector;                          odata = d->sector;
814                          debug("[ wdc: read from SECTOR: 0x%02x ]\n",(int)odata);                          debug("[ wdc: read from SECTOR: 0x%02x ]\n",(int)odata);
815                  } else {                  } else {
# Line 464  int dev_wdc_access(struct cpu *cpu, stru Line 819  int dev_wdc_access(struct cpu *cpu, stru
819                  break;                  break;
820    
821          case wd_cyl_lo: /*  4: cylinder low  */          case wd_cyl_lo: /*  4: cylinder low  */
822                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
823                          odata = d->cyl_lo;                          odata = d->cyl_lo;
824                            if (d->cur_command == COMMAND_RESET &&
825                                diskimage_is_a_cdrom(cpu->machine,
826                                d->drive + d->base_drive, DISKIMAGE_IDE))
827                                    odata = 0x14;
828                            if (d->atapi_cmd_in_progress) {
829                                    int x = d->atapi_len;
830                                    if (x > 32768)
831                                            x = 32768;
832                                    odata = x & 255;
833                            }
834                          debug("[ wdc: read from CYL_LO: 0x%02x ]\n",(int)odata);                          debug("[ wdc: read from CYL_LO: 0x%02x ]\n",(int)odata);
835                  } else {                  } else {
836                          d->cyl_lo = idata;                          d->cyl_lo = idata;
# Line 473  int dev_wdc_access(struct cpu *cpu, stru Line 838  int dev_wdc_access(struct cpu *cpu, stru
838                  }                  }
839                  break;                  break;
840    
841          case wd_cyl_hi: /*  5: cylinder low  */          case wd_cyl_hi: /*  5: cylinder high  */
842                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
843                          odata = d->cyl_hi;                          odata = d->cyl_hi;
844                            if (d->cur_command == COMMAND_RESET &&
845                                diskimage_is_a_cdrom(cpu->machine,
846                                d->drive + d->base_drive, DISKIMAGE_IDE))
847                                    odata = 0xeb;
848                            if (d->atapi_cmd_in_progress) {
849                                    int x = d->atapi_len;
850                                    if (x > 32768)
851                                            x = 32768;
852                                    odata = (x >> 8) & 255;
853                            }
854                          debug("[ wdc: read from CYL_HI: 0x%02x ]\n",(int)odata);                          debug("[ wdc: read from CYL_HI: 0x%02x ]\n",(int)odata);
855                  } else {                  } else {
856                          d->cyl_hi = idata;                          d->cyl_hi = idata;
# Line 508  int dev_wdc_access(struct cpu *cpu, stru Line 883  int dev_wdc_access(struct cpu *cpu, stru
883                                  debug("[ wdc: read from STATUS: 0x%02x ]\n",                                  debug("[ wdc: read from STATUS: 0x%02x ]\n",
884                                      (int)odata);                                      (int)odata);
885                          cpu_interrupt_ack(cpu, d->irq_nr);                          cpu_interrupt_ack(cpu, d->irq_nr);
886                            d->int_asserted = 0;
887                          d->delayed_interrupt = 0;                          d->delayed_interrupt = 0;
888                  } else {                  } else {
889                          debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);                          debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);
890                          d->cur_command = idata;                          wdc_command(cpu, d, idata);
   
                         /*  TODO:  Is this correct behaviour?  */  
                         if (!diskimage_exist(cpu->machine,  
                             d->drive + d->base_drive, DISKIMAGE_IDE)) {  
                                 d->error |= WDCE_ABRT;  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
                         }  
   
                         /*  Handle the command:  */  
                         switch (d->cur_command) {  
   
                         case WDCC_READ:  
                                 if (!quiet_mode)  
                                         debug("[ wdc: READ from drive %i, head"  
                                             " %i, cyl %i, sector %i, nsecs %i "  
                                             "]\n", d->drive, d->head,  
                                             d->cyl_hi*256+d->cyl_lo, d->sector,  
                                             d->seccnt);  
                                 wdc__read(cpu, d);  
                                 break;  
   
                         case WDCC_WRITE:  
                                 if (!quiet_mode)  
                                         debug("[ wdc: WRITE to drive %i, head"  
                                             " %i, cyl %i, sector %i, nsecs %i"  
                                             " ]\n", d->drive, d->head,  
                                             d->cyl_hi*256+d->cyl_lo, d->sector,  
                                             d->seccnt);  
                                 wdc__write(cpu, d);  
                                 break;  
   
                         case WDCC_IDP:  /*  Initialize drive parameters  */  
                                 debug("[ wdc: IDP drive %i (TODO) ]\n",  
                                     d->drive);  
                                 /*  TODO  */  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
   
                         case SET_FEATURES:  
                                 fatal("[ wdc: SET_FEATURES drive %i (TODO), "  
                                     "feature 0x%02x ]\n", d->drive, d->precomp);  
                                 /*  TODO  */  
                                 switch (d->precomp) {  
                                 case WDSF_SET_MODE:  
                                         fatal("[ wdc: WDSF_SET_MODE drive %i, "  
                                             "pio/dma flags 0x%02x ]\n",  
                                             d->drive, d->seccnt);  
                                         break;  
                                 default:  
                                         d->error |= WDCE_ABRT;  
                                 }  
                                 /*  TODO: always interrupt?  */  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
   
                         case WDCC_RECAL:  
                                 debug("[ wdc: RECAL drive %i ]\n", d->drive);  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
   
                         case WDCC_IDENTIFY:  
                                 debug("[ wdc: IDENTIFY drive %i ]\n", d->drive);  
                                 wdc_initialize_identify_struct(cpu, d);  
                                 /*  The IDENTIFY data block is sent out  
                                     in low/high byte order:  */  
                                 for (i=0; i<sizeof(d->identify_struct); i+=2) {  
                                         wdc_addtoinbuf(d, d->identify_struct  
                                             [i+1]);  
                                         wdc_addtoinbuf(d, d->identify_struct  
                                             [i+0]);  
                                 }  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
   
                         case WDCC_IDLE_IMMED:  
                                 debug("[ wdc: IDLE_IMMED drive %i ]\n",  
                                     d->drive);  
                                 /*  TODO: interrupt here?  */  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
   
                         /*  Unsupported commands, without warning:  */  
                         case ATAPI_IDENTIFY_DEVICE:  
                         case WDCC_SEC_SET_PASSWORD:  
                         case WDCC_SEC_UNLOCK:  
                         case WDCC_SEC_ERASE_PREPARE:  
                         case WDCC_SEC_ERASE_UNIT:  
                         case WDCC_SEC_FREEZE_LOCK:  
                         case WDCC_SEC_DISABLE_PASSWORD:  
                                 d->error |= WDCE_ABRT;  
                                 break;  
   
                         default:  
                                 /*  TODO  */  
                                 d->error |= WDCE_ABRT;  
   
                                 fatal("[ wdc: WARNING! Unimplemented command "  
                                     "0x%02x (drive %i, head %i, cyl %i, sector"  
                                     " %i, nsecs %i) ]\n", d->cur_command,  
                                     d->drive, d->head, d->cyl_hi*256+d->cyl_lo,  
                                     d->sector, d->seccnt);  
                         }  
891                  }                  }
892                  break;                  break;
893    
# Line 627  int dev_wdc_access(struct cpu *cpu, stru Line 900  int dev_wdc_access(struct cpu *cpu, stru
900                              (int)relative_addr, (int)idata);                              (int)relative_addr, (int)idata);
901          }          }
902    
903          if (writeflag == MEM_READ)          if (cpu->machine->machine_type != MACHINE_HPCMIPS &&
904                  memory_writemax64(cpu, data, len, odata);              cpu->machine->machine_type != MACHINE_EVBMIPS &&
905                cpu->machine->machine_type != MACHINE_BEBOX)
906                    dev_wdc_tick(cpu, extra);
907    
908            if (writeflag == MEM_READ) {
909                    if (relative_addr == wd_data)
910                            memory_writemax64(cpu, data, len, odata);
911                    else
912                            data[0] = odata;
913            }
914    
915          return 1;          return 1;
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;
923          int i;          int i, tick_shift = WDC_TICK_SHIFT;
924    
925          d = malloc(sizeof(struct wdc_data));          d = malloc(sizeof(struct wdc_data));
926          if (d == NULL) {          if (d == NULL) {
# Line 649  int devinit_wdc(struct devinit *devinit) Line 928  int devinit_wdc(struct devinit *devinit)
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;
934    
935            d->inbuf = zeroed_alloc(WDC_INBUF_SIZE);
936    
937          /*  base_drive = 0 for the primary controller, 2 for the secondary.  */          /*  base_drive = 0 for the primary controller, 2 for the secondary.  */
938          d->base_drive = 0;          d->base_drive = 0;
# Line 658  int devinit_wdc(struct devinit *devinit) Line 941  int devinit_wdc(struct devinit *devinit)
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++)
# Line 671  int devinit_wdc(struct devinit *devinit) Line 965  int devinit_wdc(struct devinit *devinit)
965                              &d->sectors_per_track[i]);                              &d->sectors_per_track[i]);
966    
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, MEM_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, MEM_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 &&
974                devinit->machine->machine_type != MACHINE_EVBMIPS)
975                    tick_shift += 1;
976    
977          machine_add_tickfunction(devinit->machine, dev_wdc_tick,          machine_add_tickfunction(devinit->machine, dev_wdc_tick,
978              d, WDC_TICK_SHIFT);              d, tick_shift, 0.0);
979    
980          return 1;          return 1;
981  }  }

Legend:
Removed from v.14  
changed lines
  Added in v.24

  ViewVC Help
Powered by ViewVC 1.1.26