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 $ */
6 * Copyright (c) 1998-2003 Michael Shalayeff
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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>
39 #include <sys/callout.h>
41 #include <sys/kauth.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>
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
;
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
);
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
;
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)];
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) {
129 printf("pdc_init: failed reading IODC (%d)\n", err
);
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 */
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"))
162 pdcattach(device_t parent
, device_t self
, void *aux
)
164 struct pdc_softc
*sc
= device_private(self
);
174 callout_init(&sc
->sc_to
, 0);
178 pdcopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
180 struct pdc_softc
*sc
;
183 int error
= 0, setuptimeout
;
185 sc
= device_lookup_private(&pdc_cd
, minor(dev
));
194 tty_attach(tp
= sc
->sc_tty
= ttymalloc());
196 tp
->t_oproc
= pdcstart
;
197 tp
->t_param
= pdcparam
;
200 if (kauth_authorize_device_tty(l
->l_cred
, KAUTH_DEVICE_TTY_OPEN
, tp
)) {
205 if ((tp
->t_state
& TS_ISOPEN
) == 0) {
206 tp
->t_state
|= TS_CARR_ON
;
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;
218 tp
->t_state
|= TS_CARR_ON
;
222 error
= (*tp
->t_linesw
->l_open
)(dev
, tp
);
223 if (error
== 0 && setuptimeout
)
230 pdcclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
233 struct pdc_softc
*sc
;
235 sc
= device_lookup_private(&pdc_cd
, minor(dev
));
240 callout_stop(&sc
->sc_to
);
241 (*tp
->t_linesw
->l_close
)(tp
, flag
);
247 pdcread(dev_t dev
, struct uio
*uio
, int flag
)
250 struct pdc_softc
*sc
;
252 sc
= device_lookup_private(&pdc_cd
, minor(dev
));
257 return ((*tp
->t_linesw
->l_read
)(tp
, uio
, flag
));
261 pdcwrite(dev_t dev
, struct uio
*uio
, int flag
)
264 struct pdc_softc
*sc
;
266 sc
= device_lookup_private(&pdc_cd
, minor(dev
));
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
)
288 struct pdc_softc
*sc
;
290 sc
= device_lookup_private(&pdc_cd
, minor(dev
));
295 error
= (*tp
->t_linesw
->l_ioctl
)(tp
, cmd
, data
, flag
, l
);
298 error
= ttioctl(tp
, cmd
, data
, flag
, l
);
306 pdcparam(struct tty
*tp
, struct termios
*t
)
313 pdcstart(struct tty
*tp
)
318 if (tp
->t_state
& (TS_TTSTOP
| TS_BUSY
)) {
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
;
331 pdcstop(struct tty
*tp
, int flag
)
336 if (tp
->t_state
& TS_BUSY
)
337 if ((tp
->t_state
& TS_TTSTOP
) == 0)
338 tp
->t_state
|= TS_FLUSH
;
345 struct pdc_softc
*sc
= v
;
346 struct tty
*tp
= sc
->sc_tty
;
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
);
360 struct pdc_softc
*sc
;
362 sc
= device_lookup_private(&pdc_cd
, minor(dev
));
370 pdccnprobe(struct consdev
*cn
)
373 cn
->cn_dev
= makedev(22,0);
374 cn
->cn_pri
= CN_NORMAL
;
378 pdccninit(struct consdev
*cn
)
381 printf("pdc0: console init\n");
386 pdccnlookc(dev_t dev
, int *cp
)
388 int s
, err
, l
, pagezero_cookie
;
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);
395 *cp
= pdc_consbuf
[0];
396 hp700_pagezero_unmap(pagezero_cookie
);
401 printf("pdccnlookc: input error: %d\n", err
);
413 while (!pdccnlookc(dev
, &c
))
419 pdccnputc(dev_t dev
, int c
)
421 int s
, err
, pagezero_cookie
;
424 pagezero_cookie
= hp700_pagezero_map();
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
);
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 */
439 * It's not a good idea to use the output to print
442 printf("pdccnputc: output error: %d\n", err
);
448 pdccnpollc(dev_t dev
, int on
)
453 pdcgettod(todr_chip_handle_t tch
, struct timeval
*tvp
)
457 error
= pdc_call((iodcio_t
)pdc
, 1, PDC_TOD
, PDC_TOD_READ
,
458 &tod
, 0, 0, 0, 0, 0);
461 tvp
->tv_sec
= tod
.sec
;
462 tvp
->tv_usec
= tod
.usec
;
468 pdcsettod(todr_chip_handle_t tch
, struct timeval
*tvp
)
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
,