xref: /openbsd-src/sys/arch/hppa/dev/pdc.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: pdc.c,v 1.25 2003/05/14 23:18:09 miod Exp $	*/
2 
3 /*
4  * Copyright (c) 1998-2002 Michael Shalayeff
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Michael Shalayeff.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF MIND,
27  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/device.h>
36 #include <sys/tty.h>
37 #include <sys/user.h>
38 #include <sys/timeout.h>
39 
40 #include <dev/cons.h>
41 
42 #include <machine/conf.h>
43 #include <machine/pdc.h>
44 #include <machine/iomod.h>
45 #include <machine/autoconf.h>
46 
47 typedef
48 struct pdc_softc {
49 	struct device sc_dv;
50 	struct tty *sc_tty;
51 	struct timeout sc_to;
52 } pdcsoftc_t;
53 
54 pdcio_t pdc;
55 int pdcret[32] PDC_ALIGNMENT;
56 char pdc_consbuf[IODC_MINIOSIZ] PDC_ALIGNMENT;
57 iodcio_t pdc_cniodc, pdc_kbdiodc;
58 pz_device_t *pz_kbd, *pz_cons;
59 hppa_hpa_t conaddr;
60 int conunit;
61 
62 int pdcmatch(struct device *, void *, void *);
63 void pdcattach(struct device *, struct device *, void *);
64 
65 struct cfattach pdc_ca = {
66 	sizeof(pdcsoftc_t), pdcmatch, pdcattach
67 };
68 
69 struct cfdriver pdc_cd = {
70 	NULL, "pdc", DV_DULL
71 };
72 
73 void pdcstart(struct tty *tp);
74 void pdctimeout(void *v);
75 int pdcparam(struct tty *tp, struct termios *);
76 int pdccnlookc(dev_t dev, int *cp);
77 
78 /* serial console speed table */
79 static int pdc_speeds[] = {
80 	B50,
81 	B75,
82 	B110,
83 	B150,
84 	B300,
85 	B600,
86 	B1200,
87 	B2400,
88 	B4800,
89 	B7200,
90 	B9600,
91 	B19200,
92 	B38400,
93 	B57600,
94 	B115200,
95 	B230400,
96 };
97 
98 void
99 pdc_init()
100 {
101 	static int kbd_iodc[IODC_MAXSIZE/sizeof(int)];
102 	static int cn_iodc[IODC_MAXSIZE/sizeof(int)];
103 	int err;
104 
105 	/* XXX locore've done it XXX pdc = (pdcio_t)PAGE0->mem_pdc; */
106 	pz_kbd = &PAGE0->mem_kbd;
107 	pz_cons = &PAGE0->mem_cons;
108 
109 	/* XXX should we reset the console/kbd here?
110 	   well, /boot did that for us anyway */
111 	if ((err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_READ,
112 	      pdcret, pz_cons->pz_hpa, IODC_IO, cn_iodc, IODC_MAXSIZE)) < 0 ||
113 	    (err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_READ,
114 	      pdcret, pz_kbd->pz_hpa, IODC_IO, kbd_iodc, IODC_MAXSIZE)) < 0) {
115 #ifdef DEBUG
116 		printf("pdc_init: failed reading IODC (%d)\n", err);
117 #endif
118 	}
119 
120 	pdc_cniodc = (iodcio_t)cn_iodc;
121 	pdc_kbdiodc = (iodcio_t)kbd_iodc;
122 
123 	/* XXX make pdc current console */
124 	cn_tab = &constab[0];
125 
126 	/* setup the console */
127 #include "com.h"
128 #if NCOM_GSC > 0
129 	if (PAGE0->mem_cons.pz_class == PCL_DUPLEX) {
130 		struct pz_device *pzd = &PAGE0->mem_cons;
131 		extern int comdefaultrate;
132 #ifdef DEBUG
133 		printf("console: class %d flags %b ",
134 		    pzd->pz_class, pzd->pz_flags, PZF_BITS);
135 		printf("bc %d/%d/%d/%d/%d/%d ",
136 		    pzd->pz_bc[0], pzd->pz_bc[1], pzd->pz_bc[2],
137 		    pzd->pz_bc[3], pzd->pz_bc[4], pzd->pz_bc[5]);
138 		printf("mod %x layers %x/%x/%x/%x/%x/%x hpa %x\n", pzd->pz_mod,
139 		    pzd->pz_layers[0], pzd->pz_layers[1], pzd->pz_layers[2],
140 		    pzd->pz_layers[3], pzd->pz_layers[4], pzd->pz_layers[5],
141 		    pzd->pz_hpa);
142 #endif
143 		conaddr = (u_long)pzd->pz_hpa + IOMOD_DEVOFFSET;
144 		conunit = 0;
145 
146 		/* compute correct baud rate */
147 		if (PZL_SPEED(pzd->pz_layers[0]) <
148 		    sizeof(pdc_speeds) / sizeof(int))
149 			comdefaultrate =
150 			    pdc_speeds[PZL_SPEED(pzd->pz_layers[0])];
151 		else
152 			comdefaultrate = B9600;	/* XXX */
153 	}
154 #endif
155 }
156 
157 int
158 pdcmatch(parent, cfdata, aux)
159 	struct device *parent;
160 	void *cfdata;
161 	void *aux;
162 {
163 	struct cfdata *cf = cfdata;
164 	struct confargs *ca = aux;
165 
166 	/* there could be only one */
167 	if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "pdc"))
168 		return 0;
169 
170 	return 1;
171 }
172 
173 void
174 pdcattach(parent, self, aux)
175 	struct device *parent;
176 	struct device *self;
177 	void *aux;
178 {
179 	struct pdc_softc *sc = (struct pdc_softc *)self;
180 
181 	if (!pdc)
182 		pdc_init();
183 
184 	printf("\n");
185 
186 	timeout_set(&sc->sc_to, pdctimeout, sc);
187 }
188 
189 int
190 pdcopen(dev, flag, mode, p)
191 	dev_t dev;
192 	int flag, mode;
193 	struct proc *p;
194 {
195 	int unit = minor(dev);
196 	struct pdc_softc *sc;
197 	struct tty *tp;
198 	int s;
199 	int error = 0, setuptimeout = 0;
200 
201 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
202 		return ENXIO;
203 
204 	s = spltty();
205 
206 	if (sc->sc_tty)
207 		tp = sc->sc_tty;
208 	else
209 		tty_attach(tp = sc->sc_tty = ttymalloc());
210 
211 	tp->t_oproc = pdcstart;
212 	tp->t_param = pdcparam;
213 	tp->t_dev = dev;
214 	if ((tp->t_state & TS_ISOPEN) == 0) {
215 		ttychars(tp);
216 		tp->t_iflag = TTYDEF_IFLAG;
217 		tp->t_oflag = TTYDEF_OFLAG;
218 		tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
219 		tp->t_lflag = TTYDEF_LFLAG;
220 		tp->t_ispeed = tp->t_ospeed = B9600;
221 		ttsetwater(tp);
222 
223 		setuptimeout = 1;
224 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) {
225 		splx(s);
226 		return (EBUSY);
227 	}
228 	tp->t_state |= TS_CARR_ON;
229 	splx(s);
230 
231 	error = (*linesw[tp->t_line].l_open)(dev, tp);
232 	if (error == 0 && setuptimeout)
233 		pdctimeout(sc);
234 
235 	return error;
236 }
237 
238 int
239 pdcclose(dev, flag, mode, p)
240 	dev_t dev;
241 	int flag, mode;
242 	struct proc *p;
243 {
244 	int unit = minor(dev);
245 	struct tty *tp;
246 	struct pdc_softc *sc;
247 
248 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
249 		return ENXIO;
250 
251 	tp = sc->sc_tty;
252 	timeout_del(&sc->sc_to);
253 	(*linesw[tp->t_line].l_close)(tp, flag);
254 	ttyclose(tp);
255 	return 0;
256 }
257 
258 int
259 pdcread(dev, uio, flag)
260 	dev_t dev;
261 	struct uio *uio;
262 	int flag;
263 {
264 	int unit = minor(dev);
265 	struct tty *tp;
266 	struct pdc_softc *sc;
267 
268 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
269 		return ENXIO;
270 
271 	tp = sc->sc_tty;
272 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
273 }
274 
275 int
276 pdcwrite(dev, uio, flag)
277 	dev_t dev;
278 	struct uio *uio;
279 	int flag;
280 {
281 	int unit = minor(dev);
282 	struct tty *tp;
283 	struct pdc_softc *sc;
284 
285 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
286 		return ENXIO;
287 
288 	tp = sc->sc_tty;
289 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
290 }
291 
292 int
293 pdcioctl(dev, cmd, data, flag, p)
294 	dev_t dev;
295 	u_long cmd;
296 	caddr_t data;
297 	int flag;
298 	struct proc *p;
299 {
300 	int unit = minor(dev);
301 	int error;
302 	struct tty *tp;
303 	struct pdc_softc *sc;
304 
305 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
306 		return ENXIO;
307 
308 	tp = sc->sc_tty;
309 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
310 	if (error >= 0)
311 		return error;
312 	error = ttioctl(tp, cmd, data, flag, p);
313 	if (error >= 0)
314 		return error;
315 
316 	return ENOTTY;
317 }
318 
319 int
320 pdcparam(tp, t)
321 	struct tty *tp;
322 	struct termios *t;
323 {
324 
325 	return 0;
326 }
327 
328 void
329 pdcstart(tp)
330 	struct tty *tp;
331 {
332 	int s;
333 
334 	s = spltty();
335 	if (tp->t_state & (TS_TTSTOP | TS_BUSY)) {
336 		splx(s);
337 		return;
338 	}
339 	if (tp->t_outq.c_cc <= tp->t_lowat) {
340 		if (tp->t_state & TS_ASLEEP) {
341 			tp->t_state &= ~TS_ASLEEP;
342 			wakeup((caddr_t)&tp->t_outq);
343 		}
344 		selwakeup(&tp->t_wsel);
345 	}
346 	tp->t_state |= TS_BUSY;
347 	while (tp->t_outq.c_cc != 0)
348 		pdccnputc(tp->t_dev, getc(&tp->t_outq));
349 	tp->t_state &= ~TS_BUSY;
350 	splx(s);
351 }
352 
353 int
354 pdcstop(tp, flag)
355 	struct tty *tp;
356 	int flag;
357 {
358 	int s;
359 
360 	s = spltty();
361 	if (tp->t_state & TS_BUSY)
362 		if ((tp->t_state & TS_TTSTOP) == 0)
363 			tp->t_state |= TS_FLUSH;
364 	splx(s);
365 	return 0;
366 }
367 
368 void
369 pdctimeout(v)
370 	void *v;
371 {
372 	struct pdc_softc *sc = v;
373 	struct tty *tp = sc->sc_tty;
374 	int c;
375 
376 	while (pdccnlookc(tp->t_dev, &c)) {
377 		if (tp->t_state & TS_ISOPEN)
378 			(*linesw[tp->t_line].l_rint)(c, tp);
379 	}
380 	timeout_add(&sc->sc_to, 1);
381 }
382 
383 struct tty *
384 pdctty(dev)
385 	dev_t dev;
386 {
387 	int unit = minor(dev);
388 	struct pdc_softc *sc;
389 
390 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
391 		return NULL;
392 
393 	return sc->sc_tty;
394 }
395 
396 void
397 pdccnprobe(cn)
398 	struct consdev *cn;
399 {
400 	cn->cn_dev = makedev(22,0);
401 	cn->cn_pri = CN_NORMAL;
402 }
403 
404 void
405 pdccninit(cn)
406 	struct consdev *cn;
407 {
408 #ifdef DEBUG
409 	printf("pdc0: console init\n");
410 #endif
411 }
412 
413 int
414 pdccnlookc(dev, cp)
415 	dev_t dev;
416 	int *cp;
417 {
418 	int err, l;
419 	int s = splhigh();
420 
421 	err = pdc_call(pdc_kbdiodc, 0, pz_kbd->pz_hpa, IODC_IO_CONSIN,
422 	    pz_kbd->pz_spa, pz_kbd->pz_layers, pdcret, 0, pdc_consbuf, 1, 0);
423 
424 	l = pdcret[0];
425 	*cp = pdc_consbuf[0];
426 	splx(s);
427 #ifdef DEBUG
428 	if (err < 0)
429 		printf("pdccnlookc: input error: %d\n", err);
430 #endif
431 
432 	return l;
433 }
434 
435 int
436 pdccngetc(dev)
437 	dev_t dev;
438 {
439 	int c;
440 
441 	if (!pdc)
442 		return 0;
443 
444 	while(!pdccnlookc(dev, &c))
445 		;
446 
447 	return (c);
448 }
449 
450 void
451 pdccnputc(dev, c)
452 	dev_t dev;
453 	int c;
454 {
455 	register int err;
456 	int s = splhigh();
457 
458 	*pdc_consbuf = c;
459 	err = pdc_call(pdc_cniodc, 0, pz_cons->pz_hpa, IODC_IO_CONSOUT,
460 	    pz_cons->pz_spa, pz_cons->pz_layers, pdcret, 0, pdc_consbuf, 1, 0);
461 	splx(s);
462 
463 	if (err < 0) {
464 #ifdef DEBUG
465 		printf("pdccnputc: output error: %d\n", err);
466 #endif
467 	}
468 }
469 
470 void
471 pdccnpollc(dev, on)
472 	dev_t dev;
473 	int on;
474 {
475 
476 }
477