xlcom.c revision 1.3 1 /* $NetBSD: xlcom.c,v 1.3 2007/10/17 19:54:20 garbled Exp $ */
2
3 /*
4 * Copyright (c) 2006 Jachym Holecek
5 * All rights reserved.
6 *
7 * Written for DFC Design, s.r.o.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: xlcom.c,v 1.3 2007/10/17 19:54:20 garbled Exp $");
34
35 #include "opt_kgdb.h"
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/conf.h>
40 #include <sys/device.h>
41 #include <sys/file.h>
42 #include <sys/ioctl.h>
43 #include <sys/kauth.h>
44 #include <sys/kernel.h>
45 #include <sys/proc.h>
46 #include <sys/tty.h>
47 #include <sys/time.h>
48 #include <sys/syslog.h>
49
50 #if defined(KGDB)
51 #include <sys/kgdb.h>
52 #endif /* KGDB */
53
54 #include <dev/cons.h>
55
56 #include <machine/intr.h>
57 #include <machine/bus.h>
58
59 #include <evbppc/virtex/virtex.h>
60 #include <evbppc/virtex/dev/xcvbusvar.h>
61 #include <evbppc/virtex/dev/xlcomreg.h>
62
63
64 #define XLCOM_UNIT_MASK 0x7f
65 #define XLCOM_DIALOUT_MASK 0x80
66
67 #define UNIT(dev) (minor(dev) & XLCOM_UNIT_MASK)
68 #define DIALOUT(dev) (minor(dev) & XLCOM_DIALOUT_MASK)
69
70 #define XLCOM_CHAR_PE 0x8000 /* Parity error flag */
71 #define XLCOM_CHAR_FE 0x4000 /* Frame error flag */
72 #define next(idx) (void)((idx) = ((idx) + 1) % XLCOM_RXBUF_SIZE)
73
74 #define XLCOM_RXBUF_SIZE 1024
75
76 struct xlcom_softc {
77 struct device sc_dev;
78 struct tty *sc_tty;
79 void *sc_ih;
80
81 bus_space_tag_t sc_iot;
82 bus_space_handle_t sc_ioh;
83
84 /* Deffered execution context. */
85 void *sc_rx_soft;
86 void *sc_tx_soft;
87
88 /* Receive buffer */
89 u_short sc_rbuf[XLCOM_RXBUF_SIZE];
90 volatile u_int sc_rput;
91 volatile u_int sc_rget;
92 volatile u_int sc_ravail;
93
94 /* Transmit buffer */
95 u_char *sc_tba;
96 u_int sc_tbc;
97 };
98
99 static int xlcom_intr(void *);
100 static void xlcom_rx_soft(void *);
101 static void xlcom_tx_soft(void *);
102 static void xlcom_reset(bus_space_tag_t, bus_space_handle_t);
103 static int xlcom_busy_getc(bus_space_tag_t, bus_space_handle_t);
104 static void xlcom_busy_putc(bus_space_tag_t, bus_space_handle_t, int);
105
106 /* System console interface. */
107 static int xlcom_cngetc(dev_t);
108 static void xlcom_cnputc(dev_t, int);
109 void xlcom_cninit(struct consdev *);
110
111 #if defined(KGDB)
112
113 void xlcom_kgdbinit(void);
114 static void xlcom_kgdb_putc(void *, int);
115 static int xlcom_kgdb_getc(void *);
116
117 #endif /* KGDB */
118
119 static struct cnm_state xlcom_cnm_state;
120
121 struct consdev consdev_xlcom = {
122 .cn_probe = nullcnprobe,
123 .cn_init = xlcom_cninit,
124 .cn_getc = xlcom_cngetc,
125 .cn_putc = xlcom_cnputc,
126 .cn_pollc = nullcnpollc,
127 .cn_pri = CN_REMOTE
128 };
129
130 /* Character device. */
131 static dev_type_open(xlcom_open);
132 static dev_type_read(xlcom_read);
133 static dev_type_write(xlcom_write);
134 static dev_type_ioctl(xlcom_ioctl);
135 static dev_type_poll(xlcom_poll);
136 static dev_type_close(xlcom_close);
137
138 static dev_type_tty(xlcom_tty);
139 static dev_type_stop(xlcom_stop);
140
141 const struct cdevsw xlcom_cdevsw = {
142 xlcom_open, xlcom_close, xlcom_read, xlcom_write, xlcom_ioctl,
143 xlcom_stop, xlcom_tty, xlcom_poll, nommap, ttykqfilter, D_TTY
144 };
145
146 extern struct cfdriver xlcom_cd;
147
148 /* Terminal line. */
149 static int xlcom_param(struct tty *, struct termios *);
150 static void xlcom_start(struct tty *);
151
152 /* Generic device. */
153 static void xlcom_attach(struct device *, struct device *, void *);
154
155 CFATTACH_DECL(xlcom, sizeof(struct xlcom_softc),
156 xcvbus_child_match, xlcom_attach, NULL, NULL);
157
158
159 static void
160 xlcom_attach(struct device *parent, struct device *self, void *aux)
161 {
162 struct xcvbus_attach_args *vaa = aux;
163 struct xlcom_softc *sc = (struct xlcom_softc *)self;
164 struct tty *tp;
165 dev_t dev;
166
167 printf(": UartLite serial port\n");
168
169 #if defined(KGDB)
170 /* We don't want to share kgdb port with the user. */
171 if (sc->sc_iot == kgdb_iot && sc->sc_ioh == kgdb_ioh) {
172 printf("%s: already in use by kgdb\n", device_xname(self));
173 return;
174 }
175 #endif /* KGDB */
176
177 if ((sc->sc_ih = intr_establish(vaa->vaa_intr, IST_LEVEL, IPL_SERIAL,
178 xlcom_intr, sc)) == NULL) {
179 printf("%s: could not establish interrupt\n",
180 device_xname(self));
181 return ;
182 }
183
184 dev = makedev(cdevsw_lookup_major(&xlcom_cdevsw), device_unit(self));
185 if (cn_tab == &consdev_xlcom) {
186 cn_init_magic(&xlcom_cnm_state);
187 cn_set_magic("\x23\x2e"); /* #. */
188 cn_tab->cn_dev = dev;
189
190 sc->sc_iot = consdev_iot;
191 sc->sc_ioh = consdev_ioh;
192
193 printf("%s: console\n", sc->sc_dev.dv_xname);
194 } else {
195 sc->sc_iot = vaa->vaa_iot;
196
197 if (bus_space_map(vaa->vaa_iot, vaa->vaa_addr, XLCOM_SIZE, 0,
198 &sc->sc_ioh) != 0) {
199 printf("%s: could not map registers\n",
200 device_xname(self));
201 return ;
202 }
203
204 /* Reset FIFOs. */
205 xlcom_reset(sc->sc_iot, sc->sc_ioh);
206 }
207
208 sc->sc_tbc = 0;
209 sc->sc_tba = NULL;
210
211 sc->sc_rput = sc->sc_rget = 0;
212 sc->sc_ravail = XLCOM_RXBUF_SIZE;
213
214 sc->sc_rx_soft = softintr_establish(IPL_SOFTSERIAL, xlcom_rx_soft, sc);
215 sc->sc_tx_soft = softintr_establish(IPL_SOFTSERIAL, xlcom_tx_soft, sc);
216
217 if (sc->sc_rx_soft == NULL || sc->sc_tx_soft == NULL) {
218 printf("%s: could not establish Rx or Tx softintr\n",
219 sc->sc_dev.dv_xname);
220 return ;
221 }
222
223 tp = ttymalloc();
224 tp->t_dev = dev;
225 tp->t_oproc = xlcom_start;
226 tp->t_param = xlcom_param;
227 tp->t_hwiflow = NULL; /* No HW flow control */
228 tty_attach(tp);
229
230 /* XXX anything else to do for console early? */
231 if (cn_tab == &consdev_xlcom) {
232 /* Before first open, so that we can enter ddb(4). */
233 bus_space_write_4(sc->sc_iot, sc->sc_ioh, XLCOM_CNTL,
234 CNTL_INTR_EN);
235 }
236
237 sc->sc_tty = tp;
238 }
239
240 /*
241 * Misc hooks.
242 */
243 static void
244 xlcom_tx_soft(void *arg)
245 {
246 struct xlcom_softc *sc = (struct xlcom_softc *)arg;
247 struct tty *tp = sc->sc_tty;
248
249 if (tp->t_state & TS_FLUSH)
250 tp->t_state &= ~TS_FLUSH;
251 else
252 ndflush(&tp->t_outq,
253 (int)(sc->sc_tba - tp->t_outq.c_cf));
254 (tp->t_linesw->l_start)(tp);
255 }
256
257 static void
258 xlcom_rx_soft(void *arg)
259 {
260 struct xlcom_softc *sc = (struct xlcom_softc *)arg;
261 struct tty *tp = sc->sc_tty;
262 int (*rint)(int, struct tty *);
263 u_short c;
264 int d;
265
266 /*
267 * XXX: we don't do any synchronization, rput may change below
268 * XXX: our hands -- it doesn't seem to be troublesome as long
269 * XXX: as "sc->sc_rget = sc->sc_rput" is atomic.
270 */
271 rint = tp->t_linesw->l_rint;
272
273 /* Run until we catch our tail. */
274 while (sc->sc_rput != sc->sc_rget) {
275 c = sc->sc_rbuf[sc->sc_rget];
276
277 next(sc->sc_rget);
278 sc->sc_ravail++;
279
280 d = (c & 0xff) |
281 ((c & XLCOM_CHAR_PE) != 0 ? TTY_PE : 0) |
282 ((c & XLCOM_CHAR_FE) != 0 ? TTY_FE : 0);
283
284 /*
285 * Drop the rest of data if discipline runs out of buffer
286 * space. We'd use flow control here, if we had any.
287 */
288 if ((rint)(d, tp) == -1) {
289 sc->sc_rget = sc->sc_rput;
290 return ;
291 }
292 }
293 }
294
295 static void
296 xlcom_send_chunk(struct xlcom_softc *sc)
297 {
298 uint32_t stat;
299
300 /* Chunk flushed, no more data available. */
301 if (sc->sc_tbc <= 0) {
302 return ;
303 }
304
305 /* Run as long as we have space and data. */
306 while (sc->sc_tbc > 0) {
307 stat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, XLCOM_STAT);
308 if (stat & STAT_TX_FULL)
309 break;
310
311 bus_space_write_4(sc->sc_iot, sc->sc_ioh, XLCOM_TX_FIFO,
312 *sc->sc_tba);
313
314 sc->sc_tbc--;
315 sc->sc_tba++;
316 }
317
318 /* Try to grab more data while FIFO drains. */
319 if (sc->sc_tbc == 0) {
320 sc->sc_tty->t_state &= ~TS_BUSY;
321 softintr_schedule(sc->sc_tx_soft);
322 }
323 }
324
325 static void
326 xlcom_recv_chunk(struct xlcom_softc *sc)
327 {
328 uint32_t stat;
329 u_short c;
330 u_int n;
331
332 n = sc->sc_ravail;
333 stat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, XLCOM_STAT);
334
335 /* Run as long as we have data and space. */
336 while ((stat & STAT_RX_DATA) != 0 && sc->sc_ravail > 0) {
337 c = bus_space_read_4(sc->sc_iot, sc->sc_ioh, XLCOM_RX_FIFO);
338
339 cn_check_magic(sc->sc_tty->t_dev, c, xlcom_cnm_state);
340
341 /* XXX: Should we pass rx-overrun upstream too? */
342 c |= ((stat & STAT_PARITY_ERR) != 0 ? XLCOM_CHAR_PE : 0) |
343 ((stat & STAT_FRAME_ERR) != 0 ? XLCOM_CHAR_FE : 0);
344 sc->sc_rbuf[sc->sc_rput] = c;
345 sc->sc_ravail--;
346
347 next(sc->sc_rput);
348 stat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, XLCOM_STAT);
349 }
350
351 /* Shedule completion hook if we received any. */
352 if (n != sc->sc_ravail)
353 softintr_schedule(sc->sc_rx_soft);
354 }
355
356 static int
357 xlcom_intr(void *arg)
358 {
359 struct xlcom_softc *sc = arg;
360 uint32_t stat;
361
362 /*
363 * Xilinx DS422, "OPB UART Lite v1.00b"
364 *
365 * If interrupts are enabled, an interrupt is generated when one
366 * of the following conditions is true:
367 */
368 stat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, XLCOM_STAT);
369
370 /*
371 * 1. When there exists any valid character in the receive FIFO,
372 * the interrupt stays active until the receive FIFO is empty.
373 * This is a level interrupt.
374 */
375 if (stat & STAT_RX_DATA)
376 xlcom_recv_chunk(sc);
377
378 /*
379 * 2. When the transmit FIFO goes from not empty to empty, such
380 * as when the last character in the transmit FIFO is transmitted,
381 * the interrupt is only active one clock cycle. This is an
382 * edge interrupt.
383 */
384 if (stat & STAT_TX_EMPTY)
385 xlcom_send_chunk(sc);
386
387 return (0);
388 }
389
390 /*
391 * Character device.
392 */
393 static int
394 xlcom_open(dev_t dev, int flags, int mode, struct lwp *l)
395 {
396 struct xlcom_softc *sc;
397 struct tty *tp;
398 struct proc *p;
399 int error, s;
400
401 sc = device_lookup(&xlcom_cd, minor(dev));
402 if (sc == NULL)
403 return (ENXIO);
404
405 tp = sc->sc_tty;
406 p = l->l_proc;
407
408 s = spltty(); /* { */
409
410 if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE) &&
411 kauth_authorize_generic(p->p_cred, KAUTH_GENERIC_ISSUSER,
412 &p->p_acflag) != 0) {
413 error = EBUSY;
414 goto fail;
415 }
416
417 /* Is this the first open? */
418 if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) {
419 tp->t_dev = dev;
420
421 /* Values hardwired at synthesis time. XXXFreza: xparam.h */
422 tp->t_ispeed = tp->t_ospeed = B38400;
423 tp->t_cflag = CLOCAL | CREAD | CS8;
424 tp->t_iflag = TTYDEF_IFLAG;
425 tp->t_oflag = TTYDEF_OFLAG;
426 tp->t_lflag = TTYDEF_LFLAG;
427
428 ttychars(tp);
429 ttsetwater(tp);
430
431 /* Enable interrupt. */
432 bus_space_write_4(sc->sc_iot, sc->sc_ioh, XLCOM_CNTL,
433 CNTL_INTR_EN);
434 }
435
436 error = ttyopen(tp, DIALOUT(dev), (flags & O_NONBLOCK));
437 if (error)
438 goto fail;
439
440 error = (tp->t_linesw->l_open)(dev, tp);
441 if (error)
442 goto fail;
443
444 splx(s); /* } */
445 return (0);
446
447 fail:
448 /* XXXFreza: Shutdown if nobody else has the device open. */
449 splx(s);
450 return (error);
451 }
452
453 static int
454 xlcom_read(dev_t dev, struct uio *uio, int flag)
455 {
456 struct xlcom_softc *sc;
457 struct tty *tp;
458
459 sc = device_lookup(&xlcom_cd, minor(dev));
460 if (sc == NULL)
461 return (ENXIO);
462 tp = sc->sc_tty;
463
464 return (tp->t_linesw->l_read)(tp, uio, flag);
465 }
466
467 static int
468 xlcom_write(dev_t dev, struct uio *uio, int flag)
469 {
470 struct xlcom_softc *sc;
471 struct tty *tp;
472
473 sc = device_lookup(&xlcom_cd, minor(dev));
474 if (sc == NULL)
475 return (ENXIO);
476 tp = sc->sc_tty;
477
478 return (tp->t_linesw->l_write)(tp, uio, flag);
479 }
480
481 static int
482 xlcom_poll(dev_t dev, int events, struct lwp *l)
483 {
484 struct xlcom_softc *sc;
485 struct tty *tp;
486
487 sc = device_lookup(&xlcom_cd, minor(dev));
488 if (sc == NULL)
489 return (ENXIO);
490 tp = sc->sc_tty;
491
492 return (tp->t_linesw->l_poll)(tp, events, l);
493 }
494
495 static struct tty *
496 xlcom_tty(dev_t dev)
497 {
498 struct xlcom_softc *sc;
499 struct tty *tp;
500
501 sc = device_lookup(&xlcom_cd, minor(dev));
502 if (sc == NULL)
503 return (NULL);
504 tp = sc->sc_tty;
505
506 return (tp);
507 }
508
509 static int
510 xlcom_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
511 {
512 struct xlcom_softc *sc;
513 struct tty *tp;
514 int error;
515
516 sc = device_lookup(&xlcom_cd, minor(dev));
517 if (sc == NULL)
518 return (ENXIO);
519 tp = sc->sc_tty;
520
521 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
522 if (error != EPASSTHROUGH)
523 return (error);
524
525 error = ttioctl(tp, cmd, data, flag, l);
526 if (error != EPASSTHROUGH)
527 return (error);
528
529 /* XXXFreza: error = 0; switch (cmd); return error; */
530
531 return (error);
532 }
533
534 static int
535 xlcom_close(dev_t dev, int flag, int mode, struct lwp *l)
536 {
537 struct xlcom_softc *sc;
538 struct tty *tp;
539
540 sc = device_lookup(&xlcom_cd, minor(dev));
541 if (sc == NULL)
542 return (ENXIO);
543 tp = sc->sc_tty;
544
545 (tp->t_linesw->l_close)(tp, flag);
546 ttyclose(tp);
547
548 /* Is this the last close? XXXFreza: hum? */
549 if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) {
550 }
551
552 return (0);
553 }
554
555 static void
556 xlcom_stop(struct tty *tp, int flag)
557 {
558 struct xlcom_softc *sc;
559 int s;
560
561 sc = device_lookup(&xlcom_cd, UNIT(tp->t_dev));
562 if (sc == NULL)
563 return ;
564
565 s = splserial();
566 if (tp->t_state & TS_BUSY) {
567 /* XXXFreza: make sure we stop xmitting at next chunk */
568
569 if (! (tp->t_state & TS_TTSTOP))
570 tp->t_state |= TS_FLUSH;
571 }
572 splx(s);
573 }
574
575 /*
576 * Terminal line.
577 */
578 static int
579 xlcom_param(struct tty *tp, struct termios *t)
580 {
581 t->c_cflag &= ~HUPCL;
582
583 if (tp->t_ospeed == t->c_ospeed &&
584 tp->t_ispeed == t->c_ispeed &&
585 tp->t_cflag == t->c_cflag)
586 return (0);
587
588 return (EINVAL);
589 }
590
591 static void
592 xlcom_start(struct tty *tp)
593 {
594 struct xlcom_softc *sc;
595 int s1, s2;
596
597 sc = device_lookup(&xlcom_cd, UNIT(tp->t_dev));
598 if (sc == NULL)
599 return ;
600
601 s1 = spltty();
602
603 if (tp->t_state & (TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
604 splx(s1);
605 return ;
606 }
607
608 if (tp->t_outq.c_cc <= tp->t_lowat) {
609 if (tp->t_state & TS_ASLEEP) {
610 tp->t_state &= ~TS_ASLEEP;
611 wakeup(&tp->t_outq);
612 }
613 selwakeup(&tp->t_wsel);
614
615 if (tp->t_outq.c_cc == 0) {
616 splx(s1);
617 return ;
618 }
619 }
620
621 tp->t_state |= TS_BUSY;
622 splx(s1);
623
624 s2 = splserial();
625 sc->sc_tba = tp->t_outq.c_cf;
626 sc->sc_tbc = ndqb(&tp->t_outq, 0);
627 xlcom_send_chunk(sc);
628 splx(s2);
629 }
630
631 static void
632 xlcom_reset(bus_space_tag_t iot, bus_space_handle_t ioh)
633 {
634 /* Wait while the fifo drains. */
635 while (! (bus_space_read_4(iot, ioh, XLCOM_STAT) & STAT_TX_EMPTY))
636 ;
637
638 bus_space_write_4(iot, ioh, XLCOM_CNTL, CNTL_RX_CLEAR | CNTL_TX_CLEAR);
639 }
640
641 static int
642 xlcom_busy_getc(bus_space_tag_t t, bus_space_handle_t h)
643 {
644 while (! (bus_space_read_4(t, h, XLCOM_STAT) & STAT_RX_DATA))
645 ;
646
647 return (bus_space_read_4(t, h, XLCOM_RX_FIFO));
648 }
649
650 static void
651 xlcom_busy_putc(bus_space_tag_t t, bus_space_handle_t h, int c)
652 {
653 while (bus_space_read_4(t, h, XLCOM_STAT) & STAT_TX_FULL)
654 ;
655
656 bus_space_write_4(t, h, XLCOM_TX_FIFO, c);
657 }
658
659 /*
660 * Console on UartLite.
661 */
662 void
663 nullcnprobe(struct consdev *cn)
664 {
665 }
666
667 void
668 xlcom_cninit(struct consdev *cn)
669 {
670 if (bus_space_map(consdev_iot, CONS_ADDR, XLCOM_SIZE, 0, &consdev_ioh))
671 panic("xlcom_cninit: could not map consdev_ioh");
672
673 xlcom_reset(consdev_iot, consdev_ioh);
674 }
675
676 static int
677 xlcom_cngetc(dev_t dev)
678 {
679 return (xlcom_busy_getc(consdev_iot, consdev_ioh));
680 }
681
682 static void
683 xlcom_cnputc(dev_t dev, int c)
684 {
685 xlcom_busy_putc(consdev_iot, consdev_ioh, c);
686 }
687
688 /*
689 * Remote GDB (aka "kgdb") interface.
690 */
691 #if defined(KGDB)
692
693 static int
694 xlcom_kgdb_getc(void *arg)
695 {
696 return (xlcom_busy_getc(kgdb_iot, kgdb_ioh));
697 }
698
699 static void
700 xlcom_kgdb_putc(void *arg, int c)
701 {
702 xlcom_busy_putc(kgdb_iot, kgdb_ioh, c);
703 }
704
705 void
706 xlcom_kgdbinit(void)
707 {
708 if (bus_space_map(kgdb_iot, KGDB_ADDR, XLCOM_SIZE, 0, &kgdb_ioh))
709 panic("xlcom_kgdbinit: could not map kgdb_ioh");
710
711 xlcom_reset(kgdb_iot, kgdb_ioh);
712
713 kgdb_attach(xlcom_kgdb_getc, xlcom_kgdb_putc, NULL);
714 kgdb_dev = 123; /* arbitrary strictly positive value */
715 }
716
717 #endif /* KGDB */
718