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