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