Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

arch_gen_atapi.c

/* $Id: arch_gen_atapi.c,v 1.48 2009-02-24 15:12:25 vrsieh Exp $ 
 *
 * Copyright (C) 2007-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

/* This will turn on in(b|w)/out(b|w) debug output. */
#define DEBUG_CONTROL_FLOW    0


#ifdef STATE

struct {
      /*
       * Config
       */
      unsigned int unit;

      /*
       * State
       */
      unsigned int irq;

      unsigned char pio_mode;
      unsigned char mdma_mode;
      unsigned char udma_mode;

#define SEND_MASK       (0 << 0) /* means: send me data */
#define COMMAND_MASK    (1 << 0) /* means: send me a command packet */
#define IN_MASK         (1 << 1) /* means: read result bytes */
      unsigned char irq_status; /* interrupt status reg (ro) */
      unsigned char status;   /* status reg (ro) */
      unsigned char features; /* features reg (wo) */
      unsigned char select;   /* select reg (r/w) */
      unsigned char control;  /* device control reg (ro) */
      uint16_t bytecount_r;
      uint16_t bytecount_w;
      unsigned char lba_low;  /* lba low reg (r/w) */
      unsigned char sector_count; /* sector count reg (wo) */
      unsigned char command;  /* command reg (wo) */

      unsigned int cmd_flag;
      unsigned int data_flag;
      unsigned int msg_flag;
      unsigned int in_flag;
      unsigned int req_count;

#if 0
      uint8_t buf[0x10000];
      unsigned int count;
      unsigned int head;
      unsigned int tail;
#endif
} NAME;

#endif /* STATE */

#ifdef BEHAVIOR

#define DELAY_OPERATION (TIME_HZ / 10000000)

#define UNIT(cpssp)     ((cpssp->NAME.select >> 4) & 1)

static void
NAME_(irq_update)(struct cpssp *cpssp)
{
      unsigned int val;

      if (cpssp->NAME.irq
       && ((cpssp->NAME.control >> 1) & 1) == 0
       && ((cpssp->NAME.select >> 4) & 1) == cpssp->NAME.unit) {
            val = 1;
      } else {
            val = 0;
      }
      sig_ide_bus_irq(cpssp->cable, cpssp, val);
}

static void
NAME_(gen_irq)(struct cpssp *cpssp)
{
      cpssp->NAME.irq = 1;
      NAME_(irq_update)(cpssp);
}

static void
NAME_(ugen_irq)(struct cpssp *cpssp)
{
      cpssp->NAME.irq = 0;
      NAME_(irq_update)(cpssp);
}

static void
NAME_(phase_free)(struct cpssp *cpssp)
{
      if (DEBUG_CONTROL_FLOW) {
            fprintf(stderr, "%s: called()\n", __FUNCTION__);
      }

      cpssp->NAME.irq_status = IN_MASK | COMMAND_MASK;
      cpssp->NAME.status = READY_STAT | SEEK_STAT | (cpssp->error ? ERR_STAT : 0);

      NAME_(gen_irq)(cpssp);
}

static void
NAME_(phase_cmd)(struct cpssp *cpssp)
{
      if (DEBUG_CONTROL_FLOW) {
            fprintf(stderr, "%s: called()\n", __FUNCTION__);
      }

      cpssp->NAME.cmd_flag = 1;
      cpssp->NAME.data_flag = 0;
      cpssp->NAME.msg_flag = 0;
      cpssp->NAME.in_flag = 0;
}

static void
NAME_(phase_status)(struct cpssp *cpssp)
{
      if (DEBUG_CONTROL_FLOW) {
            fprintf(stderr, "%s: called()\n", __FUNCTION__);
      }

      cpssp->NAME.cmd_flag = 1;
      cpssp->NAME.data_flag = 0;
      cpssp->NAME.msg_flag = 0;
      cpssp->NAME.in_flag = 1;
}

