/[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 18 by dpavlin, Mon Oct 8 16:19:11 2007 UTC revision 20 by dpavlin, Mon Oct 8 16:19:23 2007 UTC
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: dev_wdc.c,v 1.44 2005/10/26 14:37:05 debug Exp $   *  $Id: dev_wdc.c,v 1.56 2005/11/23 23:31:36 debug Exp $
29   *   *
30   *  Standard "wdc" IDE controller.   *  Standard "wdc" IDE controller.
31   */   */
# Line 55  Line 55 
55   *   *
56   *  See the following URL for more info:   *  See the following URL for more info:
57   *  http://mail-index.netbsd.org/port-hpcmips/2004/12/30/0003.html   *  http://mail-index.netbsd.org/port-hpcmips/2004/12/30/0003.html
58     *
59     *  NetBSD/malta also bugs out if wdc interrupts come too quickly. Hm.
60   */   */
61  #define INT_DELAY               1  #define INT_DELAY               1
62    
# Line 72  struct wdc_data { Line 74  struct wdc_data {
74          int             heads[2];          int             heads[2];
75          int             sectors_per_track[2];          int             sectors_per_track[2];
76    
77          unsigned char   identify_struct[512];          unsigned char   *inbuf;
   
         unsigned char   inbuf[WDC_INBUF_SIZE];  
78          int             inbuf_head;          int             inbuf_head;
79          int             inbuf_tail;          int             inbuf_tail;
80    
81          int             delayed_interrupt;          int             delayed_interrupt;
82            int             int_asserted;
83    
84          int             write_in_progress;          int             write_in_progress;
85          int             write_count;          int             write_count;
86          int64_t         write_offset;          int64_t         write_offset;
# Line 94  struct wdc_data { Line 96  struct wdc_data {
96          int             drive;          int             drive;
97          int             head;          int             head;
98          int             cur_command;          int             cur_command;
99    
100            int             atapi_cmd_in_progress;
101            int             atapi_phase;
102            struct scsi_transfer *atapi_st;
103            int             atapi_len;
104            int             atapi_received;
105    
106            unsigned char   identify_struct[512];
107  };  };
108    
109    
110    #define COMMAND_RESET   0x100
111    
112    
113  /*  /*
114   *  dev_wdc_tick():   *  dev_wdc_tick():
115   */   */
116  void dev_wdc_tick(struct cpu *cpu, void *extra)  void dev_wdc_tick(struct cpu *cpu, void *extra)
117  {  {
118          struct wdc_data *d = extra;          struct wdc_data *d = extra;
119            int old_di = d->delayed_interrupt;
120    
121          if (d->delayed_interrupt) {          if (d->delayed_interrupt)
122                  d->delayed_interrupt --;                  d->delayed_interrupt --;
123    
124                  if (d->delayed_interrupt == 0)          if (old_di == 1 || d->int_asserted) {
125                          cpu_interrupt(cpu, d->irq_nr);                  cpu_interrupt(cpu, d->irq_nr);
126                    d->int_asserted = 1;
127          }          }
128  }  }
129    
# Line 150  static uint64_t wdc_get_inbuf(struct wdc Line 165  static uint64_t wdc_get_inbuf(struct wdc
165    
166    
167  /*  /*
168   *  wdc_initialize_identify_struct(d):   *  wdc_initialize_identify_struct():
169   */   */
170  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)
171  {  {
172          uint64_t total_size;          uint64_t total_size;
173            int flags, cdrom = 0;
174          char namebuf[40];          char namebuf[40];
175    
176          total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive,          total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive,
177              DISKIMAGE_IDE);              DISKIMAGE_IDE);
178            if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive,
179                DISKIMAGE_IDE))
180                    cdrom = 1;
181    
182          memset(d->identify_struct, 0, sizeof(d->identify_struct));          memset(d->identify_struct, 0, sizeof(d->identify_struct));
183    
184          /*  Offsets are in 16-bit WORDS!  High byte, then low.  */          /*  Offsets are in 16-bit WORDS!  High byte, then low.  */
185    
186          /*  0: general flags  */          /*  0: general flags  */
187          d->identify_struct[2 * 0 + 0] = 0;          flags = 1 << 6; /*  Fixed  */
188          d->identify_struct[2 * 0 + 1] = 1 << 6;          if (cdrom)
189                    flags = 0x8580;         /*  ATAPI, CDROM, removable  */
190            d->identify_struct[2 * 0 + 0] = flags >> 8;
191            d->identify_struct[2 * 0 + 1] = flags;
192    
193          /*  1: nr of cylinders  */          /*  1: nr of cylinders  */
194          d->identify_struct[2 * 1 + 0] = (d->cyls[d->drive] >> 8);          d->identify_struct[2 * 1 + 0] = d->cyls[d->drive] >> 8;
195          d->identify_struct[2 * 1 + 1] = d->cyls[d->drive] & 255;          d->identify_struct[2 * 1 + 1] = d->cyls[d->drive];
196    
197          /*  3: nr of heads  */          /*  3: nr of heads  */
198          d->identify_struct[2 * 3 + 0] = d->heads[d->drive] >> 8;          d->identify_struct[2 * 3 + 0] = d->heads[d->drive] >> 8;
# Line 181  static void wdc_initialize_identify_stru Line 203  static void wdc_initialize_identify_stru
203          d->identify_struct[2 * 6 + 1] = d->sectors_per_track[d->drive];          d->identify_struct[2 * 6 + 1] = d->sectors_per_track[d->drive];
204    
205          /*  10-19: Serial number  */          /*  10-19: Serial number  */
206          memcpy(&d->identify_struct[2 * 10], "S/N 1234-5678       ", 20);          memcpy(&d->identify_struct[2 * 10], "#0                  ", 20);
207    
208          /*  23-26: Firmware version  */          /*  23-26: Firmware version  */
209          memcpy(&d->identify_struct[2 * 23], "VER 1.0 ", 8);          memcpy(&d->identify_struct[2 * 23], "1.0     ", 8);
210    
211          /*  27-46: Model number  */          /*  27-46: Model number  */
212          if (diskimage_getname(cpu->machine, d->drive + d->base_drive,          if (diskimage_getname(cpu->machine, d->drive + d->base_drive,
# Line 203  static void wdc_initialize_identify_stru Line 225  static void wdc_initialize_identify_stru
225    
226          /*  47: max sectors per multitransfer  */          /*  47: max sectors per multitransfer  */
227          d->identify_struct[2 * 47 + 0] = 0x80;          d->identify_struct[2 * 47 + 0] = 0x80;
228          d->identify_struct[2 * 47 + 1] = 1;     /*  1 or 16?  */          d->identify_struct[2 * 47 + 1] = 128;
229    
230            /*  49: capabilities:  */
231            /*  (0x200 = LBA, 0x100 = DMA support.)  */
232            d->identify_struct[2 * 49 + 0] = 0;
233            d->identify_struct[2 * 49 + 1] = 0;
234    
235            /*  51: PIO timing mode.  */
236            d->identify_struct[2 * 51 + 0] = 0x00;  /*  ?  */
237            d->identify_struct[2 * 51 + 1] = 0x00;
238    
239            /*  53: 0x02 = fields 64-70 valid, 0x01 = fields 54-58 valid  */
240            d->identify_struct[2 * 53 + 0] = 0x00;
241            d->identify_struct[2 * 53 + 1] = 0x02;
242    
243          /*  57-58: current capacity in sectors  */          /*  57-58: current capacity in sectors  */
244          d->identify_struct[2 * 57 + 0] = ((total_size / 512) >> 24) % 255;          d->identify_struct[2 * 57 + 0] = ((total_size / 512) >> 24) % 255;
# Line 211  static void wdc_initialize_identify_stru Line 246  static void wdc_initialize_identify_stru
246          d->identify_struct[2 * 58 + 0] = ((total_size / 512) >> 8) % 255;          d->identify_struct[2 * 58 + 0] = ((total_size / 512) >> 8) % 255;
247          d->identify_struct[2 * 58 + 1] = (total_size / 512) & 255;          d->identify_struct[2 * 58 + 1] = (total_size / 512) & 255;
248    
249          /*  60-61: total nr of addresable sectors  */          /*  60-61: total nr of addressable sectors  */
250          d->identify_struct[2 * 60 + 0] = ((total_size / 512) >> 24) % 255;          d->identify_struct[2 * 60 + 0] = ((total_size / 512) >> 24) % 255;
251          d->identify_struct[2 * 60 + 1] = ((total_size / 512) >> 16) % 255;          d->identify_struct[2 * 60 + 1] = ((total_size / 512) >> 16) % 255;
252          d->identify_struct[2 * 61 + 0] = ((total_size / 512) >> 8) % 255;          d->identify_struct[2 * 61 + 0] = ((total_size / 512) >> 8) % 255;
253          d->identify_struct[2 * 61 + 1] = (total_size / 512) & 255;          d->identify_struct[2 * 61 + 1] = (total_size / 512) & 255;
254    
255            /*  64: Advanced PIO mode support. 0x02 = mode4, 0x01 = mode3  */
256            d->identify_struct[2 * 64 + 0] = 0x00;
257            d->identify_struct[2 * 64 + 1] = 0x03;
258    
259            /*  67, 68: PIO timing  */
260            d->identify_struct[2 * 67 + 0] = 0;
261            d->identify_struct[2 * 67 + 1] = 120;
262            d->identify_struct[2 * 68 + 0] = 0;
263            d->identify_struct[2 * 68 + 1] = 120;
264  }  }
265    
266    
# Line 225  static void wdc_initialize_identify_stru Line 269  static void wdc_initialize_identify_stru
269   */   */
270  void wdc__read(struct cpu *cpu, struct wdc_data *d)  void wdc__read(struct cpu *cpu, struct wdc_data *d)
271  {  {
272          const int max_sectors_per_chunk = 64;  #define MAX_SECTORS_PER_CHUNK   64
273          unsigned char buf[512 * max_sectors_per_chunk];          const int max_sectors_per_chunk = MAX_SECTORS_PER_CHUNK;
274            unsigned char buf[512 * MAX_SECTORS_PER_CHUNK];
275          int i, cyl = d->cyl_hi * 256+ d->cyl_lo;          int i, cyl = d->cyl_hi * 256+ d->cyl_lo;
276          int count = d->seccnt? d->seccnt : 256;          int count = d->seccnt? d->seccnt : 256;
277          uint64_t offset = 512 * (d->sector - 1          uint64_t offset = 512 * (d->sector - 1
# Line 287  void wdc__write(struct cpu *cpu, struct Line 332  void wdc__write(struct cpu *cpu, struct
332          printf("WDC write to offset %lli\n", (long long)offset);          printf("WDC write to offset %lli\n", (long long)offset);
333  #endif  #endif
334    
335          d->write_in_progress = 1;          d->write_in_progress = d->cur_command;
336          d->write_count = count;          d->write_count = count;
337          d->write_offset = offset;          d->write_offset = offset;
338    
# Line 304  void wdc__write(struct cpu *cpu, struct Line 349  void wdc__write(struct cpu *cpu, struct
349  static int status_byte(struct wdc_data *d, struct cpu *cpu)  static int status_byte(struct wdc_data *d, struct cpu *cpu)
350  {  {
351          int odata = 0;          int odata = 0;
   
         /*  
          *  Modern versions of OpenBSD wants WDCS_DSC. (Thanks to Alexander  
          *  Yurchenko for noticing this.)  
          */  
352          if (diskimage_exist(cpu->machine, d->drive + d->base_drive,          if (diskimage_exist(cpu->machine, d->drive + d->base_drive,
353              DISKIMAGE_IDE))              DISKIMAGE_IDE))
354                  odata |= WDCS_DRDY | WDCS_DSC;                  odata |= WDCS_DRDY | WDCS_DSC;
# Line 318  static int status_byte(struct wdc_data * Line 358  static int status_byte(struct wdc_data *
358                  odata |= WDCS_DRQ;                  odata |= WDCS_DRQ;
359          if (d->error)          if (d->error)
360                  odata |= WDCS_ERR;                  odata |= WDCS_ERR;
361            if (d->atapi_cmd_in_progress && (d->atapi_phase & WDCS_DRQ)) {
362                    odata |= WDCS_DRQ;
363            }
364          return odata;          return odata;
365  }  }
366    
# Line 335  int dev_wdc_altstatus_access(struct cpu Line 377  int dev_wdc_altstatus_access(struct cpu
377    
378          idata = data[0];          idata = data[0];
379    
380          /*  Same as the normal status byte?  */          /*  Same as the normal status byte:  */
381          odata = status_byte(d, cpu);          odata = status_byte(d, cpu);
382    
383          if (writeflag==MEM_READ)          if (writeflag==MEM_READ)
384                  debug("[ wdc: read from ALTSTATUS: 0x%02x ]\n",                  debug("[ wdc: read from ALTSTATUS: 0x%02x ]\n",
385                      (int)odata);                      (int)odata);
386          else          else {
387                  debug("[ wdc: write to ALT. CTRL: 0x%02x ]\n",                  debug("[ wdc: write to ALT. CTRL: 0x%02x ]\n",
388                      (int)idata);                      (int)idata);
389                    if (idata & WDCTL_4BIT)
390                            d->cur_command = COMMAND_RESET;
391            }
392    
393          if (writeflag == MEM_READ)          if (writeflag == MEM_READ)
394                  data[0] = odata;                  data[0] = odata;
# Line 353  int dev_wdc_altstatus_access(struct cpu Line 398  int dev_wdc_altstatus_access(struct cpu
398    
399    
400  /*  /*
401     *  wdc_command():
402     */
403    void wdc_command(struct cpu *cpu, struct wdc_data *d, int idata)
404    {
405            int i;
406    
407            d->cur_command = idata;
408            d->atapi_cmd_in_progress = 0;
409            d->error = 0;
410    
411            /*
412             *  Disk images that do not exist return an ABORT error.  This also
413             *  happens with CDROM images with the WDCC_IDENTIFY command; CDROM
414             *  images must be detected with ATAPI_IDENTIFY_DEVICE instead.
415             *
416             *  TODO:  Is this correct/good behaviour?
417             */
418            if (!diskimage_exist(cpu->machine, d->drive + d->base_drive,
419                DISKIMAGE_IDE)) {
420                    debug("[ wdc: command 0x%02x drive %i, but no disk image ]\n",
421                        d->cur_command, d->drive + d->base_drive);
422                    d->error |= WDCE_ABRT;
423                    d->delayed_interrupt = INT_DELAY;
424                    return;
425            }
426            if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive,
427                DISKIMAGE_IDE) && d->cur_command == WDCC_IDENTIFY) {
428                    debug("[ wdc: IDENTIFY drive %i, but it is an ATAPI "
429                        "drive ]\n", d->drive + d->base_drive);
430                    d->error |= WDCE_ABRT;
431                    d->delayed_interrupt = INT_DELAY;
432                    return;
433            }
434    
435            /*  Handle the command:  */
436            switch (d->cur_command) {
437    
438            case WDCC_READ:
439            case WDCC_READMULTI:
440                    if (!quiet_mode)
441                            debug("[ wdc: READ from drive %i, head %i, cyl %i, "
442                                "sector %i, nsecs %i ]\n", d->drive, d->head,
443                                d->cyl_hi*256+d->cyl_lo, d->sector, d->seccnt);
444                    wdc__read(cpu, d);
445                    break;
446    
447            case WDCC_WRITE:
448            case WDCC_WRITEMULTI:
449                    if (!quiet_mode)
450                            debug("[ wdc: WRITE to drive %i, head %i, cyl %i, "
451                                "sector %i, nsecs %i ]\n", d->drive, d->head,
452                                d->cyl_hi*256+d->cyl_lo, d->sector, d->seccnt);
453                    wdc__write(cpu, d);
454                    break;
455    
456            case WDCC_IDP:  /*  Initialize drive parameters  */
457                    debug("[ wdc: IDP drive %i (TODO) ]\n", d->drive);
458                    /*  TODO  */
459                    d->delayed_interrupt = INT_DELAY;
460                    break;
461    
462            case SET_FEATURES:
463                    debug("[ wdc: SET_FEATURES drive %i (TODO), feature 0x%02x ]\n",
464                        d->drive, d->precomp);
465                    /*  TODO  */
466                    switch (d->precomp) {
467                    case WDSF_SET_MODE:
468                            debug("[ wdc: WDSF_SET_MODE drive %i, pio/dma flags "
469                                "0x%02x ]\n", d->drive, d->seccnt);
470                            break;
471                    default:d->error |= WDCE_ABRT;
472                    }
473                    /*  TODO: always interrupt?  */
474                    d->delayed_interrupt = INT_DELAY;
475                    break;
476    
477            case WDCC_RECAL:
478                    debug("[ wdc: RECAL drive %i ]\n", d->drive);
479                    d->delayed_interrupt = INT_DELAY;
480                    break;
481    
482            case WDCC_IDENTIFY:
483            case ATAPI_IDENTIFY_DEVICE:
484                    debug("[ wdc: %sIDENTIFY drive %i ]\n", d->cur_command ==
485                        ATAPI_IDENTIFY_DEVICE? "ATAPI " : "", d->drive);
486                    wdc_initialize_identify_struct(cpu, d);
487                    /*  The IDENTIFY data is sent out in low/high byte order:  */
488                    for (i=0; i<sizeof(d->identify_struct); i+=2) {
489                            wdc_addtoinbuf(d, d->identify_struct[i+1]);
490                            wdc_addtoinbuf(d, d->identify_struct[i+0]);
491                    }
492                    d->delayed_interrupt = INT_DELAY;
493                    break;
494    
495            case WDCC_IDLE_IMMED:
496                    debug("[ wdc: IDLE_IMMED drive %i ]\n", d->drive);
497                    /*  TODO: interrupt here?  */
498                    d->delayed_interrupt = INT_DELAY;
499                    break;
500    
501            case WDCC_SETMULTI:
502                    debug("[ wdc: SETMULTI drive %i ]\n", d->drive);
503                    /*  TODO: interrupt here?  */
504                    d->delayed_interrupt = INT_DELAY;
505                    break;
506    
507            case ATAPI_SOFT_RESET:
508                    debug("[ wdc: ATAPI_SOFT_RESET drive %i ]\n", d->drive);
509                    /*  TODO: interrupt here?  */
510                    d->delayed_interrupt = INT_DELAY;
511                    break;
512    
513            case ATAPI_PKT_CMD:
514                    debug("[ wdc: ATAPI_PKT_CMD drive %i ]\n", d->drive);
515                    /*  TODO: interrupt here?  */
516                    /*  d->delayed_interrupt = INT_DELAY;  */
517                    d->atapi_cmd_in_progress = 1;
518                    d->atapi_phase = PHASE_CMDOUT;
519                    break;
520    
521            /*  Unsupported commands, without warning:  */
522            case WDCC_SEC_SET_PASSWORD:
523            case WDCC_SEC_UNLOCK:
524            case WDCC_SEC_ERASE_PREPARE:
525            case WDCC_SEC_ERASE_UNIT:
526            case WDCC_SEC_FREEZE_LOCK:
527            case WDCC_SEC_DISABLE_PASSWORD:
528                    d->error |= WDCE_ABRT;
529                    break;
530    
531            default:/*  TODO  */
532                    d->error |= WDCE_ABRT;
533                    fatal("[ wdc: WARNING! Unimplemented command 0x%02x (drive %i,"
534                        " head %i, cyl %i, sector %i, nsecs %i) ]\n",
535                        d->cur_command, d->drive, d->head, d->cyl_hi*256+d->cyl_lo,
536                        d->sector, d->seccnt);
537            }
538    }
539    
540    
541    /*
542   *  dev_wdc_access():   *  dev_wdc_access():
543   */   */
544  int dev_wdc_access(struct cpu *cpu, struct memory *mem,  int dev_wdc_access(struct cpu *cpu, struct memory *mem,
# Line 366  int dev_wdc_access(struct cpu *cpu, stru Line 552  int dev_wdc_access(struct cpu *cpu, stru
552          if (writeflag == MEM_WRITE) {          if (writeflag == MEM_WRITE) {
553                  if (relative_addr == wd_data)                  if (relative_addr == wd_data)
554                          idata = memory_readmax64(cpu, data, len);                          idata = memory_readmax64(cpu, data, len);
555                  else                  else {
556                            if (len != 1)
557                                    fatal("[ wdc: WARNING! non-8-bit access! ]\n");
558                          idata = data[0];                          idata = data[0];
559                    }
560          }          }
561    
562          switch (relative_addr) {          switch (relative_addr) {
# Line 376  int dev_wdc_access(struct cpu *cpu, stru Line 565  int dev_wdc_access(struct cpu *cpu, stru
565                  if (writeflag == MEM_READ) {                  if (writeflag == MEM_READ) {
566                          odata = 0;                          odata = 0;
567    
                         /*  TODO: This is hardcoded for little-endian?  */  
   
568                          odata += wdc_get_inbuf(d);                          odata += wdc_get_inbuf(d);
569                          if (len >= 2)  
570                                  odata += (wdc_get_inbuf(d) << 8);                          if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
571                          if (len == 4) {                                  if (len >= 2)
572                                  odata += (wdc_get_inbuf(d) << 16);                                          odata += (wdc_get_inbuf(d) << 8);
573                                  odata += (wdc_get_inbuf(d) << 24);                                  if (len == 4) {
574                                            odata += (wdc_get_inbuf(d) << 16);
575                                            odata += (wdc_get_inbuf(d) << 24);
576                                    }
577                            } else {
578                                    if (len >= 2)
579                                            odata = (odata << 8) + wdc_get_inbuf(d);
580                                    if (len == 4) {
581                                            odata = (odata << 8) + wdc_get_inbuf(d);
582                                            odata = (odata << 8) + wdc_get_inbuf(d);
583                                    }
584                          }                          }
585    
586                          if (d->data_debug)                          if (d->data_debug) {
587                                  debug("[ wdc: read from DATA: 0x%04x ]\n",                                  char *s = "0x%04llx ]\n";
588                                      (int)odata);                                  if (len == 1)
589                                            s = "0x%02llx ]\n";
590                                    if (len == 4)
591                                            s = "0x%08llx ]\n";
592                                    if (len == 8)
593                                            s = "0x%016llx ]\n";
594                                    debug("[ wdc: read from DATA: ");
595                                    debug(s, (long long)odata);
596                            }
597    
598                            if (d->atapi_cmd_in_progress) {
599                                    d->atapi_len -= len;
600                                    d->atapi_received += len;
601                                    if (d->atapi_len == 0) {
602                                            if (d->atapi_received < d->atapi_st->
603                                                data_in_len) {
604                                                    d->atapi_phase = PHASE_DATAIN;
605                                                    d->atapi_len = d->atapi_st->
606                                                        data_in_len -
607                                                        d->atapi_received;
608                                                    if (d->atapi_len > 32768)
609                                                            d->atapi_len = 0;
610                                            } else
611                                                    d->atapi_phase =
612                                                        PHASE_COMPLETED;
613                                            d->delayed_interrupt = INT_DELAY;
614                                    }
615                            } else {
616  #if 0  #if 0
617                          if (d->inbuf_tail != d->inbuf_head)                                  if (d->inbuf_tail != d->inbuf_head)
618  #else  #else
619                          if (d->inbuf_tail != d->inbuf_head &&                                  if (d->inbuf_tail != d->inbuf_head &&
620                              ((d->inbuf_tail - d->inbuf_head) % 512) == 0)                                      ((d->inbuf_tail - d->inbuf_head) % 512)
621                                        == 0)
622  #endif  #endif
623                                  d->delayed_interrupt = INT_DELAY;                                          d->delayed_interrupt = INT_DELAY;
624                            }
625                  } else {                  } else {
626                          int inbuf_len;                          int inbuf_len;
627                          if (d->data_debug)                          if (d->data_debug) {
628                                  debug("[ wdc: write to DATA (len=%i): "                                  char *s = "0x%04llx ]\n";
629                                      "0x%08lx ]\n", (int)len, (long)idata);                                  if (len == 1)
630                          if (!d->write_in_progress) {                                          s = "0x%02llx ]\n";
631                                    if (len == 4)
632                                            s = "0x%08llx ]\n";
633                                    if (len == 8)
634                                            s = "0x%016llx ]\n";
635                                    debug("[ wdc: write to DATA: ");
636                                    debug(s, (long long)idata);
637                            }
638                            if (!d->write_in_progress &&
639                                !d->atapi_cmd_in_progress) {
640                                  fatal("[ wdc: write to DATA, but not "                                  fatal("[ wdc: write to DATA, but not "
641                                      "expecting any? (len=%i): 0x%08lx ]\n",                                      "expecting any? (len=%i): 0x%08lx ]\n",
642                                      (int)len, (long)idata);                                      (int)len, (long)idata);
643                          }                          }
644    
645                          switch (len) {                          if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
646                          case 4: wdc_addtoinbuf(d, idata & 0xff);                                  switch (len) {
647                                  wdc_addtoinbuf(d, (idata >> 8) & 0xff);                                  case 4: wdc_addtoinbuf(d, idata & 0xff);
648                                  wdc_addtoinbuf(d, (idata >> 16) & 0xff);                                          wdc_addtoinbuf(d, (idata >> 8) & 0xff);
649                                  wdc_addtoinbuf(d, (idata >> 24) & 0xff);                                          wdc_addtoinbuf(d, (idata >> 16) & 0xff);
650                                  break;                                          wdc_addtoinbuf(d, (idata >> 24) & 0xff);
651                          case 2: wdc_addtoinbuf(d, idata & 0xff);                                          break;
652                                  wdc_addtoinbuf(d, (idata >> 8) & 0xff);                                  case 2: wdc_addtoinbuf(d, idata & 0xff);
653                                  break;                                          wdc_addtoinbuf(d, (idata >> 8) & 0xff);
654                          case 1: wdc_addtoinbuf(d, idata); break;                                          break;
655                          default:fatal("wdc: unimplemented write len %i\n", len);                                  case 1: wdc_addtoinbuf(d, idata); break;
656                                  exit(1);                                  default:fatal("wdc: unimplemented write "
657                                                "len %i\n", len);
658                                            exit(1);
659                                    }
660                            } else {
661                                    switch (len) {
662                                    case 4: wdc_addtoinbuf(d, (idata >> 24) & 0xff);
663                                            wdc_addtoinbuf(d, (idata >> 16) & 0xff);
664                                            wdc_addtoinbuf(d, (idata >> 8) & 0xff);
665                                            wdc_addtoinbuf(d, idata & 0xff);
666                                            break;
667                                    case 2: wdc_addtoinbuf(d, (idata >> 8) & 0xff);
668                                            wdc_addtoinbuf(d, idata & 0xff);
669                                            break;
670                                    case 1: wdc_addtoinbuf(d, idata); break;
671                                    default:fatal("wdc: unimplemented write "
672                                                "len %i\n", len);
673                                            exit(1);
674                                    }
675                          }                          }
676    
677                          inbuf_len = d->inbuf_head - d->inbuf_tail;                          inbuf_len = d->inbuf_head - d->inbuf_tail;
678                          while (inbuf_len < 0)                          while (inbuf_len < 0)
679                                  inbuf_len += WDC_INBUF_SIZE;                                  inbuf_len += WDC_INBUF_SIZE;
680    
681  #if 0                          if (d->atapi_cmd_in_progress && inbuf_len == 12) {
682                          if ((inbuf_len % (512 * d->write_count)) == 0) {                                  unsigned char *scsi_cmd = malloc(12);
683  #else                                  int x = 0, res;
684                          if ((inbuf_len % 512) == 0) {  
685  #endif                                  if (d->atapi_st != NULL)
686                                  int count = 1;  /*  d->write_count;  */                                          scsi_transfer_free(d->atapi_st);
687                                    d->atapi_st = scsi_transfer_alloc();
688    
689                                    debug("[ wdc: ATAPI command ]\n");
690    
691                                    while (inbuf_len > 0) {
692                                            scsi_cmd[x++] = wdc_get_inbuf(d);
693                                            inbuf_len --;
694                                    }
695    
696                                    d->atapi_st->cmd = scsi_cmd;
697                                    d->atapi_st->cmd_len = 12;
698    
699                                    if (scsi_cmd[0] == SCSIBLOCKCMD_READ_CAPACITY
700                                        || scsi_cmd[0] == SCSICMD_READ_10
701                                        || scsi_cmd[0] == SCSICMD_MODE_SENSE10)
702                                            d->atapi_st->cmd_len = 10;
703    
704                                    res = diskimage_scsicommand(cpu,
705                                        d->drive + d->base_drive, DISKIMAGE_IDE,
706                                        d->atapi_st);
707    
708                                    if (res == 0) {
709                                            fatal("WDC: ATAPI scsi error?\n");
710                                            exit(1);
711                                    }
712    
713                                    d->atapi_len = 0;
714                                    d->atapi_received = 0;
715    
716                                    if (res == 1) {
717                                            if (d->atapi_st->data_in != NULL) {
718                                                    int i;
719                                                    d->atapi_phase = PHASE_DATAIN;
720                                                    d->atapi_len = d->atapi_st->
721                                                        data_in_len;
722                                                    for (i=0; i<d->atapi_len; i++)
723                                                            wdc_addtoinbuf(d,
724                                                                d->atapi_st->
725                                                                data_in[i]);
726                                                    if (d->atapi_len > 32768)
727                                                            d->atapi_len = 32768;
728                                            } else {
729                                                    d->atapi_phase =
730                                                        PHASE_COMPLETED;
731                                            }
732                                    } else {
733                                            fatal("wdc atapi Dataout? TODO\n");
734                                            d->atapi_phase = PHASE_DATAOUT;
735                                            exit(1);
736                                    }
737    
738                                    d->delayed_interrupt = INT_DELAY;
739                            }
740    
741                            if (( d->write_in_progress == WDCC_WRITEMULTI &&
742                                inbuf_len % (512 * d->write_count) == 0)
743                                ||
744                                ( d->write_in_progress == WDCC_WRITE &&
745                                inbuf_len % 512 == 0) ) {
746                                    int count = (d->write_in_progress ==
747                                        WDCC_WRITEMULTI)? d->write_count : 1;
748                                  unsigned char buf[512 * count];                                  unsigned char buf[512 * count];
749                                  unsigned char *b = buf;                                  unsigned char *b = buf;
750    
# Line 447  int dev_wdc_access(struct cpu *cpu, stru Line 761  int dev_wdc_access(struct cpu *cpu, stru
761                                      d->drive + d->base_drive, DISKIMAGE_IDE, 1,                                      d->drive + d->base_drive, DISKIMAGE_IDE, 1,
762                                      d->write_offset, b, 512 * count);                                      d->write_offset, b, 512 * count);
763    
764                                  d->write_count --;                                  d->write_count -= count;
765                                  d->write_offset += 512;                                  d->write_offset += 512 * count;
766    
767                                  d->delayed_interrupt = INT_DELAY;                                  d->delayed_interrupt = INT_DELAY;
768    
# Line 459  int dev_wdc_access(struct cpu *cpu, stru Line 773  int dev_wdc_access(struct cpu *cpu, stru
773                  break;                  break;
774    
775          case wd_error:  /*  1: error (r), precomp (w)  */          case wd_error:  /*  1: error (r), precomp (w)  */
776                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
777                          odata = d->error;                          odata = d->error;
778                          debug("[ wdc: read from ERROR: 0x%02x ]\n",                          debug("[ wdc: read from ERROR: 0x%02x ]\n",
779                              (int)odata);                              (int)odata);
# Line 471  int dev_wdc_access(struct cpu *cpu, stru Line 785  int dev_wdc_access(struct cpu *cpu, stru
785                  }                  }
786                  break;                  break;
787    
788          case wd_seccnt: /*  2: sector count  */          case wd_seccnt: /*  2: sector count (or "ireason" for ATAPI)  */
789                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
790                          odata = d->seccnt;                          odata = d->seccnt;
791                            if (d->atapi_cmd_in_progress) {
792                                    odata = d->atapi_phase & (WDCI_CMD | WDCI_IN);
793                            }
794                          debug("[ wdc: read from SECCNT: 0x%02x ]\n",(int)odata);                          debug("[ wdc: read from SECCNT: 0x%02x ]\n",(int)odata);
795                  } else {                  } else {
796                          d->seccnt = idata;                          d->seccnt = idata;
# Line 482  int dev_wdc_access(struct cpu *cpu, stru Line 799  int dev_wdc_access(struct cpu *cpu, stru
799                  break;                  break;
800    
801          case wd_sector: /*  3: first sector  */          case wd_sector: /*  3: first sector  */
802                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
803                          odata = d->sector;                          odata = d->sector;
804                          debug("[ wdc: read from SECTOR: 0x%02x ]\n",(int)odata);                          debug("[ wdc: read from SECTOR: 0x%02x ]\n",(int)odata);
805                  } else {                  } else {
# Line 492  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_cyl_lo: /*  4: cylinder low  */          case wd_cyl_lo: /*  4: cylinder low  */
812                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
813                          odata = d->cyl_lo;                          odata = d->cyl_lo;
814                            if (d->cur_command == COMMAND_RESET &&
815                                diskimage_is_a_cdrom(cpu->machine,
816                                d->drive + d->base_drive, DISKIMAGE_IDE))
817                                    odata = 0x14;
818                            if (d->atapi_cmd_in_progress) {
819                                    int x = d->atapi_len;
820                                    if (x > 32768)
821                                            x = 32768;
822                                    odata = x & 255;
823                            }
824                          debug("[ wdc: read from CYL_LO: 0x%02x ]\n",(int)odata);                          debug("[ wdc: read from CYL_LO: 0x%02x ]\n",(int)odata);
825                  } else {                  } else {
826                          d->cyl_lo = idata;                          d->cyl_lo = idata;
# Line 501  int dev_wdc_access(struct cpu *cpu, stru Line 828  int dev_wdc_access(struct cpu *cpu, stru
828                  }                  }
829                  break;                  break;
830    
831          case wd_cyl_hi: /*  5: cylinder low  */          case wd_cyl_hi: /*  5: cylinder high  */
832                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
833                          odata = d->cyl_hi;                          odata = d->cyl_hi;
834                            if (d->cur_command == COMMAND_RESET &&
835                                diskimage_is_a_cdrom(cpu->machine,
836                                d->drive + d->base_drive, DISKIMAGE_IDE))
837                                    odata = 0xeb;
838                            if (d->atapi_cmd_in_progress) {
839                                    int x = d->atapi_len;
840                                    if (x > 32768)
841                                            x = 32768;
842                                    odata = (x >> 8) & 255;
843                            }
844                          debug("[ wdc: read from CYL_HI: 0x%02x ]\n",(int)odata);                          debug("[ wdc: read from CYL_HI: 0x%02x ]\n",(int)odata);
845                  } else {                  } else {
846                          d->cyl_hi = idata;                          d->cyl_hi = idata;
# Line 536  int dev_wdc_access(struct cpu *cpu, stru Line 873  int dev_wdc_access(struct cpu *cpu, stru
873                                  debug("[ wdc: read from STATUS: 0x%02x ]\n",                                  debug("[ wdc: read from STATUS: 0x%02x ]\n",
874                                      (int)odata);                                      (int)odata);
875                          cpu_interrupt_ack(cpu, d->irq_nr);                          cpu_interrupt_ack(cpu, d->irq_nr);
876                            d->int_asserted = 0;
877                          d->delayed_interrupt = 0;                          d->delayed_interrupt = 0;
878                  } else {                  } else {
879                          debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);                          debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);
880                          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);  
                         }  
