xref: /openbsd-src/sys/arch/hppa/dev/pdc.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: pdc.c,v 1.14 2001/04/29 21:05:43 mickey Exp $	*/
2 
3 /*
4  * Copyright (c) 1998-2001 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 int CONADDR;
60 
61 int pdcmatch __P((struct device *, void *, void*));
62 void pdcattach __P((struct device *, struct device *, void *));
63 
64 struct cfattach pdc_ca = {
65 	sizeof(pdcsoftc_t), pdcmatch, pdcattach
66 };
67 
68 struct cfdriver pdc_cd = {
69 	NULL, "pdc", DV_DULL
70 };
71 
72 void pdcstart __P((struct tty *tp));
73 void pdctimeout __P((void *v));
74 int pdcparam __P((struct tty *tp, struct termios *));
75 int pdccnlookc __P((dev_t dev, int *cp));
76 
77 void
78 pdc_init()
79 {
80 	static int kbd_iodc[IODC_MAXSIZE/sizeof(int)];
81 	static int cn_iodc[IODC_MAXSIZE/sizeof(int)];
82 	int err;
83 
84 	/* XXX locore've done it XXX pdc = (pdcio_t)PAGE0->mem_pdc; */
85 	pz_kbd = &PAGE0->mem_kbd;
86 	pz_cons = &PAGE0->mem_cons;
87 
88 	/* XXX should we reset the console/kbd here?
89 	   well, /boot did that for us anyway */
90 	if ((err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_READ,
91 	      pdcret, pz_cons->pz_hpa, IODC_IO, cn_iodc, IODC_MAXSIZE)) < 0 ||
92 	    (err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_READ,
93 	      pdcret, pz_kbd->pz_hpa, IODC_IO, kbd_iodc, IODC_MAXSIZE)) < 0) {
94 #ifdef DEBUG
95 		printf("pdc_init: failed reading IODC (%d)\n", err);
96 #endif
97 	}
98 
99 	pdc_cniodc = (iodcio_t)cn_iodc;
100 	pdc_kbdiodc = (iodcio_t)kbd_iodc;
101 
102 	/* XXX make pdc current console */
103 	cn_tab = &constab[0];
104 	/* TODO: detect that we are on cereal, and set CONADDR */
105 }
106 
107 int
108 pdcmatch(parent, cfdata, aux)
109 	struct device *parent;
110 	void *cfdata;
111 	void *aux;
112 {
113 	struct cfdata *cf = cfdata;
114 	struct confargs *ca = aux;
115 
116 	/* there could be only one */
117 	if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "pdc"))
118 		return 0;
119 
120 	return 1;
121 }
122 
123 void
124 pdcattach(parent, self, aux)
125 	struct device *parent;
126 	struct device *self;
127 	void *aux;
128 {
129 	struct pdc_softc *sc = (struct pdc_softc *)self;
130 
131 	if (!pdc)
132 		pdc_init();
133 
134 	printf("\n");
135 
136 	timeout_set(&sc->sc_to, pdctimeout, sc);
137 }
138 
139 int
140 pdcopen(dev, flag, mode, p)
141 	dev_t dev;
142 	int flag, mode;
143 	struct proc *p;
144 {
145 	int unit = minor(dev);
146 	struct pdc_softc *sc;
147 	struct tty *tp;
148 	int s;
149 	int error = 0, setuptimeout;
150 
151 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
152 		return ENXIO;
153 
154 	s = spltty();
155 
156 	if (sc->sc_tty)
157 		tp = sc->sc_tty;
158 	else
159 		tty_attach(tp = sc->sc_tty = ttymalloc());
160 
161 	tp->t_oproc = pdcstart;
162 	tp->t_param = pdcparam;
163 	tp->t_dev = dev;
164 	if ((tp->t_state & TS_ISOPEN) == 0) {
165 		tp->t_state |= TS_WOPEN|TS_CARR_ON;
166 		ttychars(tp);
167 		tp->t_iflag = TTYDEF_IFLAG;
168 		tp->t_oflag = TTYDEF_OFLAG;
169 		tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
170 		tp->t_lflag = TTYDEF_LFLAG;
171 		tp->t_ispeed = tp->t_ospeed = 9600;
172 		ttsetwater(tp);
173 
174 		setuptimeout = 1;
175 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) {
176 		splx(s);
177 		return EBUSY;
178 	}
179 	tp->t_state |= TS_CARR_ON;
180 
181 	splx(s);
182 
183 	error = (*linesw[tp->t_line].l_open)(dev, tp);
184 	if (error == 0 && setuptimeout)
185 		pdctimeout(sc);
186 
187 	return error;
188 }
189 
190 int
191 pdcclose(dev, flag, mode, p)
192 	dev_t dev;
193 	int flag, mode;
194 	struct proc *p;
195 {
196 	int unit = minor(dev);
197 	struct tty *tp;
198 	struct pdc_softc *sc;
199 
200 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
201 		return ENXIO;
202 
203 	tp = sc->sc_tty;
204 	timeout_del(&sc->sc_to);
205 	(*linesw[tp->t_line].l_close)(tp, flag);
206 	ttyclose(tp);
207 	return 0;
208 }
209 
210 int
211 pdcread(dev, uio, flag)
212 	dev_t dev;
213 	struct uio *uio;
214 	int flag;
215 {
216 	int unit = minor(dev);
217 	struct tty *tp;
218 	struct pdc_softc *sc;
219 
220 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
221 		return ENXIO;
222 
223 	tp = sc->sc_tty;
224 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
225 }
226 
227 int
228 pdcwrite(dev, uio, flag)
229 	dev_t dev;
230 	struct uio *uio;
231 	int flag;
232 {
233 	int unit = minor(dev);
234 	struct tty *tp;
235 	struct pdc_softc *sc;
236 
237 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
238 		return ENXIO;
239 
240 	tp = sc->sc_tty;
241 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
242 }
243 
244 int
245 pdcioctl(dev, cmd, data, flag, p)
246 	dev_t dev;
247 	u_long cmd;
248 	caddr_t data;
249 	int flag;
250 	struct proc *p;
251 {
252 	int unit = minor(dev);
253 	int error;
254 	struct tty *tp;
255 	struct pdc_softc *sc;
256 
257 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
258 		return ENXIO;
259 
260 	tp = sc->sc_tty;
261 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
262 	if (error >= 0)
263 		return error;
264 	error = ttioctl(tp, cmd, data, flag, p);
265 	if (error >= 0)
266 		return error;
267 
268 	return ENOTTY;
269 }
270 
271 int
272 pdcparam(tp, t)
273 	struct tty *tp;
274 	struct termios *t;
275 {
276 
277 	return 0;
278 }
279 
280 void
281 pdcstart(tp)
282 	struct tty *tp;
283 {
284 	int s;
285 
286 	s = spltty();
287 	if (tp->t_state & (TS_TTSTOP | TS_BUSY)) {
288 		splx(s);
289 		return;
290 	}
291 	if (tp->t_outq.c_cc <= tp->t_lowat) {
292 		if (tp->t_state & TS_ASLEEP) {
293 			tp->t_state &= ~TS_ASLEEP;
294 			wakeup((caddr_t)&tp->t_outq);
295 		}
296 		selwakeup(&tp->t_wsel);
297 	}
298 	tp->t_state |= TS_BUSY;
299 	while (tp->t_outq.c_cc != 0)
300 		pdccnputc(tp->t_dev, getc(&tp->t_outq));
301 	tp->t_state &= ~TS_BUSY;
302 	splx(s);
303 }
304 
305 int
306 pdcstop(tp, flag)
307 	struct tty *tp;
308 	int flag;
309 {
310 	int s;
311 
312 	s = spltty();
313 	if (tp->t_state & TS_BUSY)
314 		if ((tp->t_state & TS_TTSTOP) == 0)
315 			tp->t_state |= TS_FLUSH;
316 	splx(s);
317 	return 0;
318 }
319 
320 void
321 pdctimeout(v)
322 	void *v;
323 {
324 	struct pdc_softc *sc = v;
325 	struct tty *tp = sc->sc_tty;
326 	int c;
327 
328 	while (pdccnlookc(tp->t_dev, &c)) {
329 		if (tp->t_state & TS_ISOPEN)
330 			(*linesw[tp->t_line].l_rint)(c, tp);
331 	}
332 	timeout_add(&sc->sc_to, 1);
333 }
334 
335 struct tty *
336 pdctty(dev)
337 	dev_t dev;
338 {
339 	int unit = minor(dev);
340 	struct pdc_softc *sc;
341 
342 	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
343 		return NULL;
344 
345 	return sc->sc_tty;
346 }
347 
348 void
349 pdccnprobe(cn)
350 	struct consdev *cn;
351 {
352 	cn->cn_dev = makedev(22,0);
353 	cn->cn_pri = CN_NORMAL;
354 }
355 
356 void
357 pdccninit(cn)
358 	struct consdev *cn;
359 {
360 #ifdef DEBUG
361 	printf("pdc0: console init\n");
362 #endif
363 }
364 
365 int
366 pdccnlookc(dev, cp)
367 	dev_t dev;
368 	int *cp;
369 {
370 	int err, l;
371 	int s = splhigh();
372 
373 	err = pdc_call(pdc_kbdiodc, 0, pz_kbd->pz_hpa, IODC_IO_CONSIN,
374 	    pz_kbd->pz_spa, pz_kbd->pz_layers, pdcret, 0, pdc_consbuf, 1, 0);
375 
376 	l = pdcret[0];
377 	*cp = pdc_consbuf[0];
378 	splx(s);
379 #ifdef DEBUG
380 	if (err < 0)
381 		printf("pdccnlookc: input error: %d\n", err);
382 #endif
383 
384 	return l;
385 }
386 
387 int
388 pdccngetc(dev)
389 	dev_t dev;
390 {
391 	int c;
392 
393 	if (!pdc)
394 		return 0;
395 
396 	while(!pdccnlookc(dev, &c))
397 		;
398 
399 	return (c);
400 }
401 
402 void
403 pdccnputc(dev, c)
404 	dev_t dev;
405 	int c;
406 {
407 	register int err;
408 	int s = splhigh();
409 
410 	*pdc_consbuf = c;
411 	err = pdc_call(pdc_cniodc, 0, pz_cons->pz_hpa, IODC_IO_CONSOUT,
412 	    pz_cons->pz_spa, pz_cons->pz_layers, pdcret, 0, pdc_consbuf, 1, 0);
413 	splx(s);
414 
415 	if (err < 0) {
416 #ifdef DEBUG
417 		printf("pdccnputc: output error: %d\n", err);
418 #endif
419 	}
420 }
421 
422 void
423 pdccnpollc(dev, on)
424 	dev_t dev;
425 	int on;
426 {
427 
428 }
429