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 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 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 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 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 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 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 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 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 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 323 lcdshow(const char *s) 324 { 325 int cc; 326 327 while ((cc = *s++) != '\0') 328 lcdput(cc); 329 } 330 331 void 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