Пример #1
0
/**
 * Outputs one character to the TTY. If the \texttt{polltty_iobase} is
 * invalid nothing is done.
 *
 * @param c The character to be output to the TTY.
 *
 */
void polltty_putchar(char c)
{
    /* Check that the iobase is valid */
    if (polltty_iobase != 0) {
    
        /* Wait until the TTY is no longer busy */
        while(TTY_STATUS_WBUSY(polltty_iobase->status) != 0);
        polltty_iobase->data = c;
        while(TTY_STATUS_WBUSY(polltty_iobase->status) != 0);

        /* We can't clear the interrupt here because it will break the
         * interrupt driven tty driver. The IRQ will be handled later
         * by the interrupt driven tty driver.
         */
    }
}
Пример #2
0
/**
 * TTY's interrupt handler. Functinality depends on status of TTY's
 * status port. On WIRQ status writes internal buffer from
 * tty_real_device_t data structure to data port. On RIRQ
 * status reads data from data port to the internal buffer.
 * Implements read from the gbd interface.
 *
 * @param device Pointer to the TTY device.
 */
void tty_interrupt_handle(device_t *device) {
  volatile tty_io_area_t *iobase = (tty_io_area_t *)device->io_address;
  volatile tty_real_device_t *tty_rd
    = (tty_real_device_t *)device->real_device;

  if(TTY_STATUS_WIRQ(iobase->status)) {
    spinlock_acquire(tty_rd->slock);

    iobase->command = TTY_COMMAND_WIRQD;
    iobase->command = TTY_COMMAND_WIRQ;
    while(!TTY_STATUS_WBUSY(iobase->status) && tty_rd->write_count > 0) {
      iobase->command = TTY_COMMAND_WIRQ;
      iobase->data = tty_rd->write_buf[tty_rd->write_head];
      tty_rd->write_head = (tty_rd->write_head + 1) % TTY_BUF_SIZE;
      tty_rd->write_count--;
    }
    iobase->command = TTY_COMMAND_WIRQE;

    if (tty_rd->write_count == 0)
      sleepq_wake_all((void *)tty_rd->write_buf);

    spinlock_release(tty_rd->slock);
  }

  if(TTY_STATUS_RIRQ(iobase->status)) {
    spinlock_acquire(tty_rd->slock);

    iobase->command = TTY_COMMAND_RIRQ;

    if (TTY_STATUS_ERROR(iobase->status))
      KERNEL_PANIC("Could not issue RIRQ to TTY.");

    while (TTY_STATUS_RAVAIL(iobase->status)) {
      char data = iobase->data;
      int index;

      if (tty_rd->read_count > TTY_BUF_SIZE)
        continue;

      index = (tty_rd->read_head + tty_rd->read_count) % TTY_BUF_SIZE;

      tty_rd->read_buf[index] = data;
      tty_rd->read_count++;
    }

    spinlock_release(tty_rd->slock);
    sleepq_wake_all((void *)tty_rd->read_buf);

  }
}
Пример #3
0
/**
 * Writes len bytes from buffer buf to tty-device
 * pointed by gcd. Implements write from the gbd interface.
 *
 * @param gcd Pointer to the tty-device.
 * @param buf Buffer to be written from.
 * @param len number of bytes to be written.
 *
 * @return Number of succesfully writeten characters.
 */
static int tty_write(gcd_t *gcd, const void *buf, int len) {
  interrupt_status_t intr_status;
  volatile tty_io_area_t *iobase = (tty_io_area_t *)gcd->device->io_address;
  volatile tty_real_device_t *tty_rd
    = (tty_real_device_t *)gcd->device->real_device;
  int i;

  intr_status = _interrupt_disable();
  spinlock_acquire(tty_rd->slock);

  i = 0;
  while (i < len) {
    while (tty_rd->write_count > 0) {
      /* buffer contains data, so wait until empty. */
      sleepq_add((void *)tty_rd->write_buf);
      spinlock_release(tty_rd->slock);
      thread_switch();
      spinlock_acquire(tty_rd->slock);
    }

    /* Fill internal buffer. */
    while (tty_rd->write_count < TTY_BUF_SIZE  && i < len) {
      int index;
      index = (tty_rd->write_head + tty_rd->write_count) % TTY_BUF_SIZE;
      tty_rd->write_buf[index] = ((char *)buf)[i++];
      tty_rd->write_count++;
    }

    /* If device is not currently busy, write one charater to
       cause interrupt. Head and count are adjusted not to write
       first character twice. Rest of the buffer is written by
       interrupt handler.

       If the device is busy, interrupt will appear by itself and
       the whole buffer will be written by interrupt handler.
    */
    if (!TTY_STATUS_WBUSY(iobase->status)) {
      iobase->data = tty_rd->write_buf[tty_rd->write_head];
      tty_rd->write_head = (tty_rd->write_head + 1) % TTY_BUF_SIZE;
      tty_rd->write_count--;
    }

  }

  spinlock_release(tty_rd->slock);
  _interrupt_set_state(intr_status);

  return i;
}