881                  }                  }
882                  break;                  break;
883    
# Line 655  int dev_wdc_access(struct cpu *cpu, stru Line 890  int dev_wdc_access(struct cpu *cpu, stru
890                              (int)relative_addr, (int)idata);                              (int)relative_addr, (int)idata);
891          }          }
892    
893          if (cpu->machine->machine_type != MACHINE_HPCMIPS)          if (cpu->machine->machine_type != MACHINE_HPCMIPS &&
894                cpu->machine->machine_type != MACHINE_EVBMIPS &&
895                cpu->machine->machine_type != MACHINE_BEBOX)
896                  dev_wdc_tick(cpu, extra);                  dev_wdc_tick(cpu, extra);
897    
898          if (writeflag == MEM_READ) {          if (writeflag == MEM_READ) {
# Line 686  int devinit_wdc(struct devinit *devinit) Line 923  int devinit_wdc(struct devinit *devinit)
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    
926            d->data_debug = 1;
927    
928            d->inbuf = zeroed_alloc(WDC_INBUF_SIZE);
929    
930          /*  base_drive = 0 for the primary controller, 2 for the secondary.  */          /*  base_drive = 0 for the primary controller, 2 for the secondary.  */
931          d->base_drive = 0;          d->base_drive = 0;
932          if ((devinit->addr & 0xfff) == 0x170)          if ((devinit->addr & 0xfff) == 0x170)
# Line 706  int devinit_wdc(struct devinit *devinit) Line 947  int devinit_wdc(struct devinit *devinit)
947                              &d->sectors_per_track[i]);                              &d->sectors_per_track[i]);
948    
949          memory_device_register(devinit->machine->memory, "wdc_altstatus",          memory_device_register(devinit->machine->memory, "wdc_altstatus",
950              alt_status_addr, 2, dev_wdc_altstatus_access, d, MEM_DEFAULT, NULL);              alt_status_addr, 2, dev_wdc_altstatus_access, d, DM_DEFAULT, NULL);
951          memory_device_register(devinit->machine->memory, devinit->name,          memory_device_register(devinit->machine->memory, devinit->name,
952              devinit->addr, DEV_WDC_LENGTH, dev_wdc_access, d, MEM_DEFAULT,              devinit->addr, DEV_WDC_LENGTH, dev_wdc_access, d, DM_DEFAULT,
953              NULL);              NULL);
954    
955          if (devinit->machine->machine_type != MACHINE_HPCMIPS)          if (devinit->machine->machine_type != MACHINE_HPCMIPS &&
956                  tick_shift += 2;              devinit->machine->machine_type != MACHINE_EVBMIPS)
957                    tick_shift += 1;
958    
959          machine_add_tickfunction(devinit->machine, dev_wdc_tick,          machine_add_tickfunction(devinit->machine, dev_wdc_tick,
960              d, tick_shift);              d, tick_shift);

Legend:
Removed from v.18  
changed lines
  Added in v.20

  ViewVC Help
Powered by ViewVC 1.1.26