No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / hp700 / dev / pdc.c
blob6f5fdadf5c1170ef6bb7114515a4727dccd89407
1 /* $NetBSD: pdc.c,v 1.33 2009/11/21 15:36:33 rmind Exp $ */
3 /* $OpenBSD: pdc.c,v 1.14 2001/04/29 21:05:43 mickey Exp $ */
5 /*
6 * Copyright (c) 1998-2003 Michael Shalayeff
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: pdc.c,v 1.33 2009/11/21 15:36:33 rmind Exp $");
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37 #include <sys/proc.h>
38 #include <sys/tty.h>
39 #include <sys/callout.h>
40 #include <sys/conf.h>
41 #include <sys/kauth.h>
43 #include <dev/cons.h>
44 #include <dev/clock_subr.h>
46 #include <machine/pdc.h>
47 #include <machine/iomod.h>
48 #include <machine/autoconf.h>
50 #include <hp700/hp700/machdep.h>
52 typedef
53 struct pdc_softc {
54 device_t sc_dv;
55 struct tty *sc_tty;
56 struct callout sc_to;
57 } pdcsoftc_t;
59 pdcio_t pdc;
60 int pdcret[32] PDC_ALIGNMENT;
61 char pdc_consbuf[IODC_MINIOSIZ] PDC_ALIGNMENT;
62 iodcio_t pdc_cniodc, pdc_kbdiodc;
63 pz_device_t *pz_kbd, *pz_cons;
64 int CONADDR;
66 int pdcmatch(device_t, cfdata_t, void *);
67 void pdcattach(device_t, device_t, void *);
69 CFATTACH_DECL_NEW(pdc, sizeof(pdcsoftc_t),
70 pdcmatch, pdcattach, NULL, NULL);
72 extern struct cfdriver pdc_cd;
74 static int pdc_attached;
76 dev_type_open(pdcopen);
77 dev_type_close(pdcclose);
78 dev_type_read(pdcread);
79 dev_type_write(pdcwrite);
80 dev_type_ioctl(pdcioctl);
81 dev_type_stop(pdcstop);
82 dev_type_tty(pdctty);
83 dev_type_poll(pdcpoll);
85 const struct cdevsw pdc_cdevsw = {
86 pdcopen, pdcclose, pdcread, pdcwrite, pdcioctl,
87 pdcstop, pdctty, pdcpoll, nommap, ttykqfilter, D_TTY
90 void pdcstart(struct tty *);
91 void pdctimeout(void *);
92 int pdcparam(struct tty *, struct termios *);
93 int pdccnlookc(dev_t, int *);
95 static struct cnm_state pdc_cnm_state;
97 static int pdcgettod(todr_chip_handle_t, struct timeval *);
98 static int pdcsettod(todr_chip_handle_t, struct timeval *);
100 static struct pdc_tod tod PDC_ALIGNMENT;
102 void
103 pdc_init(void)
105 static struct todr_chip_handle todr = {
106 .todr_settime = pdcsettod,
107 .todr_gettime = pdcgettod,
109 static int kbd_iodc[IODC_MAXSIZE/sizeof(int)];
110 static int cn_iodc[IODC_MAXSIZE/sizeof(int)];
111 int err;
112 int pagezero_cookie;
114 pagezero_cookie = hp700_pagezero_map();
117 * locore has updated pdc with (pdcio_t)PAGE0->mem_pdc
119 pz_kbd = &PAGE0->mem_kbd;
120 pz_cons = &PAGE0->mem_cons;
122 /* XXX should we reset the console/kbd here?
123 well, /boot did that for us anyway */
124 if ((err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_READ,
125 pdcret, pz_cons->pz_hpa, IODC_IO, cn_iodc, IODC_MAXSIZE)) < 0 ||
126 (err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_READ,
127 pdcret, pz_kbd->pz_hpa, IODC_IO, kbd_iodc, IODC_MAXSIZE)) < 0) {
128 #ifdef DEBUG
129 printf("pdc_init: failed reading IODC (%d)\n", err);
130 #endif
133 pdc_cniodc = (iodcio_t)cn_iodc;
134 pdc_kbdiodc = (iodcio_t)kbd_iodc;
136 /* XXX make pdc current console */
137 cn_tab = &constab[0];
138 /* TODO: detect that we are on cereal, and set CONADDR */
140 cn_init_magic(&pdc_cnm_state);
141 cn_set_magic("+++++");
143 hp700_pagezero_unmap(pagezero_cookie);
145 /* attach the TOD clock */
146 todr_attach(&todr);
150 pdcmatch(device_t parent, cfdata_t cf, void *aux)
152 struct confargs *ca = aux;
154 /* there could be only one */
155 if (pdc_attached || strcmp(ca->ca_name, "pdc"))
156 return 0;
158 return 1;
161 void
162 pdcattach(device_t parent, device_t self, void *aux)
164 struct pdc_softc *sc = device_private(self);
166 sc->sc_dv = self;
167 pdc_attached = 1;
169 if (!pdc)
170 pdc_init();
172 aprint_normal("\n");
174 callout_init(&sc->sc_to, 0);
178 pdcopen(dev_t dev, int flag, int mode, struct lwp *l)
180 struct pdc_softc *sc;
181 struct tty *tp;
182 int s;
183 int error = 0, setuptimeout;
185 sc = device_lookup_private(&pdc_cd, minor(dev));
186 if (sc == NULL)
187 return ENXIO;
189 s = spltty();
191 if (sc->sc_tty)
192 tp = sc->sc_tty;
193 else
194 tty_attach(tp = sc->sc_tty = ttymalloc());
196 tp->t_oproc = pdcstart;
197 tp->t_param = pdcparam;
198 tp->t_dev = dev;
200 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) {
201 splx(s);
202 return (EBUSY);
205 if ((tp->t_state & TS_ISOPEN) == 0) {
206 tp->t_state |= TS_CARR_ON;
207 ttychars(tp);
208 tp->t_iflag = TTYDEF_IFLAG;
209 tp->t_oflag = TTYDEF_OFLAG;
210 tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
211 tp->t_lflag = TTYDEF_LFLAG;
212 tp->t_ispeed = tp->t_ospeed = 9600;
213 ttsetwater(tp);
215 setuptimeout = 1;
216 } else
217 setuptimeout = 0;
218 tp->t_state |= TS_CARR_ON;
220 splx(s);
222 error = (*tp->t_linesw->l_open)(dev, tp);
223 if (error == 0 && setuptimeout)
224 pdctimeout(sc);
226 return error;
230 pdcclose(dev_t dev, int flag, int mode, struct lwp *l)
232 struct tty *tp;
233 struct pdc_softc *sc;
235 sc = device_lookup_private(&pdc_cd, minor(dev));
236 if (sc == NULL)
237 return ENXIO;
239 tp = sc->sc_tty;
240 callout_stop(&sc->sc_to);
241 (*tp->t_linesw->l_close)(tp, flag);
242 ttyclose(tp);
243 return 0;
247 pdcread(dev_t dev, struct uio *uio, int flag)
249 struct tty *tp;
250 struct pdc_softc *sc;
252 sc = device_lookup_private(&pdc_cd, minor(dev));
253 if (sc == NULL)
254 return ENXIO;
256 tp = sc->sc_tty;
257 return ((*tp->t_linesw->l_read)(tp, uio, flag));
261 pdcwrite(dev_t dev, struct uio *uio, int flag)
263 struct tty *tp;
264 struct pdc_softc *sc;
266 sc = device_lookup_private(&pdc_cd, minor(dev));
267 if (sc == NULL)
268 return ENXIO;
270 tp = sc->sc_tty;
271 return ((*tp->t_linesw->l_write)(tp, uio, flag));
275 pdcpoll(dev_t dev, int events, struct lwp *l)
277 struct pdc_softc *sc = device_lookup_private(&pdc_cd,minor(dev));
278 struct tty *tp = sc->sc_tty;
280 return ((*tp->t_linesw->l_poll)(tp, events, l));
284 pdcioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
286 int error;
287 struct tty *tp;
288 struct pdc_softc *sc;
290 sc = device_lookup_private(&pdc_cd, minor(dev));
291 if (sc == NULL)
292 return ENXIO;
294 tp = sc->sc_tty;
295 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
296 if (error >= 0)
297 return error;
298 error = ttioctl(tp, cmd, data, flag, l);
299 if (error >= 0)
300 return error;
302 return ENOTTY;
306 pdcparam(struct tty *tp, struct termios *t)
309 return 0;
312 void
313 pdcstart(struct tty *tp)
315 int s;
317 s = spltty();
318 if (tp->t_state & (TS_TTSTOP | TS_BUSY)) {
319 splx(s);
320 return;
322 ttypull(tp);
323 tp->t_state |= TS_BUSY;
324 while (tp->t_outq.c_cc != 0)
325 pdccnputc(tp->t_dev, getc(&tp->t_outq));
326 tp->t_state &= ~TS_BUSY;
327 splx(s);
330 void
331 pdcstop(struct tty *tp, int flag)
333 int s;
335 s = spltty();
336 if (tp->t_state & TS_BUSY)
337 if ((tp->t_state & TS_TTSTOP) == 0)
338 tp->t_state |= TS_FLUSH;
339 splx(s);
342 void
343 pdctimeout(void *v)
345 struct pdc_softc *sc = v;
346 struct tty *tp = sc->sc_tty;
347 int c;
349 while (pdccnlookc(tp->t_dev, &c)) {
350 cn_check_magic(tp->t_dev, c, pdc_cnm_state);
351 if (tp->t_state & TS_ISOPEN)
352 (*tp->t_linesw->l_rint)(c, tp);
354 callout_reset(&sc->sc_to, 1, pdctimeout, sc);
357 struct tty *
358 pdctty(dev_t dev)
360 struct pdc_softc *sc;
362 sc = device_lookup_private(&pdc_cd, minor(dev));
363 if (sc == NULL)
364 return NULL;
366 return sc->sc_tty;
369 void
370 pdccnprobe(struct consdev *cn)
373 cn->cn_dev = makedev(22,0);
374 cn->cn_pri = CN_NORMAL;
377 void
378 pdccninit(struct consdev *cn)
380 #ifdef DEBUG
381 printf("pdc0: console init\n");
382 #endif
386 pdccnlookc(dev_t dev, int *cp)
388 int s, err, l, pagezero_cookie;
390 s = splhigh();
391 pagezero_cookie = hp700_pagezero_map();
392 err = pdc_call(pdc_kbdiodc, 0, pz_kbd->pz_hpa, IODC_IO_CONSIN,
393 pz_kbd->pz_spa, pz_kbd->pz_layers, pdcret, 0, pdc_consbuf, 1, 0);
394 l = pdcret[0];
395 *cp = pdc_consbuf[0];
396 hp700_pagezero_unmap(pagezero_cookie);
397 splx(s);
399 #ifdef DEBUG
400 if (err < 0)
401 printf("pdccnlookc: input error: %d\n", err);
402 #endif
403 return l;
407 pdccngetc(dev_t dev)
409 int c;
411 if (!pdc)
412 return 0;
413 while (!pdccnlookc(dev, &c))
415 return (c);
418 void
419 pdccnputc(dev_t dev, int c)
421 int s, err, pagezero_cookie;
423 s = splhigh();
424 pagezero_cookie = hp700_pagezero_map();
425 *pdc_consbuf = c;
426 err = pdc_call(pdc_cniodc, 0, pz_cons->pz_hpa, IODC_IO_CONSOUT,
427 pz_cons->pz_spa, pz_cons->pz_layers, pdcret, 0, pdc_consbuf, 1, 0);
428 hp700_pagezero_unmap(pagezero_cookie);
429 splx(s);
431 if (err < 0) {
432 #if defined(DDB) || defined(KGDB)
433 __asm volatile ("break %0, %1"
434 :: "i" (HPPA_BREAK_KERNEL), "i" (HPPA_BREAK_KGDB));
435 #endif /* DDB || KGDB */
436 delay(250000);
437 #if 0
439 * It's not a good idea to use the output to print
440 * an output error.
442 printf("pdccnputc: output error: %d\n", err);
443 #endif
447 void
448 pdccnpollc(dev_t dev, int on)
452 static int
453 pdcgettod(todr_chip_handle_t tch, struct timeval *tvp)
455 int error;
457 error = pdc_call((iodcio_t)pdc, 1, PDC_TOD, PDC_TOD_READ,
458 &tod, 0, 0, 0, 0, 0);
460 if (error == 0) {
461 tvp->tv_sec = tod.sec;
462 tvp->tv_usec = tod.usec;
464 return error;
467 static int
468 pdcsettod(todr_chip_handle_t tch, struct timeval *tvp)
470 int error;
472 tod.sec = tvp->tv_sec;
473 tod.usec = tvp->tv_usec;
475 error = pdc_call((iodcio_t)pdc, 1, PDC_TOD, PDC_TOD_WRITE,
476 tod.sec, tod.usec);
477 return error;