static void
NAME_(phase_data_in)(struct cpssp *cpssp)
{
      if (DEBUG_CONTROL_FLOW) {
            fprintf(stderr, "%s: called()\n", __FUNCTION__);
      }

      cpssp->NAME.cmd_flag = 0;
      cpssp->NAME.data_flag = 1;
      cpssp->NAME.msg_flag = 0;
      cpssp->NAME.in_flag = 1;
}

static void
NAME_(phase_data_out)(struct cpssp *cpssp)
{
      if (DEBUG_CONTROL_FLOW) {
            fprintf(stderr, "%s: called()\n", __FUNCTION__);
      }

      cpssp->NAME.cmd_flag = 0;
      cpssp->NAME.data_flag = 1;
      cpssp->NAME.msg_flag = 0;
      cpssp->NAME.in_flag = 0;
}

static void
NAME_(phase_msg_in)(struct cpssp *cpssp)
{
      if (DEBUG_CONTROL_FLOW) {
            fprintf(stderr, "%s: called()\n", __FUNCTION__);
      }

      cpssp->NAME.cmd_flag = 0;
      cpssp->NAME.data_flag = 0;
      cpssp->NAME.msg_flag = 1;
      cpssp->NAME.in_flag = 1;
}

static void
NAME_(phase_msg_out)(struct cpssp *cpssp)
{
      if (DEBUG_CONTROL_FLOW) {
            fprintf(stderr, "%s: called()\n", __FUNCTION__);
      }

      cpssp->NAME.cmd_flag = 0;
      cpssp->NAME.data_flag = 0;
      cpssp->NAME.msg_flag = 1;
      cpssp->NAME.in_flag = 0;
}

static void
NAME_(should_send)(struct cpssp *cpssp, unsigned long count)
{
      uint8_t byte;

      if (DEBUG_CONTROL_FLOW) {
            fprintf(stderr, "%s: called(count=%lu)\n", __FUNCTION__, count);
      }

      assert(! cpssp->NAME.in_flag);

      cpssp->NAME.req_count = count;

      if (cpssp->NAME.cmd_flag) {
            /* Command Phase */
            cpssp->NAME.irq_status = COMMAND_MASK;
            cpssp->NAME.status = DRQ_STAT;

      } else if (cpssp->NAME.data_flag) {
            /* Data Out Phase */
            if (cpssp->NAME.req_count < cpssp->NAME.bytecount_w) {
                  cpssp->NAME.bytecount_r = cpssp->NAME.req_count;
            } else {
                  cpssp->NAME.bytecount_r = cpssp->NAME.bytecount_w;
            }

            cpssp->NAME.irq_status = 0;
            cpssp->NAME.status = DRQ_STAT;

            if (cpssp->NAME.features & 1) {
                  sig_ide_bus_dmarq_set(cpssp->cable, 1);
            } else {
                  NAME_(gen_irq)(cpssp);
            }

      } else if (cpssp->NAME.msg_flag) {
            /* Message Out Phase */
            byte = 0x80; /* Identify message: use LUN 0. */
            cpssp->NAME.req_count = NAME_(send)(cpssp, &byte, sizeof(byte));
            assert(cpssp->NAME.req_count == 0);

      } else {
            assert(0); /* Mustn't happen. */
      }

      if (cpssp->NAME.req_count == 0) {
            cpssp->NAME.status = BUSY_STAT;
      }
}

