1 /* $NetBSD: panel.c,v 1.19 2009/08/20 11:43:59 tsutsui Exp $ */
4 * Copyright (c) 2002 Dennis I. Chernoivanov
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission
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 BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: panel.c,v 1.19 2009/08/20 11:43:59 tsutsui Exp $");
33 #include <sys/param.h>
34 #include <sys/systm.h>
39 #include <sys/types.h>
40 #include <sys/kernel.h>
41 #include <sys/device.h>
42 #include <sys/callout.h>
43 #include <sys/select.h>
44 #include <sys/reboot.h>
46 #include <machine/bus.h>
47 #include <machine/autoconf.h>
49 #include <dev/ic/hd44780reg.h>
50 #include <dev/ic/hd44780var.h>
51 #include <dev/ic/lcdkp_subr.h>
55 #define PANEL_POLLRATE (hz / 10)
56 #define PANEL_REGION 0x20
57 #define DATA_OFFSET 0x10
59 #define PANEL_VCOLS 40
65 struct hd44780_chip sc_lcd
;
66 struct lcdkp_chip sc_kp
;
68 struct selinfo sc_selq
;
69 struct callout sc_callout
;
73 const char firstcol
[PANEL_VCOLS
];
74 const char secondcol
[PANEL_VCOLS
];
76 static const struct lcd_message startup_message
= {
80 static const struct lcd_message halt_message
= {
84 static const struct lcd_message reboot_message
= {
89 static int panel_match(device_t
, cfdata_t
, void *);
90 static void panel_attach(device_t
, device_t
, void *);
91 static bool panel_shutdown(device_t
, int);
93 static void panel_soft(void *);
95 static uint8_t panel_cbt_kprread(bus_space_tag_t
, bus_space_handle_t
);
96 static uint8_t panel_cbt_hdreadreg(struct hd44780_chip
*, uint32_t, uint32_t);
97 static void panel_cbt_hdwritereg(struct hd44780_chip
*, uint32_t, uint32_t,
100 dev_type_open(panelopen
);
101 dev_type_close(panelclose
);
102 dev_type_read(panelread
);
103 dev_type_write(panelwrite
);
104 dev_type_ioctl(panelioctl
);
105 dev_type_poll(panelpoll
);
107 const struct cdevsw panel_cdevsw
= {
108 panelopen
, panelclose
, panelread
, panelwrite
, panelioctl
,
109 nostop
, notty
, panelpoll
, nommap
,
112 CFATTACH_DECL_NEW(panel
, sizeof(struct panel_softc
),
113 panel_match
, panel_attach
, NULL
, NULL
);
116 panel_match(device_t parent
, cfdata_t cf
, void *aux
)
123 panel_attach(device_t parent
, device_t self
, void *aux
)
125 struct panel_softc
*sc
= device_private(self
);
126 struct mainbus_attach_args
*maa
= aux
;
127 struct hd44780_io io
;
128 static struct lcdkp_xlate keys
[] = {
137 sc
->sc_lcd
.sc_dev
= self
;
138 sc
->sc_lcd
.sc_iot
= maa
->ma_iot
;
139 if (bus_space_map(sc
->sc_lcd
.sc_iot
, maa
->ma_addr
, PANEL_REGION
,
140 0, &sc
->sc_lcd
.sc_ioir
)) {
141 aprint_error(": unable to map registers\n");
144 bus_space_subregion(sc
->sc_lcd
.sc_iot
, sc
->sc_lcd
.sc_ioir
, DATA_OFFSET
,
145 1, &sc
->sc_lcd
.sc_iodr
);
149 sc
->sc_lcd
.sc_dev_ok
= 1;
150 sc
->sc_lcd
.sc_cols
= PANEL_COLS
;
151 sc
->sc_lcd
.sc_vcols
= PANEL_VCOLS
;
152 sc
->sc_lcd
.sc_flags
= HD_8BIT
| HD_MULTILINE
| HD_KEYPAD
;
154 sc
->sc_lcd
.sc_writereg
= panel_cbt_hdwritereg
;
155 sc
->sc_lcd
.sc_readreg
= panel_cbt_hdreadreg
;
157 hd44780_attach_subr(&sc
->sc_lcd
);
161 io
.len
= PANEL_VCOLS
* PANEL_ROWS
;
162 memcpy(io
.buf
, &startup_message
, io
.len
);
163 hd44780_ddram_io(&sc
->sc_lcd
, sc
->sc_lcd
.sc_curchip
, &io
,
166 pmf_device_register1(self
, NULL
, NULL
, panel_shutdown
);
168 sc
->sc_kp
.sc_iot
= maa
->ma_iot
;
169 sc
->sc_kp
.sc_ioh
= MIPS_PHYS_TO_KSEG1(PANEL_BASE
); /* XXX */
171 sc
->sc_kp
.sc_knum
= sizeof(keys
) / sizeof(struct lcdkp_xlate
);
172 sc
->sc_kp
.sc_kpad
= keys
;
173 sc
->sc_kp
.sc_rread
= panel_cbt_kprread
;
175 lcdkp_attach_subr(&sc
->sc_kp
);
177 callout_init(&sc
->sc_callout
, 0);
178 selinit(&sc
->sc_selq
);
182 panel_shutdown(device_t self
, int howto
)
184 struct panel_softc
*sc
= device_private(self
);
185 struct hd44780_io io
;
189 io
.len
= PANEL_VCOLS
* PANEL_ROWS
;
191 memcpy(io
.buf
, &halt_message
, io
.len
);
193 memcpy(io
.buf
, &reboot_message
, io
.len
);
194 hd44780_ddram_io(&sc
->sc_lcd
, sc
->sc_lcd
.sc_curchip
, &io
,
201 panel_cbt_kprread(bus_space_tag_t iot
, bus_space_handle_t ioh
)
204 delay(HD_TIMEOUT_NORMAL
);
205 return (bus_space_read_4(iot
, ioh
, 0x00) >> 24) & 0xff;
210 panel_cbt_hdwritereg(struct hd44780_chip
*hd
, uint32_t en
, uint32_t rs
,
215 bus_space_write_4(hd
->sc_iot
, hd
->sc_iodr
, 0x00, dat
<< 24);
217 bus_space_write_4(hd
->sc_iot
, hd
->sc_ioir
, 0x00, dat
<< 24);
218 delay(HD_TIMEOUT_NORMAL
);
222 panel_cbt_hdreadreg(struct hd44780_chip
*hd
, uint32_t en
, uint32_t rs
)
225 delay(HD_TIMEOUT_NORMAL
);
227 return (bus_space_read_4(hd
->sc_iot
, hd
->sc_iodr
, 0x00) >> 24)
230 return (bus_space_read_4(hd
->sc_iot
, hd
->sc_ioir
, 0x00) >> 24)
235 panelopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
237 struct panel_softc
*sc
= device_lookup_private(&panel_cd
, minor(dev
));
239 return (sc
->sc_lcd
.sc_dev_ok
== 0) ? ENXIO
: 0;
243 panelclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
245 struct panel_softc
*sc
= device_lookup_private(&panel_cd
, minor(dev
));
247 selnotify(&sc
->sc_selq
, 0, 0);
252 panelread(dev_t dev
, struct uio
*uio
, int flag
)
256 struct panel_softc
*sc
= device_lookup_private(&panel_cd
, minor(dev
));
258 if (uio
->uio_resid
< sizeof(b
))
261 if ((error
= lcdkp_readkey(&sc
->sc_kp
, &b
)) != 0)
264 return uiomove((void*)&b
, sizeof(b
), uio
);
268 panelwrite(dev_t dev
, struct uio
*uio
, int flag
)
271 struct hd44780_io io
;
272 struct panel_softc
*sc
= device_lookup_private(&panel_cd
, minor(dev
));
275 io
.len
= uio
->uio_resid
;
276 if (io
.len
> HD_MAX_CHARS
)
277 io
.len
= HD_MAX_CHARS
;
279 if ((error
= uiomove((void*)io
.buf
, io
.len
, uio
)) != 0)
282 hd44780_ddram_redraw(&sc
->sc_lcd
, 0, &io
);
287 panelioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
289 struct panel_softc
*sc
= device_lookup_private(&panel_cd
, minor(dev
));
291 return hd44780_ioctl_subr(&sc
->sc_lcd
, cmd
, data
);
295 panelpoll(dev_t dev
, int events
, struct lwp
*l
)
299 if ((events
& (POLLIN
| POLLRDNORM
)) != 0) {
300 struct panel_softc
*sc
;
302 sc
= device_lookup_private(&panel_cd
, minor(dev
));
303 if (lcdkp_scankey(&sc
->sc_kp
) != 0) {
304 revents
= events
& (POLLIN
| POLLRDNORM
);
306 selrecord(l
, &sc
->sc_selq
);
307 callout_reset(&sc
->sc_callout
, PANEL_POLLRATE
,
316 panel_soft(void *arg
)
318 struct panel_softc
*sc
= arg
;
320 if (lcdkp_scankey(&sc
->sc_kp
) != 0)
321 selnotify(&sc
->sc_selq
, 0, 0);
323 callout_reset(&sc
->sc_callout
, PANEL_POLLRATE
, panel_soft
, sc
);