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