static void
NAME_(should_recv)(struct cpssp *cpssp, unsigned long count)
{
      uint8_t byte;

      if (DEBUG_CONTROL_FLOW) {
            fprintf(stderr, "%s: called(count=%lu)\n", __FUNCTION__, count);
      }

      assert(cpssp->NAME.in_flag);

      cpssp->NAME.req_count = count;

      if (cpssp->NAME.cmd_flag) {
            /* Status Phase */
            cpssp->NAME.req_count = NAME_(recv)(cpssp, &byte, sizeof(byte));
            cpssp->error = byte << 4;

            assert(cpssp->NAME.req_count == 0);

      } else if (cpssp->NAME.data_flag) {
            /* Data In Phase */
            if (cpssp->NAME.req_count < cpssp->NAME.bytecount_w) {
                  cpssp->NAME.bytecount_r = cpssp->NAME.req_count;
            } else {
                  cpssp->NAME.bytecount_r = cpssp->NAME.bytecount_w;
            }

            cpssp->NAME.irq_status = IN_MASK;
            cpssp->NAME.status = DRQ_STAT;

            if (cpssp->NAME.features & 1) {
                  sig_ide_bus_dmarq_set(cpssp->cable, 1);
            } else {
                  NAME_(gen_irq)(cpssp);
            }
      
      } else if (cpssp->NAME.msg_flag) {
            /* Message In Phase */
            cpssp->NAME.req_count = NAME_(recv)(cpssp, &byte, sizeof(byte));

            assert(byte == 0x00); /* Completion Byte */
            assert(cpssp->NAME.req_count == 0);

      } else {
            assert(0); /* Mustn't happen. */
      }

      if (cpssp->NAME.req_count == 0) {
            cpssp->NAME.status = BUSY_STAT;
      }
}

static void
NAME_(reset)(struct cpssp *cpssp);

/*forward*/ static void
NAME_(command)(struct cpssp *cpssp);

static void
NAME_(notice_separate_process)(void *_c)
{
      struct cpssp *c = (struct cpssp *) _c;

      NAME_(command)(c);
}

static void
NAME_(call_logic)(struct cpssp *s)
{
#if 0 < DELAY_OPERATION
      time_call_after(DELAY_OPERATION,
                  NAME_(notice_separate_process), s);
#else
      NAME_(notice_separate_process)(s);
#endif
}

static void
NAME_(read_param_callback)(struct cpssp *s)
{
      s->NAME.status = READY_STAT;
      NAME_(gen_irq)(s);
}

static void
NAME_(write_param_callback)(struct cpssp *s)
{
      NAME_(call_logic)(s);
}

static void
NAME_(set_signature)(struct cpssp *s)
{
      s->error = 0x01; /* FreeBSD-7.0 (and others?) needs it... */
      s->NAME.irq_status = COMMAND_MASK;
      s->NAME.lba_low = 0x01;
      s->NAME.bytecount_r = 0xEB14;
      s->NAME.select &= 0x10;
}

static void
NAME_(reset)(struct cpssp *s)
{
      s->head = 0;
      s->tail = 0;
      s->count = 0;

      s->m2t_count = 0;
      s->m2t_pos = 0;

      s->NAME.features = 0;

      NAME_(set_signature)(s);

      s->NAME.status = 0;
      s->NAME.control = 0;

      s->NAME.pio_mode = 0;
      s->NAME.mdma_mode = 0;
      s->NAME.udma_mode = 0;

      scsi_gen_cdrom_reset(s);
}

static void
NAME_(abort)(struct cpssp *s)
{
      s->error = 1 << 2; /* Abort */
      s->NAME.status = ERR_STAT | READY_STAT;
}

static void
NAME_(dummy)(struct cpssp *s)
{
      s->NAME.status = READY_STAT;
}

static void
NAME_(nop)(struct cpssp *s)
{
      s->tail = 0;
      s->head = 0;
      s->count = 0;

      s->error = 1 << 2; /* Abort */
      s->NAME.status = READY_STAT | ERR_STAT;
      NAME_(gen_irq)(s);
}

static void
NAME_(execute_device_diagnostic)(struct cpssp *s)
{
      s->tail = 0;
      s->head = 0;
      s->count = 0;

      NAME_(set_signature)(s);

      s->NAME.status = READY_STAT;
      NAME_(gen_irq)(s);
}

/* Adapted from QEMU */

static void
padstr(char *str, const char *src, int len)
{
    int i, v;
    for(i = 0; i < len; i++) {
      if (*src) {
          v = *src++;
      } else {
          v = ' ';
      }
      *(char *)((long)str ^ 1) = v;
      str++;
    }
}


