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