darwin-xnu/osfmk/ppc/console_feed.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22/*
  23 * @OSF_FREE_COPYRIGHT@
  24 * 
  25 */
  26
  27/* Intercept mach console output and supply it to a user application */
  28
  29#include <mach_kdb.h>
  30
  31#include <types.h>
  32#include <device/buf.h>
  33#include <device/conf.h>
  34#include <device/errno.h>
  35#include <device/misc_protos.h>
  36#include <device/ds_routines.h>
  37#include <device/cirbuf.h>
  38#include <ppc/console_feed_entries.h>
  39#include <ppc/serial_io.h>
  40
  41#if     MACH_KDB
  42#include <ppc/db_machdep.h>
  43#endif  /* MACH_KDB */
  44
  45static struct cirbuf cons_feed_cb;
  46static int cons_feed_count = 0;
  47io_req_t   cons_feed_queued = 0;
  48
  49/* console feed lock should be taken at splhigh */
  50decl_simple_lock_data(,cons_feed_lock)
  51
  52boolean_t cons_feed_read_done(io_req_t ior);
  53
  54io_return_t
  55console_feed_open(
  56        dev_t           dev,
  57        dev_mode_t      flag,
  58        io_req_t        ior)
  59{
  60        spl_t   s;
  61
  62        simple_lock_init(&cons_feed_lock, 0);
  63#if     MACH_KDB
  64        if (console_is_serial()) {
  65                return D_DEVICE_DOWN;
  66        }
  67#endif  /* MACH_KDB */
  68        cb_alloc(&cons_feed_cb, CONSOLE_FEED_BUFSIZE);
  69        s = splhigh();
  70        simple_lock(&cons_feed_lock);
  71        cons_feed_count++;
  72        simple_unlock(&cons_feed_lock);
  73        splx(s);
  74        return D_SUCCESS;
  75}
  76
  77void
  78console_feed_close(
  79        dev_t           dev)
  80{
  81        spl_t   s;
  82
  83        s = splhigh();
  84        simple_lock(&cons_feed_lock);
  85        cons_feed_count--;
  86        simple_unlock(&cons_feed_lock);
  87        splx(s);
  88
  89        console_feed_cancel_and_flush();
  90        cb_free(&cons_feed_cb);
  91
  92        return;
  93}
  94
  95/* A routine that can be called from a panic or other problem
  96 * situation. It switches off the console feed and dumps any
  97 * remaining buffered information to the original console
  98 * (usually the screen). It doesn't free up the buffer, since
  99 * it tries to be as minimal as possible 
 100 */
 101
 102void console_feed_cancel_and_flush(void)
 103{
 104        int     c;
 105        spl_t   s;
 106        
 107#if     NCONSFEED > 0
 108#if     MACH_KDB
 109        if (console_is_serial()) {
 110                return;
 111        }
 112#endif  /* MACH_KDB */
 113
 114        s = splhigh();
 115        simple_lock(&cons_feed_lock);
 116        if (cons_feed_count == 0) {
 117                simple_unlock(&cons_feed_lock);
 118                splx(s);
 119                return;
 120        }
 121        cons_feed_count = 0;
 122        simple_unlock(&cons_feed_lock);
 123        splx(s);
 124
 125        do {
 126                c = getc(&cons_feed_cb);
 127                if (c == -1)
 128                        break;
 129                cnputc(c);
 130        } while (1);
 131#endif /* NCONSFEED > 0 */
 132}
 133
 134io_return_t
 135console_feed_read(
 136        dev_t           dev,
 137        io_req_t        ior)
 138{
 139        spl_t           s;
 140        kern_return_t   rc;
 141        int             count;
 142
 143        rc = device_read_alloc(ior, (vm_size_t) ior->io_count);
 144        if (rc != KERN_SUCCESS)
 145                return rc;
 146
 147        s = splhigh();
 148        simple_lock(&cons_feed_lock);
 149
 150        ior->io_residual = ior->io_count;
 151
 152        count = q_to_b(&cons_feed_cb, (char *) ior->io_data, ior->io_count);
 153        if (count == 0) {
 154                if (ior->io_mode & D_NOWAIT) {
 155                        rc = D_WOULD_BLOCK;
 156                }
 157                if (cons_feed_queued == NULL) {
 158                        ior->io_done = cons_feed_read_done;
 159                        cons_feed_queued = ior;
 160                        rc = D_IO_QUEUED;
 161                } else {
 162                        /* Can't queue multiple read requests yet */
 163                        rc = D_INVALID_OPERATION;
 164                }
 165                simple_unlock(&cons_feed_lock);
 166                splx(s);
 167                return rc;
 168        }
 169
 170        simple_unlock(&cons_feed_lock);
 171        splx(s);
 172
 173        ior->io_residual -= count;
 174
 175        iodone(ior);
 176
 177        if (ior->io_op & IO_SYNC) {
 178                iowait(ior);
 179        }
 180
 181        return D_SUCCESS;
 182}
 183
 184/* Called when data is ready and there's a queued-up read waiting */
 185boolean_t cons_feed_read_done(io_req_t ior)
 186{
 187        spl_t   s;
 188        int     count;
 189
 190        s = splhigh();
 191        simple_lock(&cons_feed_lock);
 192
 193        count = q_to_b(&cons_feed_cb, (char *) ior->io_data, ior->io_count);
 194        if (count == 0) {
 195                if (cons_feed_queued == NULL) {
 196                        ior->io_done = cons_feed_read_done;
 197                        cons_feed_queued = ior;
 198                }
 199                simple_unlock(&cons_feed_lock);
 200                splx(s);
 201                return FALSE;
 202        }
 203
 204        simple_unlock(&cons_feed_lock);
 205        splx(s);
 206
 207        ior->io_residual -= count;
 208        ds_read_done(ior);
 209
 210        return TRUE;
 211}
 212
 213/* This routine is called from putc() - it should return TRUE if
 214 * the character should be passed on to a physical console, FALSE
 215 * if the feed has intercepted the character. It may be called from
 216 * under interrupt (even splhigh)
 217 */
 218
 219boolean_t console_feed_putc(char c)
 220{
 221        spl_t           s;
 222        io_req_t        ior;
 223        boolean_t       retval;
 224
 225#if     MACH_KDB
 226        if (db_active) {
 227                return TRUE;
 228        }
 229#endif  /* MACH_KDB */
 230
 231        retval=TRUE;    /* TRUE : character should be displayed now */
 232        if (!cons_feed_count) {
 233                return TRUE;
 234        }
 235        s = splhigh();
 236        simple_lock(&cons_feed_lock);
 237        if (!cons_feed_count) {
 238                simple_unlock(&cons_feed_lock);
 239                splx(s);
 240                return TRUE;
 241        }
 242        /* queue up the data if we can */
 243        if (!putc(c, &cons_feed_cb)) {
 244                /* able to stock the character */
 245                retval = FALSE;
 246        }
 247        if (cons_feed_queued != NULL) {
 248                /* Queued up request - service it */
 249                ior = cons_feed_queued;
 250                cons_feed_queued = NULL;
 251                simple_unlock(&cons_feed_lock);
 252                splx(s);
 253                iodone(ior);
 254                retval=FALSE;
 255        } else {
 256                simple_unlock(&cons_feed_lock);
 257                splx(s);
 258        }
 259        return retval;
 260}
 261
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.