1 /* $NetBSD: lcd.c,v 1.9 2018/03/08 03:12:02 mrg Exp $ */ 2 /* $OpenBSD: lcd.c,v 1.7 2015/02/10 22:42:35 miod 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/cdefs.h> /* RCS ID & Copyright macro defns */ 34 35 __KERNEL_RCSID(0, "$NetBSD: lcd.c,v 1.9 2018/03/08 03:12:02 mrg Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/conf.h> 40 #include <sys/device.h> 41 #include <sys/ioctl.h> 42 #include <sys/fcntl.h> 43 #include <sys/errno.h> 44 45 #include <machine/autoconf.h> 46 #include <machine/cpu.h> 47 #include <machine/lcd.h> 48 49 #include "ioconf.h" 50 51 #define PIO1_MODE_OUTPUT 0x84 52 #define PIO1_MODE_INPUT 0x94 53 54 #define POWER 0x10 55 56 #define ENABLE 0x80 57 #define DISABLE 0x00 58 59 #define WRITE_CMD (0x00 | 0x00) 60 #define WRITE_DATA (0x00 | 0x40) 61 #define READ_BUSY (0x20 | 0x00) 62 #define READ_DATA (0x20 | 0x40) 63 64 #define LCD_INIT 0x38 65 #define LCD_ENTRY 0x06 66 #define LCD_ON 0x0c 67 #define LCD_CLS 0x01 68 #define LCD_HOME 0x02 69 #define LCD_LOCATE(X, Y) (((Y) & 1 ? 0xc0 : 0x80) | ((X) & 0x0f)) 70 71 #define LCD_MAXBUFLEN 80 72 73 struct pio { 74 volatile u_int8_t portA; 75 volatile u_int8_t portB; 76 volatile u_int8_t portC; 77 volatile u_int8_t cntrl; 78 }; 79 80 /* Autoconf stuff */ 81 static int lcd_match(device_t, cfdata_t, void *); 82 static void lcd_attach(device_t, device_t, void *); 83 84 dev_type_open(lcdopen); 85 dev_type_close(lcdclose); 86 dev_type_write(lcdwrite); 87 dev_type_ioctl(lcdioctl); 88 89 const struct cdevsw lcd_cdevsw = { 90 .d_open = lcdopen, 91 .d_close = lcdclose, 92 .d_read = noread, 93 .d_write = lcdwrite, 94 .d_ioctl = lcdioctl, 95 .d_stop = nostop, 96 .d_tty = notty, 97 .d_poll = nopoll, 98 .d_mmap = nommap, 99 .d_kqfilter = nokqfilter, 100 .d_discard = nodiscard, 101 .d_flag = 0 102 }; 103 104 struct lcd_softc { 105 device_t sc_dev; 106 107 bool sc_opened; 108 }; 109 110 CFATTACH_DECL_NEW(lcd, sizeof(struct lcd_softc), 111 lcd_match, lcd_attach, NULL, NULL); 112 113 void lcdbusywait(void); 114 void lcdput(int); 115 void lcdctrl(int); 116 void lcdshow(char *); 117 void greeting(void); 118 /* "1234567890123456" */ 119 static char lcd_boot_message1[] = " NetBSD/luna68k "; 120 static char lcd_boot_message2[] = " SX-9100/DT "; 121 122 /* 123 * Autoconf functions 124 */ 125 static int 126 lcd_match(device_t parent, cfdata_t cf, void *aux) 127 { 128 struct mainbus_attach_args *ma = aux; 129 130 if (strcmp(ma->ma_name, lcd_cd.cd_name)) 131 return 0; 132 if (badaddr((void *)ma->ma_addr, 4)) 133 return 0; 134 return 1; 135 } 136 137 static void 138 lcd_attach(device_t parent, device_t self, void *aux) 139 { 140 141 printf("\n"); 142 143 /* Say hello to the world on LCD. */ 144 greeting(); 145 } 146 147 /* 148 * open/close/write/ioctl 149 */ 150 int 151 lcdopen(dev_t dev, int flags, int fmt, struct lwp *l) 152 { 153 int unit; 154 struct lcd_softc *sc; 155 156 unit = minor(dev); 157 sc = device_lookup_private(&lcd_cd, unit); 158 if (sc == NULL) 159 return ENXIO; 160 if (sc->sc_opened) 161 return EBUSY; 162 sc->sc_opened = true; 163 164 return 0; 165 } 166 167 int 168 lcdclose(dev_t dev, int flags, int fmt, struct lwp *l) 169 { 170 int unit; 171 struct lcd_softc *sc; 172 173 unit = minor(dev); 174 sc = device_lookup_private(&lcd_cd, unit); 175 sc->sc_opened = false; 176 177 return 0; 178 } 179 180 int 181 lcdwrite(dev_t dev, struct uio *uio, int flag) 182 { 183 int error; 184 size_t len, i; 185 char buf[LCD_MAXBUFLEN]; 186 187 len = uio->uio_resid; 188 189 if (len > LCD_MAXBUFLEN) 190 return EIO; 191 192 error = uiomove(buf, len, uio); 193 if (error) 194 return EIO; 195 196 for (i = 0; i < len; i++) { 197 lcdput((int)buf[i]); 198 } 199 200 return 0; 201 } 202 203 int 204 lcdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 205 { 206 int val; 207 208 /* check if the device opened with write mode */ 209 switch (cmd) { 210 case LCDCLS: 211 case LCDHOME: 212 case LCDMODE: 213 case LCDDISP: 214 case LCDMOVE: 215 case LCDSEEK: 216 case LCDRESTORE: 217 if ((flag & FWRITE) == 0) 218 return EACCES; 219 } 220 221 switch (cmd) { 222 case LCDCLS: 223 lcdctrl(LCD_CLS); 224 break; 225 226 case LCDHOME: 227 lcdctrl(LCD_HOME); 228 break; 229 230 case LCDMODE: 231 val = *(int *)addr; 232 switch (val) { 233 case LCDMODE_C_LEFT: 234 case LCDMODE_C_RIGHT: 235 case LCDMODE_D_LEFT: 236 case LCDMODE_D_RIGHT: 237 lcdctrl(val); 238 break; 239 default: 240 return EINVAL; 241 } 242 break; 243 244 case LCDDISP: 245 val = *(int *)addr; 246 if ((val & 0x7) != val) 247 return EINVAL; 248 lcdctrl(val | 0x8); 249 break; 250 251 case LCDMOVE: 252 val = *(int *)addr; 253 switch (val) { 254 case LCDMOVE_C_LEFT: 255 case LCDMOVE_C_RIGHT: 256 case LCDMOVE_D_LEFT: 257 case LCDMOVE_D_RIGHT: 258 lcdctrl(val); 259 break; 260 default: 261 return EINVAL; 262 } 263 break; 264 265 case LCDSEEK: 266 val = *(int *)addr & 0x7f; 267 lcdctrl(val | 0x80); 268 break; 269 270 case LCDRESTORE: 271 greeting(); 272 break; 273 274 default: 275 return ENOTTY; 276 } 277 return EPASSTHROUGH; 278 } 279 280 void 281 lcdbusywait(void) 282 { 283 struct pio *p1 = (struct pio *)0x4D000000; 284 int msb, s; 285 286 s = splhigh(); 287 p1->cntrl = PIO1_MODE_INPUT; 288 p1->portC = POWER | READ_BUSY | ENABLE; 289 splx(s); 290 291 do { 292 msb = p1->portA & ENABLE; 293 delay(5); 294 } while (msb != 0); 295 296 s = splhigh(); 297 p1->portC = POWER | READ_BUSY | DISABLE; 298 splx(s); 299 } 300 301 void 302 lcdput(int cc) 303 { 304 struct pio *p1 = (struct pio *)0x4D000000; 305 int s; 306 307 lcdbusywait(); 308 309 s = splhigh(); 310 p1->cntrl = PIO1_MODE_OUTPUT; 311 312 p1->portC = POWER | WRITE_DATA | ENABLE; 313 p1->portA = cc; 314 p1->portC = POWER | WRITE_DATA | DISABLE; 315 splx(s); 316 } 317 318 void 319 lcdctrl(int cc) 320 { 321 struct pio *p1 = (struct pio *)0x4D000000; 322 int s; 323 324 lcdbusywait(); 325 326 s = splhigh(); 327 p1->cntrl = PIO1_MODE_OUTPUT; 328 329 p1->portC = POWER | WRITE_CMD | ENABLE; 330 p1->portA = cc; 331 p1->portC = POWER | WRITE_CMD | DISABLE; 332 splx(s); 333 } 334 335 void 336 lcdshow(char *s) 337 { 338 int cc; 339 340 while ((cc = *s++) != '\0') 341 lcdput(cc); 342 } 343 344 void 345 greeting(void) 346 { 347 lcdctrl(LCD_INIT); 348 lcdctrl(LCD_ENTRY); 349 lcdctrl(LCD_ON); 350 351 lcdctrl(LCD_CLS); 352 lcdctrl(LCD_HOME); 353 354 lcdctrl(LCD_LOCATE(0, 0)); 355 lcdshow(lcd_boot_message1); 356 lcdctrl(LCD_LOCATE(0, 1)); 357 if (machtype == LUNA_II) 358 lcd_boot_message2[13] = '2'; 359 lcdshow(lcd_boot_message2); 360 } 361