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