]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/serial_io.c
xnu-792.2.4.tar.gz
[apple/xnu.git] / osfmk / ppc / serial_io.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
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.
1c79356b 11 *
e5568f75
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
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.
1c79356b
A
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>
91447636 72#include <kern/thread.h>
1c79356b
A
73#include <ppc/misc_protos.h>
74#include <ppc/proc_reg.h>
75#include <ppc/exception.h>
76#include <ppc/Firmware.h>
55e303ae
A
77#include <ppc/serial_io.h>
78#include <ppc/scc_8530.h>
1c79356b
A
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
91struct 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
d7e50217
A
99extern unsigned int disableSerialOuput;
100
1c79356b 101int serial_initted = 0;
de355530 102unsigned int scc_parm_done = 0; /* (TEST/DEBUG) */
1c79356b 103
55e303ae
A
104extern unsigned int serialmode;
105
1c79356b
A
106static 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
134static int scc_init_hw_count = sizeof(scc_init_hw)/sizeof(scc_init_hw[0]);
135
136enum 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 */
de355530 145
1c79356b
A
146#define SERIAL_CLOCK_FREQUENCY (115200*2) /* Power Mac value */
147#define convert_baud_rate(rate) ((((SERIAL_CLOCK_FREQUENCY) + (rate)) / (2 * (rate))) - 2)
148
0b4e3aa0 149#define DEFAULT_SPEED 57600
55e303ae 150#define DEFAULT_PORT0_SPEED 1200
1c79356b
A
151#define DEFAULT_FLAGS (TF_LITOUT|TF_ECHO)
152
153int scc_param(struct scc_tty *tp);
154
de355530 155
1c79356b
A
156struct scc_softc scc_softc[NSCC];
157caddr_t scc_std[NSCC] = { (caddr_t) 0};
158
de355530
A
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
168static int total_chars, total_ints, total_overruns, total_errors, num_ints, max_chars;
169static int chars_received[8];
170static int __SCC_STATS = 0;
171static int max_in_q = 0;
172static int max_out_q = 0;
173#endif
174
175DECL_FUNNEL(, scc_funnel) /* funnel to serialize the SCC driver */
176boolean_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 */
184boolean_t scc_uses_modem_control = FALSE;/* patch this with adb */
185decl_simple_lock_data(,scc_stomp) /* (TEST/DEBUG) */
1c79356b
A
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
193void
91447636 194initialize_serial( caddr_t scc_phys_base, int32_t serial_baud )
1c79356b
A
195{
196 int i, chan, bits;
197 scc_regmap_t regs;
de355530 198 DECL_FUNNEL_VARS
1c79356b
A
199
200 assert( scc_phys_base );
201
de355530
A
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);
1c79356b 210 return;
de355530 211 }
1c79356b 212
de355530 213 simple_lock_init(&scc_stomp, FALSE); /* (TEST/DEBUG) */
1c79356b 214
91447636
A
215 if (serial_baud == -1) serial_baud = DEFAULT_SPEED;
216
1c79356b
A
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. */
91447636 235 if (scc_probe(serial_baud)) {
1c79356b
A
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 }
de355530 244 scc_parm_done = 1; /* (TEST/DEBUG) */
1c79356b
A
245 }
246
247 serial_initted = TRUE;
de355530
A
248
249 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b
A
250 return;
251}
252
253int
91447636 254scc_probe(int32_t serial_baud)
1c79356b
A
255{
256 scc_softc_t scc;
257 register int val, i;
258 register scc_regmap_t regs;
259 spl_t s;
de355530
A
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
1c79356b
A
272 regs = (scc_regmap_t)scc_std[0];
273
de355530
A
274 if (regs == (scc_regmap_t) 0) {
275 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b 276 return 0;
de355530 277 }
1c79356b
A
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. */
55e303ae
A
292 if (i == 0) {
293 tp->t_ispeed = DEFAULT_PORT0_SPEED;
294 tp->t_ospeed = DEFAULT_PORT0_SPEED;
295 } else {
91447636
A
296 tp->t_ispeed = serial_baud;
297 tp->t_ospeed = serial_baud;
55e303ae 298 }
1c79356b
A
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);
de355530
A
309
310 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b
A
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
320int
321scc_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 spl_t s = splhigh();
de355530 327 DECL_FUNNEL_VARS
1c79356b 328
de355530
A
329 FUNNEL_ENTER(&SCC_FUNNEL);
330
331 simple_lock(&scc_stomp); /* (TEST/DEBUG) */
1c79356b
A
332 regs = scc_softc[0].regs;
333
334 /*
335 * wait till something available
de355530 336 *
1c79356b
A
337 */
338again:
339 rcvalue = 0;
340 while (1) {
341 scc_read_reg_zero(regs, line, value);
342
343 if (value & SCC_RR0_RX_AVAIL)
344 break;
345
346 if (!wait) {
de355530 347 simple_unlock(&scc_stomp); /* (TEST/DEBUG) */
1c79356b 348 splx(s);
de355530 349 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b
A
350 return -1;
351 }
352 }
353
354 /*
355 * if nothing found return -1
356 */
357
358 scc_read_reg(regs, line, SCC_RR1, value);
359 scc_read_data(regs, line, c);
360
361#if MACH_KDB
362 if (console_is_serial() &&
363 c == ('_' & 0x1f)) {
364 /* Drop into the debugger */
de355530 365 simple_unlock(&scc_stomp); /* (TEST/DEBUG) */
1c79356b 366 Debugger("Serial Line Request");
de355530 367 simple_lock(&scc_stomp); /* (TEST/DEBUG) */
1c79356b
A
368 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_HIGHEST_IUS);
369 if (wait) {
370 goto again;
371 }
de355530 372 simple_unlock(&scc_stomp); /* (TEST/DEBUG) */
1c79356b 373 splx(s);
de355530 374 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b
A
375 return -1;
376 }
377#endif /* MACH_KDB */
378
379 /*
380 * bad chars not ok
381 */
382 if (value&(SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN | SCC_RR1_FRAME_ERR)) {
383 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_ERROR);
384
385 if (wait) {
386 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_HIGHEST_IUS);
387 goto again;
388 }
389 }
de355530 390
1c79356b
A
391 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_HIGHEST_IUS);
392
de355530 393 simple_unlock(&scc_stomp); /* (TEST/DEBUG) */
1c79356b 394 splx(s);
de355530
A
395
396 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b
A
397 return c;
398}
399
400/*
401 * Put a char on a specific SCC line
402 * use splhigh since we might be doing a printf in high spl'd code
403 */
404
405int
406scc_putc(int unit, int line, int c)
407{
408 scc_regmap_t regs;
d7e50217 409 spl_t s;
1c79356b 410 unsigned char value;
de355530 411 DECL_FUNNEL_VARS
1c79356b 412
d7e50217
A
413 if (disableSerialOuput)
414 return 0;
415
416 s = splhigh();
de355530
A
417 FUNNEL_ENTER(&SCC_FUNNEL);
418 simple_lock(&scc_stomp); /* (TEST/DEBUG) */
1c79356b
A
419
420 regs = scc_softc[0].regs;
421
422 do {
423 scc_read_reg(regs, line, SCC_RR0, value);
424 if (value & SCC_RR0_TX_EMPTY)
425 break;
426 delay(1);
427 } while (1);
428
429 scc_write_data(regs, line, c);
430/* wait for it to swallow the char ? */
431
432 do {
433 scc_read_reg(regs, line, SCC_RR0, value);
434 if (value & SCC_RR0_TX_EMPTY)
435 break;
436 } while (1);
437 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_HIGHEST_IUS);
de355530 438 simple_unlock(&scc_stomp); /* (TEST/DEBUG) */
1c79356b
A
439
440 splx(s);
de355530
A
441
442 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b
A
443 return 0;
444}
445
446
447void
448powermac_scc_set_datum(scc_regmap_t regs, unsigned int offset, unsigned char value)
449{
450 volatile unsigned char *address = (unsigned char *) regs + offset;
451
de355530
A
452 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
453
1c79356b
A
454 *address = value;
455 eieio();
de355530
A
456
457 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
1c79356b
A
458}
459
460unsigned char
461powermac_scc_get_datum(scc_regmap_t regs, unsigned int offset)
462{
463 volatile unsigned char *address = (unsigned char *) regs + offset;
464 unsigned char value;
465
de355530
A
466 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
467
468 value = *address; eieio();
1c79356b 469 return value;
de355530
A
470
471 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
1c79356b
A
472}
473
474int
475scc_param(struct scc_tty *tp)
476{
477 scc_regmap_t regs;
478 unsigned char value;
479 unsigned short speed_value;
480 int bits, chan;
481 spl_t s;
482 struct scc_softreg *sr;
483 scc_softc_t scc;
484
de355530
A
485 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
486
1c79356b 487 s = splhigh();
de355530 488 simple_lock(&scc_stomp); /* (TEST/DEBUG) */
1c79356b
A
489
490 chan = scc_chan(tp->t_dev);
491 scc = &scc_softc[0];
492 regs = scc->regs;
493
494 sr = &scc->softr[chan];
495
496 /* Do a quick check to see if the hardware needs to change */
497 if ((sr->flags & (TF_ODDP|TF_EVENP)) == (tp->t_flags & (TF_ODDP|TF_EVENP))
498 && sr->speed == tp->t_ispeed) {
de355530
A
499 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
500 simple_unlock(&scc_stomp); /* (TEST/DEBUG) */
501 splx(s); /* (TEST/DEBUG) */
502 return 0; /* (TEST/DEBUG) */
1c79356b
A
503 }
504
505 if(scc_parm_done) {
506
de355530
A
507 scc_write_reg(regs, chan, 3, SCC_WR3_RX_8_BITS|SCC_WR3_RX_ENABLE); /* (TEST/DEBUG) */
508 sr->wr1 = SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_EXT_IE; /* (TEST/DEBUG) */
509 scc_write_reg(regs, chan, 1, sr->wr1); /* (TEST/DEBUG) */
510 scc_write_reg(regs, chan, 15, SCC_WR15_ENABLE_ESCC); /* (TEST/DEBUG) */
511 scc_write_reg(regs, chan, 7, SCC_WR7P_RX_FIFO); /* (TEST/DEBUG) */
512 scc_write_reg(regs, chan, 0, SCC_IE_NEXT_CHAR); /* (TEST/DEBUG) */
513 scc_write_reg(regs, chan, 0, SCC_RESET_EXT_IP); /* (TEST/DEBUG) */
514 scc_write_reg(regs, chan, 0, SCC_RESET_EXT_IP); /* (TEST/DEBUG) */
515 scc_write_reg(regs, chan, 9, SCC_WR9_MASTER_IE|SCC_WR9_NV); /* (TEST/DEBUG) */
516 scc_read_reg_zero(regs, 0, bits); /* (TEST/DEBUG) */
517 sr->wr1 = SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_EXT_IE; /* (TEST/DEBUG) */
518 scc_write_reg(regs, chan, 1, sr->wr1); /* (TEST/DEBUG) */
519 scc_write_reg(regs, chan, 0, SCC_IE_NEXT_CHAR); /* (TEST/DEBUG) */
520 simple_unlock(&scc_stomp); /* (TEST/DEBUG) */
521 splx(s); /* (TEST/DEBUG) */
522 return 0; /* (TEST/DEBUG) */
1c79356b
A
523 }
524
525 sr->flags = tp->t_flags;
526 sr->speed = tp->t_ispeed;
527
528
529 if (tp->t_ispeed == 0) {
530 sr->wr5 &= ~SCC_WR5_DTR;
531 scc_write_reg(regs, chan, 5, sr->wr5);
de355530 532 simple_unlock(&scc_stomp); /* (TEST/DEBUG) */
1c79356b 533 splx(s);
de355530
A
534
535 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
1c79356b
A
536 return 0;
537 }
538
539
540#if SCC_DMA_TRANSFERS
541 if (scc->dma_initted & (1<<chan))
542 scc->dma_ops->scc_dma_reset_rx(chan);
543#endif
544
545 value = SCC_WR4_1_STOP;
546
547 /*
548 * For 115K the clocking divide changes to 64.. to 230K will
549 * start at the normal clock divide 16.
550 *
551 * However, both speeds will pull from a different clocking
552 * source
553 */
554
555 if (tp->t_ispeed == 115200)
556 value |= SCC_WR4_CLK_x32;
557 else
558 value |= SCC_WR4_CLK_x16 ;
559
560 /* .. and parity */
561 if ((tp->t_flags & (TF_ODDP | TF_EVENP)) == TF_EVENP)
562 value |= (SCC_WR4_EVEN_PARITY | SCC_WR4_PARITY_ENABLE);
563 else if ((tp->t_flags & (TF_ODDP | TF_EVENP)) == TF_ODDP)
564 value |= SCC_WR4_PARITY_ENABLE;
565
566 /* set it now, remember it must be first after reset */
567 sr->wr4 = value;
568
569 /* Program Parity, and Stop bits */
570 scc_write_reg(regs, chan, 4, sr->wr4);
571
572 /* Setup for 8 bits */
573 scc_write_reg(regs, chan, 3, SCC_WR3_RX_8_BITS);
574
575 // Set DTR, RTS, and transmitter bits/character.
576 sr->wr5 = SCC_WR5_TX_8_BITS | SCC_WR5_RTS | SCC_WR5_DTR;
577
578 scc_write_reg(regs, chan, 5, sr->wr5);
579
580 scc_write_reg(regs, chan, 14, 0); /* Disable baud rate */
581
582 /* Setup baud rate 57.6Kbps, 115K, 230K should all yeild
583 * a converted baud rate of zero
584 */
585 speed_value = convert_baud_rate(tp->t_ispeed);
586
587 if (speed_value == 0xffff)
588 speed_value = 0;
589
590 scc_set_timing_base(regs, chan, speed_value);
591
592 if (tp->t_ispeed == 115200 || tp->t_ispeed == 230400) {
593 /* Special case here.. change the clock source*/
594 scc_write_reg(regs, chan, 11, 0);
595 /* Baud rate generator is disabled.. */
596 } else {
597 scc_write_reg(regs, chan, 11, SCC_WR11_RCLK_BAUDR|SCC_WR11_XTLK_BAUDR);
598 /* Enable the baud rate generator */
599 scc_write_reg(regs, chan, 14, SCC_WR14_BAUDR_ENABLE);
600 }
601
602
603 scc_write_reg(regs, chan, 3, SCC_WR3_RX_8_BITS|SCC_WR3_RX_ENABLE);
604
605
606 sr->wr1 = SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_EXT_IE;
607 scc_write_reg(regs, chan, 1, sr->wr1);
608 scc_write_reg(regs, chan, 15, SCC_WR15_ENABLE_ESCC);
609 scc_write_reg(regs, chan, 7, SCC_WR7P_RX_FIFO);
610 scc_write_reg(regs, chan, 0, SCC_IE_NEXT_CHAR);
611
612
613 /* Clear out any pending external or status interrupts */
614 scc_write_reg(regs, chan, 0, SCC_RESET_EXT_IP);
615 scc_write_reg(regs, chan, 0, SCC_RESET_EXT_IP);
616 //scc_write_reg(regs, chan, 0, SCC_RESET_ERROR);
617
618 /* Enable SCC interrupts (how many interrupts are to this thing?!?) */
619 scc_write_reg(regs, chan, 9, SCC_WR9_MASTER_IE|SCC_WR9_NV);
620
621 scc_read_reg_zero(regs, 0, bits);/* Clear the status */
622
623#if SCC_DMA_TRANSFERS
624 if (scc->dma_initted & (1<<chan)) {
625 scc->dma_ops->scc_dma_start_rx(chan);
626 scc->dma_ops->scc_dma_setup_8530(chan);
627 } else
628#endif
629 {
630 sr->wr1 = SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_EXT_IE;
631 scc_write_reg(regs, chan, 1, sr->wr1);
632 scc_write_reg(regs, chan, 0, SCC_IE_NEXT_CHAR);
633 }
634
635 sr->wr5 |= SCC_WR5_TX_ENABLE;
636 scc_write_reg(regs, chan, 5, sr->wr5);
637
de355530 638 simple_unlock(&scc_stomp); /* (TEST/DEBUG) */
1c79356b 639 splx(s);
1c79356b 640
de355530
A
641 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
642 return 0;
d7e50217 643
d7e50217
A
644}
645
55e303ae
A
646/*
647 * This routine will start a thread that polls the serial port, listening for
648 * characters that have been typed.
649 */
650
651void
652serial_keyboard_init(void)
653{
91447636
A
654 kern_return_t result;
655 thread_t thread;
55e303ae
A
656
657 if(!(serialmode & 2)) return; /* Leave if we do not want a serial console */
658
659 kprintf("Serial keyboard started\n");
91447636
A
660 result = kernel_thread_start_priority((thread_continue_t)serial_keyboard_start, NULL, MAXPRI_KERNEL, &thread);
661 if (result != KERN_SUCCESS)
662 panic("serial_keyboard_init");
663
664 thread_deallocate(thread);
55e303ae
A
665}
666
667void
668serial_keyboard_start(void)
669{
55e303ae
A
670 serial_keyboard_poll(); /* Go see if there are any characters pending now */
671 panic("serial_keyboard_start: we can't get back here\n");
672}
673
674void
675serial_keyboard_poll(void)
676{
677 int chr;
678 uint64_t next;
679 extern void cons_cinput(char ch); /* The BSD routine that gets characters */
680
681 while(1) { /* Do this for a while */
682 chr = scc_getc(0, 1, 0, 1); /* Get a character if there is one */
683 if(chr < 0) break; /* The serial buffer is empty */
684 cons_cinput((char)chr); /* Buffer up the character */
685 }
686
687 clock_interval_to_deadline(16, 1000000, &next); /* Get time of pop */
688
91447636
A
689 assert_wait_deadline((event_t)serial_keyboard_poll, THREAD_UNINT, next); /* Show we are "waiting" */
690 thread_block((thread_continue_t)serial_keyboard_poll); /* Wait for it */
55e303ae
A
691 panic("serial_keyboard_poll: Shouldn't never ever get here...\n");
692}
693
1c79356b 694#endif /* NSCC > 0 */