static void
NAME_(pidentify)(struct cpssp *s)
{
      unsigned short *p = (unsigned short *) s->buf;

      memset(p, 0, 512);
      p[0] = 0x85c0; /* ATAPI removable media CDROM, 50 us DRQ, 12b packet */
      padstr((char *) (p + 10), "FAUMDVD001", 20);    /* Serial No. */
      padstr((char *) (p + 23), "1.0", 8);            /* Firmware rev. */
#if CD_WRITER_SUPPORT
      padstr((char *) (p + 27), "FAUmachine ATAPI CD/DVD-WRITER", 40);
#else
      padstr((char *) (p + 27), "FAUmachine ATAPI CD/DVD-ROM", 40);
#endif
      p[49] |= (1 << 11); /* IORDY supported */
      p[49] |= (1 << 10); /* IORDY may be disabled */
      p[49] |= (1 <<  9); /* LBA supported */
#if 1
      p[49] |= (1 <<  8); /* DMA supported */
#endif

      p[51] = (s->NAME.pio_mode << 8) | 0x00;
      p[53] = 0x0006; /* word 88 and word 64-70 are valid */
#if 1
      p[63] = (s->NAME.mdma_mode << 8) | 0x07; /* Highbyte: Currently selected DMA mode. lowbyte: supported DMA modes */
#endif
      p[64] = 0x0003; /* Supported PIO Modes */
      /* DMA and PIO timings */
      p[65] = 0x0078;
      p[66] = 0x0078;
      p[67] = 0x0078;
      p[68] = 0x0078;
      p[80] = 0x001E; /* We support ATA/ATAPI 1-4 */
      p[82] = (1 << 9) /* Device Reset supported */ | (1 << 4); /* PACKET Command feature set */
      p[83] = (1 << 14); /* This should be set to One */
      p[84] = (1 << 14); /* This should be set to One */
      /* FIXME: Make this configurable: Which feature is enabled?! */
      p[85] = (1 << 9) /* Device Reset supported */ | (1 << 4); /* PACKET Command feature set */
      p[87] = (1 << 14); /* This should be set to One */
#if 1
      p[88] = (s->NAME.udma_mode << 8) | 0x07;
#endif

      s->tail = 0;
      s->head = 512;
      s->count = 512;
      s->NAME.status = DRQ_STAT;
      NAME_(gen_irq)(s);
}

static void
NAME_(setfeatures)(struct cpssp *s)
{                    /* 0xEF */
      switch(s->NAME.features) {
      case 0x02: /* Enable write cache */
      case 0x82: /* Disable write cache */
            /* FIXME --tg 21:04 05-01-25 */
            break;

      case 0x03: /* Set transfer mode */
            switch (s->NAME.sector_count & 0xF8) {
            case 0x08: /* PIO Mode */
                  s->NAME.pio_mode = s->NAME.sector_count & 0x07;
                  break;

      /* Multiword- *or* Ultra- DMA is selected */

            case 0x20: /* Multiword DMA Mode */
                  s->NAME.mdma_mode = s->NAME.sector_count & 0x07;
                  s->NAME.udma_mode = 0;
                  break;
            case 0x40: /* UDMA Mode */
                  s->NAME.udma_mode = s->NAME.sector_count & 0x07;
                  s->NAME.mdma_mode = 0;
                  break;
            }
            break;

      case 0x55: /* Disable read look-ahead. */
            /* Nothing to do (yet)... */
            break;

      case 0xaa: /* Enable read look-ahead. */
            /* Nothing to do (yet)... */
            break;

      default:
            fprintf(stderr, "%s: Warning: tried to set feature: 0x%02x: not implemented\n",
                        __FUNCTION__, s->NAME.features);
            NAME_(abort)(s);
            break;
      }

      s->NAME.status = READY_STAT;
      NAME_(gen_irq)(s);
}

