HelenOS sources

root/kernel/generic/src/console/chardev.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. indev_initialize
  2. indev_push_character
  3. indev_pop_character
  4. indev_signal
  5. outdev_initialize
  6. check_poll

/*
 * Copyright (c) 2005 Jakub Jermar
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/** @addtogroup kernel_generic_console
 * @{
 */
/** @file
 */

#include <assert.h>
#include <adt/list.h>
#include <console/chardev.h>
#include <synch/waitq.h>
#include <synch/spinlock.h>
#include <stdio.h>
#include <halt.h>
#include <cpu.h>

/** Initialize input character device.
 *
 * @param indev Input character device.
 * @param op    Implementation of input character device operations.
 *
 */
void indev_initialize(const char *name, indev_t *indev,
    indev_operations_t *op)
{
        indev->name = name;
        semaphore_initialize(&indev->wq, 0);
        irq_spinlock_initialize(&indev->lock, "chardev.indev.lock");
        indev->counter = 0;
        indev->index = 0;
        indev->op = op;
}

/** Push character read from input character device.
 *
 * @param indev Input character device.
 * @param ch    Character being pushed.
 *
 */
void indev_push_character(indev_t *indev, char32_t ch)
{
        assert(indev);

        irq_spinlock_lock(&indev->lock, true);
        if (indev->counter == INDEV_BUFLEN - 1) {
                /* Buffer full */
                irq_spinlock_unlock(&indev->lock, true);
                return;
        }

        indev->counter++;
        indev->buffer[indev->index++] = ch;

        /* Index modulo size of buffer */
        indev->index = indev->index % INDEV_BUFLEN;
        semaphore_up(&indev->wq);
        irq_spinlock_unlock(&indev->lock, true);
}

/** Pop character from input character device.
 *
 * @param indev Input character device.
 *
 * @return Character read.
 *
 */
char32_t indev_pop_character(indev_t *indev)
{
        if (atomic_load(&haltstate)) {
                /*
                 * If we are here, we are hopefully on the processor that
                 * issued the 'halt' command, so proceed to read the character
                 * directly from input
                 */
                if (check_poll(indev))
                        return indev->op->poll(indev);

                /* No other way of interacting with user */
                interrupts_disable();

                if (CPU)
                        printf("cpu%u: ", CPU->id);
                else
                        printf("cpu: ");

                printf("halted (no polling input)\n");
                cpu_halt();
        }

        semaphore_down(&indev->wq);
        irq_spinlock_lock(&indev->lock, true);
        char32_t ch = indev->buffer[(indev->index - indev->counter) %
            INDEV_BUFLEN];
        indev->counter--;
        irq_spinlock_unlock(&indev->lock, true);

        return ch;
}

/** Signal out-of-band condition
 *
 * @param indev  Input character device.
 * @param signal Out-of-band condition to signal.
 *
 */
void indev_signal(indev_t *indev, indev_signal_t signal)
{
        if ((indev != NULL) && (indev->op != NULL) &&
            (indev->op->signal != NULL))
                indev->op->signal(indev, signal);
}

/** Initialize output character device.
 *
 * @param outdev Output character device.
 * @param op     Implementation of output character device operations.
 *
 */
void outdev_initialize(const char *name, outdev_t *outdev,
    outdev_operations_t *op)
{
        outdev->name = name;
        spinlock_initialize(&outdev->lock, "chardev.outdev.lock");
        link_initialize(&outdev->link);
        list_initialize(&outdev->list);
        outdev->op = op;
}

bool check_poll(indev_t *indev)
{
        if (indev == NULL)
                return false;

        if (indev->op == NULL)
                return false;

        return (indev->op->poll != NULL);
}

/** @}
 */

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub