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