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