X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6601e61aa18bf4f09af135ff61fc7f4771d23b06..4bd07ac2140668789aa3ee8ec4dde4a3e0a3bba5:/bsd/dev/i386/km.c diff --git a/bsd/dev/i386/km.c b/bsd/dev/i386/km.c index 6de6ff0bb..d276b6d95 100644 --- a/bsd/dev/i386/km.c +++ b/bsd/dev/i386/km.c @@ -1,23 +1,29 @@ /* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (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. + * 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 + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * 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. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * 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, * 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. + * 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_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved. * @@ -29,7 +35,7 @@ #include #include -#include +#include #include #include #include @@ -40,6 +46,7 @@ #include #include #include +#include extern int hz; @@ -47,20 +54,12 @@ extern void cnputcusr(char); 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); /* * '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 @@ -81,18 +80,16 @@ 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) +kmopen(dev_t dev, int flag, __unused int devtype, proc_t pp) { int unit; struct tty *tp; @@ -103,7 +100,10 @@ kmopen( if(unit >= 1) return (ENXIO); - tp = (struct tty *)&cons; + tp = km_tty[unit]; + + tty_lock(tp); + tp->t_oproc = kmstart; tp->t_param = NULL; tp->t_dev = dev; @@ -116,26 +116,35 @@ 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; + 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 { @@ -143,149 +152,148 @@ 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) +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) +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) +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) +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; + + tty_lock(tp); switch (cmd) { - - - case KMIOCSIZE: wp = (struct winsize *)data; *wp = tp->t_winsize; - return 0; + 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; - t->c_cflag |= CLOCAL; - /* No Break */ - } + case TIOCSETA_32: + case TIOCSETAW_32: + case TIOCSETAF_32: + { + struct termios32 *t = (struct termios32 *)data; + t->c_cflag |= CLOCAL; + /* No Break */ + } + 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); + 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); } +/* + * 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 -kmgetc( - __unused dev_t dev) +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) +/* + * 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) +kmstart(struct tty *tp) { if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) goto out; @@ -300,54 +308,95 @@ 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); } + +/* + * 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) +kmoutput(struct tty *tp) { - /* - * FIXME - to be grokked...copied from m68k km.c. - */ - char buf[80]; - char *cp; + 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) 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 */ + kmputc(tp->t_dev, *cp & 0x7f); } } + /* + * 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; - + struct tty *tp = km_tty[0]; /* XXX */ + + tty_lock(tp); (*linesw[tp->t_line].l_rint) (ch, tp); + tty_unlock(tp); } -