static void
NAME_(device_reset)(struct cpssp *s)
{
      s->NAME.status = 0;
      NAME_(set_signature)(s);
      NAME_(gen_irq)(s);
}

static void
NAME_(command)(struct cpssp *s)
{
#if DEBUGPCOM
      fprintf(stderr, "%s: ", __FUNCTION__);
      if (s->NAME.command == WIN_NOP) {
            fprintf(stderr, "WIN_NOP\n");
      } else if (s->NAME.command == WIN_EXECUTE_DEVICE_DIAGNOSTIC) {
            fprintf(stderr, "WIN_EXECUTE_DEVICE_DIAGNOSTIC\n");
      } else if (s->NAME.command == WIN_PACKETCMD) {
            fprintf(stderr, "WIN_PACKETCMD\n");
      } else if (s->NAME.command == WIN_PIDENTIFY) {
            fprintf(stderr, "WIN_PIDENTIFY\n");
      } else if (s->NAME.command == WIN_STANDBYNOW1) {
            fprintf(stderr, "WIN_STANDBYNOW1\n");
      } else if (s->NAME.command == WIN_IDLEIMMEDIATE) {
            fprintf(stderr, "WIN_IDLEIMMEDIATE\n");
      } else if (s->NAME.command == WIN_SLEEPNOW1) {
            fprintf(stderr, "WIN_SLEEPNOW1\n");
      } else if (s->NAME.command == WIN_SRST) {
            fprintf(stderr, "WIN_SRST\n");
      } else if (s->NAME.command == WIN_IDENTIFY) {
            fprintf(stderr, "WIN_IDENTIFY\n");
      } else if (s->NAME.command == WIN_SETFEATURES) {
            fprintf(stderr, "WIN_SETFEATURES\n");
      } else if (s->NAME.command == WIN_CHECKPOWERMODE1) {
            fprintf(stderr, "WIN_CHECKPOWERMODE1\n");
      } else if (s->NAME.command == WIN_CHECKPOWERMODE1) {
            fprintf(stderr, "WIN_CHECKPOWERMODE1\n");
      } else {
            fprintf(stderr, "command 0x%02x\n", s->NAME.command);
      }
#endif

      switch (s->NAME.command) {
      case WIN_NOP: /* 0x00, mandatory */
            /* ATAPI-7, 164 */
            NAME_(nop)(s);
            break;

      case WIN_READ: /* 0x20, mandatory */
            NAME_(set_signature)(s);
            NAME_(abort)(s);
            NAME_(gen_irq)(s);
            break;

      case WIN_EXECUTE_DEVICE_DIAGNOSTIC: /* 0x90, mandatory */
            /* ATAPI-7, 106 */
            NAME_(execute_device_diagnostic)(s);
            break;

      case WIN_PACKETCMD: /* 0xa0, mandatory */
            /* ATAPI-7, 166 */
            NAME_(phase_select)(s);
            break;

      case WIN_PIDENTIFY: /* ATAPI Identify Device, 0xa1, mandatory */
            /* do we need ide_gen_cdrom_set_signature(s) here? */
            NAME_(pidentify)(s);
            break;

      case WIN_STANDBYNOW1: /* standby immediate, 0xe0, mandatory */
            fixme();
#if 0
            NAME_(dummy)(s);
#endif
            NAME_(gen_irq)(s);
            break;

      case WIN_IDLEIMMEDIATE: /* 0xe1, mandatory */
            NAME_(dummy)(s);
            NAME_(gen_irq)(s);
            break;

      case WIN_SLEEPNOW1: /* 0xe6, mandatory */
            fixme();
#if 0
            NAME_(dummy)(s);
#endif
            NAME_(gen_irq)(s);
            break;

      case WIN_SRST: /* ATAPI soft reset, 0x08, mandatory */
            NAME_(device_reset)(s);
            break;

      case WIN_IDENTIFY: /* 0xec, shall be aborted */
            NAME_(abort)(s);
            NAME_(gen_irq)(s);
            break;

      case WIN_SETFEATURES: /* 0xef, mandatory */
            NAME_(setfeatures)(s);
            break;

      case WIN_CHECKPOWERMODE1: /* 0xe5, mandatory */
            fixme();
            break;

      default:
            /* FIXME */
            fprintf(stderr, "%s: %s: unknown step 0x%02x\n", __FILE__,
                        __FUNCTION__, s->NAME.command);
            NAME_(abort)(s);
            NAME_(gen_irq)(s);
      }
}

