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