]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/i386/km.c
a5a6c3f6c80e01d2d1503de4819aa17fe7fd3bb5
[apple/xnu.git] / bsd / dev / i386 / km.c
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved.
31 *
32 * km.m - kernel keyboard/monitor module, procedural interface.
33 *
34 * HISTORY
35 */
36
37 #include <sys/param.h>
38 #include <sys/tty.h>
39
40 #include <dev/i386/cons.h>
41 #include <sys/conf.h>
42 #include <sys/systm.h>
43 #include <sys/uio.h>
44 #include <sys/fcntl.h> /* for kmopen */
45 #include <sys/errno.h>
46 #include <sys/proc.h> /* for kmopen */
47 #include <sys/msgbuf.h>
48 #include <sys/time.h>
49 #include <dev/kmreg_com.h>
50 #include <pexpert/pexpert.h>
51
52 extern int hz;
53
54 extern void cnputcusr(char);
55 extern int cngetc(void);
56
57 void kminit(void);
58 int kmopen(dev_t dev, int flag, int devtype, struct proc *pp);
59 int kmclose(dev_t dev, int flag, int mode, struct proc *p);
60 int kmread(dev_t dev, struct uio *uio, int ioflag);
61 int kmwrite(dev_t dev, struct uio *uio, int ioflag);
62 int kmioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p);
63 int kmputc(int c);
64 int kmgetc(dev_t dev);
65 int kmgetc_silent(dev_t dev);
66 void cons_cinput(char ch);
67
68 /*
69 * 'Global' variables, shared only by this file and conf.c.
70 */
71 struct tty *km_tty[1] = { &cons };
72
73 /*
74 * this works early on, after initialize_screen() but before autoconf (and thus
75 * before we have a kmDevice).
76 */
77 int disableConsoleOutput;
78
79 /*
80 * 'Global' variables, shared only by this file and kmDevice.m.
81 */
82 int initialized = 0;
83
84 static int kmoutput(struct tty *tp);
85 static void kmstart(struct tty *tp);
86
87 extern void KeyboardOpen(void);
88
89 void
90 kminit(void)
91 {
92 cons.t_dev = makedev(12, 0);
93 initialized = 1;
94 }
95 /*
96 * cdevsw interface to km driver.
97 */
98 int
99 kmopen(
100 dev_t dev,
101 int flag,
102 __unused int devtype,
103 struct proc *pp)
104 {
105 int unit;
106 struct tty *tp;
107 struct winsize *wp;
108 int ret;
109
110 unit = minor(dev);
111 if(unit >= 1)
112 return (ENXIO);
113
114 tp = (struct tty *)&cons;
115 tp->t_oproc = kmstart;
116 tp->t_param = NULL;
117 tp->t_dev = dev;
118
119 if ( !(tp->t_state & TS_ISOPEN) ) {
120 tp->t_iflag = TTYDEF_IFLAG;
121 tp->t_oflag = TTYDEF_OFLAG;
122 tp->t_cflag = (CREAD | CS8 | CLOCAL);
123 tp->t_lflag = TTYDEF_LFLAG;
124 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
125 termioschars(&tp->t_termios);
126 ttsetwater(tp);
127 } else if ((tp->t_state & TS_XCLUDE) && proc_suser(pp))
128 return EBUSY;
129
130 tp->t_state |= TS_CARR_ON; /* lie and say carrier exists and is on. */
131 ret = ((*linesw[tp->t_line].l_open)(dev, tp));
132 {
133 PE_Video video;
134 wp = &tp->t_winsize;
135 /* Magic numbers. These are CHARWIDTH and CHARHEIGHT
136 * from pexpert/i386/video_console.c
137 */
138 wp->ws_xpixel = 8;
139 wp->ws_ypixel = 16;
140
141 if (flag & O_POPUP)
142 PE_initialize_console(0, kPETextScreen);
143
144 bzero(&video, sizeof(video));
145 PE_current_console(&video);
146 if( video.v_width != 0 && video.v_height != 0 ) {
147 wp->ws_col = video.v_width / wp->ws_xpixel;
148 wp->ws_row = video.v_height / wp->ws_ypixel;
149 } else {
150 wp->ws_col = 100;
151 wp->ws_row = 36;
152 }
153 }
154 return ret;
155 }
156
157 int
158 kmclose(
159 __unused dev_t dev,
160 int flag,
161 __unused int mode,
162 __unused struct proc *p)
163 {
164
165 struct tty *tp;
166
167 tp = &cons;
168 (*linesw[tp->t_line].l_close)(tp,flag);
169 ttyclose(tp);
170 return (0);
171 }
172
173 int
174 kmread(
175 __unused dev_t dev,
176 struct uio *uio,
177 int ioflag)
178 {
179 register struct tty *tp;
180
181 tp = &cons;
182 return ((*linesw[tp->t_line].l_read)(tp, uio, ioflag));
183 }
184
185 int
186 kmwrite(
187 __unused dev_t dev,
188 struct uio *uio,
189 int ioflag)
190 {
191 register struct tty *tp;
192
193 tp = &cons;
194 return ((*linesw[tp->t_line].l_write)(tp, uio, ioflag));
195 }
196
197 int
198 kmioctl(
199 __unused dev_t dev,
200 int cmd,
201 caddr_t data,
202 int flag,
203 struct proc *p)
204 {
205 int error;
206 struct tty *tp = &cons;
207 struct winsize *wp;
208
209 switch (cmd) {
210
211
212
213 case KMIOCSIZE:
214 wp = (struct winsize *)data;
215 *wp = tp->t_winsize;
216 return 0;
217
218 case TIOCSWINSZ:
219 /* Prevent changing of console size --
220 * this ensures that login doesn't revert to the
221 * termcap-defined size
222 */
223 return EINVAL;
224
225 /* Bodge in the CLOCAL flag as the km device is always local */
226 case TIOCSETA:
227 case TIOCSETAW:
228 case TIOCSETAF: {
229 register struct termios *t = (struct termios *)data;
230 t->c_cflag |= CLOCAL;
231 /* No Break */
232 }
233 default:
234 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
235 if (ENOTTY != error)
236 return error;
237 return ttioctl (tp, cmd, data, flag, p);
238 }
239 }
240
241 int
242 kmputc(
243 int c)
244 {
245
246 if( disableConsoleOutput)
247 return( 0);
248
249 if(!initialized)
250 return( 0);
251
252 if(c == '\n')
253 cnputcusr('\r');
254
255 cnputcusr(c);
256
257 return 0;
258 }
259
260 int
261 kmgetc(
262 __unused dev_t dev)
263 {
264 int c;
265
266 c= cngetc();
267
268 if (c == '\r') {
269 c = '\n';
270 }
271 cnputcusr(c);
272 return c;
273 }
274
275 int
276 kmgetc_silent(
277 __unused dev_t dev)
278 {
279 int c;
280
281 c= cngetc();
282 if (c == '\r') {
283 c = '\n';
284 }
285 return c;
286 }
287
288 /*
289 * Callouts from linesw.
290 */
291
292 #define KM_LOWAT_DELAY ((ns_time_t)1000)
293
294 static void
295 kmstart(
296 struct tty *tp)
297 {
298 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
299 goto out;
300 if (tp->t_outq.c_cc == 0)
301 goto out;
302 tp->t_state |= TS_BUSY;
303 kmoutput(tp);
304 return;
305
306 out:
307 (*linesw[tp->t_line].l_start)(tp);
308 return;
309 }
310
311 static void
312 kmtimeout(void *arg)
313 {
314 boolean_t funnel_state;
315 struct tty *tp = (struct tty *) arg;
316
317 funnel_state = thread_funnel_set(kernel_flock, TRUE);
318 kmoutput(tp);
319 (void) thread_funnel_set(kernel_flock, funnel_state);
320
321
322 }
323 static int
324 kmoutput(
325 struct tty *tp)
326 {
327 /*
328 * FIXME - to be grokked...copied from m68k km.c.
329 */
330 char buf[80];
331 char *cp;
332 int cc = -1;
333
334
335 while (tp->t_outq.c_cc > 0) {
336 cc = ndqb(&tp->t_outq, 0);
337 if (cc == 0)
338 break;
339 cc = min(cc, sizeof buf);
340 (void) q_to_b(&tp->t_outq, buf, cc);
341 for (cp = buf; cp < &buf[cc]; cp++) {
342 kmputc(*cp & 0x7f);
343 }
344 }
345 if (tp->t_outq.c_cc > 0) {
346 timeout(kmtimeout, tp, hz);
347 }
348 tp->t_state &= ~TS_BUSY;
349 (*linesw[tp->t_line].l_start)(tp);
350
351 return 0;
352 }
353
354 void
355 cons_cinput(char ch)
356 {
357 struct tty *tp = &cons;
358
359 (*linesw[tp->t_line].l_rint) (ch, tp);
360 }
361