static void
NAME_(power_set)(struct cpssp *css, unsigned int val)
{
      if (val) {
            /* Power On Event */
            NAME_(reset)(css);
      }
}

static void
NAME_(report_end)(void)
{
      static int reported = 0;

      if (! reported) {
            faum_log(FAUM_LOG_WARNING, __FUNCTION__, "",
                        "Reading beyond end of data block.\n");
            reported = 1;
      }
}

static int
NAME_(inw)(struct cpssp *cpssp, unsigned short port, uint16_t *valp)
{
      if (UNIT(cpssp) != cpssp->NAME.unit) {
            return 1;
      }

#if DEBUG_CONTROL_FLOW
      fprintf(stderr, "%s: port: %i\n", __FUNCTION__, port);
#endif

      switch (port) {
      case 0:           /* data port */
            if (cpssp->NAME.command == WIN_PACKETCMD) {
                  assert(cpssp->NAME.in_flag);

                  if (cpssp->NAME.req_count) {
                        cpssp->NAME.req_count = NAME_(recv)(cpssp,
                                    valp, sizeof(*valp));

                        if (cpssp->NAME.req_count == 0
                         && (cpssp->NAME.features & 1)) {
                              sig_ide_bus_dmarq_set(cpssp->cable, 0);
                        }

                        if (cpssp->NAME.req_count == 0) {
                              cpssp->NAME.status = BUSY_STAT;
                        }
                  } else {
                        /*
                         * Some programs / OSes seem to read beyond
                         * the end of the transferred block:
                         * return an "undefined" value (e.g. zero).
                         */
                        NAME_(report_end)();

                        *valp = 0x0000;
                  }

            } else {
                  assert(cpssp->tail < sizeof(cpssp->buf));

                  if (sizeof(*valp) <= cpssp->count) {
                        memcpy(valp, &cpssp->buf[cpssp->tail], sizeof(*valp));
                        cpssp->tail += sizeof(*valp);
                        cpssp->count -= sizeof(*valp);

                        if (cpssp->count == 0
                         && (cpssp->NAME.features & 1)) {
                              sig_ide_bus_dmarq_set(cpssp->cable, 0);
                        }

                        if (cpssp->count == 0) {
                              cpssp->NAME.status = BUSY_STAT;
                              NAME_(read_param_callback)(cpssp);
                        }
                  } else {
                        /*
                         * Some programs / OSes seem to read beyond
                         * the end of the transferred block:
                         * return an "undefined" value (e.g. zero).
                         */
                        NAME_(report_end)();

                        *valp = 0x0000;
                  }
            }
            break;
      case 1:           /* error register */
            *valp = cpssp->error;
            break;
      case 2:           /* interrupt status register */
            *valp = cpssp->NAME.irq_status;
            break;
      case 3:           /* LBA low register */
            *valp = cpssp->NAME.lba_low;
            break;
      case 4:           /* bytecount low register */
            *valp = (cpssp->NAME.bytecount_r >> 0) & 0xff;
            break;
      case 5:           /* bytecount high register */
            *valp = (cpssp->NAME.bytecount_r >> 8) & 0xff;
            break;
      case 6:           /* drive/head register */
            *valp = cpssp->NAME.select | 0xa0;
            break;

      case 7:           /* status register */
            *valp = cpssp->NAME.status;
            NAME_(ugen_irq)(cpssp);

            break;
      case 8:           /* altstatus register */
            *valp = cpssp->NAME.status;
#if 0
            cpssp->NAME.status &= ~ERR_STAT;
#endif
            break;
      default:
            assert(0);
            *valp = 0;  /* Just to make gcc happy... */
            /*NOTREACHED*/
      }

#if DEBUG_CONTROL_FLOW
      fprintf(stderr, "%s: -> 0x%x\n", __FUNCTION__, *valp);
#endif

      return 0;
}

