xref: /csrg-svn/sys/luna68k/dev/bmc.c (revision 56876)
1 /*
2  * Copyright (c) 1992 OMRON Corporation.
3  * Copyright (c) 1992 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * OMRON Corporation.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)bmc.c	7.1 (Berkeley) 11/17/92
12  */
13 
14 #define	BMC_NOCONSOLE
15 #define	BMD
16 
17 #ifdef	BMD
18 #define	BMC_CNPORT	1
19 #else
20 #define	BMC_CNPORT	0
21 #endif
22 
23 #include "bmc.h"
24 #if NBMC > 0
25 
26 #include "sys/param.h"
27 #include "sys/systm.h"
28 #include "sys/ioctl.h"
29 #include "sys/proc.h"
30 #include "sys/tty.h"
31 #include "sys/conf.h"
32 #include "sys/file.h"
33 #include "sys/uio.h"
34 #include "sys/kernel.h"
35 #include "sys/syslog.h"
36 
37 #include "device.h"
38 #include "sioreg.h"
39 #include "siovar.h"
40 
41 #ifdef	BMD
42 #include "kbdreg.h"
43 #endif
44 
45 extern	struct sio_portc *sio_port_assign();
46 
47 int     bmcprobe();
48 int     bmcopen();
49 void    bmcstart();
50 int     bmcparam();
51 int     bmcintr();
52 
53 struct	driver bmcdriver = {
54 	bmcprobe, "bmc",
55 };
56 
57 struct	bmc_softc {
58 	struct sio_portc *sc_pc;
59 	int	sc_mask;
60 };
61 
62 struct	bmc_softc bmc_softc[NBMC];
63 
64 struct	tty bmc_tty[NBMC];
65 
66 int	bmc_config_done = 0;
67 
68 int	bmcconsole;
69 int	bmcdefaultrate = B9600;				/* speed of console line is fixed */
70 int	bmcmajor = 0;
71 
72 #define	bmcunit(x)		minor(x)
73 
74 
75 /*
76  *  probe routine
77  */
78 
79 bmcprobe(hd)
80 	register struct hp_device *hd;
81 {
82 }
83 
84 bmcinit(port)
85 	register int port;
86 {
87 	register struct bmc_softc *sc = &bmc_softc[0];
88 
89 	/*
90 	 * if BMC is already configured, should be skipped.
91          */
92 	if (bmc_config_done)
93 		return(0);
94 
95 	/*
96 	 * Check out bitmap Interface board
97 	 */
98 
99 	/* port checking (for keyboard) */
100 	if (port != 1)
101 		return(0);
102 
103 	/* locate the major number */
104 	for (bmcmajor = 0; bmcmajor < nchrdev; bmcmajor++)
105 		if (cdevsw[bmcmajor].d_open == bmcopen)
106 			break;
107 
108 	sc->sc_pc = sio_port_assign(port, bmcmajor, 0, bmcintr);
109 
110 	printf("bmc%d: port %d, address 0x%x\n", sc->sc_pc->pc_unit, port, sc->sc_pc->pc_addr);
111 
112 #ifdef	BMD
113 	bmdinit();
114 #endif
115 
116 	bmc_config_done = 1;
117 	return(1);
118 }
119 
120 
121 /*
122  *  entry routines
123  */
124 
125 /* ARGSUSED */
126 #ifdef __STDC__
127 bmcopen(dev_t dev, int flag, int mode, struct proc *p)
128 #else
129 bmcopen(dev, flag, mode, p)
130 	dev_t dev;
131 	int flag, mode;
132 	struct proc *p;
133 #endif
134 {
135 	register struct tty *tp;
136 	register int unit;
137 	int error = 0;
138 
139 	unit = bmcunit(dev);
140 	if (unit >= NBMC)
141 		return (ENXIO);
142 	tp = &bmc_tty[unit];
143 	tp->t_oproc = bmcstart;
144 	tp->t_param = bmcparam;
145 	tp->t_dev = dev;
146 	if ((tp->t_state & TS_ISOPEN) == 0) {
147 		tp->t_state |= TS_WOPEN;
148 		ttychars(tp);
149 		if (tp->t_ispeed == 0) {
150 			tp->t_iflag = TTYDEF_IFLAG;
151 			tp->t_oflag = TTYDEF_OFLAG;
152 			tp->t_cflag = TTYDEF_CFLAG;
153 /*			tp->t_cflag = (CREAD | CS8 | HUPCL);	*/
154 			tp->t_lflag = TTYDEF_LFLAG;
155 			tp->t_ispeed = tp->t_ospeed = bmcdefaultrate;
156 		}
157 		bmcparam(tp, &tp->t_termios);
158 		ttsetwater(tp);
159 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
160 		return (EBUSY);
161 	tp->t_state |= TS_CARR_ON;
162 	(void) spltty();
163 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
164 	       (tp->t_state & TS_CARR_ON) == 0) {
165 		tp->t_state |= TS_WOPEN;
166 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
167 		    ttopen, 0))
168 			break;
169 	}
170 	(void) spl0();
171 	if (error == 0)
172 		error = (*linesw[tp->t_line].l_open)(dev, tp);
173 
174 	return (error);
175 }
176 
177 /*ARGSUSED*/
178 bmcclose(dev, flag, mode, p)
179 	dev_t dev;
180 	int flag, mode;
181 	struct proc *p;
182 {
183 	register struct tty *tp;
184 	register int unit;
185 
186 	unit = bmcunit(dev);
187 	tp = &bmc_tty[unit];
188 	(*linesw[tp->t_line].l_close)(tp, flag);
189 	ttyclose(tp);
190 	return (0);
191 }
192 
193 bmcread(dev, uio, flag)
194 	dev_t dev;
195 	struct uio *uio;
196 {
197 	register struct tty *tp = &bmc_tty[bmcunit(dev)];
198 
199 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
200 }
201 
202 bmcwrite(dev, uio, flag)
203 	dev_t dev;
204 	struct uio *uio;
205 {
206 	register struct tty *tp = &bmc_tty[bmcunit(dev)];
207 
208 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
209 }
210 
211 /*
212  * Stop output on a line.
213  */
214 /*ARGSUSED*/
215 bmcstop(tp, flag)
216 	register struct tty *tp;
217 {
218 	register int s;
219 
220 	s = spltty();
221 	if (tp->t_state & TS_BUSY) {
222 		if ((tp->t_state&TS_TTSTOP)==0)
223 			tp->t_state |= TS_FLUSH;
224 	}
225 	splx(s);
226 }
227 
228 bmcioctl(dev, cmd, data, flag, p)
229 	dev_t dev;
230 	int cmd;
231 	caddr_t data;
232 	int flag;
233 	struct proc *p;
234 {
235 	register struct tty *tp;
236 	register int unit = bmcunit(dev);
237 	register int error;
238 
239 	tp = &bmc_tty[unit];
240 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
241 	if (error >= 0)
242 		return (error);
243 	error = ttioctl(tp, cmd, data, flag);
244 	if (error >= 0)
245 		return (error);
246 
247 	switch (cmd) {
248 	default:
249 		return (ENOTTY);
250 	}
251 	return (0);
252 }
253 
254 /*
255  *
256  */
257 #ifdef BMD
258 void
259 bmcstart(tp)
260 	register struct tty *tp;
261 {
262 	int unit = bmcunit(tp->t_dev);
263 	register struct bmc_softc *sc = &bmc_softc[unit];
264 	register int cc, s;
265 	int hiwat = 0;
266 
267 	s = spltty();
268 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) {
269 		splx(s);
270 		return;
271 	}
272 	tp->t_state |= TS_BUSY;
273 	cc = tp->t_outq.c_cc;
274 	if (cc <= tp->t_lowat) {
275 		if (tp->t_state & TS_ASLEEP) {
276 			tp->t_state &= ~TS_ASLEEP;
277 			wakeup((caddr_t)&tp->t_outq);
278 		}
279 		selwakeup(&tp->t_wsel);
280 	}
281 	/*
282 	 * Limit the amount of output we do in one burst
283 	 * to prevent hogging the CPU.
284 	 */
285 /*
286 	if (cc > iteburst) {
287 		hiwat++;
288 		cc = iteburst;
289 	}
290  */
291 	while (--cc >= 0) {
292 		register int c;
293 
294 		c = getc(&tp->t_outq);
295 		/*
296 		 * iteputchar() may take a long time and we don't want to
297 		 * block all interrupts for long periods of time.  Since
298 		 * there is no need to stay at high priority while outputing
299 		 * the character (since we don't have to worry about
300 		 * interrupts), we don't.  We just need to make sure that
301 		 * we don't reenter iteputchar, which is guarenteed by the
302 		 * earlier setting of TS_BUSY.
303 		 */
304 		splx(s);
305 		bmdputc(c & sc->sc_mask);
306 		spltty();
307 	}
308 /*
309 	if (hiwat) {
310 		tp->t_state |= TS_TIMEOUT;
311 		timeout(ttrstrt, tp, 1);
312 	}
313  */
314 	tp->t_state &= ~TS_BUSY;
315 	splx(s);
316 }
317 #else
318 void
319 bmcstart(tp)
320 	register struct tty *tp;
321 {
322 	register struct siodevice *sio;
323 	register int rr;
324 	int s, unit, c;
325 
326 	unit = bmcunit(tp->t_dev);
327 	sio = bmc_softc[unit].sc_pc->pc_addr;
328 	s = spltty();
329 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
330 		goto out;
331 	if (tp->t_outq.c_cc <= tp->t_lowat) {
332 		if (tp->t_state&TS_ASLEEP) {
333 			tp->t_state &= ~TS_ASLEEP;
334 			wakeup((caddr_t)&tp->t_outq);
335 		}
336 		selwakeup(&tp->t_wsel);
337 	}
338 	if (tp->t_outq.c_cc == 0)
339 		goto out;
340 	rr = siogetreg(sio);
341 	if (rr & RR_TXRDY) {
342 		c = getc(&tp->t_outq);
343 		tp->t_state |= TS_BUSY;
344 		sio->sio_data = c;
345 	}
346 out:
347 	splx(s);
348 }
349 #endif
350 
351 bmcparam(tp, t)
352 	register struct tty *tp;
353 	register struct termios *t;
354 {
355 	int unit = bmcunit(tp->t_dev);
356 	register struct bmc_softc *sc = &bmc_softc[unit];
357 	register int cflag = t->c_cflag;
358 
359         /* and copy to tty */
360         tp->t_ispeed = t->c_ispeed;
361         tp->t_ospeed = t->c_ospeed;
362         tp->t_cflag = cflag;
363 
364 	/*
365 	 * change line speed
366 	 */
367 
368 	switch (cflag&CSIZE) {
369 	case CS5:
370 		sc->sc_mask = 0x1F ; break;
371 	case CS6:
372 		sc->sc_mask = 0x3F ; break;
373 	case CS7:
374 		sc->sc_mask = 0x7F ; break;
375 	case CS8:
376 		sc->sc_mask = 0xFF ; break;
377 	}
378 
379 	/*
380 	 * parity
381 	 */
382 
383 	/*
384 	 * stop bit
385 	 */
386 
387 	return (0);
388 }
389 
390 
391 /*
392  *  interrupt handling
393  */
394 
395 #ifdef BMD
396 bmcintr(unit)
397 	register int unit;
398 {
399 	register struct siodevice *sio = bmc_softc[unit].sc_pc->pc_addr;
400 	register struct tty *tp;
401 	register u_char code;
402 	register int c;
403 	int s, rr;
404 
405 	tp = &bmc_tty[unit];
406 	rr = siogetreg(sio);
407 
408 	if (rr & RR_RXRDY) {
409 		code = sio->sio_data;
410 		c = kbd_decode(code);
411 		if (c & KC_TYPE)			/* skip special codes */
412 			return;
413 		code = (c & KC_CHAR);
414 		if ((tp->t_state & TS_ISOPEN) != 0)
415 			(*linesw[tp->t_line].l_rint)(code, tp);
416 	}
417 }
418 #else
419 bmcintr(unit)
420 	register int unit;
421 {
422 	register struct siodevice *sio = bmc_softc[unit].sc_pc->pc_addr;
423 	register u_char code;
424 	register struct tty *tp;
425 	int s, rr;
426 
427 	tp = &bmc_tty[unit];
428 	rr = siogetreg(sio);
429 
430 	if (rr & RR_RXRDY) {
431 		code = sio->sio_data;
432 		if ((tp->t_state & TS_ISOPEN) != 0)
433 			(*linesw[tp->t_line].l_rint)(code, tp);
434 	}
435 
436 	if (rr & RR_TXRDY) {
437 		sio->sio_cmd = WR0_RSTPEND;
438 		tp->t_state &= ~(TS_BUSY|TS_FLUSH);
439 		if (tp->t_line)
440 			(*linesw[tp->t_line].l_start)(tp);
441 		else
442 			bmcstart(tp);
443 	}
444 
445 }
446 #endif
447 
448 /*
449  * Following are all routines needed for SIO to act as console
450  */
451 #include "../luna68k/cons.h"
452 
453 bmccnprobe(cp)
454 	register struct consdev *cp;
455 {
456 #ifdef BMC_NOCONSOLE
457 	cp->cn_pri = CN_DEAD;
458 	return;
459 #else
460 	/* check DIP-SW setup */
461 	/* check bitmap interface board */
462 
463 	/* locate the major number */
464 	for (bmcmajor = 0; bmcmajor < nchrdev; bmcmajor++)
465 		if (cdevsw[bmcmajor].d_open == bmcopen)
466 			break;
467 
468 	/* initialize required fields */
469 	cp->cn_dev = makedev(bmcmajor, 0);
470 	cp->cn_tp  = &bmc_tty[0];
471 	cp->cn_pri = CN_INTERNAL;
472 
473 	bmc_config_done = 1;
474 #endif
475 }
476 
477 bmccninit(cp)
478 	struct consdev *cp;
479 {
480 	int unit = bmcunit(cp->cn_dev);
481 	register struct bmc_softc *sc = &bmc_softc[0];
482 
483 	sioinit((struct siodevice *) SIO_HARDADDR, bmcdefaultrate);
484 #ifdef	BMD
485 	bmdinit();
486 #endif
487 
488 	/* port assign */
489 	sc->sc_pc = sio_port_assign(BMC_CNPORT, bmcmajor, 0, bmcintr);
490 
491 	bmcconsole = unit;
492 }
493 
494 bmccngetc(dev)
495 	dev_t dev;
496 {
497 	struct bmc_softc *sc = &bmc_softc[bmcunit(dev)];
498 	struct sio_portc *pc = sc->sc_pc;
499 #ifdef	BMD
500 	register int c;
501 	register u_char code;
502 
503 	do {
504 		code = sio_imgetc(pc->pc_addr);
505 	} while ((c = kbd_decode(code)) & KC_TYPE);
506 
507 	return(c);
508 #else
509 	return(sio_imgetc(pc->pc_addr));
510 #endif
511 }
512 
513 bmccnputc(dev, c)
514 	dev_t dev;
515 	int c;
516 {
517 	struct bmc_softc *sc = &bmc_softc[bmcunit(dev)];
518 	struct sio_portc *pc = sc->sc_pc;
519 
520 #ifdef BMD
521 	bmdputc(c);
522 #else
523 	sio_imputc(pc->pc_addr, c);
524 #endif
525 }
526 #endif
527