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