]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/serial_io.c
xnu-792.6.61.tar.gz
[apple/xnu.git] / osfmk / ppc / serial_io.c
1 /*
2 * Copyright (c) 2000-2005 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_COPYRIGHT@
24 */
25 /*
26 * @APPLE_FREE_COPYRIGHT@
27 */
28 /*
29 * Mach Operating System
30 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
31 * All Rights Reserved.
32 *
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
38 *
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
42 *
43 * Carnegie Mellon requests users of this software to return to
44 *
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
49 *
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
52 */
53 /*
54 */
55 /*
56 * File: scc_8530_hdw.c
57 * Author: Alessandro Forin, Carnegie Mellon University
58 * Date: 6/91
59 *
60 * Hardware-level operations for the SCC Serial Line Driver
61 */
62
63 #define NSCC 1 /* Number of serial chips, two ports per chip. */
64 #if NSCC > 0
65
66 #include <mach_kdb.h>
67 #include <platforms.h>
68 #include <kern/spl.h>
69 #include <mach/std_types.h>
70 #include <types.h>
71 #include <sys/syslog.h>
72 #include <kern/thread.h>
73 #include <ppc/misc_protos.h>
74 #include <ppc/proc_reg.h>
75 #include <ppc/exception.h>
76 #include <ppc/Firmware.h>
77 #include <ppc/serial_io.h>
78 #include <ppc/scc_8530.h>
79
80 #if MACH_KDB
81 #include <machine/db_machdep.h>
82 #endif /* MACH_KDB */
83
84 #define kdebug_state() (1)
85 #define delay(x) { volatile int _d_; for (_d_ = 0; _d_ < (10000*x); _d_++) ; }
86
87 #define NSCC_LINE 2 /* 2 ttys per chip */
88
89 #define SCC_DMA_TRANSFERS 0
90
91 struct scc_tty scc_tty[NSCC_LINE];
92
93 #define scc_tty_for(chan) (&scc_tty[chan])
94 /* #define scc_unit(dev_no) (dev_no) */
95
96 #define scc_dev_no(chan) ((chan)^0x01)
97 #define scc_chan(dev_no) ((dev_no)^0x01)
98
99 extern unsigned int disableSerialOuput;
100
101 int serial_initted = 0;
102 unsigned int scc_parm_done = 0;
103
104 extern unsigned int serialmode;
105
106 static struct scc_byte {
107 unsigned char reg;
108 unsigned char val;
109 } scc_init_hw[] = {
110
111 9, 0x80,
112 4, 0x44,
113 3, 0xC0,
114 5, 0xE2,
115 2, 0x00,
116 10, 0x00,
117 11, 0x50,
118 12, 0x0A,
119 13, 0x00,
120 3, 0xC1,
121 5, 0xEA,
122 14, 0x01,
123 15, 0x00,
124 0, 0x10,
125 0, 0x10,
126 #if 0
127 1, 0x12, /* int or Rx, Tx int enable */
128 #else
129 1, 0x10, /* int or Rx, no Tx int enable */
130 #endif
131 9, 0x0A
132 };
133
134 static int scc_init_hw_count = sizeof(scc_init_hw)/sizeof(scc_init_hw[0]);
135
136 enum scc_error {SCC_ERR_NONE, SCC_ERR_PARITY, SCC_ERR_BREAK, SCC_ERR_OVERRUN};
137
138
139 /*
140 * BRG formula is:
141 * ClockFrequency (115200 for Power Mac)
142 * BRGconstant = --------------------------- - 2
143 * BaudRate
144 */
145
146 #define SERIAL_CLOCK_FREQUENCY (115200*2) /* Power Mac value */
147 #define convert_baud_rate(rate) ((((SERIAL_CLOCK_FREQUENCY) + (rate)) / (2 * (rate))) - 2)
148
149 #define DEFAULT_SPEED 57600
150 #define DEFAULT_PORT0_SPEED 1200
151 #define DEFAULT_FLAGS (TF_LITOUT|TF_ECHO)
152
153 int scc_param(struct scc_tty *tp);
154
155
156 struct scc_softc scc_softc[NSCC];
157 caddr_t scc_std[NSCC] = { (caddr_t) 0};
158
159
160 #define SCC_RR1_ERRS (SCC_RR1_FRAME_ERR|SCC_RR1_RX_OVERRUN|SCC_RR1_PARITY_ERR)
161 #define SCC_RR3_ALL (SCC_RR3_RX_IP_A|SCC_RR3_TX_IP_A|SCC_RR3_EXT_IP_A|\
162 SCC_RR3_RX_IP_B|SCC_RR3_TX_IP_B|SCC_RR3_EXT_IP_B)
163
164 #define DEBUG_SCC
165 #undef DEBUG_SCC
166
167 #ifdef DEBUG_SCC
168 static int total_chars, total_ints, total_overruns, total_errors, num_ints, max_chars;
169 static int chars_received[8];
170 static int __SCC_STATS = 0;
171 static int max_in_q = 0;
172 static int max_out_q = 0;
173 #endif
174
175 DECL_FUNNEL(, scc_funnel) /* funnel to serialize the SCC driver */
176 boolean_t scc_funnel_initted = FALSE;
177 #define SCC_FUNNEL scc_funnel
178 #define SCC_FUNNEL_INITTED scc_funnel_initted
179
180
181 /*
182 * Adapt/Probe/Attach functions
183 */
184 boolean_t scc_uses_modem_control = FALSE;/* patch this with adb */
185 decl_simple_lock_data(,scc_stomp)
186
187 /* This is called VERY early on in the init and therefore has to have
188 * hardcoded addresses of the serial hardware control registers. The
189 * serial line may be needed for console and debugging output before
190 * anything else takes place
191 */
192
193 void
194 initialize_serial( caddr_t scc_phys_base, int32_t serial_baud )
195 {
196 int i, chan, bits;
197 scc_regmap_t regs;
198 DECL_FUNNEL_VARS
199
200 assert( scc_phys_base );
201
202 if (!SCC_FUNNEL_INITTED) {
203 FUNNEL_INIT(&SCC_FUNNEL, master_processor);
204 SCC_FUNNEL_INITTED = TRUE;
205 }
206 FUNNEL_ENTER(&SCC_FUNNEL);
207
208 if (serial_initted) {
209 FUNNEL_EXIT(&SCC_FUNNEL);
210 return;
211 }
212
213 simple_lock_init(&scc_stomp, FALSE);
214
215 if (serial_baud == -1) serial_baud = DEFAULT_SPEED;
216
217 scc_softc[0].full_modem = TRUE;
218
219 scc_std[0] = scc_phys_base;
220
221 regs = scc_softc[0].regs = (scc_regmap_t)scc_std[0];
222
223 for (chan = 0; chan < NSCC_LINE; chan++) {
224 if (chan == 1)
225 scc_init_hw[0].val = 0x80;
226
227 for (i = 0; i < scc_init_hw_count; i++) {
228 scc_write_reg(regs, chan,
229 scc_init_hw[i].reg, scc_init_hw[i].val);
230 }
231 }
232
233 /* Call probe so we are ready very early for remote gdb and for serial
234 console output if appropriate. */
235 if (scc_probe(serial_baud)) {
236 for (i = 0; i < NSCC_LINE; i++) {
237 scc_softc[0].softr[i].wr5 = SCC_WR5_DTR | SCC_WR5_RTS;
238 scc_param(scc_tty_for(i));
239 /* Enable SCC interrupts (how many interrupts are to this thing?!?) */
240 scc_write_reg(regs, i, 9, SCC_WR9_NV);
241
242 scc_read_reg_zero(regs, 0, bits);/* Clear the status */
243 }
244 scc_parm_done = 1;
245 }
246
247 serial_initted = TRUE;
248
249 FUNNEL_EXIT(&SCC_FUNNEL);
250 return;
251 }
252
253 int
254 scc_probe(int32_t serial_baud)
255 {
256 scc_softc_t scc;
257 register int val, i;
258 register scc_regmap_t regs;
259 spl_t s;
260 DECL_FUNNEL_VARS
261
262 if (!SCC_FUNNEL_INITTED) {
263 FUNNEL_INIT(&SCC_FUNNEL, master_processor);
264 SCC_FUNNEL_INITTED = TRUE;
265 }
266 FUNNEL_ENTER(&SCC_FUNNEL);
267
268 /* Readjust the I/O address to handling
269 * new memory mappings.
270 */
271
272 regs = (scc_regmap_t)scc_std[0];
273
274 if (regs == (scc_regmap_t) 0) {
275 FUNNEL_EXIT(&SCC_FUNNEL);
276 return 0;
277 }
278
279 scc = &scc_softc[0];
280 scc->regs = regs;
281
282 s = splhigh();
283
284 for (i = 0; i < NSCC_LINE; i++) {
285 register struct scc_tty *tp;
286 tp = scc_tty_for(i);
287 tp->t_addr = (char*)(0x80000000L + (i&1));
288 /* Set default values. These will be overridden on
289 open but are needed if the port will be used
290 independently of the Mach interfaces, e.g., for
291 gdb or for a serial console. */
292 if (i == 0) {
293 tp->t_ispeed = DEFAULT_PORT0_SPEED;
294 tp->t_ospeed = DEFAULT_PORT0_SPEED;
295 } else {
296 tp->t_ispeed = serial_baud;
297 tp->t_ospeed = serial_baud;
298 }
299 tp->t_flags = DEFAULT_FLAGS;
300 scc->softr[i].speed = -1;
301
302 /* do min buffering */
303 tp->t_state |= TS_MIN;
304
305 tp->t_dev = scc_dev_no(i);
306 }
307
308 splx(s);
309
310 FUNNEL_EXIT(&SCC_FUNNEL);
311 return 1;
312 }
313
314 /*
315 * Get a char from a specific SCC line
316 * [this is only used for console&screen purposes]
317 * must be splhigh since it may be called from another routine under spl
318 */
319
320 int
321 scc_getc(int unit, int line, boolean_t wait, boolean_t raw)
322 {
323 register scc_regmap_t regs;
324 unsigned char c, value;
325 int rcvalue, from_line;
326 uint32_t fcrmunge;
327 spl_t s = splhigh();
328 DECL_FUNNEL_VARS
329
330 FUNNEL_ENTER(&SCC_FUNNEL);
331
332
333 simple_lock(&scc_stomp);
334 regs = scc_softc[0].regs;
335
336 /*
337 * wait till something available
338 *
339 */
340 again:
341 rcvalue = 0;
342 while (1) {
343 scc_read_reg_zero(regs, line, value);
344
345 if (value & SCC_RR0_RX_AVAIL)
346 break;
347
348 if (!wait) {
349 simple_unlock(&scc_stomp);
350 splx(s);
351 FUNNEL_EXIT(&SCC_FUNNEL);
352 return -1;
353 }
354 }
355
356 /*
357 * if nothing found return -1
358 */
359
360 scc_read_reg(regs, line, SCC_RR1, value);
361 scc_read_data(regs, line, c);
362
363 #if MACH_KDB
364 if (console_is_serial() &&
365 c == ('_' & 0x1f)) {
366 /* Drop into the debugger */
367 simple_unlock(&scc_stomp);
368 Debugger("Serial Line Request");
369 simple_lock(&scc_stomp);
370 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_HIGHEST_IUS);
371 if (wait) {
372 goto again;
373 }
374 simple_unlock(&scc_stomp);
375 splx(s);
376 FUNNEL_EXIT(&SCC_FUNNEL);
377 return -1;
378 }
379 #endif /* MACH_KDB */
380
381 /*
382 * bad chars not ok
383 */
384 if (value&(SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN | SCC_RR1_FRAME_ERR)) {
385 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_ERROR);
386
387 if (wait) {
388 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_HIGHEST_IUS);
389 goto again;
390 }
391 }
392
393 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_HIGHEST_IUS);
394
395 simple_unlock(&scc_stomp);
396 splx(s);
397
398 FUNNEL_EXIT(&SCC_FUNNEL);
399 return c;
400 }
401
402 /*
403 * Put a char on a specific SCC line
404 * use splhigh since we might be doing a printf in high spl'd code
405 */
406
407 int
408 scc_putc(int unit, int line, int c)
409 {
410 scc_regmap_t regs;
411 spl_t s;
412 unsigned char value;
413 uint32_t fcrmunge;
414 DECL_FUNNEL_VARS
415
416
417 if (disableSerialOuput)
418 return 0;
419
420 s = splhigh();
421 FUNNEL_ENTER(&SCC_FUNNEL);
422 simple_lock(&scc_stomp);
423
424 regs = scc_softc[0].regs;
425
426 do {
427 scc_read_reg(regs, line, SCC_RR0, value);
428 if (value & SCC_RR0_TX_EMPTY)
429 break;
430 delay(1);
431 } while (1);
432
433 scc_write_data(regs, line, c);
434 /* wait for it to swallow the char ? */
435
436 do {
437 scc_read_reg(regs, line, SCC_RR0, value);
438 if (value & SCC_RR0_TX_EMPTY)
439 break;
440 } while (1);
441 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_HIGHEST_IUS);
442 simple_unlock(&scc_stomp);
443
444 splx(s);
445
446 FUNNEL_EXIT(&SCC_FUNNEL);
447 return 0;
448 }
449
450
451 void
452 powermac_scc_set_datum(scc_regmap_t regs, unsigned int offset, unsigned char value)
453 {
454 volatile unsigned char *address = (unsigned char *) regs + offset;
455
456 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
457
458 *address = value;
459 eieio();
460
461 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
462 }
463
464 unsigned char
465 powermac_scc_get_datum(scc_regmap_t regs, unsigned int offset)
466 {
467 volatile unsigned char *address = (unsigned char *) regs + offset;
468 unsigned char value;
469
470 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
471
472 value = *address; eieio();
473 return value;
474
475 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
476 }
477
478 int
479 scc_param(struct scc_tty *tp)
480 {
481 scc_regmap_t regs;
482 unsigned char value;
483 unsigned short speed_value;
484 int bits, chan;
485 spl_t s;
486 struct scc_softreg *sr;
487 scc_softc_t scc;
488
489 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
490
491 s = splhigh();
492 simple_lock(&scc_stomp);
493
494 chan = scc_chan(tp->t_dev);
495 scc = &scc_softc[0];
496 regs = scc->regs;
497
498 sr = &scc->softr[chan];
499
500 /* Do a quick check to see if the hardware needs to change */
501 if ((sr->flags & (TF_ODDP|TF_EVENP)) == (tp->t_flags & (TF_ODDP|TF_EVENP))
502 && sr->speed == tp->t_ispeed) {
503 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
504 simple_unlock(&scc_stomp);
505 splx(s);
506 return 0;
507 }
508
509 if(scc_parm_done) {
510
511 scc_write_reg(regs, chan, 3, SCC_WR3_RX_8_BITS|SCC_WR3_RX_ENABLE);
512 sr->wr1 = SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_EXT_IE;
513 scc_write_reg(regs, chan, 1, sr->wr1);
514 scc_write_reg(regs, chan, 15, SCC_WR15_ENABLE_ESCC);
515 scc_write_reg(regs, chan, 7, SCC_WR7P_RX_FIFO);
516 scc_write_reg(regs, chan, 0, SCC_IE_NEXT_CHAR);
517 scc_write_reg(regs, chan, 0, SCC_RESET_EXT_IP);
518 scc_write_reg(regs, chan, 0, SCC_RESET_EXT_IP);
519 scc_write_reg(regs, chan, 9, SCC_WR9_MASTER_IE|SCC_WR9_NV);
520 scc_read_reg_zero(regs, 0, bits);
521 sr->wr1 = SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_EXT_IE;
522 scc_write_reg(regs, chan, 1, sr->wr1);
523 scc_write_reg(regs, chan, 0, SCC_IE_NEXT_CHAR);
524 simple_unlock(&scc_stomp);
525 splx(s);
526 return 0;
527 }
528
529 sr->flags = tp->t_flags;
530 sr->speed = tp->t_ispeed;
531
532
533 if (tp->t_ispeed == 0) {
534 sr->wr5 &= ~SCC_WR5_DTR;
535 scc_write_reg(regs, chan, 5, sr->wr5);
536 simple_unlock(&scc_stomp);
537 splx(s);
538
539 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
540 return 0;
541 }
542
543
544 #if SCC_DMA_TRANSFERS
545 if (scc->dma_initted & (1<<chan))
546 scc->dma_ops->scc_dma_reset_rx(chan);
547 #endif
548
549 value = SCC_WR4_1_STOP;
550
551 /*
552 * For 115K the clocking divide changes to 64.. to 230K will
553 * start at the normal clock divide 16.
554 *
555 * However, both speeds will pull from a different clocking
556 * source
557 */
558
559 if (tp->t_ispeed == 115200)
560 value |= SCC_WR4_CLK_x32;
561 else
562 value |= SCC_WR4_CLK_x16 ;
563
564 /* .. and parity */
565 if ((tp->t_flags & (TF_ODDP | TF_EVENP)) == TF_EVENP)
566 value |= (SCC_WR4_EVEN_PARITY | SCC_WR4_PARITY_ENABLE);
567 else if ((tp->t_flags & (TF_ODDP | TF_EVENP)) == TF_ODDP)
568 value |= SCC_WR4_PARITY_ENABLE;
569
570 /* set it now, remember it must be first after reset */
571 sr->wr4 = value;
572
573 /* Program Parity, and Stop bits */
574 scc_write_reg(regs, chan, 4, sr->wr4);
575
576 /* Setup for 8 bits */
577 scc_write_reg(regs, chan, 3, SCC_WR3_RX_8_BITS);
578
579 // Set DTR, RTS, and transmitter bits/character.
580 sr->wr5 = SCC_WR5_TX_8_BITS | SCC_WR5_RTS | SCC_WR5_DTR;
581
582 scc_write_reg(regs, chan, 5, sr->wr5);
583
584 scc_write_reg(regs, chan, 14, 0); /* Disable baud rate */
585
586 /* Setup baud rate 57.6Kbps, 115K, 230K should all yeild
587 * a converted baud rate of zero
588 */
589 speed_value = convert_baud_rate(tp->t_ispeed);
590
591 if (speed_value == 0xffff)
592 speed_value = 0;
593
594 scc_set_timing_base(regs, chan, speed_value);
595
596 if (tp->t_ispeed == 115200 || tp->t_ispeed == 230400) {
597 /* Special case here.. change the clock source*/
598 scc_write_reg(regs, chan, 11, 0);
599 /* Baud rate generator is disabled.. */
600 } else {
601 scc_write_reg(regs, chan, 11, SCC_WR11_RCLK_BAUDR|SCC_WR11_XTLK_BAUDR);
602 /* Enable the baud rate generator */
603 scc_write_reg(regs, chan, 14, SCC_WR14_BAUDR_ENABLE);
604 }
605
606
607 scc_write_reg(regs, chan, 3, SCC_WR3_RX_8_BITS|SCC_WR3_RX_ENABLE);
608
609
610 sr->wr1 = SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_EXT_IE;
611 scc_write_reg(regs, chan, 1, sr->wr1);
612 scc_write_reg(regs, chan, 15, SCC_WR15_ENABLE_ESCC);
613 scc_write_reg(regs, chan, 7, SCC_WR7P_RX_FIFO);
614 scc_write_reg(regs, chan, 0, SCC_IE_NEXT_CHAR);
615
616
617 /* Clear out any pending external or status interrupts */
618 scc_write_reg(regs, chan, 0, SCC_RESET_EXT_IP);
619 scc_write_reg(regs, chan, 0, SCC_RESET_EXT_IP);
620 //scc_write_reg(regs, chan, 0, SCC_RESET_ERROR);
621
622 /* Enable SCC interrupts (how many interrupts are to this thing?!?) */
623 scc_write_reg(regs, chan, 9, SCC_WR9_MASTER_IE|SCC_WR9_NV);
624
625 scc_read_reg_zero(regs, 0, bits);/* Clear the status */
626
627 #if SCC_DMA_TRANSFERS
628 if (scc->dma_initted & (1<<chan)) {
629 scc->dma_ops->scc_dma_start_rx(chan);
630 scc->dma_ops->scc_dma_setup_8530(chan);
631 } else
632 #endif
633 {
634 sr->wr1 = SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_EXT_IE;
635 scc_write_reg(regs, chan, 1, sr->wr1);
636 scc_write_reg(regs, chan, 0, SCC_IE_NEXT_CHAR);
637 }
638
639 sr->wr5 |= SCC_WR5_TX_ENABLE;
640 scc_write_reg(regs, chan, 5, sr->wr5);
641
642 simple_unlock(&scc_stomp);
643 splx(s);
644
645 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
646 return 0;
647
648 }
649
650 /*
651 * This routine will start a thread that polls the serial port, listening for
652 * characters that have been typed.
653 */
654
655 void
656 serial_keyboard_init(void)
657 {
658 kern_return_t result;
659 thread_t thread;
660
661 if(!(serialmode & 2)) return; /* Leave if we do not want a serial console */
662
663 kprintf("Serial keyboard started\n");
664 result = kernel_thread_start_priority((thread_continue_t)serial_keyboard_start, NULL, MAXPRI_KERNEL, &thread);
665 if (result != KERN_SUCCESS)
666 panic("serial_keyboard_init");
667
668 thread_deallocate(thread);
669 }
670
671 void
672 serial_keyboard_start(void)
673 {
674 serial_keyboard_poll(); /* Go see if there are any characters pending now */
675 panic("serial_keyboard_start: we can't get back here\n");
676 }
677
678 static int ptestxxx = 0;
679
680 void
681 serial_keyboard_poll(void)
682 {
683 int chr;
684 uint64_t next;
685 extern void cons_cinput(char ch); /* The BSD routine that gets characters */
686
687
688 while(1) { /* Do this for a while */
689 chr = scc_getc(0, 1, 0, 1); /* Get a character if there is one */
690 if(chr < 0) break; /* The serial buffer is empty */
691 cons_cinput((char)chr); /* Buffer up the character */
692 }
693
694 clock_interval_to_deadline(16, 1000000, &next); /* Get time of pop */
695
696 assert_wait_deadline((event_t)serial_keyboard_poll, THREAD_UNINT, next); /* Show we are "waiting" */
697 thread_block((thread_continue_t)serial_keyboard_poll); /* Wait for it */
698 panic("serial_keyboard_poll: Shouldn't never ever get here...\n");
699 }
700
701 #endif /* NSCC > 0 */