Source to bsd/dev/i386/km.m
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License."
*
* @APPLE_LICENSE_HEADER_END@
*/
/* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved.
*
* km.m - kernel keyboard/monitor module, procedural interface.
*
* HISTORY
* 21 Sep 92 Joe Pasqua
* Created i386 version based on m88k version.
*/
#import <driverkit/IODevice.h>
#import <driverkit/generalFuncs.h>
#import <bsd/sys/param.h>
#import <bsd/sys/proc.h>
#import <bsd/sys/conf.h>
#import <sys/systm.h>
#import <bsd/sys/tty.h>
#import <bsd/sys/uio.h>
#import <bsd/sys/fcntl.h> /* for kmopen */
#import <bsd/sys/errno.h>
#import <bsd/sys/msgbuf.h>
#import <bsd/dev/kmreg_com.h>
#import <kern/thread_call.h>
#import <kernserv/ns_timer.h>
#import <bsd/dev/i386/kmDevice.h>
#import <bsd/dev/i386/km.h>
#import <bsd/dev/i386/BasicConsole.h>
#include <machdep/i386/kernBootStruct.h>
#import <kern/assert.h>
/*
* 'Global' variables, shared only by this file and conf.c.
*/
extern struct tty cons;
struct tty *km_tty[1] = { &cons };
/*
* 'Global' variables, shared only by this file and kmDevice.m.
*/
kmDevice *kmId; // the kmDevice
IOConsoleInfo *basicConsole;
ScreenMode basicConsoleMode;
extern IOConsoleInfo *kmAlertConsole;
static int initialized; // = 0
/*
* Static functions.
*/
static int kmoutput(struct tty *tp);
static void kmstart(struct tty *tp);
void kminit();
/*
* cdevsw interface to km driver.
*/
int
kmopen(
dev_t dev,
int flag,
int devtype,
struct proc *pp)
{
int rtn;
int unit;
struct tty *tp;
struct winsize *wp;
struct ConsoleSize size;
int ret;
#if notdef
if (flag & (O_POPUP|O_ALERT))
{
/* ensure text console visible, in case someone does a late */
/* open of /dev/console for alert purposes */
bcTextMode();
}
#endif
unit = minor(dev);
if(unit >= NUM_KM_DEVS)
return (ENXIO);
if ( (rtn = [kmId kmOpen:flag]) )
return rtn;
/*
* This code lifted from 68k km.c.
*/
tp = (struct tty *)&cons;
tp->t_oproc = kmstart;
tp->t_param = NULL;
tp->t_dev = dev;
if ((tp->t_state & TS_ISOPEN) == 0) {
tp->t_iflag = TTYDEF_IFLAG;
tp->t_oflag = TTYDEF_OFLAG;
tp->t_cflag = (CREAD | CS8 | CLOCAL);
tp->t_lflag = TTYDEF_LFLAG;
tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
termioschars(&tp->t_termios);
ttsetwater(tp);
} else if ((tp->t_state & TS_XCLUDE) && pp->p_ucred->cr_uid != 0)
return EBUSY;
tp->t_state |= TS_CARR_ON; /* lie and say carrier exists and is on. */
ret = ((*linesw[tp->t_line].l_open)(dev, tp));
if (ret == 0) {
[kmId getScreenSize:&size];
wp = &tp->t_winsize;
wp->ws_row = size.rows;
wp->ws_col = size.cols;
wp->ws_xpixel = size.pixel_width;
wp->ws_ypixel = size.pixel_height;
}
return ret;
}
int
kmclose(
dev_t dev,
int flag,
int mode,
struct proc *p)
{
/*
* Note we don't close possible alert window here; we have to rely on
* user to do a KMIOCRESTORE.
*/
struct tty *tp;
tp = &cons;
(*linesw[tp->t_line].l_close)(tp,flag);
ttyclose(tp);
return (0);
}
int
kmread(
dev_t dev,
struct uio *uio,
int ioflag)
{
register struct tty *tp;
tp = &cons;
return ((*linesw[tp->t_line].l_read)(tp, uio, ioflag));
}
int
kmwrite(
dev_t dev,
struct uio *uio,
int ioflag)
{
register struct tty *tp;
tp = &cons;
return ((*linesw[tp->t_line].l_write)(tp, uio, ioflag));
}
int
kmioctl(
dev_t dev,
int cmd,
caddr_t data,
int flag,
struct proc *p)
{
int error;
struct tty *tp = &cons;
struct ConsoleSize size;
struct winsize *wp;
switch (cmd) {
case KMIOCRESTORE:
return [kmId restore];
case KMIOCDRAWRECT:
return [kmId drawRect:(struct km_drawrect *)data];
case KMIOCERASERECT:
return [kmId eraseRect:(struct km_drawrect *)data];
case KMIOCDISABLCONS:
return [kmId disableCons];
case KMIOCDUMPLOG:
return [kmId dumpMsgBuf];
case KMIOCANIMCTL:
return [kmId animationCtl:*(km_anim_ctl_t *)data];
case KMIOCSTATUS:
return [kmId getStatus:(unsigned *)data];
case KMIOCSIZE:
[kmId getScreenSize:&size];
wp = (struct winsize *)data;
wp->ws_row = size.rows;
wp->ws_col = size.cols;
wp->ws_xpixel = size.pixel_width;
wp->ws_ypixel = size.pixel_height;
return 0;
case TIOCSWINSZ:
/* Prevent changing of console size --
* this ensures that login doesn't revert to the
* termcap-defined size
*/
return EINVAL;
/* Bodge in the CLOCAL flag as the km device is always local */
case TIOCSETA:
case TIOCSETAW:
case TIOCSETAF: {
register struct termios *t = (struct termios *)data;
t->c_cflag |= CLOCAL;
/* No Break */
}
default:
error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
if (error >= 0) {
return error;
}
error = ttioctl (tp, cmd, data, flag, p);
if (error >= 0) {
return error;
}
else {
return ENOTTY;
}
}
}
/*
* this works early on, after console_init() but before autoconf (and thus
* before we have a kmDevice).
*/
int
kmputc(
dev_t dev,
int c)
{
IOConsoleInfo *console;
ASSERT(fbg != NULL);
if(kmId) {
/*
* After autoconfig, let kmDevice handle this.
*/
if (c == '\n') {
[kmId kmPutc:'\r'];
}
return [kmId kmPutc:c];
}
console = kmAlertConsole ? kmAlertConsole : basicConsole;
if(c == '\n') {
(*console->PutC)(console, '\r');
}
(*console->PutC)(console, c);
return 0;
}
int
kmgetc(
dev_t dev)
{
/* found in bsd/dev/i386/cons.c */
extern int cnputc(char c);
int c;
if(kmId == nil) {
return 0;
}
c = [kmId kmGetc];
if (c == '\r') {
c = '\n';
}
cnputc(c);
return c;
}
int
kmgetc_silent(
dev_t dev)
{
int c;
if(kmId == nil) {
return 0;
}
c = [kmId kmGetc];
if (c == '\r') {
c = '\n';
}
return c;
}
/*
* Callouts from linesw.
*/
#define KM_LOWAT_DELAY ((ns_time_t)1000)
static void
kmstart(struct tty *tp)
{
if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
goto out;
if (tp->t_outq.c_cc == 0)
goto out;
tp->t_state |= TS_BUSY;
if (tp->t_outq.c_cc > tp->t_lowat) {
/*
* Start immediately.
*/
thread_call_func(
(thread_call_func_t) kmoutput, tp, TRUE);
}
else {
/*
* Wait a bit...
*/
ns_timeout((func) kmoutput, tp, KM_LOWAT_DELAY,
CALLOUT_PRI_THREAD);
}
out:
ttwwakeup(tp);
}
static int
kmoutput(
struct tty *tp)
{
/*
* FIXME - to be grokked...copied from m68k km.c.
*/
char buf[80];
char *cp;
int cc = -1;
while (tp->t_outq.c_cc > 0) {
cc = ndqb(&tp->t_outq, 0);
if (cc == 0)
break;
cc = min(cc, sizeof buf);
(void) q_to_b(&tp->t_outq, buf, cc);
for (cp = buf; cp < &buf[cc]; cp++) {
[kmId kmPutc:(*cp & 0x7f)];
}
}
if (tp->t_outq.c_cc > 0) {
thread_call_func(
(thread_call_func_t)kmoutput, tp, TRUE);
}
tp->t_state &= ~TS_BUSY;
ttwwakeup(tp);
return 0;
}
/*
* Alert panel interface (which we'd like to do away with if at all
* possible).
*/
int
kmpopup (
const char *title,
int flag,
int width,
int height,
boolean_t allocmem)
{
if (!initialized) {
kminit();
}
DoAlert(title, "");
return 0;
}
int
kmrestore()
{
DoRestore();
return 0;
}
/*
* Write message to console; create an alert panel if no text-type window
* currently exists. Caller must call alert_done() when finished.
* The height and width arguments are not used; they are provided for
* compatibility with the 68k version of alert().
*/
int
alert(
int width,
int height,
const char *title,
const char *msg,
int p1,
int p2,
int p3,
int p4,
int p5,
int p6,
int p7,
int p8)
{
char smsg[200];
sprintf(smsg, msg, p1, p2, p3, p4, p5, p6, p7, p8);
DoAlert(title, smsg);
return 0;
}
int
alert_done()
{
DoRestore();
return 0;
}
/*
* printf() a message to an an alert panel. Can be used any time after calling
* alert(). This might go away before release, let's see..
*/
void
aprint(
const char *msg,
int p1,
int p2,
int p3,
int p4,
int p5,
int p6,
int p7,
int p8)
{
char smsg[200];
char *cp = smsg;
ASSERT(kmId != nil);
sprintf(smsg, msg, p1, p2, p3, p4, p5, p6, p7, p8);
while(cp) {
kmputc(0, *cp++);
}
}
/*
* Dump message log.
*/
void kmdumplog()
{
if (kmId != nil)
[kmId dumpMsgBuf];
}
/*
* Initialize the console enough for printf's to work via kmputc. No
* text window will be created if booting in icon mode. Keyboard is
* not enabled.
*/
void
kminit()
{
KERNBOOTSTRUCT *kernbootstruct = KERNSTRUCT_ADDR;
initialized = TRUE;
basicConsole = BasicAllocateConsole();
if (kernbootstruct->graphicsMode) {
basicConsoleMode = SCM_GRAPHIC;
(*basicConsole->Init)(
basicConsole, SCM_GRAPHIC, FALSE, FALSE, mach_title);
} else {
basicConsoleMode = SCM_TEXT;
(*basicConsole->Init)(
basicConsole, SCM_TEXT, TRUE, TRUE, mach_title);
}
}
void
kmDrawGraphicPanel(GraphicPanelType panelType)
{
if (kmId != nil)
[kmId drawGraphicPanel:panelType];
}
void
kmGraphicPanelString(char *str)
{
if (kmId != nil)
[kmId graphicPanelString:str];
}
/* end of km.m */