Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / alpha / a12 / a12dc.c
bloba2100a34ef290925dc2dd03ed2d1f0ec10cc13a7
1 /* $NetBSD: a12dc.c,v 1.23 2009/03/18 10:22:22 cegger Exp $ */
3 /* [Notice revision 2.2]
4 * Copyright (c) 1997, 1998 Avalon Computer Systems, Inc.
5 * All rights reserved.
7 * Author: Ross Harvey
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 * 1. Redistributions of source code must retain the above copyright and
13 * author notice, this list of conditions, and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of Avalon Computer Systems, Inc. nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 * 4. This copyright will be assigned to The NetBSD Foundation on
21 * 1/1/2000 unless these terms (including possibly the assignment
22 * date) are updated in writing by Avalon prior to the latest specified
23 * assignment date.
25 * THIS SOFTWARE IS PROVIDED BY AVALON COMPUTER SYSTEMS, INC. AND CONTRIBUTORS
26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AVALON OR THE CONTRIBUTORS
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
39 * The A12 uses what DEC calls a "detached console", i.e., some of the console
40 * implementation is on a dedicated processor with its own RAM.
42 * The A12 Detached Console interface uses two 16 bit registers (per CPU), one
43 * going from the CPU to the a12ctrl processor and one going back the other
44 * way. The first is polled, the second produces a GInt.
46 * In the very early days we loaded program images through this interface.
48 * Consequently, it developed an overly complicated (but sort of fast)
49 * inverting sync/ack that isn't needed at all for its present application as
50 * a text console device.
52 * One possible solution: most of the channels are undefined, so a console
53 * channel using a stateless ack could be defined, with corresponding changes
54 * to the backplane 68360 code.
56 * This file is complicated somewhat by its use in three different kernels:
57 * NetBSD, the A12 CPU-resident console, and the a12ctrl backplane processor.
58 * (The protocol is symmetrical.)
61 #include "opt_avalon_a12.h" /* Config options headers */
62 #include "opt_kgdb.h"
64 #ifndef BSIDE
65 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
67 __KERNEL_RCSID(0, "$NetBSD: a12dc.c,v 1.23 2009/03/18 10:22:22 cegger Exp $");
69 #include <sys/types.h>
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/malloc.h>
74 #include <sys/tty.h>
75 #include <sys/proc.h>
76 #include <sys/uio.h>
77 #include <sys/device.h>
78 #include <sys/conf.h>
79 #include <sys/kauth.h>
81 #include <dev/cons.h>
83 #include <machine/cpuconf.h>
84 #include <machine/autoconf.h>
85 #include <machine/rpb.h>
87 #include <alpha/pci/a12creg.h>
88 #include <alpha/pci/a12cvar.h>
89 #include <alpha/pci/pci_a12.h>
91 #include "a12dcreg.h"
93 #define A12DC() /* Generate ctags(1) key */
95 #define MAX_MODULES 1
97 int a12dcmatch(struct device *, struct cfdata *, void *);
98 void a12dcattach(struct device *, struct device *, void *);
100 struct a12dc_softc {
101 struct device sc_dev;
102 } a12dc_softc;
104 CFATTACH_DECL(a12dc, sizeof(struct a12dc_softc),
105 a12dcmatch, a12dcattach, NULL, NULL);
107 extern struct cfdriver a12dc_cd;
109 dev_type_open(a12dcopen);
110 dev_type_close(a12dcclose);
111 dev_type_read(a12dcread);
112 dev_type_write(a12dcwrite);
113 dev_type_ioctl(a12dcioctl);
114 dev_type_stop(a12dcstop);
115 dev_type_tty(a12dctty);
116 dev_type_poll(a12dcpoll);
118 const struct cdevsw a12dc_cdevsw = {
119 a12dcopen, a12dcclose, a12dcread, a12dcwrite, a12dcioctl,
120 a12dcstop, a12dctty, a12dcpoll, nommap, ttykqfilter, D_TTY
123 int a12dcfound; /* There Can Be Only One. */
125 struct a12dc_config { int im_not_used; } a12dc_configuration;
127 static struct tty *a12dc_tty[1];
129 void a12dcstart(struct tty *);
130 void a12dctimeout(void *);
131 int a12dcparam(struct tty *, struct termios *);
132 void a12dc_init(struct a12dc_config *, int);
133 static void a12cdrputc(int);
134 int a12dccngetc(dev_t);
135 void a12dccnputc(dev_t, int);
136 void a12dccnpollc(dev_t, int);
137 /* static int get_bc_char(int mn, int chan); */
138 /* static int get_bc_any(int,int *,int *); */
139 int a12dcintr(void *);
140 static void a12_worry(int worry_number);
141 static void A12InitBackDriver(int);
144 a12dcmatch(struct device *parent, struct cfdata *match, void *aux)
146 struct pcibus_attach_args *pba = aux;
148 return cputype == ST_AVALON_A12
149 && !a12dcfound;
152 void
153 a12dcattach(struct device *parent, struct device *self, void *aux)
155 struct tty *tp;
156 struct a12dc_config *ccp;
158 /* note that we've attached the chipset; can't have 2 A12Cs. */
159 a12dcfound = 1;
161 printf(": driver %s\n", "$Revision: 1.24 $");
163 tp = a12dc_tty[0] = ttymalloc();
164 tp->t_oproc = a12dcstart;
165 tp->t_param = a12dcparam;
166 tty_attach(tp);
168 ccp = &a12dc_configuration;
169 a12dc_init(ccp, 1);
172 void
173 a12dc_init(struct a12dc_config *ccp, int mallocsafe)
178 * XXX definitions specific to only one of the kernels will be moved into
179 * kernel-local include files. (One of these days.)
181 #define spla12dc() spltty()
182 #define a12yield()
183 #define CDRADDR(m) ((mmreg_t *)(REGADDR(A12_CDR))) /* ignore m */
184 #define modenormal()
185 #define mb() alpha_mb()
186 #define wmb() alpha_wmb()
188 #else
190 #include "product.def"
191 #include "ghs.h"
192 #include "a12ctrl.h"
194 #define wmb()
195 #define mb()
196 #define swpipl(a) (a)
197 #define splx(a) (a)
198 #define spla12dc()
199 #define hrhpanic(s,v) panic((s))
200 #define CDRADDR(m) ((mmreg_t *)(A12_BACKPLANE+(m)))
202 #endif
204 static int msgetput(register mstate_type *, int, int);
205 static void checkinit(void);
207 static void
208 A12InitBackDriver(int m)
211 * XXX memset() would be good here, but there is a (temporary) reason
212 * for all this right now
214 a12_mstate[m].xcdr = CDRADDR(m);
215 a12_mstate[m].txrdy_out = A12C_TXRDY;
216 a12_mstate[m].txrdy_in = A12C_TXRDY;
217 a12_mstate[m].txack_out = A12C_TXACK;
218 a12_mstate[m].txack_in = A12C_TXACK;
219 a12_mstate[m].txsv = tx_idle;
220 a12_mstate[m].rxsv = rx_idle;
221 a12_mstate[m].reset_scanner= 1;
222 a12_mstate[m].reset_loader = 1;
223 a12_mstate[m].up = 1;
224 a12_mstate[m].lastr = 0; /* last char. received */
225 a12_mstate[m].lastrc = 0; /* last received channel */
226 a12_mstate[m].rx_busy_wait = 0; /* last received busy ticks */
227 a12_mstate[m].rx_busy_cnt = 0; /* last received start clock */
228 a12_mstate[m].lastt = 0; /* last char. trasmitted */
229 a12_mstate[m].lasttc = 0; /* last transmit channel */
230 a12_mstate[m].tx_busy_wait = 0; /* last transmitted busy ticks */
231 a12_mstate[m].tx_busy_cnt = 0; /* last transmitted start clock */
232 a12_mstate[m].tbytes = 0;
233 a12_mstate[m].tblkbytes = 0;
234 a12_mstate[m].tblks = 0;
235 a12_mstate[m].blwobe = 0;
236 a12_mstate[m].blwbe = 0;
237 a12_mstate[m].max_blkretry = 0;
238 a12_mstate[m].max_blktime = 0;
239 a12_mstate[m].max_blktimesz = 0;
240 a12_mstate[m].avg_blksz = 0;
241 a12_mstate[m].avg_blktime = 0;
242 a12_mstate[m].retry_time = 0;
245 static void
246 checkinit(void)
248 static int did_init;
250 if (!did_init) {
251 A12InitBackDriver(0);
252 did_init = 1;
257 a12dcopen(dev_t dev, int flag, int mode, struct lwp *l)
259 int unit = minor(dev);
260 struct tty *tp;
261 int s;
263 if (unit >= 1)
264 return ENXIO;
266 #ifdef KGDB
267 if (flags & COM_HW_KGDB)
268 return EBUSY;
269 #endif
271 if (!a12dc_tty[unit]) {
272 tp = a12dc_tty[unit] = ttymalloc();
273 tty_attach(tp);
274 } else
275 tp = a12dc_tty[unit];
277 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
278 return (EBUSY);
280 s = spltty();
282 tp->t_oproc = a12dcstart;
283 tp->t_param = a12dcparam;
284 tp->t_dev = dev;
285 if ((tp->t_state & TS_ISOPEN) == 0) {
286 tp->t_state |= TS_CARR_ON;
287 ttychars(tp);
288 tp->t_iflag = TTYDEF_IFLAG;
289 tp->t_oflag = TTYDEF_OFLAG;
290 tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
291 tp->t_lflag = TTYDEF_LFLAG;
292 tp->t_ispeed = tp->t_ospeed = 9600;
293 ttsetwater(tp);
294 /* XXX XXX XXX
295 a12_intr_register_icw(a12dcintr);
299 splx(s);
301 return (*tp->t_linesw->l_open)(dev, tp);
305 a12dcclose(dev_t dev, int flag, int mode, struct proc *p)
307 int unit = minor(dev);
308 struct tty *tp = a12dc_tty[unit];
310 (*tp->t_linesw->l_close)(tp, flag);
311 ttyclose(tp);
312 return 0;
316 a12dcread(dev_t dev, struct uio *uio, int flag)
318 struct tty *tp = a12dc_tty[minor(dev)];
320 return ((*tp->t_linesw->l_read)(tp, uio, flag));
324 a12dcwrite(dev_t dev, struct uio *uio, int flag)
326 struct tty *tp = a12dc_tty[minor(dev)];
328 return ((*tp->t_linesw->l_write)(tp, uio, flag));
332 a12dcpoll(dev_t dev, int events, struct proc *p)
334 struct tty *tp = a12dc_tty[minor(dev)];
336 return ((*tp->t_linesw->l_poll)(tp, events, p));
340 a12dcioctl(dev_t dev, u_long cmd, void *data, int flag, struct proc *p)
342 int unit = minor(dev);
343 struct tty *tp = a12dc_tty[unit];
344 int error;
346 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
347 if (error != EPASSTHROUGH)
348 return error;
349 return ttioctl(tp, cmd, data, flag, p);
353 a12dcparam(struct tty *tp, struct termios *t)
355 return 0;
358 void
359 a12dcstart(struct tty *tp)
361 int s;
363 s = spltty();
364 if (tp->t_state & (TS_TTSTOP | TS_BUSY))
365 goto out;
366 ttypull(tp);
367 tp->t_state |= TS_BUSY;
368 while (tp->t_outq.c_cc != 0)
369 a12dccnputc(tp->t_dev, getc(&tp->t_outq));
370 tp->t_state &= ~TS_BUSY;
371 out:
372 splx(s);
376 * Stop output on a line.
378 void
379 a12dcstop(struct tty *tp, flag)
381 int s;
383 s = spltty();
384 if (tp->t_state & TS_BUSY)
385 if ((tp->t_state & TS_TTSTOP) == 0)
386 tp->t_state |= TS_FLUSH;
387 splx(s);
391 a12dcintr(void *v)
393 #if 1
394 DIE();
395 #else
396 struct tty *tp = v;
397 u_char c;
399 while (a12dccnlookc(tp->t_dev, &c)) {
400 if (tp->t_state & TS_ISOPEN)
401 (*tp->t_linesw->l_rint)(c, tp);
403 #endif
406 struct tty *
407 a12dctty(dev_t dev)
410 if (minor(dev) != 0)
411 panic("a12dctty: bogus");
413 return a12dc_tty[0];
417 a12dccnattach()
419 static struct consdev a12dccons = {
420 NULL, NULL, a12dccngetc, a12dccnputc, a12dccnpollc, NULL,
421 NODEV, CN_NORMAL
424 a12dccons.cn_dev = makedev(cdevsw_lookup_major(&a12dc_cdevsw), 0);
426 cn_tab = &a12dccons;
427 return 0;
431 a12dccngetc(dev_t dev)
433 for(;;)
434 continue;
437 void
438 a12dccnputc(dev_t dev, int c)
440 a12cdrputc(c);
443 void
444 a12dccnpollc(dev_t dev, int on)
448 static void
449 a12cdrputc(int c)
451 int s = spla12dc();
453 checkinit();
454 while(msgetput(MSP(0),CHANNEL_MONITOR,c)) {
455 /*if(check_cdr_ok)
456 check_cdr();*/
457 DELAY(100);
459 splx(s);
462 #if 0
463 static void
464 check_cdr(void)
466 int bpchar,cnumber;
467 static int srom_word_address,
468 kmsg;
469 int push_check_ok;
470 int ipl;
472 if(!get_bc_any(0,&bpchar,&cnumber))
473 return;
474 switch(cnumber) {
475 default:
476 printf("Unknown cdr channel %d",cnumber);
477 break;
478 case CHANNEL_KDATA:
479 if(!kmsg)
480 printf("Ignoring new kernel\n");
481 kmsg = 1;
482 break;
483 case CHANNEL_KMARK:
484 kmsg = 0;
485 break;
486 #ifndef _KERNEL /* NetBSD kernel, that is. "if defined: rtmon kernel" */
487 case CHANNEL_SROM_A:
488 srom_word_address = bpchar;
489 break;
490 case CHANNEL_SROM_D:
491 push_check_ok = check_cdr_ok;
492 check_cdr_ok = 0;
493 ipl = swpipl(7);
494 write_ethernet_srom(srom_word_address,bpchar);
495 ++srom_word_address;
496 (void)swpipl(ipl);
497 check_cdr_ok = push_check_ok;
498 break;
500 case CHANNEL_MULTI:
501 logmchar(bpchar,"<");
502 SerialByteReceived(bpchar);
503 break;
504 case CHANNEL_MONITOR:
505 if (bpchar == CPX_PANIC)
506 /* TJF - Could kill all processes and then panic? */
507 hrhpanic("Panic in cooperating CPU.",0);
508 else cpxchar(bpchar);
509 break;
510 #endif
511 case CHANNEL_CONSOLE:
512 #ifdef A12CON /* XXX this can be done much better */
513 virtual_keyboard_byte(bpchar);
514 #else
515 ipl7putc(bpchar);
516 #endif
517 break;
520 #endif
522 #if 0
523 static int
524 get_bc_any(int mn, int *c, int *chan) {
525 mstate_type *ms = &a12_mstate[mn];
527 (void)mcgetput(mn, 0, -1);
528 if(ms->rxsv==rx_busy) {
529 *c = ms->c2b_char & 0xff;
530 *chan = ms->c2b_channel;
531 ms->rxsv = rx_idle;
532 return 1;
534 return 0;
537 static int
538 get_bc_char(int mn, int chan) {
539 int newc,newchan;
541 if(get_bc_any(mn,&newc,&newchan)) {
542 if(newchan!=chan)
543 printf("receiver busy on dumb channel %d", newchan);
544 return newc;
546 return -1;
548 #endif
550 static int
551 msgetput(register mstate_type *ms, int channel, int c)
553 int i,t;
554 int ipl;
556 if(c==-2 || ms->up==0) {
557 if(c!=-2)
558 a12_worry(10);
559 ms->txsv = tx_idle;
560 ms->rxsv = rx_idle;
561 ms->cdr = 0;
562 return 0;
564 if(!(0<=channel && channel<64)) {
565 a12_worry(7);
566 return 0;
568 ipl = spla12dc();
569 for(i=0; i<20; ++i) {
570 switch(ms->txsv) {
571 case tx_idle:
572 if(c!=-1) {
573 ms->lastt = c;
574 ms->lasttc = channel;
575 ms->cdr = (ms->cdr & (A12C_TXACK | A12C_TXRDY))
576 | channel<<8
577 | c;
578 *ms->xcdr = ms->cdr;
579 wmb();
580 ms->cdr = ((ms->cdr & A12C_TXACK) &~ A12C_TXRDY)
581 | ms->txrdy_out
582 | channel<<8
583 | c;
584 *ms->xcdr = ms->cdr;
585 wmb();
586 ms->txsv = tx_braaw;
587 c = -1;
588 continue;
590 break;
591 case tx_braaw:
592 mb();
593 if((*ms->xcdr & A12C_TXACK)==ms->txack_in) {
594 ms->txrdy_out ^= A12C_TXRDY;
595 ms->txack_in ^= A12C_TXACK;
596 ms->txsv = tx_idle;
597 ms->tbytes++;
598 continue;
600 break;
601 default:
602 (void)splx(ipl);
603 a12_worry(5);
604 return 0;
606 switch(ms->rxsv) {
607 case rx_idle:
608 mb();
609 t = *ms->xcdr;
610 if((t & A12C_TXRDY)==ms->txrdy_in) {
611 ms->cdr = (ms->cdr & ~A12C_TXACK)
612 | ms->txack_out;
613 *ms->xcdr = ms->cdr;
614 wmb();
615 ms->c2b_char = t & 0xff;
616 ms->lastr = ms->c2b_char;
617 ms->c2b_channel = (t & CHMASK) >> 8;
618 ms->lastrc = ms->c2b_channel;
619 ms->txrdy_in ^= A12C_TXRDY;
620 ms->txack_out^= A12C_TXACK;
621 ms->rxsv = rx_busy;
622 continue;
624 break;
625 case rx_busy:
626 break;
627 default:
628 (void)splx(ipl);
629 a12_worry(6);
630 return 0;
632 if(c==-1)
633 break;
635 (void)splx(ipl);
636 return c!=-1;
639 static void
640 a12_worry(int worry_number)
642 a12console_last_unexpected_error = worry_number;