static void
NAME_(outw)(struct cpssp *cpssp, unsigned short port, uint16_t value)
{
#if DEBUG_CONTROL_FLOW
      if (UNIT(cpssp) == cpssp->NAME.unit) {
            fprintf(stderr, "%s: port: %i value: %i\n", __FUNCTION__, port, value);
      }
#endif

      switch (port) {
      case 1:           /* write precompensation */
            cpssp->NAME.features = value;
            return;
      case 2:           /* sector count register */
            cpssp->NAME.sector_count = value;
            return;
      case 3:           /* LBA low register */
            cpssp->NAME.lba_low = value;
            return;
      case 4:           /* bytecount low register */
            cpssp->NAME.bytecount_r
                  = (cpssp->NAME.bytecount_r & 0xff00) | (value << 0);
            cpssp->NAME.bytecount_w
                  = (cpssp->NAME.bytecount_w & 0xff00) | (value << 0);
            return;
      case 5:           /* bytecount high register */
            cpssp->NAME.bytecount_r
                  = (value << 8) | (cpssp->NAME.bytecount_r & 0x00ff);
            cpssp->NAME.bytecount_w
                  = (value << 8) | (cpssp->NAME.bytecount_w & 0x00ff);
            return;
      case 6:      /* drive/head register */
            cpssp->NAME.select = value & ~0xa0;
            NAME_(irq_update)(cpssp);
            return;
      case 8:           /* device control register */
            cpssp->NAME.control = value;
            if (value & 0x04) {
                  /* if SFRS bit set -> reset */
                  NAME_(reset)(cpssp);
            }
            return;
      }

      if (UNIT(cpssp) != cpssp->NAME.unit) {
            return;
      }

      switch (port) {
      case 0:      /* data port */
            if (cpssp->NAME.command == WIN_PACKETCMD) {
                  assert(! cpssp->NAME.in_flag);
                  assert(cpssp->NAME.req_count);

                  cpssp->NAME.req_count = NAME_(send)(cpssp, &value,
                              sizeof(value));

                  if (cpssp->NAME.req_count == 0
                   && (cpssp->NAME.features & 1)) {
                        sig_ide_bus_dmarq_set(cpssp->cable, 0);
                  }
                  if (cpssp->NAME.req_count == 0) {
                        cpssp->NAME.status = BUSY_STAT;
                  }

            } else {
                  assert(cpssp->head < sizeof(cpssp->buf));
                  assert(sizeof(value) <= cpssp->count);

                  memcpy(&cpssp->buf[cpssp->head], &value, sizeof(value));

                  cpssp->head += sizeof(value);
                  cpssp->count -= sizeof(value);

                  if (cpssp->count == 0
                   && (cpssp->NAME.features & 1)) {
                        sig_ide_bus_dmarq_set(cpssp->cable, 0);
                  }

                  if (cpssp->count == 0) {
                        cpssp->NAME.status = BUSY_STAT;
                        NAME_(write_param_callback)(cpssp);
                  }
            }
            break;
      case 7:           /* command register */
            cpssp->NAME.command = value;
            cpssp->NAME.status = BUSY_STAT;
            NAME_(call_logic)(cpssp);
            break;
      default:
            assert(0); /* Cannot happen. */
      }
}

static void
NAME_(create)(struct cpssp *cpssp, unsigned int unit)
{
      cpssp->NAME.unit = unit;
}

static void
NAME_(destroy)(struct cpssp *cpssp)
{
}

#undef DELAY_OPERATION

#endif /* BEHAVIOR */

#undef DEBUG_CONTROL_FLOW

Generated by  Doxygen 1.6.0   Back to index