1 /* $OpenBSD: lcd.c,v 1.11 2021/10/24 09:18:51 deraadt Exp $ */
2 /* $NetBSD: lcd.c,v 1.2 2000/01/07 05:13:08 nisimura Exp $ */
3
4 /*-
5 * Copyright (c) 2000 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Tohru Nishimura.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/device.h>
36 #include <sys/ioctl.h>
37 #include <sys/fcntl.h>
38
39 #include <machine/autoconf.h>
40 #include <machine/board.h>
41 #include <machine/conf.h>
42 #include <machine/lcd.h>
43
44 #define PIO1_MODE_OUTPUT 0x84
45 #define PIO1_MODE_INPUT 0x94
46
47 #define POWER 0x10
48
49 #define ENABLE 0x80
50 #define DISABLE 0x00
51
52 #define WRITE_CMD (0x00 | 0x00)
53 #define WRITE_DATA (0x00 | 0x40)
54 #define READ_BUSY (0x20 | 0x00)
55 #define READ_DATA (0x20 | 0x40)
56
57 #define LCD_INIT 0x38
58 #define LCD_ENTRY 0x06
59 #define LCD_ON 0x0c
60 #define LCD_CLS 0x01
61 #define LCD_HOME 0x02
62 #define LCD_LOCATE(X, Y) (((Y) & 1 ? 0xc0 : 0x80) | ((X) & 0x0f))
63
64 #define LCD_MAXBUFLEN 80
65
66 struct pio {
67 volatile u_int8_t portA;
68 volatile unsigned : 24;
69 volatile u_int8_t portB;
70 volatile unsigned : 24;
71 volatile u_int8_t portC;
72 volatile unsigned : 24;
73 volatile u_int8_t cntrl;
74 volatile unsigned : 24;
75 };
76
77 /* Autoconf stuff */
78 int lcd_match(struct device *, void *, void *);
79 void lcd_attach(struct device *, struct device *, void *);
80
81 struct lcd_softc {
82 struct device sc_dev;
83 int sc_opened;
84 };
85
86 const struct cfattach lcd_ca = {
87 sizeof(struct lcd_softc), lcd_match, lcd_attach
88 };
89
90 struct cfdriver lcd_cd = {
91 NULL, "lcd", DV_DULL,
92 };
93
94 /* Internal prototypes */
95 void lcdbusywait(void);
96 void lcdput(int);
97 void lcdctrl(int);
98 void lcdshow(const char *);
99 void greeting(void);
100
101 /* Internal variables */
102 /* "1234567890123456" */
103 static const char lcd_boot_message1[] = "OpenBSD/luna88k ";
104 static const char lcd_boot_message2[] = " SX-9100/DT ";
105
106 /*
107 * Autoconf functions
108 */
109 int
lcd_match(struct device * parent,void * cf,void * aux)110 lcd_match(struct device *parent, void *cf, void *aux)
111 {
112 struct mainbus_attach_args *ma = aux;
113
114 if (strcmp(ma->ma_name, lcd_cd.cd_name))
115 return 0;
116 if (badaddr((vaddr_t)ma->ma_addr, 4))
117 return 0;
118 return 1;
119 }
120
121 void
lcd_attach(struct device * parent,struct device * self,void * aux)122 lcd_attach(struct device *parent, struct device *self, void *aux)
123 {
124 printf("\n");
125
126 /* Say hello to the world on LCD. */
127 greeting();
128 }
129
130 /*
131 * open/close/write/ioctl
132 */
133
134 int
lcdopen(dev_t dev,int flags,int fmt,struct proc * p)135 lcdopen(dev_t dev, int flags, int fmt, struct proc *p)
136 {
137 int unit = minor(dev);
138 struct lcd_softc *sc;
139
140 if (unit >= lcd_cd.cd_ndevs)
141 return ENXIO;
142 if ((sc = lcd_cd.cd_devs[unit]) == NULL)
143 return ENXIO;
144 if (sc->sc_opened)
145 return EBUSY;
146 sc->sc_opened = 1;
147
148 return 0;
149 }
150
151 int
lcdclose(dev_t dev,int flags,int fmt,struct proc * p)152 lcdclose(dev_t dev, int flags, int fmt, struct proc *p)
153 {
154 int unit = minor(dev);
155 struct lcd_softc *sc;
156
157 sc = lcd_cd.cd_devs[unit];
158 sc->sc_opened = 0;
159
160 return 0;
161 }
162
163 int
lcdwrite(dev_t dev,struct uio * uio,int flag)164 lcdwrite(dev_t dev, struct uio *uio, int flag)
165 {
166 int error;
167 size_t len, i;
168 char buf[LCD_MAXBUFLEN];
169
170 len = uio->uio_resid;
171
172 if (len > LCD_MAXBUFLEN)
173 return EIO;
174
175 error = uiomove(buf, len, uio);
176 if (error)
177 return EIO;
178
179 for (i = 0; i < len; i++) {
180 lcdput((int)buf[i]);
181 }
182
183 return 0;
184 }
185
186 int
lcdioctl(dev_t dev,u_long cmd,caddr_t addr,int flag,struct proc * p)187 lcdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
188 {
189 int val;
190
191 /* check if the device opened with write mode */
192 switch(cmd) {
193 case LCDCLS:
194 case LCDHOME:
195 case LCDMODE:
196 case LCDDISP:
197 case LCDMOVE:
198 case LCDSEEK:
199 case LCDRESTORE:
200 if ((flag & FWRITE) == 0)
201 return EACCES;
202 break;
203 }
204
205 switch(cmd) {
206 case LCDCLS:
207 lcdctrl(LCD_CLS);
208 break;
209
210 case LCDHOME:
211 lcdctrl(LCD_HOME);
212 break;
213
214 case LCDMODE:
215 val = *(int *)addr;
216 switch (val) {
217 case LCDMODE_C_LEFT:
218 case LCDMODE_C_RIGHT:
219 case LCDMODE_D_LEFT:
220 case LCDMODE_D_RIGHT:
221 lcdctrl(val);
222 break;
223 default:
224 return EINVAL;
225 }
226 break;
227
228 case LCDDISP:
229 val = *(int *)addr;
230 if ((val & 0x7) != val)
231 return EINVAL;
232 lcdctrl(val | 0x8);
233 break;
234
235 case LCDMOVE:
236 val = *(int *)addr;
237 switch (val) {
238 case LCDMOVE_C_LEFT:
239 case LCDMOVE_C_RIGHT:
240 case LCDMOVE_D_LEFT:
241 case LCDMOVE_D_RIGHT:
242 lcdctrl(val);
243 break;
244 default:
245 return EINVAL;
246 }
247 break;
248
249 case LCDSEEK:
250 val = *(int *)addr & 0x7f;
251 lcdctrl(val | 0x80);
252 break;
253
254 case LCDRESTORE:
255 greeting();
256 break;
257
258 default:
259 return ENOTTY;
260 }
261 return 0;
262 }
263
264 /*
265 * Internal functions
266 */
267 void
lcdbusywait()268 lcdbusywait()
269 {
270 struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
271 int msb, s;
272
273 s = splhigh();
274 p1->cntrl = PIO1_MODE_INPUT;
275 p1->portC = POWER | READ_BUSY | ENABLE;
276 splx(s);
277
278 do {
279 msb = p1->portA & ENABLE;
280 delay(5);
281 } while (msb != 0);
282
283 s = splhigh();
284 p1->portC = POWER | READ_BUSY | DISABLE;
285 splx(s);
286 }
287
288 void
lcdput(int cc)289 lcdput(int cc)
290 {
291 struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
292 int s;
293
294 lcdbusywait();
295
296 s = splhigh();
297 p1->cntrl = PIO1_MODE_OUTPUT;
298
299 p1->portC = POWER | WRITE_DATA | ENABLE;
300 p1->portA = cc;
301 p1->portC = POWER | WRITE_DATA | DISABLE;
302 splx(s);
303 }
304
305 void
lcdctrl(int cc)306 lcdctrl(int cc)
307 {
308 struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
309 int s;
310
311 lcdbusywait();
312
313 s = splhigh();
314 p1->cntrl = PIO1_MODE_OUTPUT;
315
316 p1->portC = POWER | WRITE_CMD | ENABLE;
317 p1->portA = cc;
318 p1->portC = POWER | WRITE_CMD | DISABLE;
319 splx(s);
320 }
321
322 void
lcdshow(const char * s)323 lcdshow(const char *s)
324 {
325 int cc;
326
327 while ((cc = *s++) != '\0')
328 lcdput(cc);
329 }
330
331 void
greeting()332 greeting()
333 {
334 lcdctrl(LCD_INIT);
335 lcdctrl(LCD_ENTRY);
336 lcdctrl(LCD_ON);
337
338 lcdctrl(LCD_CLS);
339 lcdctrl(LCD_HOME);
340
341 lcdctrl(LCD_LOCATE(0, 0));
342 lcdshow(lcd_boot_message1);
343 lcdctrl(LCD_LOCATE(0, 1));
344 lcdshow(lcd_boot_message2);
345 }
346