X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8f6c56a50524aa785f7e596d52dddfb331e18961..refs/heads/master:/bsd/dev/i386/km.c diff --git a/bsd/dev/i386/km.c b/bsd/dev/i386/km.c index 7b53090ff..aee4edee8 100644 --- a/bsd/dev/i386/km.c +++ b/bsd/dev/i386/km.c @@ -2,7 +2,7 @@ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * 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 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ 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, @@ -22,10 +22,10 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ -/* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved. +/* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved. * * km.m - kernel keyboard/monitor module, procedural interface. * @@ -35,38 +35,32 @@ #include #include -#include +#include #include #include #include -#include /* for kmopen */ -#include -#include /* for kmopen */ +#include /* for kmopen */ +#include +#include /* for kmopen */ #include #include #include #include +#include extern int hz; extern void cnputcusr(char); +extern void cnputsusr(char *, int); extern int cngetc(void); -void kminit(void); -int kmopen(dev_t dev, int flag, int devtype, struct proc *pp); -int kmclose(dev_t dev, int flag, int mode, struct proc *p); -int kmread(dev_t dev, struct uio *uio, int ioflag); -int kmwrite(dev_t dev, struct uio *uio, int ioflag); -int kmioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p); -int kmputc(int c); -int kmgetc(dev_t dev); -int kmgetc_silent(dev_t dev); -void cons_cinput(char ch); +void kminit(void); +void cons_cinput(char ch); /* * 'Global' variables, shared only by this file and conf.c. */ -struct tty *km_tty[1] = { &cons }; +struct tty *km_tty[1] = { 0 }; /* * this works early on, after initialize_screen() but before autoconf (and thus @@ -87,34 +81,36 @@ extern void KeyboardOpen(void); void kminit(void) { - cons.t_dev = makedev(12, 0); + km_tty[0] = ttymalloc(); + km_tty[0]->t_dev = makedev(12, 0); initialized = 1; } + /* * cdevsw interface to km driver. */ -int -kmopen( - dev_t dev, - int flag, - __unused int devtype, - struct proc *pp) +int +kmopen(dev_t dev, int flag, __unused int devtype, proc_t pp) { int unit; struct tty *tp; struct winsize *wp; int ret; - + unit = minor(dev); - if(unit >= 1) - return (ENXIO); + if (unit >= 1) { + return ENXIO; + } + + tp = km_tty[unit]; + + tty_lock(tp); - tp = (struct tty *)&cons; tp->t_oproc = kmstart; tp->t_param = NULL; tp->t_dev = dev; - - if ( !(tp->t_state & TS_ISOPEN) ) { + + if (!(tp->t_state & TS_ISOPEN)) { tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_cflag = (CREAD | CS8 | CLOCAL); @@ -122,26 +118,36 @@ kmopen( tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; termioschars(&tp->t_termios); ttsetwater(tp); - } else if ((tp->t_state & TS_XCLUDE) && proc_suser(pp)) - return EBUSY; + } else if ((tp->t_state & TS_XCLUDE) && proc_suser(pp)) { + ret = EBUSY; + goto out; + } tp->t_state |= TS_CARR_ON; /* lie and say carrier exists and is on. */ + ret = ((*linesw[tp->t_line].l_open)(dev, tp)); { PE_Video video; wp = &tp->t_winsize; - /* Magic numbers. These are CHARWIDTH and CHARHEIGHT + /* + * Magic numbers. These are CHARWIDTH and CHARHEIGHT * from pexpert/i386/video_console.c */ wp->ws_xpixel = 8; wp->ws_ypixel = 16; - if (flag & O_POPUP) + tty_unlock(tp); /* XXX race window */ + + if (flag & O_POPUP) { PE_initialize_console(0, kPETextScreen); + } bzero(&video, sizeof(video)); PE_current_console(&video); - if( video.v_width != 0 && video.v_height != 0 ) { + + tty_lock(tp); + + if (video.v_display == FB_TEXT_MODE && video.v_width != 0 && video.v_height != 0) { wp->ws_col = video.v_width / wp->ws_xpixel; wp->ws_row = video.v_height / wp->ws_ypixel; } else { @@ -149,154 +155,157 @@ kmopen( wp->ws_row = 36; } } + +out: + tty_unlock(tp); + return ret; } -int -kmclose( - __unused dev_t dev, - int flag, - __unused int mode, - __unused struct proc *p) +int +kmclose(dev_t dev, int flag, __unused int mode, __unused proc_t p) { - - struct tty *tp; + int ret; + struct tty *tp = km_tty[minor(dev)]; - tp = &cons; - (*linesw[tp->t_line].l_close)(tp,flag); + tty_lock(tp); + ret = (*linesw[tp->t_line].l_close)(tp, flag); ttyclose(tp); - return (0); + tty_unlock(tp); + + return ret; } -int -kmread( - __unused dev_t dev, - struct uio *uio, - int ioflag) +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 ret; + struct tty *tp = km_tty[minor(dev)]; + + tty_lock(tp); + ret = (*linesw[tp->t_line].l_read)(tp, uio, ioflag); + tty_unlock(tp); + + return ret; } -int -kmwrite( - __unused dev_t dev, - struct uio *uio, - int 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 ret; + struct tty *tp = km_tty[minor(dev)]; + + tty_lock(tp); + ret = (*linesw[tp->t_line].l_write)(tp, uio, ioflag); + tty_unlock(tp); + + return ret; } -int -kmioctl( - __unused dev_t dev, - int cmd, - caddr_t data, - int flag, - struct proc *p) +int +kmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, proc_t p) { - int error; - struct tty *tp = &cons; + int error = 0; + struct tty *tp = km_tty[minor(dev)]; struct winsize *wp; - - switch (cmd) { - + tty_lock(tp); - case KMIOCSIZE: + switch (cmd) { + case KMIOCSIZE: wp = (struct winsize *)data; *wp = tp->t_winsize; - return 0; - - case TIOCSWINSZ: + break; + + case TIOCSWINSZ: /* Prevent changing of console size -- * this ensures that login doesn't revert to the * termcap-defined size */ - return EINVAL; + error = EINVAL; + break; - /* 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; + /* Bodge in the CLOCAL flag as the km device is always local */ + case TIOCSETA_32: + case TIOCSETAW_32: + case TIOCSETAF_32: + { + struct termios32 *t = (struct termios32 *)data; t->c_cflag |= CLOCAL; /* No Break */ - } - default: + } + goto fallthrough; + case TIOCSETA_64: + case TIOCSETAW_64: + case TIOCSETAF_64: + { + struct user_termios *t = (struct user_termios *)data; + t->c_cflag |= CLOCAL; + /* No Break */ + } +fallthrough: + default: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); - if (ENOTTY != error) - return error; - return ttioctl (tp, cmd, data, flag, p); + if (ENOTTY != error) { + break; + } + error = ttioctl_locked(tp, cmd, data, flag, p); + break; } -} - -int -kmputc( - int c) -{ - - if( disableConsoleOutput) - return( 0); - - if(!initialized) - return( 0); - if(c == '\n') - cnputcusr('\r'); + tty_unlock(tp); - cnputcusr(c); - - return 0; + return error; } -int -kmgetc( - __unused dev_t dev) +/* + * kmputc + * + * Output a character to the serial console driver via cnputcusr(), + * which is exported by that driver. + * + * Locks: Assumes tp in the calling tty driver code is locked on + * entry, remains locked on exit + * + * Notes: Called from kmoutput(); giving the locking output + * assumptions here, this routine should be static (and + * inlined, given there is only one call site). + */ +int +kmputc(__unused dev_t dev, char c) { - int c; - - c= cngetc(); - - if (c == '\r') { - c = '\n'; + if (!disableConsoleOutput && initialized) { + /* OCRNL */ + if (c == '\n') { + cnputcusr('\r'); + } + cnputcusr(c); } - cnputcusr(c); - return c; -} -int -kmgetc_silent( - __unused dev_t dev) -{ - int c; - - c= cngetc(); - if (c == '\r') { - c = '\n'; - } - return c; + return 0; } + /* * Callouts from linesw. */ - -#define KM_LOWAT_DELAY ((ns_time_t)1000) -static void -kmstart( - struct tty *tp) +#define KM_LOWAT_DELAY ((ns_time_t)1000) + +/* + * t_oproc for this driver; called from within the line discipline + * + * Locks: Assumes tp is locked on entry, remains locked on exit + */ +static void +kmstart(struct tty *tp) { - if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) + if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { goto out; - if (tp->t_outq.c_cc == 0) + } + if (tp->t_outq.c_cc == 0) { goto out; + } tp->t_state |= TS_BUSY; kmoutput(tp); return; @@ -306,54 +315,102 @@ out: return; } +/* + * One-shot output retry timeout from kmoutput(); re-calls kmoutput() at + * intervals until the output queue for the tty is empty, at which point + * the timeout is not rescheduled by kmoutput() + * + * This function must take the tty_lock() around the kmoutput() call; it + * ignores the return value. + */ static void kmtimeout(void *arg) { - boolean_t funnel_state; - struct tty *tp = (struct tty *) arg; - - funnel_state = thread_funnel_set(kernel_flock, TRUE); - kmoutput(tp); - (void) thread_funnel_set(kernel_flock, funnel_state); - + struct tty *tp = (struct tty *)arg; + tty_lock(tp); + (void)kmoutput(tp); + tty_unlock(tp); } -static int -kmoutput( - struct tty *tp) + +/* + * kmoutput + * + * Locks: Assumes tp is locked on entry, remains locked on exit + * + * Notes: Called from kmstart() and kmtimeout(); kmtimeout() is a + * timer initiated by this routine to deal with pending + * output not yet flushed (output is flushed at a maximum + * of sizeof(buf) charatcers at a time before dropping into + * the timeout code). + */ +static int +kmoutput(struct tty *tp) { - /* - * FIXME - to be grokked...copied from m68k km.c. - */ - char buf[80]; - char *cp; - int cc = -1; + unsigned char buf[80]; /* buffer; limits output per call */ + unsigned char *cp; + int cc = -1; + /* While there is data available to be output... */ while (tp->t_outq.c_cc > 0) { cc = ndqb(&tp->t_outq, 0); - if (cc == 0) + if (cc == 0) { break; - cc = min(cc, sizeof buf); + } + /* + * attempt to output as many characters as are available, + * up to the available transfer buffer size. + */ + cc = min(cc, sizeof(buf)); + /* copy the output queue contents to the buffer */ (void) q_to_b(&tp->t_outq, buf, cc); for (cp = buf; cp < &buf[cc]; cp++) { - kmputc(*cp & 0x7f); + /* output the buffer one charatcer at a time */ + *cp = *cp & 0x7f; + } + + if (cc > 1) { + cnputsusr((char *)buf, cc); + } else { + kmputc(tp->t_dev, *buf); } } - if (tp->t_outq.c_cc > 0) { + /* + * XXX This is likely not necessary, as the tty output queue is not + * XXX writeable while we hold the tty_lock(). + */ + if (tp->t_outq.c_cc > 0) { timeout(kmtimeout, tp, hz); } tp->t_state &= ~TS_BUSY; + /* Start the output processing for the line discipline */ (*linesw[tp->t_line].l_start)(tp); return 0; } + +/* + * cons_cinput + * + * Driver character input from the polled mode serial console driver calls + * this routine to input a character from the serial driver into the tty + * line discipline specific input processing receiv interrupt routine, + * l_rint(). + * + * Locks: Assumes that the tty_lock() is NOT held on the tp, so a + * serial driver should NOT call this function as a result + * of being called from a function which already holds the + * lock; ECHOE will be handled at the line discipline, if + * output echo processing is going to occur. + */ void cons_cinput(char ch) { - struct tty *tp = &cons; - - (*linesw[tp->t_line].l_rint) (ch, tp); -} + struct tty *tp = km_tty[0]; /* XXX */ + tty_lock(tp); + (*linesw[tp->t_line].l_rint)(ch, tp); + tty_unlock(tp); +}