xref: /openbsd-src/sys/arch/hppa/dev/pdc.c (revision 32ffafad193fd9d5bc1743017cf37d821be47b78)
1 /*	$OpenBSD: pdc.c,v 1.42 2024/05/22 14:25:47 jsg 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 struct consdev pdccons = { NULL, NULL, pdccngetc, pdccnputc,
58      nullcnpollc, NULL, makedev(22, 0), CN_LOWPRI };
59 
60 int pdcmatch(struct device *, void *, void *);
61 void pdcattach(struct device *, struct device *, void *);
62 
63 const struct cfattach pdc_ca = {
64 	sizeof(pdcsoftc_t), pdcmatch, pdcattach
65 };
66 
67 struct cfdriver pdc_cd = {
68 	NULL, "pdc", DV_DULL
69 };
70 
71 void pdcstart(struct tty *tp);
72 void pdctimeout(void *v);
73 int pdcparam(struct tty *tp, struct termios *);
74 int pdccnlookc(dev_t dev, int *cp);
75 
76 #if NCOM > 0
77 /* serial console speed table */
78 static int pdc_speeds[] = {
79 	B50,
80 	B75,
81 	B110,
82 	B150,
83 	B300,
84 	B600,
85 	B1200,
86 	B2400,
87 	B4800,
88 	B7200,
89 	B9600,
90 	B19200,
91 	B38400,
92 	B57600,
93 	B115200,
94 	B230400,
95 };
96 #endif
97 
98 void
pdc_init()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 	/* Start out with pdc as the console. */
124 	cn_tab = &pdccons;
125 
126 	/* Figure out console settings. */
127 #if NCOM > 0
128 	if (PAGE0->mem_cons.pz_class == PCL_DUPLEX) {
129 		struct pz_device *pzd = &PAGE0->mem_cons;
130 		extern int comdefaultrate;
131 #ifdef DEBUG
132 		printf("console: class %d flags %b ",
133 		    pzd->pz_class, pzd->pz_flags, PZF_BITS);
134 		printf("bc %d/%d/%d/%d/%d/%d ",
135 		    pzd->pz_bc[0], pzd->pz_bc[1], pzd->pz_bc[2],
136 		    pzd->pz_bc[3], pzd->pz_bc[4], pzd->pz_bc[5]);
137 		printf("mod %x layers %x/%x/%x/%x/%x/%x hpa %x\n", pzd->pz_mod,
138 		    pzd->pz_layers[0], pzd->pz_layers[1], pzd->pz_layers[2],
139 		    pzd->pz_layers[3], pzd->pz_layers[4], pzd->pz_layers[5],
140 		    pzd->pz_hpa);
141 
142 #endif
143 
144 		/* compute correct baud rate */
145 		if (PZL_SPEED(pzd->pz_layers[0]) <
146 		    sizeof(pdc_speeds) / sizeof(int))
147 			comdefaultrate =
148 			    pdc_speeds[PZL_SPEED(pzd->pz_layers[0])];
149 		else
150 			comdefaultrate = B9600;	/* XXX */
151 	}
152 #endif
153 }
154 
155 int
pdcmatch(parent,cfdata,aux)156 pdcmatch(parent, cfdata, aux)
157 	struct device *parent;
158 	void *cfdata;
159 	void *aux;
160 {
161 	struct cfdata *cf = cfdata;
162 	struct confargs *ca = aux;
163 
164 	/* there could be only one */
165 	if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "pdc"))
166 		return 0;
167 
168 	return 1;
169 }
170 
171 void
pdcattach(parent,self,aux)172 pdcattach(parent, self, aux)
173 	struct device *parent;
174 	struct device *self;
175 	void *aux;
176 {
177 	struct pdc_softc *sc = (struct pdc_softc *)self;
178 
179 	if (!pdc)
180 		pdc_init();
181 
182 	printf("\n");
183 
184 	timeout_set(&sc->sc_to, pdctimeout, sc);
185 }
186 
187 int
pdcopen(dev,flag,mode,p)188 pdcopen(dev, flag, mode, p)
189 	dev_t dev;
190 	int flag, mode;
191 	struct proc *p;
192 {
193 	int unit = minor(dev);
194 	struct pdc_softc *sc;
195 	struct tty *tp;
196 	int s;
197 	int error = 0, setuptimeout = 0;
198 
199 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
200 		return ENXIO;
201 
202 	s = spltty();
203 
204 	if (sc->sc_tty)
205 		tp = sc->sc_tty;
206 	else {
207 		tp = sc->sc_tty = ttymalloc(0);
208 	}
209 
210 	tp->t_oproc = pdcstart;
211 	tp->t_param = pdcparam;
212 	tp->t_dev = dev;
213 	if ((tp->t_state & TS_ISOPEN) == 0) {
214 		ttychars(tp);
215 		tp->t_iflag = TTYDEF_IFLAG;
216 		tp->t_oflag = TTYDEF_OFLAG;
217 		tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
218 		tp->t_lflag = TTYDEF_LFLAG;
219 		tp->t_ispeed = tp->t_ospeed = B9600;
220 		ttsetwater(tp);
221 
222 		setuptimeout = 1;
223 	} else if (tp->t_state&TS_XCLUDE && suser(p) != 0) {
224 		splx(s);
225 		return (EBUSY);
226 	}
227 	tp->t_state |= TS_CARR_ON;
228 	splx(s);
229 
230 	error = (*linesw[tp->t_line].l_open)(dev, tp, p);
231 	if (error == 0 && setuptimeout)
232 		pdctimeout(sc);
233 
234 	return error;
235 }
236 
237 int
pdcclose(dev,flag,mode,p)238 pdcclose(dev, flag, mode, p)
239 	dev_t dev;
240 	int flag, mode;
241 	struct proc *p;
242 {
243 	int unit = minor(dev);
244 	struct tty *tp;
245 	struct pdc_softc *sc;
246 
247 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
248 		return ENXIO;
249 
250 	tp = sc->sc_tty;
251 	timeout_del(&sc->sc_to);
252 	(*linesw[tp->t_line].l_close)(tp, flag, p);
253 	ttyclose(tp);
254 	return 0;
255 }
256 
257 int
pdcread(dev,uio,flag)258 pdcread(dev, uio, flag)
259 	dev_t dev;
260 	struct uio *uio;
261 	int flag;
262 {
263 	int unit = minor(dev);
264 	struct tty *tp;
265 	struct pdc_softc *sc;
266 
267 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
268 		return ENXIO;
269 
270 	tp = sc->sc_tty;
271 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
272 }
273 
274 int
pdcwrite(dev,uio,flag)275 pdcwrite(dev, uio, flag)
276 	dev_t dev;
277 	struct uio *uio;
278 	int flag;
279 {
280 	int unit = minor(dev);
281 	struct tty *tp;
282 	struct pdc_softc *sc;
283 
284 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
285 		return ENXIO;
286 
287 	tp = sc->sc_tty;
288 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
289 }
290 
291 int
pdcioctl(dev,cmd,data,flag,p)292 pdcioctl(dev, cmd, data, flag, p)
293 	dev_t dev;
294 	u_long cmd;
295 	caddr_t data;
296 	int flag;
297 	struct proc *p;
298 {
299 	int unit = minor(dev);
300 	int error;
301 	struct tty *tp;
302 	struct pdc_softc *sc;
303 
304 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
305 		return ENXIO;
306 
307 	tp = sc->sc_tty;
308 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
309 	if (error >= 0)
310 		return error;
311 	error = ttioctl(tp, cmd, data, flag, p);
312 	if (error >= 0)
313 		return error;
314 
315 	return ENOTTY;
316 }
317 
318 int
pdcparam(tp,t)319 pdcparam(tp, t)
320 	struct tty *tp;
321 	struct termios *t;
322 {
323 
324 	return 0;
325 }
326 
327 void
pdcstart(tp)328 pdcstart(tp)
329 	struct tty *tp;
330 {
331 	int s;
332 
333 	s = spltty();
334 	if (tp->t_state & (TS_TTSTOP | TS_BUSY)) {
335 		splx(s);
336 		return;
337 	}
338 	ttwakeupwr(tp);
339 	tp->t_state |= TS_BUSY;
340 	while (tp->t_outq.c_cc != 0)
341 		pdccnputc(tp->t_dev, getc(&tp->t_outq));
342 	tp->t_state &= ~TS_BUSY;
343 	splx(s);
344 }
345 
346 int
pdcstop(tp,flag)347 pdcstop(tp, flag)
348 	struct tty *tp;
349 	int flag;
350 {
351 	int s;
352 
353 	s = spltty();
354 	if (tp->t_state & TS_BUSY)
355 		if ((tp->t_state & TS_TTSTOP) == 0)
356 			tp->t_state |= TS_FLUSH;
357 	splx(s);
358 	return 0;
359 }
360 
361 void
pdctimeout(v)362 pdctimeout(v)
363 	void *v;
364 {
365 	struct pdc_softc *sc = v;
366 	struct tty *tp = sc->sc_tty;
367 	int c;
368 
369 	while (pdccnlookc(tp->t_dev, &c)) {
370 		if (tp->t_state & TS_ISOPEN)
371 			(*linesw[tp->t_line].l_rint)(c, tp);
372 	}
373 	timeout_add(&sc->sc_to, 1);
374 }
375 
376 struct tty *
pdctty(dev)377 pdctty(dev)
378 	dev_t dev;
379 {
380 	int unit = minor(dev);
381 	struct pdc_softc *sc;
382 
383 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
384 		return NULL;
385 
386 	return sc->sc_tty;
387 }
388 
389 int
pdccnlookc(dev,cp)390 pdccnlookc(dev, cp)
391 	dev_t dev;
392 	int *cp;
393 {
394 	int err, l;
395 	int s = splhigh();
396 
397 	err = pdc_call(pdc_kbdiodc, 0, pz_kbd->pz_hpa, IODC_IO_CONSIN,
398 	    pz_kbd->pz_spa, pz_kbd->pz_layers, pdcret, 0, pdc_consbuf, 1, 0);
399 
400 	l = pdcret[0];
401 	*cp = pdc_consbuf[0];
402 	splx(s);
403 #ifdef DEBUG
404 	if (err < 0)
405 		printf("pdccnlookc: input error: %d\n", err);
406 #endif
407 
408 	return l;
409 }
410 
411 int
pdccngetc(dev)412 pdccngetc(dev)
413 	dev_t dev;
414 {
415 	int c;
416 
417 	if (!pdc)
418 		return 0;
419 
420 	while(!pdccnlookc(dev, &c))
421 		;
422 
423 	return (c);
424 }
425 
426 void
pdccnputc(dev,c)427 pdccnputc(dev, c)
428 	dev_t dev;
429 	int c;
430 {
431 	register int err;
432 	int s = splhigh();
433 
434 	*pdc_consbuf = c;
435 	err = pdc_call(pdc_cniodc, 0, pz_cons->pz_hpa, IODC_IO_CONSOUT,
436 	    pz_cons->pz_spa, pz_cons->pz_layers, pdcret, 0, pdc_consbuf, 1, 0);
437 	splx(s);
438 
439 	if (err < 0) {
440 #ifdef DEBUG
441 		printf("pdccnputc: output error: %d\n", err);
442 #endif
443 	}
444 }
445