xref: /illumos-gate/usr/src/uts/intel/io/polled_io.c (revision 2d6eb4a5)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/stropts.h>
28 #include <sys/devops.h>
29 #include <sys/modctl.h>
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/promif.h>
33 #include <sys/note.h>
34 #include <sys/consdev.h>
35 #include <sys/polled_io.h>
36 
37 /*
38  * consconfig is aware of which devices are the stdin and stout.  The
39  * post-attach/pre-detach functions are an extension of consconfig because
40  * they know about the dynamic changes to the stdin device.  Neither an
41  * individual driver nor the DDI framework knows what device is really the
42  * stdin.
43  */
44 /*
45  * Issues:
46  *	o There are probably race conditions between vx_handler for "read"
47  *	  being called by OBP and the update of the polled_input_t
48  *	  structure.  We need to be careful how the structure is updated.
49  *
50  * Solaris/Intel note:  While OBP is not in the picture, there are probably
51  * similar issues with kmdb.
52  */
53 
54 #if	defined(MAYBE_SOMETIME)
55 static void	polled_give_input(void);
56 static void	polled_take_input(void);
57 static void	polled_give_output(void);
58 static void	polled_take_output(void);
59 
60 static void	polled_io_register(cons_polledio_t *,
61 			polled_io_console_type_t, int);
62 
63 static void	polled_io_unregister(polled_io_console_type_t, int);
64 
65 
66 /*
67  * Make the registered device become the console for OBP
68  */
69 static int	polled_io_take_console(polled_io_console_type_t, int);
70 
71 /*
72  * Restore the old console device for OBP.
73  */
74 static int	polled_io_release_console(polled_io_console_type_t, int);
75 #endif	/* MAYBE_SOMETIME */
76 
77 static polled_device_t	polled_input_device;
78 static polled_device_t	polled_output_device;
79 
80 /*
81  * This routine is called to initialize polled I/O.  We insert our entry
82  * points so that OBP will call into this code when the switch is thrown
83  * in polled_io_take_console().
84  */
85 void
polled_io_init(void)86 polled_io_init(void)
87 {
88 	/*
89 	 * Initialize lock to protect multiple thread access to the
90 	 * polled_input_device structure.  This does not protect
91 	 * us from access in OBP mode.
92 	 */
93 	mutex_init(&polled_input_device.polled_device_lock,
94 		NULL, MUTEX_DRIVER, NULL);
95 
96 	/*
97 	 * Initialize lock to protect multiple thread access to the
98 	 * polled_output_device structure.  This does not protect
99 	 * us from access in OBP mode.
100 	 */
101 	mutex_init(&polled_output_device.polled_device_lock,
102 		NULL, MUTEX_DRIVER, NULL);
103 }
104 
105 /*
106  * Register a device for input or output.  The polled_io structure
107  * will be filled in with the callbacks that are appropriate for
108  * that device.
109  */
110 int
polled_io_register_callbacks(cons_polledio_t * polled_io,int flags)111 polled_io_register_callbacks(
112 cons_polledio_t			*polled_io,
113 int				flags
114 )
115 {
116 #if	defined(MAYBE_SOMETIME)
117 	/*
118 	 * If the input structure entries are filled in, then register this
119 	 * structure as an input device.
120 	 */
121 	if ((polled_io->cons_polledio_getchar != NULL) &&
122 		(polled_io->cons_polledio_ischar != NULL)) {
123 
124 		polled_io_register(polled_io,
125 			POLLED_IO_CONSOLE_INPUT, flags);
126 	}
127 
128 	/*
129 	 * If the output structure entries are filled in, then register this
130 	 * structure as an output device.
131 	 */
132 	if (polled_io->cons_polledio_putchar != NULL) {
133 
134 		polled_io_register(polled_io,
135 			POLLED_IO_CONSOLE_OUTPUT, flags);
136 	}
137 #else
138 _NOTE(ARGUNUSED(flags))
139 	cons_polledio = polled_io;
140 #endif
141 
142 	return (DDI_SUCCESS);
143 }
144 
145 /*
146  * Unregister a device for console input/output.
147  */
148 int
polled_io_unregister_callbacks(cons_polledio_t * polled_io,int flags)149 polled_io_unregister_callbacks(
150 cons_polledio_t			*polled_io,
151 int				flags
152 )
153 {
154 #if	defined(MAYBE_SOMETIME)
155 	/*
156 	 * If polled_io is being used for input, then unregister it.
157 	 */
158 	if (polled_io == polled_input_device.polled_io) {
159 
160 		polled_io_unregister(
161 			POLLED_IO_CONSOLE_INPUT, flags);
162 	}
163 
164 	/*
165 	 * If polled_io is being used for output, then unregister it.
166 	 */
167 	if (polled_io == polled_output_device.polled_io) {
168 
169 		polled_io_unregister(
170 			POLLED_IO_CONSOLE_OUTPUT, flags);
171 	}
172 #else
173 _NOTE(ARGUNUSED(polled_io,flags))
174 #endif	/* MAYBE_SOMETIME */
175 
176 	return (DDI_SUCCESS);
177 }
178 
179 /*
180  * This routine is called when we are done handling polled io.  We will
181  * remove all of our handlers and destroy any memory that we have allocated.
182  */
183 void
polled_io_fini()184 polled_io_fini()
185 {
186 	/*
187 	 * Destroy the mutexes, we will not need them anymore.
188 	 */
189 	mutex_destroy(&polled_input_device.polled_device_lock);
190 
191 	mutex_destroy(&polled_output_device.polled_device_lock);
192 }
193 
194 #if	defined(MAYBE_SOMETIME)
195 /*
196  * Generic internal routine for registering a polled input or output device.
197  */
198 /* ARGSUSED */
199 static void
polled_io_register(cons_polledio_t * polled_io,polled_io_console_type_t type,int flags)200 polled_io_register(
201 cons_polledio_t			*polled_io,
202 polled_io_console_type_t	type,
203 int				flags
204 )
205 {
206 	switch (type) {
207 	case POLLED_IO_CONSOLE_INPUT:
208 		/*
209 		 * Grab the device lock, because we are going to access
210 		 * protected structure entries.  We do this before the
211 		 * POLLED_IO_CONSOLE_OPEN_INPUT so that we serialize
212 		 * registration.
213 		 */
214 		mutex_enter(&polled_input_device.polled_device_lock);
215 
216 		/*
217 		 * Save the polled_io pointers so that we can access
218 		 * them later.
219 		 */
220 		polled_input_device.polled_io = polled_io;
221 
222 		mutex_exit(&polled_input_device.polled_device_lock);
223 
224 		/*
225 		 * Tell the generic console framework to
226 		 * repoint OBP's stdin to this keyboard device.
227 		 */
228 		(void) polled_io_take_console(type, 0);
229 
230 		break;
231 
232 	case POLLED_IO_CONSOLE_OUTPUT:
233 		/*
234 		 * Grab the device lock, because we are going to access
235 		 * protected structure entries. We do this before the
236 		 * POLLED_IO_CONSOLE_OPEN_OUTPUT so that we serialize
237 		 * registration.
238 		 */
239 		mutex_enter(&polled_output_device.polled_device_lock);
240 
241 		/*
242 		 * Save the polled_io pointers so that we can access
243 		 * them later.
244 		 */
245 		polled_input_device.polled_io = polled_io;
246 
247 		mutex_exit(&polled_output_device.polled_device_lock);
248 
249 		break;
250 	}
251 }
252 
253 /*
254  * Generic internal routine for unregistering a polled input or output device.
255  */
256 /* ARGSUSED */
257 static void
polled_io_unregister(polled_io_console_type_t type,int flags)258 polled_io_unregister(
259 polled_io_console_type_t	type,
260 int				flags
261 )
262 {
263 	switch (type) {
264 	case POLLED_IO_CONSOLE_INPUT:
265 		/*
266 		 * Tell the generic console framework to restore OBP's
267 		 * old stdin pointers.
268 		 */
269 		(void) polled_io_release_console(type, 0);
270 
271 		/*
272 		 * Grab the device lock, because we are going to access
273 		 * protected structure entries.
274 		 */
275 		mutex_enter(&polled_input_device.polled_device_lock);
276 
277 		/*
278 		 * We are closing the device, so get the value for the op
279 		 * pointer.  We use the polled_io structure to determine if
280 		 * there is a device registered,  so null the dev_ops
281 		 * structure.
282 		 */
283 		polled_input_device.polled_io = NULL;
284 
285 		mutex_exit(&polled_input_device.polled_device_lock);
286 
287 		break;
288 
289 	case POLLED_IO_CONSOLE_OUTPUT:
290 		/*
291 		 * Grab the device lock, because we are going to access
292 		 * protected structure entries.
293 		 */
294 		mutex_enter(&polled_output_device.polled_device_lock);
295 
296 		/*
297 		 * We are closing the device, so get the value for the op
298 		 * pointer.  We use the polled_io structure to determine if
299 		 * there is a device registered.
300 		 */
301 		polled_output_device.polled_io = NULL;
302 
303 		mutex_exit(&polled_output_device.polled_device_lock);
304 
305 		break;
306 	}
307 }
308 
309 /*
310  * This is the routine that is called to throw the switch from boot
311  * ownership of stdout/stdin to the kernel.
312  */
313 /* ARGSUSED */
314 static int
polled_io_take_console(polled_io_console_type_t type,int flags)315 polled_io_take_console(
316 polled_io_console_type_t	type,
317 int				flags
318 )
319 {
320 	switch (type) {
321 	case POLLED_IO_CONSOLE_INPUT:
322 		/*
323 		 * Perhaps this should be where we switch *sysp
324 		 */
325 		break;
326 
327 	case POLLED_IO_CONSOLE_OUTPUT:
328 		/*
329 		 * Perhaps this should be where we switch *sysp
330 		 */
331 		break;
332 	}
333 
334 	return (DDI_SUCCESS);
335 }
336 
337 /*
338  * This routine gives control of console input/output back to ???.
339  *
340  * Solaris/Intel has nobody to give it back to.  Hope we don't get here!
341  */
342 /* ARGSUSED */
343 static int
polled_io_release_console(polled_io_console_type_t type,int flags)344 polled_io_release_console(
345 polled_io_console_type_t	type,
346 int				flags
347 )
348 {
349 	cmn_err(CE_WARN,
350 	    "polled_io_release_console:  nobody to hand console back to");
351 
352 	return (DDI_SUCCESS);
353 }
354 
355 /*
356  * This is the routine that kmdb calls to save any state information
357  * before using the input device.  This routine, and all of the
358  * routines that it calls, are responsible for saving any state
359  * information so that it can be restored when polled mode is over.
360  */
361 static void
polled_give_input(void)362 polled_give_input(void)
363 {
364 	cons_polledio_t		*polled_io;
365 
366 	/*
367 	 * We check the dev_ops pointer to see if there is an
368 	 * input device that has been registered.
369 	 */
370 	polled_io = polled_input_device.polled_io;
371 
372 	if (polled_io == NULL || polled_io->cons_polledio_enter == NULL) {
373 		return;
374 	}
375 
376 	/*
377 	 * Call down to the lower layers to save the state.
378 	 */
379 	polled_io->cons_polledio_enter(
380 		polled_io->cons_polledio_argument);
381 }
382 
383 /*
384  * This is the routine that kmdb calls when it is giving up control of the
385  * input device.  This routine, and the lower layer routines that it calls,
386  * are responsible for restoring the controller state to the state it was
387  * in before kmdb took control.
388  */
389 static void
polled_take_input(void)390 polled_take_input(void)
391 {
392 	cons_polledio_t		*polled_io;
393 
394 	/*
395 	 * We check the dev_ops pointer to see if there is an
396 	 * input device that has been registered.
397 	 */
398 	polled_io = polled_input_device.polled_io;
399 
400 	if (polled_io == NULL || polled_io->cons_polledio_exit == NULL) {
401 		return;
402 	}
403 
404 	/*
405 	 * Call down to the lower layers to save the state.
406 	 */
407 	polled_io->cons_polledio_exit(
408 		polled_io->cons_polledio_argument);
409 }
410 
411 /*
412  * This is the routine that kmdb calls to save any state information
413  * before using the output device.  This routine, and all of the
414  * routines that it calls, are responsible for saving any state
415  * information so that it can be restored when polled mode is over.
416  */
417 static void
polled_give_output()418 polled_give_output()
419 {
420 	cons_polledio_t		*polled_io;
421 
422 	/*
423 	 * We check the dev_ops pointer to see if there is an
424 	 * output device that has been registered.
425 	 */
426 	polled_io = polled_output_device.polled_io;
427 
428 	if (polled_io == NULL || polled_io->cons_polledio_enter == NULL) {
429 		return;
430 	}
431 
432 	/*
433 	 * Call down to the lower layers to save the state.
434 	 */
435 	polled_io->cons_polledio_enter(
436 		polled_io->cons_polledio_argument);
437 }
438 
439 /*
440  * This is the routine that kmdb calls when it is giving up control of the
441  * output device.  This routine, and the lower layer routines that it calls,
442  * are responsible for restoring the controller state to the state it was
443  * in before kmdb took control.
444  */
445 static void
polled_take_output(void)446 polled_take_output(void)
447 {
448 	cons_polledio_t		*polled_io;
449 
450 	/*
451 	 * We check the dev_ops pointer to see if there is an
452 	 * output device that has been registered.
453 	 */
454 	polled_io = polled_output_device.polled_io;
455 
456 	if (polled_io == NULL || polled_io->cons_polledio_exit == NULL) {
457 		return;
458 	}
459 
460 	/*
461 	 * Call down to the lower layers to save the state.
462 	 */
463 	polled_io->cons_polledio_exit(
464 		polled_io->cons_polledio_argument);
465 }
466 #endif	/* MAYBE_SOMETIME */
467