dev_wdc.cc Source File

Back to the index.

dev_wdc.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004-2009 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *
28  * COMMENT: Standard "wdc" IDE controller
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "cpu.h"
36 #include "device.h"
37 #include "diskimage.h"
38 #include "machine.h"
39 #include "memory.h"
40 #include "misc.h"
41 
42 #include "thirdparty/wdcreg.h"
43 
44 
45 #define DEV_WDC_LENGTH 8
46 #define WDC_TICK_SHIFT 14
47 #define WDC_MAX_SECTORS 512
48 #define WDC_INBUF_SIZE (512*(WDC_MAX_SECTORS+1))
49 
50 extern int quiet_mode;
51 
52 /* #define debug fatal */
53 
54 struct wdc_data {
55  struct interrupt irq;
56  int addr_mult;
60 
61  /* Cached values: */
62  int cyls[2];
63  int heads[2];
65 
66  unsigned char *inbuf;
69 
71 
74  int64_t write_offset;
75 
76  int error;
77  int precomp;
78  int seccnt;
79  int sector;
80  int cyl_lo;
81  int cyl_hi;
83  int lba;
84  int drive;
85  int head;
87 
91  int atapi_len;
93 
94  unsigned char identify_struct[512];
95 };
96 
97 
98 #define COMMAND_RESET 0x100
99 
100 
102 {
103  struct wdc_data *d = (struct wdc_data *) extra;
104 
105  if (d->int_assert)
106  INTERRUPT_ASSERT(d->irq);
107 }
108 
109 
110 /*
111  * wdc_set_io_enabled():
112  *
113  * Set io_enabled to zero to disable the I/O registers temporarily (e.g.
114  * used by PCI code in NetBSD to detect whether multiple controllers collide
115  * in I/O space).
116  *
117  * Return value is old contents of the io_enabled variable.
118  */
120 {
121  int old = d->io_enabled;
122  d->io_enabled = io_enabled;
123  return old;
124 }
125 
126 
127 /*
128  * wdc_addtoinbuf():
129  *
130  * Write to the inbuf at its head, read at its tail.
131  */
132 static void wdc_addtoinbuf(struct wdc_data *d, int c)
133 {
134  d->inbuf[d->inbuf_head] = c;
135 
136  d->inbuf_head = (d->inbuf_head + 1) % WDC_INBUF_SIZE;
137  if (d->inbuf_head == d->inbuf_tail)
138  fatal("[ wdc_addtoinbuf(): WARNING! wdc inbuf overrun!"
139  " Increase WDC_MAX_SECTORS. ]\n");
140 }
141 
142 
143 /*
144  * wdc_get_inbuf():
145  *
146  * Read from the tail of inbuf.
147  */
148 static uint64_t wdc_get_inbuf(struct wdc_data *d)
149 {
150  int c = d->inbuf[d->inbuf_tail];
151 
152  if (d->inbuf_head == d->inbuf_tail) {
153  fatal("[ wdc: WARNING! someone is reading too much from the "
154  "wdc inbuf! ]\n");
155  return (uint64_t) -1;
156  }
157 
158  d->inbuf_tail = (d->inbuf_tail + 1) % WDC_INBUF_SIZE;
159  return c;
160 }
161 
162 
163 /*
164  * wdc_initialize_identify_struct():
165  */
166 static void wdc_initialize_identify_struct(struct cpu *cpu, struct wdc_data *d)
167 {
168  uint64_t total_size;
169  int flags, cdrom = 0;
170  char namebuf[40];
171 
172  total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive,
173  DISKIMAGE_IDE);
174  if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive,
175  DISKIMAGE_IDE))
176  cdrom = 1;
177 
178  memset(d->identify_struct, 0, sizeof(d->identify_struct));
179 
180  /* Offsets are in 16-bit WORDS! High byte, then low. */
181 
182  /* 0: general flags */
183  flags = 1 << 6; /* Fixed */
184  if (cdrom)
185  flags = 0x8580; /* ATAPI, CDROM, removable */
186  d->identify_struct[2 * 0 + 0] = flags >> 8;
187  d->identify_struct[2 * 0 + 1] = flags;
188 
189  /* 1: nr of cylinders */
190  d->identify_struct[2 * 1 + 0] = d->cyls[d->drive] >> 8;
191  d->identify_struct[2 * 1 + 1] = d->cyls[d->drive];
192 
193  /* 3: nr of heads */
194  d->identify_struct[2 * 3 + 0] = d->heads[d->drive] >> 8;
195  d->identify_struct[2 * 3 + 1] = d->heads[d->drive];
196 
197  /* 6: sectors per track */
198  d->identify_struct[2 * 6 + 0] = d->sectors_per_track[d->drive] >> 8;
199  d->identify_struct[2 * 6 + 1] = d->sectors_per_track[d->drive];
200 
201  /* 10-19: Serial number */
202  memcpy(&d->identify_struct[2 * 10], "#0 ", 20);
203 
204  /* 23-26: Firmware version */
205  memcpy(&d->identify_struct[2 * 23], "1.0 ", 8);
206 
207  /* 27-46: Model number */
208  if (diskimage_getname(cpu->machine, d->drive + d->base_drive,
209  DISKIMAGE_IDE, namebuf, sizeof(namebuf))) {
210  size_t i;
211  for (i=0; i<sizeof(namebuf); i++)
212  if (namebuf[i] == 0) {
213  for (; i<sizeof(namebuf); i++)
214  namebuf[i] = ' ';
215  break;
216  }
217  memcpy(&d->identify_struct[2 * 27], namebuf, 40);
218  } else
219  memcpy(&d->identify_struct[2 * 27],
220  "Fake GXemul IDE disk ", 40);
221 
222  /* 47: max sectors per multitransfer */
223  d->identify_struct[2 * 47 + 0] = 0x80;
224  d->identify_struct[2 * 47 + 1] = 128;
225 
226  /* 49: capabilities: */
227  /* (0x200 = LBA, 0x100 = DMA support.) */
228  d->identify_struct[2 * 49 + 0] = 0;
229  d->identify_struct[2 * 49 + 1] = 0;
230 
231  /* 51: PIO timing mode. */
232  d->identify_struct[2 * 51 + 0] = 0x00; /* ? */
233  d->identify_struct[2 * 51 + 1] = 0x00;
234 
235  /* 53: 0x02 = fields 64-70 valid, 0x01 = fields 54-58 valid */
236  d->identify_struct[2 * 53 + 0] = 0x00;
237  d->identify_struct[2 * 53 + 1] = 0x02;
238 
239  /* 57-58: current capacity in sectors */
240  d->identify_struct[2 * 58 + 0] = ((total_size / 512) >> 24) % 255;
241  d->identify_struct[2 * 58 + 1] = ((total_size / 512) >> 16) % 255;
242  d->identify_struct[2 * 57 + 0] = ((total_size / 512) >> 8) % 255;
243  d->identify_struct[2 * 57 + 1] = (total_size / 512) & 255;
244 
245  /* 60-61: total nr of addressable sectors */
246  d->identify_struct[2 * 61 + 0] = ((total_size / 512) >> 24) % 255;
247  d->identify_struct[2 * 61 + 1] = ((total_size / 512) >> 16) % 255;
248  d->identify_struct[2 * 60 + 0] = ((total_size / 512) >> 8) % 255;
249  d->identify_struct[2 * 60 + 1] = (total_size / 512) & 255;
250 
251  /* 64: Advanced PIO mode support. 0x02 = mode4, 0x01 = mode3 */
252  d->identify_struct[2 * 64 + 0] = 0x00;
253  d->identify_struct[2 * 64 + 1] = 0x03;
254 
255  /* 67, 68: PIO timing */
256  d->identify_struct[2 * 67 + 0] = 0;
257  d->identify_struct[2 * 67 + 1] = 120;
258  d->identify_struct[2 * 68 + 0] = 0;
259  d->identify_struct[2 * 68 + 1] = 120;
260 }
261 
262 
263 /*
264  * wdc__read():
265  */
266 void wdc__read(struct cpu *cpu, struct wdc_data *d)
267 {
268 #define MAX_SECTORS_PER_CHUNK 64
269  const int max_sectors_per_chunk = MAX_SECTORS_PER_CHUNK;
270  unsigned char buf[512 * MAX_SECTORS_PER_CHUNK];
271  int i, cyl = d->cyl_hi * 256+ d->cyl_lo;
272  int count = d->seccnt? d->seccnt : 256;
273  uint64_t offset = 512 * (d->sector - 1
274  + (int64_t)d->head * d->sectors_per_track[d->drive] +
275  (int64_t)d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl);
276 
277 #if 0
278  /* LBA: */
279  if (d->lba)
280  offset = 512 * (((d->head & 0xf) << 24) + (cyl << 8)
281  + d->sector);
282  printf("WDC read from offset %lli\n", (long long)offset);
283 #endif
284 
285  while (count > 0) {
286  int to_read = count > max_sectors_per_chunk?
287  max_sectors_per_chunk : count;
288 
289  /* TODO: result code from the read? */
290 
291  if (d->inbuf_head + 512 * to_read <= WDC_INBUF_SIZE) {
293  DISKIMAGE_IDE, 0, offset,
294  d->inbuf + d->inbuf_head, 512 * to_read);
295  d->inbuf_head += 512 * to_read;
296  if (d->inbuf_head == WDC_INBUF_SIZE)
297  d->inbuf_head = 0;
298  } else {
300  DISKIMAGE_IDE, 0, offset, buf, 512 * to_read);
301  for (i=0; i<512 * to_read; i++)
302  wdc_addtoinbuf(d, buf[i]);
303  }
304 
305  offset += 512 * to_read;
306  count -= to_read;
307  }
308 
309  d->int_assert = 1;
310 }
311 
312 
313 /*
314  * wdc__write():
315  */
316 void wdc__write(struct cpu *cpu, struct wdc_data *d)
317 {
318  int cyl = d->cyl_hi * 256+ d->cyl_lo;
319  int count = d->seccnt? d->seccnt : 256;
320  uint64_t offset = 512 * (d->sector - 1
321  + (int64_t)d->head * d->sectors_per_track[d->drive] +
322  (int64_t)d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl);
323 #if 0
324  /* LBA: */
325  if (d->lba)
326  offset = 512 * (((d->head & 0xf) << 24) +
327  (cyl << 8) + d->sector);
328  printf("WDC write to offset %lli\n", (long long)offset);
329 #endif
330 
332  d->write_count = count;
333  d->write_offset = offset;
334 
335  /* TODO: result code? */
336 }
337 
338 
339 /*
340  * status_byte():
341  *
342  * Return a reasonable status byte corresponding to the controller's current
343  * state.
344  */
345 static int status_byte(struct wdc_data *d, struct cpu *cpu)
346 {
347  int odata = 0;
348  if (diskimage_exist(cpu->machine, d->drive + d->base_drive,
349  DISKIMAGE_IDE))
350  odata |= WDCS_DRDY | WDCS_DSC;
351  if (d->inbuf_head != d->inbuf_tail)
352  odata |= WDCS_DRQ;
353  if (d->write_in_progress)
354  odata |= WDCS_DRQ;
355  if (d->error)
356  odata |= WDCS_ERR;
357  if (d->atapi_cmd_in_progress && (d->atapi_phase & WDCS_DRQ)) {
358  odata |= WDCS_DRQ;
359  }
360  return odata;
361 }
362 
363 
364 DEVICE_ACCESS(wdc_altstatus)
365 {
366  struct wdc_data *d = (struct wdc_data *) extra;
367  uint64_t idata = 0, odata = 0;
368 
369  idata = data[0];
370 
371  /* Same as the normal status byte: */
372  odata = status_byte(d, cpu);
373 
374  if (writeflag==MEM_READ)
375  debug("[ wdc: read from ALTSTATUS: 0x%02x ]\n",
376  (int)odata);
377  else {
378  debug("[ wdc: write to ALT. CTRL: 0x%02x ]\n",
379  (int)idata);
380  if (idata & WDCTL_4BIT)
382  }
383 
384  if (writeflag == MEM_READ)
385  data[0] = odata;
386 
387  return 1;
388 }
389 
390 
391 /*
392  * wdc_command():
393  */
394 void wdc_command(struct cpu *cpu, struct wdc_data *d, int idata)
395 {
396  size_t i;
397 
398  d->cur_command = idata;
399  d->atapi_cmd_in_progress = 0;
400  d->error = 0;
401 
402  /*
403  * Disk images that do not exist return an ABORT error. This also
404  * happens with CDROM images with the WDCC_IDENTIFY command; CDROM
405  * images must be detected with ATAPI_IDENTIFY_DEVICE instead.
406  *
407  * TODO: Is this correct/good behaviour?
408  */
409  if (!diskimage_exist(cpu->machine, d->drive + d->base_drive,
410  DISKIMAGE_IDE)) {
411  debug("[ wdc: command 0x%02x drive %i, but no disk image ]\n",
412  d->cur_command, d->drive + d->base_drive);
413  d->error |= WDCE_ABRT;
414  d->int_assert = 1;
415  return;
416  }
417  if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive,
419  debug("[ wdc: IDENTIFY drive %i, but it is an ATAPI "
420  "drive ]\n", d->drive + d->base_drive);
421  d->error |= WDCE_ABRT;
422  d->int_assert = 1;
423  return;
424  }
425 
426  /* Handle the command: */
427  switch (d->cur_command) {
428 
429  case WDCC_READ:
430  case WDCC_READMULTI:
431  if (!quiet_mode)
432  debug("[ wdc: READ from drive %i, head %i, cyl %i, "
433  "sector %i, nsecs %i ]\n", d->drive, d->head,
434  d->cyl_hi*256+d->cyl_lo, d->sector, d->seccnt);
435  wdc__read(cpu, d);
436  break;
437 
438  case WDCC_WRITE:
439  case WDCC_WRITEMULTI:
440  if (!quiet_mode)
441  debug("[ wdc: WRITE to 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__write(cpu, d);
445  break;
446 
447  case WDCC_IDP: /* Initialize drive parameters */
448  debug("[ wdc: IDP drive %i (TODO) ]\n", d->drive);
449  /* TODO */
450  d->int_assert = 1;
451  break;
452 
453  case SET_FEATURES:
454  debug("[ wdc: SET_FEATURES drive %i (TODO), feature 0x%02x ]\n",
455  d->drive, d->precomp);
456  /* TODO */
457  switch (d->precomp) {
458  case WDSF_SET_MODE:
459  debug("[ wdc: WDSF_SET_MODE drive %i, pio/dma flags "
460  "0x%02x ]\n", d->drive, d->seccnt);
461  break;
462  default:d->error |= WDCE_ABRT;
463  }
464  /* TODO: always interrupt? */
465  d->int_assert = 1;
466  break;
467 
468  case WDCC_RECAL:
469  debug("[ wdc: RECAL drive %i ]\n", d->drive);
470  d->int_assert = 1;
471  break;
472 
473  case WDCC_IDENTIFY:
475  debug("[ wdc: %sIDENTIFY drive %i ]\n", d->cur_command ==
476  ATAPI_IDENTIFY_DEVICE? "ATAPI " : "", d->drive);
477  wdc_initialize_identify_struct(cpu, d);
478  /* The IDENTIFY data is sent out in low/high byte order: */
479  for (i=0; i<sizeof(d->identify_struct); i+=2) {
480  wdc_addtoinbuf(d, d->identify_struct[i+1]);
481  wdc_addtoinbuf(d, d->identify_struct[i+0]);
482  }
483  d->int_assert = 1;
484  break;
485 
486  case WDCC_IDLE_IMMED:
487  debug("[ wdc: IDLE_IMMED drive %i ]\n", d->drive);
488  /* TODO: interrupt here? */
489  d->int_assert = 1;
490  break;
491 
492  case WDCC_SETMULTI:
493  debug("[ wdc: SETMULTI drive %i ]\n", d->drive);
494  /* TODO: interrupt here? */
495  d->int_assert = 1;
496  break;
497 
498  case ATAPI_SOFT_RESET:
499  debug("[ wdc: ATAPI_SOFT_RESET drive %i ]\n", d->drive);
500  /* TODO: interrupt here? */
501  d->int_assert = 1;
502  break;
503 
504  case ATAPI_PKT_CMD:
505  debug("[ wdc: ATAPI_PKT_CMD drive %i ]\n", d->drive);
506  /* TODO: interrupt here? */
507  /* d->int_assert = 1; */
508  d->atapi_cmd_in_progress = 1;
510  break;
511 
512  case WDCC_DIAGNOSE:
513  debug("[ wdc: WDCC_DIAGNOSE drive %i: TODO ]\n", d->drive);
514  /* TODO: interrupt here? */
515  d->int_assert = 1;
516  d->error = 1; /* No error? */
517  break;
518 
519  /* Unsupported commands, without warning: */
521  case WDCC_SEC_UNLOCK:
523  case WDCC_SEC_ERASE_UNIT:
526  d->error |= WDCE_ABRT;
527  break;
528 
529  default:/* TODO */
530  d->error |= WDCE_ABRT;
531  fatal("[ wdc: WARNING! Unimplemented command 0x%02x (drive %i,"
532  " head %i, cyl %i, sector %i, nsecs %i) ]\n",
533  d->cur_command, d->drive, d->head, d->cyl_hi*256+d->cyl_lo,
534  d->sector, d->seccnt);
535  }
536 }
537 
538 
540 {
541  struct wdc_data *d = (struct wdc_data *) extra;
542  uint64_t idata = 0, odata = 0;
543  int i;
544 
545  relative_addr /= d->addr_mult;
546 
547  if (!d->io_enabled)
548  goto ret;
549 
550  if (writeflag == MEM_WRITE) {
551  if (relative_addr == wd_data)
552  idata = memory_readmax64(cpu, data, len);
553  else {
554  if (len != 1)
555  fatal("[ wdc: WARNING! non-8-bit access on WRITE! ]\n");
556  idata = data[0];
557  }
558  }
559 
560  switch (relative_addr) {
561 
562  case wd_data: /* 0: data */
563  if (writeflag == MEM_READ) {
564  odata = wdc_get_inbuf(d);
565 
566  if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
567  if (len >= 2)
568  odata += (wdc_get_inbuf(d) << 8);
569  if (len == 4) {
570  odata += (wdc_get_inbuf(d) << 16);
571  odata += (wdc_get_inbuf(d) << 24);
572  }
573  } else {
574  if (len >= 2)
575  odata = (odata << 8) + wdc_get_inbuf(d);
576  if (len == 4) {
577  odata = (odata << 8) + wdc_get_inbuf(d);
578  odata = (odata << 8) + wdc_get_inbuf(d);
579  }
580  }
581 
582  if (d->data_debug) {
583  const char *s = "0x%04" PRIx64" ]\n";
584  if (len == 1)
585  s = "0x%02" PRIx64" ]\n";
586  if (len == 4)
587  s = "0x%08" PRIx64" ]\n";
588  if (len == 8)
589  s = "0x%016" PRIx64" ]\n";
590  debug("[ wdc: read from DATA: ");
591  debug(s, (uint64_t) odata);
592  }
593 
594  if (d->atapi_cmd_in_progress) {
595  d->atapi_len -= len;
596  d->atapi_received += len;
597  if (d->atapi_len == 0) {
598  if (d->atapi_received < d->atapi_st->
599  data_in_len) {
601  d->atapi_len = d->atapi_st->
602  data_in_len -
603  d->atapi_received;
604  if (d->atapi_len > 32768)
605  d->atapi_len = 0;
606  } else
607  d->atapi_phase =
609  d->int_assert = 1;
610  }
611  } else {
612 #if 0
613  if (d->inbuf_tail != d->inbuf_head)
614 #else
615  if (d->inbuf_tail != d->inbuf_head &&
616  ((d->inbuf_tail - d->inbuf_head) % 512)
617  == 0)
618 #endif
619  d->int_assert = 1;
620  }
621  } else {
622  int inbuf_len;
623  if (d->data_debug) {
624  const char *s = "0x%04" PRIx64" ]\n";
625  if (len == 1)
626  s = "0x%02" PRIx64" ]\n";
627  if (len == 4)
628  s = "0x%08" PRIx64" ]\n";
629  if (len == 8)
630  s = "0x%016" PRIx64" ]\n";
631  debug("[ wdc: write to DATA: ");
632  debug(s, (uint64_t) idata);
633  }
634  if (!d->write_in_progress &&
635  !d->atapi_cmd_in_progress) {
636  fatal("[ wdc: write to DATA, but not "
637  "expecting any? (len=%i): 0x%08lx ]\n",
638  (int)len, (long)idata);
639  }
640 
641  if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
642  switch (len) {
643  case 4: wdc_addtoinbuf(d, idata & 0xff);
644  wdc_addtoinbuf(d, (idata >> 8) & 0xff);
645  wdc_addtoinbuf(d, (idata >> 16) & 0xff);
646  wdc_addtoinbuf(d, (idata >> 24) & 0xff);
647  break;
648  case 2: wdc_addtoinbuf(d, idata & 0xff);
649  wdc_addtoinbuf(d, (idata >> 8) & 0xff);
650  break;
651  case 1: wdc_addtoinbuf(d, idata); break;
652  default:fatal("wdc: unimplemented write "
653  "len %i\n", len);
654  exit(1);
655  }
656  } else {
657  switch (len) {
658  case 4: wdc_addtoinbuf(d, (idata >> 24) & 0xff);
659  wdc_addtoinbuf(d, (idata >> 16) & 0xff);
660  wdc_addtoinbuf(d, (idata >> 8) & 0xff);
661  wdc_addtoinbuf(d, idata & 0xff);
662  break;
663  case 2: wdc_addtoinbuf(d, (idata >> 8) & 0xff);
664  wdc_addtoinbuf(d, idata & 0xff);
665  break;
666  case 1: wdc_addtoinbuf(d, idata); break;
667  default:fatal("wdc: unimplemented write "
668  "len %i\n", len);
669  exit(1);
670  }
671  }
672 
673  inbuf_len = d->inbuf_head - d->inbuf_tail;
674  while (inbuf_len < 0)
675  inbuf_len += WDC_INBUF_SIZE;
676 
677  if (d->atapi_cmd_in_progress && inbuf_len == 12) {
678  unsigned char *scsi_cmd;
679  int x = 0, res;
680 
681  CHECK_ALLOCATION(scsi_cmd = (unsigned char *) malloc(12));
682 
683  if (d->atapi_st != NULL)
686 
687  debug("[ wdc: ATAPI command ]\n");
688 
689  while (inbuf_len > 0) {
690  scsi_cmd[x++] = wdc_get_inbuf(d);
691  inbuf_len --;
692  }
693 
694  d->atapi_st->cmd = scsi_cmd;
695  d->atapi_st->cmd_len = 12;
696 
697  if (scsi_cmd[0] == SCSIBLOCKCMD_READ_CAPACITY
698  || scsi_cmd[0] == SCSICMD_READ_10
699  || scsi_cmd[0] == SCSICMD_MODE_SENSE10)
700  d->atapi_st->cmd_len = 10;
701 
702  res = diskimage_scsicommand(cpu,
703  d->drive + d->base_drive, DISKIMAGE_IDE,
704  d->atapi_st);
705 
706  if (res == 0) {
707  fatal("WDC: ATAPI scsi error?\n");
708  exit(1);
709  }
710 
711  d->atapi_len = 0;
712  d->atapi_received = 0;
713 
714  if (res == 1) {
715  if (d->atapi_st->data_in != NULL) {
717  d->atapi_len = d->atapi_st->data_in_len;
718  for (int j=0; j<d->atapi_len; j++)
719  wdc_addtoinbuf(d, d->atapi_st->data_in[j]);
720 
721  if (d->atapi_len > 32768)
722  d->atapi_len = 32768;
723  } else {
724  d->atapi_phase =
726  }
727  } else {
728  fatal("wdc atapi Dataout? TODO\n");
730  exit(1);
731  }
732 
733  d->int_assert = 1;
734  }
735 
736  if (( d->write_in_progress == WDCC_WRITEMULTI &&
737  inbuf_len % (512 * d->write_count) == 0)
738  ||
739  ( d->write_in_progress == WDCC_WRITE &&
740  inbuf_len % 512 == 0) ) {
741  int count = (d->write_in_progress ==
742  WDCC_WRITEMULTI)? d->write_count : 1;
743  unsigned char *buf, *b;
744 
745  CHECK_ALLOCATION(buf = (unsigned char *) malloc(512 * count));
746  b = buf;
747 
748  if (d->inbuf_tail+512*count <= WDC_INBUF_SIZE) {
749  b = d->inbuf + d->inbuf_tail;
750  d->inbuf_tail = (d->inbuf_tail + 512
751  * count) % WDC_INBUF_SIZE;
752  } else {
753  for (i=0; i<512 * count; i++)
754  buf[i] = wdc_get_inbuf(d);
755  }
756 
758  d->drive + d->base_drive, DISKIMAGE_IDE, 1,
759  d->write_offset, b, 512 * count);
760 
761  d->write_count -= count;
762  d->write_offset += 512 * count;
763 
764  d->int_assert = 1;
765 
766  if (d->write_count == 0)
767  d->write_in_progress = 0;
768 
769  free(buf);
770  }
771  }
772  break;
773 
774  case wd_error: /* 1: error (r), precomp (w) */
775  if (writeflag == MEM_READ) {
776  odata = d->error;
777  debug("[ wdc: read from ERROR: 0x%02x ]\n", (int)odata);
778  } else {
779  d->precomp = idata;
780  debug("[ wdc: write to PRECOMP: 0x%02x ]\n",(int)idata);
781  }
782  break;
783 
784  case wd_seccnt: /* 2: sector count (or "ireason" for ATAPI) */
785  if (writeflag == MEM_READ) {
786  odata = d->seccnt;
787  if (d->atapi_cmd_in_progress) {
788  odata = d->atapi_phase & (WDCI_CMD | WDCI_IN);
789  }
790  debug("[ wdc: read from SECCNT: 0x%02x ]\n",(int)odata);
791  } else {
792  d->seccnt = idata;
793  debug("[ wdc: write to SECCNT: 0x%02x ]\n", (int)idata);
794  }
795  break;
796 
797  case wd_sector: /* 3: first sector */
798  if (writeflag == MEM_READ) {
799  odata = d->sector;
800  debug("[ wdc: read from SECTOR: 0x%02x ]\n",(int)odata);
801  } else {
802  d->sector = idata;
803  debug("[ wdc: write to SECTOR: 0x%02x ]\n", (int)idata);
804  }
805  break;
806 
807  case wd_cyl_lo: /* 4: cylinder low */
808  if (writeflag == MEM_READ) {
809  odata = d->cyl_lo;
810  if (d->cur_command == COMMAND_RESET &&
812  d->drive + d->base_drive, DISKIMAGE_IDE))
813  odata = 0x14;
814  if (d->atapi_cmd_in_progress) {
815  int x = d->atapi_len;
816  if (x > 32768)
817  x = 32768;
818  odata = x & 255;
819  }
820  debug("[ wdc: read from CYL_LO: 0x%02x ]\n",(int)odata);
821  } else {
822  d->cyl_lo = idata;
823  debug("[ wdc: write to CYL_LO: 0x%02x ]\n", (int)idata);
824  }
825  break;
826 
827  case wd_cyl_hi: /* 5: cylinder high */
828  if (writeflag == MEM_READ) {
829  odata = d->cyl_hi;
830  if (d->cur_command == COMMAND_RESET &&
832  d->drive + d->base_drive, DISKIMAGE_IDE))
833  odata = 0xeb;
834  if (d->atapi_cmd_in_progress) {
835  int x = d->atapi_len;
836  if (x > 32768)
837  x = 32768;
838  odata = (x >> 8) & 255;
839  }
840  debug("[ wdc: read from CYL_HI: 0x%02x ]\n",(int)odata);
841  } else {
842  d->cyl_hi = idata;
843  debug("[ wdc: write to CYL_HI: 0x%02x ]\n", (int)idata);
844  }
845  break;
846 
847  case wd_sdh: /* 6: sectorsize/drive/head */
848  if (writeflag==MEM_READ) {
849  odata = (d->sectorsize << 6) + (d->lba << 5) +
850  (d->drive << 4) + (d->head);
851  debug("[ wdc: read from SDH: 0x%02x (sectorsize %i,"
852  " lba=%i, drive %i, head %i) ]\n", (int)odata,
853  d->sectorsize, d->lba, d->drive, d->head);
854  } else {
855  d->sectorsize = (idata >> 6) & 3;
856  d->lba = (idata >> 5) & 1;
857  d->drive = (idata >> 4) & 1;
858  d->head = idata & 0xf;
859  debug("[ wdc: write to SDH: 0x%02x (sectorsize %i,"
860  " lba=%i, drive %i, head %i) ]\n", (int)idata,
861  d->sectorsize, d->lba, d->drive, d->head);
862  }
863  break;
864 
865  case wd_command: /* 7: command or status */
866  if (writeflag==MEM_READ) {
867  odata = status_byte(d, cpu);
868  if (!quiet_mode)
869  debug("[ wdc: read from STATUS: 0x%02x ]\n",
870  (int)odata);
872  d->int_assert = 0;
873  } else {
874  debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);
875  wdc_command(cpu, d, idata);
876  }
877  break;
878 
879  default:
880  if (writeflag==MEM_READ)
881  debug("[ wdc: read from 0x%02x ]\n",
882  (int)relative_addr);
883  else
884  debug("[ wdc: write to 0x%02x: 0x%02x ]\n",
885  (int)relative_addr, (int)idata);
886  }
887 
888  /* Assert interrupt, if necessary: */
889  dev_wdc_tick(cpu, extra);
890 
891 ret:
892  if (writeflag == MEM_READ) {
893  if (relative_addr == wd_data)
894  memory_writemax64(cpu, data, len, odata);
895  else {
896  if (len != 1)
897  fatal("[ wdc: WARNING! non-8-bit access on READ! ]\n");
898  data[0] = odata;
899  }
900  }
901 
902  return 1;
903 }
904 
905 
907 {
908  struct wdc_data *d;
909  uint64_t alt_status_addr;
910  int i, tick_shift = WDC_TICK_SHIFT;
911 
912  CHECK_ALLOCATION(d = (struct wdc_data *) malloc(sizeof(struct wdc_data)));
913  memset(d, 0, sizeof(struct wdc_data));
914 
917  d->data_debug = 1;
918  d->io_enabled = 1;
919  d->error = 1;
920 
921  d->inbuf = (unsigned char *) zeroed_alloc(WDC_INBUF_SIZE);
922 
923  /* base_drive = 0 for the primary controller, 2 for the secondary. */
924  d->base_drive = 0;
925  if ((devinit->addr & 0xfff) == 0x170)
926  d->base_drive = 2;
927 
928  alt_status_addr = devinit->addr + 0x206;
929 
930  /* Special hacks for individual machines: */
931  switch (devinit->machine->machine_type) {
932  case MACHINE_MACPPC:
933  alt_status_addr = devinit->addr + 0x160;
934  break;
935  case MACHINE_HPCMIPS:
936  /* TODO: Fix */
937  if (devinit->addr == 0x14000180)
938  alt_status_addr = 0x14000386;
939  break;
940  case MACHINE_IQ80321:
941  alt_status_addr = devinit->addr + 0x402;
942  break;
943  }
944 
945  /* Get disk geometries: */
946  for (i=0; i<2; i++)
948  DISKIMAGE_IDE))
950  DISKIMAGE_IDE, &d->cyls[i], &d->heads[i],
951  &d->sectors_per_track[i]);
952 
953  memory_device_register(devinit->machine->memory, "wdc_altstatus",
954  alt_status_addr, 2, dev_wdc_altstatus_access, d, DM_DEFAULT, NULL);
956  devinit->addr, DEV_WDC_LENGTH * devinit->addr_mult, dev_wdc_access,
957  d, DM_DEFAULT, NULL);
958 
960  d, tick_shift);
961 
962  devinit->return_ptr = d;
963 
964  return 1;
965 }
966 
#define WDC_INBUF_SIZE
Definition: dev_wdc.cc:48
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
Definition: memory.cc:55
void * zeroed_alloc(size_t s)
Definition: memory.cc:118
void fatal(const char *fmt,...)
Definition: main.cc:152
#define WDCS_ERR
Definition: wdcreg.h:85
int drive
Definition: dev_wdc.cc:84
#define DM_DEFAULT
Definition: memory.h:130
int write_count
Definition: dev_wdc.cc:73
#define DEV_WDC_LENGTH
Definition: dev_wdc.cc:45
int diskimage_getname(struct machine *machine, int id, int type, char *buf, size_t bufsize)
Definition: diskimage.cc:1013
int diskimage_exist(struct machine *machine, int id, int type)
Definition: diskimage.cc:106
#define WDCC_SEC_SET_PASSWORD
Definition: wdcreg.h:141
size_t cmd_len
Definition: diskimage.h:100
int wdc_set_io_enabled(struct wdc_data *d, int io_enabled)
Definition: dev_wdc.cc:119
char * name
Definition: device.h:43
int machine_type
Definition: machine.h:111
#define WDCC_WRITEMULTI
Definition: wdcreg.h:120
#define COMMAND_RESET
Definition: dev_wdc.cc:98
#define SCSICMD_MODE_SENSE10
Definition: diskimage.h:167
unsigned char identify_struct[512]
Definition: dev_wdc.cc:94
#define wd_cyl_hi
Definition: wdcreg.h:57
#define WDCI_CMD
Definition: wdcreg.h:213
int head
Definition: dev_wdc.cc:85
#define WDCE_ABRT
Definition: wdcreg.h:98
#define SCSICMD_READ_10
Definition: diskimage.h:160
#define ATAPI_PKT_CMD
Definition: wdcreg.h:202
struct machine * machine
Definition: cpu.h:328
int cyl_lo
Definition: dev_wdc.cc:80
#define MEM_READ
Definition: memory.h:116
#define WDCC_SEC_ERASE_PREPARE
Definition: wdcreg.h:143
int cyls[2]
Definition: dev_wdc.cc:62
#define WDCC_READMULTI
Definition: wdcreg.h:119
struct memory * memory
Definition: machine.h:126
size_t data_in_len
Definition: diskimage.h:110
DEVICE_TICK(wdc)
Definition: dev_wdc.cc:101
DEVICE_ACCESS(wdc_altstatus)
Definition: dev_wdc.cc:364
int io_enabled
Definition: dev_wdc.cc:59
#define SCSIBLOCKCMD_READ_CAPACITY
Definition: diskimage.h:172
#define WDC_TICK_SHIFT
Definition: dev_wdc.cc:46
#define WDCC_SEC_UNLOCK
Definition: wdcreg.h:142
#define WDSF_SET_MODE
Definition: wdcreg.h:163
int data_debug
Definition: dev_wdc.cc:58
int sectorsize
Definition: dev_wdc.cc:82
void * return_ptr
Definition: device.h:56
#define wd_command
Definition: wdcreg.h:59
int sector
Definition: dev_wdc.cc:79
#define WDCS_DSC
Definition: wdcreg.h:81
void wdc_command(struct cpu *cpu, struct wdc_data *d, int idata)
Definition: dev_wdc.cc:394
#define WDCC_RECAL
Definition: wdcreg.h:106
#define WDCC_DIAGNOSE
Definition: wdcreg.h:114
#define wd_data
Definition: wdcreg.h:49
#define EMUL_LITTLE_ENDIAN
Definition: misc.h:164
int addr_mult
Definition: device.h:53
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
int cur_command
Definition: dev_wdc.cc:86
int heads[2]
Definition: dev_wdc.cc:63
unsigned char * data_in
Definition: diskimage.h:109
#define MAX_SECTORS_PER_CHUNK
int base_drive
Definition: dev_wdc.cc:57
void wdc__write(struct cpu *cpu, struct wdc_data *d)
Definition: dev_wdc.cc:316
#define WDCI_IN
Definition: wdcreg.h:214
#define ATAPI_IDENTIFY_DEVICE
Definition: wdcreg.h:203
struct scsi_transfer * scsi_transfer_alloc(void)
#define WDCC_SEC_ERASE_UNIT
Definition: wdcreg.h:144
#define DISKIMAGE_IDE
Definition: diskimage.h:41
#define WDCC_IDLE_IMMED
Definition: wdcreg.h:135
void scsi_transfer_free(struct scsi_transfer *p)
#define WDCC_IDP
Definition: wdcreg.h:115
u_short data
Definition: siireg.h:79
struct scsi_transfer * atapi_st
Definition: dev_wdc.cc:90
#define WDCS_DRDY
Definition: wdcreg.h:79
int error
Definition: dev_wdc.cc:76
int precomp
Definition: dev_wdc.cc:77
#define INTERRUPT_ASSERT(istruct)
Definition: interrupt.h:74
#define WDCC_IDENTIFY
Definition: wdcreg.h:131
DEVINIT(wdc)
Definition: dev_wdc.cc:906
#define MEM_WRITE
Definition: memory.h:117
int64_t diskimage_getsize(struct machine *machine, int id, int type)
Definition: diskimage.cc:203
int sectors_per_track[2]
Definition: dev_wdc.cc:64
unsigned char * inbuf
Definition: dev_wdc.cc:66
int cyl_hi
Definition: dev_wdc.cc:81
struct interrupt irq
Definition: dev_wdc.cc:55
Definition: device.h:40
int addr_mult
Definition: dev_wdc.cc:56
int atapi_phase
Definition: dev_wdc.cc:89
#define debug
Definition: dev_adb.cc:57
void diskimage_getchs(struct machine *machine, int id, int type, int *c, int *h, int *s)
Definition: diskimage.cc:266
int write_in_progress
Definition: dev_wdc.cc:72
int quiet_mode
Definition: main.cc:78
#define INTERRUPT_CONNECT(name, istruct)
Definition: interrupt.h:77
Definition: cpu.h:326
int inbuf_head
Definition: dev_wdc.cc:67
struct machine * machine
Definition: device.h:41
int lba
Definition: dev_wdc.cc:83
int diskimage_is_a_cdrom(struct machine *machine, int id, int type)
Definition: diskimage.cc:1042
#define wd_sdh
Definition: wdcreg.h:58
#define WDCC_SEC_FREEZE_LOCK
Definition: wdcreg.h:145
size_t atapi_received
Definition: dev_wdc.cc:92
#define WDCTL_4BIT
Definition: wdcreg.h:68
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data)
Definition: memory.cc:89
#define PHASE_DATAOUT
Definition: wdcreg.h:219
#define wd_cyl_lo
Definition: wdcreg.h:56
#define PHASE_CMDOUT
Definition: wdcreg.h:217
#define wd_seccnt
Definition: wdcreg.h:53
#define WDCC_SEC_DISABLE_PASSWORD
Definition: wdcreg.h:146
int inbuf_tail
Definition: dev_wdc.cc:68
void memory_device_register(struct memory *mem, const char *, uint64_t baseaddr, uint64_t len, int(*f)(struct cpu *, struct memory *, uint64_t, unsigned char *, size_t, int, void *), void *extra, int flags, unsigned char *dyntrans_data)
Definition: memory.cc:339
#define PHASE_COMPLETED
Definition: wdcreg.h:220
#define wd_sector
Definition: wdcreg.h:55
#define PHASE_DATAIN
Definition: wdcreg.h:218
#define ATAPI_SOFT_RESET
Definition: wdcreg.h:204
uint8_t byte_order
Definition: cpu.h:347
int atapi_cmd_in_progress
Definition: dev_wdc.cc:88
#define SET_FEATURES
Definition: wdcreg.h:132
uint64_t addr
Definition: device.h:46
int64_t write_offset
Definition: dev_wdc.cc:74
#define WDCC_READ
Definition: wdcreg.h:108
void machine_add_tickfunction(struct machine *machine, void(*func)(struct cpu *, void *), void *extra, int clockshift)
Definition: machine.cc:280
void wdc__read(struct cpu *cpu, struct wdc_data *d)
Definition: dev_wdc.cc:266
#define WDCC_SETMULTI
Definition: wdcreg.h:121
int atapi_len
Definition: dev_wdc.cc:91
#define MACHINE_IQ80321
Definition: machine.h:243
unsigned char * cmd
Definition: diskimage.h:99
int seccnt
Definition: dev_wdc.cc:78
int int_assert
Definition: dev_wdc.cc:70
#define WDCC_WRITE
Definition: wdcreg.h:109
int diskimage_scsicommand(struct cpu *cpu, int id, int type, struct scsi_transfer *xferp)
int diskimage_access(struct machine *machine, int id, int type, int writeflag, off_t offset, unsigned char *buf, size_t len)
Definition: diskimage.cc:605
#define MACHINE_MACPPC
Definition: machine.h:229
#define wd_error
Definition: wdcreg.h:50
char * interrupt_path
Definition: device.h:50
#define MACHINE_HPCMIPS
Definition: machine.h:215
#define INTERRUPT_DEASSERT(istruct)
Definition: interrupt.h:75
#define WDCS_DRQ
Definition: wdcreg.h:82

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13