1 /* $NetBSD: hd44780_subr.c,v 1.24 2023/08/08 17:31:13 nat Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Dennis I. Chernoivanov 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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 17 * 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. 28 */ 29 30 /* 31 * Subroutines for Hitachi HD44870 style displays 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: hd44780_subr.c,v 1.24 2023/08/08 17:31:13 nat Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/conf.h> 40 #include <sys/kernel.h> 41 #include <sys/malloc.h> 42 #include <sys/types.h> 43 #include <sys/ioccom.h> 44 45 #include <machine/autoconf.h> 46 #include <sys/intr.h> 47 #include <sys/bus.h> 48 49 #include <dev/wscons/wsdisplayvar.h> 50 #include <dev/wscons/wsconsio.h> 51 #include <dev/wscons/wscons_callbacks.h> 52 53 #include <dev/ic/hd44780reg.h> 54 #include <dev/ic/hd44780var.h> 55 56 #define COORD_TO_IDX(x, y) ((y) * sc->sc_cols + (x)) 57 #define COORD_TO_DADDR(x, y) ((y) * HD_ROW2_ADDR + (x)) 58 #define IDX_TO_ROW(idx) ((idx) / sc->sc_cols) 59 #define IDX_TO_COL(idx) ((idx) % sc->sc_cols) 60 #define IDX_TO_DADDR(idx) (IDX_TO_ROW((idx)) * HD_ROW2_ADDR + \ 61 IDX_TO_COL((idx))) 62 #define DADDR_TO_ROW(daddr) ((daddr) / HD_ROW2_ADDR) 63 #define DADDR_TO_COL(daddr) ((daddr) % HD_ROW2_ADDR) 64 #define DADDR_TO_CHIPDADDR(daddr) ((daddr) % (HD_ROW2_ADDR * 2)) 65 #define DADDR_TO_CHIPNO(daddr) ((daddr) / (HD_ROW2_ADDR * 2)) 66 67 static void hlcd_cursor(void *, int, int, int); 68 static int hlcd_mapchar(void *, int, unsigned int *); 69 static void hlcd_putchar(void *, int, int, u_int, long); 70 static void hlcd_copycols(void *, int, int, int,int); 71 static void hlcd_erasecols(void *, int, int, int, long); 72 static void hlcd_copyrows(void *, int, int, int); 73 static void hlcd_eraserows(void *, int, int, long); 74 static int hlcd_allocattr(void *, int, int, int, long *); 75 static void hlcd_updatechar(struct hd44780_chip *, int, int); 76 static void hlcd_redraw(void *); 77 78 const struct wsdisplay_emulops hlcd_emulops = { 79 hlcd_cursor, 80 hlcd_mapchar, 81 hlcd_putchar, 82 hlcd_copycols, 83 hlcd_erasecols, 84 hlcd_copyrows, 85 hlcd_eraserows, 86 hlcd_allocattr 87 }; 88 89 static int hlcd_ioctl(void *, void *, u_long, void *, int, struct lwp *); 90 static paddr_t hlcd_mmap(void *, void *, off_t, int); 91 static int hlcd_alloc_screen(void *, const struct wsscreen_descr *, 92 void **, int *, int *, long *); 93 static void hlcd_free_screen(void *, void *); 94 static int hlcd_show_screen(void *, void *, int, 95 void (*) (void *, int, int), void *); 96 97 const struct wsdisplay_accessops hlcd_accessops = { 98 hlcd_ioctl, 99 hlcd_mmap, 100 hlcd_alloc_screen, 101 hlcd_free_screen, 102 hlcd_show_screen, 103 0 /* load_font */ 104 }; 105 106 static void 107 hlcd_cursor(void *id, int on, int row, int col) 108 { 109 struct hlcd_screen *hdscr = id; 110 111 hdscr->hlcd_curon = on; 112 hdscr->hlcd_curx = col; 113 hdscr->hlcd_cury = row; 114 } 115 116 static int 117 hlcd_mapchar(void *id, int uni, unsigned int *index) 118 { 119 120 if (uni < 256) { 121 *index = uni; 122 return 5; 123 } 124 *index = ' '; 125 return 0; 126 } 127 128 static void 129 hlcd_putchar(void *id, int row, int col, u_int c, long attr) 130 { 131 struct hlcd_screen *hdscr = id; 132 133 c &= 0xff; 134 if (row > 0 && (hdscr->hlcd_sc->sc_flags & (HD_MULTILINE|HD_MULTICHIP))) 135 hdscr->image[hdscr->hlcd_sc->sc_cols * row + col] = c; 136 else 137 hdscr->image[col] = c; 138 } 139 140 /* 141 * copies columns inside a row. 142 */ 143 static void 144 hlcd_copycols(void *id, int row, int srccol, int dstcol, int ncols) 145 { 146 struct hlcd_screen *hdscr = id; 147 148 if ((dstcol + ncols - 1) > hdscr->hlcd_sc->sc_cols) 149 ncols = hdscr->hlcd_sc->sc_cols - srccol; 150 151 if (row > 0 && (hdscr->hlcd_sc->sc_flags & (HD_MULTILINE|HD_MULTICHIP))) 152 memmove(&hdscr->image[hdscr->hlcd_sc->sc_cols * row + dstcol], 153 &hdscr->image[hdscr->hlcd_sc->sc_cols * row + srccol], 154 ncols); 155 else 156 memmove(&hdscr->image[dstcol], &hdscr->image[srccol], ncols); 157 } 158 159 160 /* 161 * Erases a bunch of chars inside one row. 162 */ 163 static void 164 hlcd_erasecols(void *id, int row, int startcol, int ncols, long fillattr) 165 { 166 struct hlcd_screen *hdscr = id; 167 168 if ((startcol + ncols) > hdscr->hlcd_sc->sc_cols) 169 ncols = hdscr->hlcd_sc->sc_cols - startcol; 170 171 if (row > 0 && (hdscr->hlcd_sc->sc_flags & (HD_MULTILINE|HD_MULTICHIP))) 172 memset(&hdscr->image[hdscr->hlcd_sc->sc_cols * row + startcol], 173 ' ', ncols); 174 else 175 memset(&hdscr->image[startcol], ' ', ncols); 176 } 177 178 179 static void 180 hlcd_copyrows(void *id, int srcrow, int dstrow, int nrows) 181 { 182 struct hlcd_screen *hdscr = id; 183 int ncols = hdscr->hlcd_sc->sc_cols; 184 185 if (!(hdscr->hlcd_sc->sc_flags & (HD_MULTILINE|HD_MULTICHIP))) 186 return; 187 memmove(&hdscr->image[dstrow * ncols], &hdscr->image[srcrow * ncols], 188 nrows * ncols); 189 } 190 191 static void 192 hlcd_eraserows(void *id, int startrow, int nrows, long fillattr) 193 { 194 struct hlcd_screen *hdscr = id; 195 int ncols = hdscr->hlcd_sc->sc_cols; 196 197 memset(&hdscr->image[startrow * ncols], ' ', ncols * nrows); 198 } 199 200 201 static int 202 hlcd_allocattr(void *id, int fg, int bg, int flags, long *attrp) 203 { 204 205 *attrp = flags; 206 return 0; 207 } 208 209 static int 210 hlcd_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 211 { 212 213 switch (cmd) { 214 case WSDISPLAYIO_GTYPE: 215 *(u_int *)data = WSDISPLAY_TYPE_HDLCD; 216 break; 217 218 case WSDISPLAYIO_SVIDEO: 219 break; 220 221 case WSDISPLAYIO_GVIDEO: 222 *(u_int *)data = WSDISPLAYIO_VIDEO_ON; 223 break; 224 225 default: 226 return EPASSTHROUGH; 227 } 228 return 0; 229 } 230 231 static paddr_t 232 hlcd_mmap(void *v, void *vs, off_t offset, int prot) 233 { 234 235 return -1; 236 } 237 238 static int 239 hlcd_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 240 int *curxp, int *curyp, long *defattrp) 241 { 242 struct hlcd_screen *hdscr = v, *new; 243 244 new = *cookiep = malloc(sizeof(struct hlcd_screen), 245 M_DEVBUF, M_WAITOK|M_ZERO); 246 new->hlcd_sc = hdscr->hlcd_sc; 247 new->image = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); 248 memset(new->image, ' ', PAGE_SIZE); 249 *curxp = *curyp = *defattrp = 0; 250 return 0; 251 } 252 253 static void 254 hlcd_free_screen(void *v, void *cookie) 255 { 256 } 257 258 static int 259 hlcd_show_screen(void *v, void *cookie, int waitok, 260 void (*cb)(void *, int, int), void *cbarg) 261 { 262 struct hlcd_screen *hdscr = v; 263 264 hdscr->hlcd_sc->sc_curscr = cookie; 265 callout_schedule(&hdscr->hlcd_sc->redraw, 1); 266 return 0; 267 } 268 269 static void 270 hlcd_updatechar(struct hd44780_chip *sc, int daddr, int c) 271 { 272 int curdaddr, en, chipdaddr; 273 274 curdaddr = COORD_TO_DADDR(sc->sc_screen.hlcd_curx, 275 sc->sc_screen.hlcd_cury); 276 en = DADDR_TO_CHIPNO(daddr); 277 chipdaddr = DADDR_TO_CHIPDADDR(daddr); 278 if (daddr != curdaddr) 279 hd44780_ir_write(sc, en, cmd_ddramset(chipdaddr)); 280 281 hd44780_dr_write(sc, en, c); 282 283 daddr++; 284 sc->sc_screen.hlcd_curx = DADDR_TO_COL(daddr); 285 sc->sc_screen.hlcd_cury = DADDR_TO_ROW(daddr); 286 } 287 288 static void 289 hlcd_redraw(void *arg) 290 { 291 struct hd44780_chip *sc = arg; 292 int len, crsridx, startidx, x, y; 293 int old_en, new_en; 294 uint8_t *img, *curimg; 295 296 if (sc->sc_curscr == NULL) 297 return; 298 299 if (sc->sc_flags & HD_MULTILINE) 300 len = 2 * sc->sc_cols; 301 else 302 len = sc->sc_cols; 303 304 if (sc->sc_flags & HD_MULTICHIP) 305 len = len * 2; 306 307 x = sc->sc_screen.hlcd_curx; 308 y = sc->sc_screen.hlcd_cury; 309 old_en = DADDR_TO_CHIPNO(COORD_TO_DADDR(x, y)); 310 311 img = sc->sc_screen.image; 312 curimg = sc->sc_curscr->image; 313 startidx = crsridx = 314 COORD_TO_IDX(sc->sc_screen.hlcd_curx, sc->sc_screen.hlcd_cury); 315 do { 316 if (img[crsridx] != curimg[crsridx]) { 317 hlcd_updatechar(sc, IDX_TO_DADDR(crsridx), 318 curimg[crsridx]); 319 img[crsridx] = curimg[crsridx]; 320 } 321 crsridx++; 322 if (crsridx == len) 323 crsridx = 0; 324 } while (crsridx != startidx); 325 326 x = sc->sc_curscr->hlcd_curx; 327 y = sc->sc_curscr->hlcd_cury; 328 new_en = DADDR_TO_CHIPNO(COORD_TO_DADDR(x, y)); 329 330 if (sc->sc_screen.hlcd_curx != sc->sc_curscr->hlcd_curx || 331 sc->sc_screen.hlcd_cury != sc->sc_curscr->hlcd_cury) { 332 333 x = sc->sc_screen.hlcd_curx = sc->sc_curscr->hlcd_curx; 334 y = sc->sc_screen.hlcd_cury = sc->sc_curscr->hlcd_cury; 335 336 hd44780_ir_write(sc, new_en, cmd_ddramset( 337 DADDR_TO_CHIPDADDR(COORD_TO_DADDR(x, y)))); 338 339 } 340 341 /* visible cursor switched to other chip */ 342 if (old_en != new_en && sc->sc_screen.hlcd_curon) { 343 hd44780_ir_write(sc, old_en, cmd_dispctl(1, 0, 0)); 344 hd44780_ir_write(sc, new_en, cmd_dispctl(1, 1, 1)); 345 } 346 347 if (sc->sc_screen.hlcd_curon != sc->sc_curscr->hlcd_curon) { 348 sc->sc_screen.hlcd_curon = sc->sc_curscr->hlcd_curon; 349 if (sc->sc_screen.hlcd_curon) 350 hd44780_ir_write(sc, new_en, cmd_dispctl(1, 1, 1)); 351 else 352 hd44780_ir_write(sc, new_en, cmd_dispctl(1, 0, 0)); 353 } 354 355 callout_schedule(&sc->redraw, 1); 356 } 357 358 359 /* 360 * Finish device attach. sc_writereg, sc_readreg and sc_flags must be properly 361 * initialized prior to this call. 362 */ 363 void 364 hd44780_attach_subr(struct hd44780_chip *sc) 365 { 366 int err = 0; 367 368 /* Putc/getc are supposed to be set by platform-dependent code. */ 369 if ((sc->sc_writereg == NULL) || (sc->sc_readreg == NULL)) 370 sc->sc_dev_ok = 0; 371 372 /* Make sure that HD_MAX_CHARS is enough. */ 373 if ((sc->sc_flags & HD_MULTILINE) && (2 * sc->sc_cols > HD_MAX_CHARS)) 374 sc->sc_dev_ok = 0; 375 else if (sc->sc_cols > HD_MAX_CHARS) 376 sc->sc_dev_ok = 0; 377 378 if (sc->sc_dev_ok) { 379 if ((sc->sc_flags & HD_UP) == 0) 380 err = hd44780_init(sc); 381 if (err != 0) 382 aprint_error_dev(sc->sc_dev, 383 "LCD not responding or unconnected\n"); 384 } 385 386 sc->sc_screen.hlcd_sc = sc; 387 388 sc->sc_screen.image = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); 389 memset(sc->sc_screen.image, ' ', PAGE_SIZE); 390 sc->sc_curscr = NULL; 391 sc->sc_curchip = 0; 392 callout_init(&sc->redraw, 0); 393 callout_setfunc(&sc->redraw, hlcd_redraw, sc); 394 } 395 396 void hd44780_detach(struct hd44780_chip *sc) 397 { 398 callout_stop(&sc->redraw); 399 callout_destroy(&sc->redraw); 400 401 if (sc->sc_screen.image) 402 free(sc->sc_screen.image, M_DEVBUF); 403 } 404 405 int hd44780_init(struct hd44780_chip *sc) 406 { 407 int ret; 408 409 ret = hd44780_chipinit(sc, 0); 410 if (ret != 0 || !(sc->sc_flags & HD_MULTICHIP)) 411 return ret; 412 else 413 return hd44780_chipinit(sc, 1); 414 } 415 416 /* 417 * Initialize 4-bit or 8-bit connected device. 418 */ 419 int 420 hd44780_chipinit(struct hd44780_chip *sc, uint32_t en) 421 { 422 uint8_t cmd, dat; 423 424 sc->sc_flags &= ~(HD_TIMEDOUT|HD_UP); 425 sc->sc_dev_ok = 1; 426 427 cmd = cmd_init(sc->sc_flags & HD_8BIT); 428 hd44780_ir_write(sc, en, cmd); 429 delay(HD_TIMEOUT_LONG); 430 hd44780_ir_write(sc, en, cmd); 431 hd44780_ir_write(sc, en, cmd); 432 433 cmd = cmd_funcset( 434 sc->sc_flags & HD_8BIT, 435 sc->sc_flags & HD_MULTILINE, 436 sc->sc_flags & HD_BIGFONT); 437 438 if ((sc->sc_flags & HD_8BIT) == 0) 439 hd44780_ir_write(sc, en, cmd); 440 441 sc->sc_flags |= HD_UP; 442 443 hd44780_ir_write(sc, en, cmd); 444 hd44780_ir_write(sc, en, cmd_dispctl(0, 0, 0)); 445 hd44780_ir_write(sc, en, cmd_clear()); 446 hd44780_ir_write(sc, en, cmd_modset(1, 0)); 447 448 if (sc->sc_flags & HD_TIMEDOUT) { 449 sc->sc_flags &= ~HD_UP; 450 return EIO; 451 } 452 453 /* Turn display on and clear it. */ 454 hd44780_ir_write(sc, en, cmd_clear()); 455 hd44780_ir_write(sc, en, cmd_dispctl(1, 0, 0)); 456 457 /* Attempt a simple probe for presence */ 458 hd44780_ir_write(sc, en, cmd_ddramset(0x5)); 459 hd44780_ir_write(sc, en, cmd_shift(0, 1)); 460 hd44780_busy_wait(sc, en); 461 if (!(sc->sc_flags & HD_WRITEONLY) && 462 (dat = hd44780_ir_read(sc, en) & 0x7f) != 0x6) { 463 sc->sc_dev_ok = 0; 464 sc->sc_flags &= ~HD_UP; 465 return EIO; 466 } 467 hd44780_ir_write(sc, en, cmd_ddramset(0)); 468 469 return 0; 470 } 471 472 /* 473 * Standard hd44780 ioctl() functions. 474 */ 475 int 476 hd44780_ioctl_subr(struct hd44780_chip *sc, u_long cmd, void *data) 477 { 478 uint8_t tmp; 479 int error = 0; 480 uint32_t en = sc->sc_curchip; 481 482 #define hd44780_io() ((struct hd44780_io *)data) 483 #define hd44780_info() ((struct hd44780_info *)data) 484 #define hd44780_ctrl() ((struct hd44780_dispctl *)data) 485 486 switch (cmd) { 487 case HLCD_CLEAR: 488 /* Clear the LCD. */ 489 hd44780_ir_write(sc, en, cmd_clear()); 490 break; 491 492 case HLCD_CURSOR_LEFT: 493 /* Move the cursor one position to the left. */ 494 hd44780_ir_write(sc, en, cmd_shift(0, 0)); 495 break; 496 497 case HLCD_CURSOR_RIGHT: 498 /* Move the cursor one position to the right. */ 499 hd44780_ir_write(sc, en, cmd_shift(0, 1)); 500 break; 501 502 case HLCD_DISPCTL: 503 /* Control the LCD. */ 504 hd44780_ir_write(sc, en, cmd_dispctl( 505 hd44780_ctrl()->display_on, 506 hd44780_ctrl()->cursor_on, 507 hd44780_ctrl()->blink_on)); 508 break; 509 510 case HLCD_GET_INFO: 511 /* Get LCD configuration. */ 512 hd44780_info()->lines 513 = (sc->sc_flags & HD_MULTILINE) ? 2 : 1; 514 if (sc->sc_flags & HD_MULTICHIP) 515 hd44780_info()->lines *= 2; 516 hd44780_info()->phys_rows = sc->sc_cols; 517 hd44780_info()->virt_rows = sc->sc_vcols; 518 hd44780_info()->is_wide = sc->sc_flags & HD_8BIT; 519 hd44780_info()->is_bigfont = sc->sc_flags & HD_BIGFONT; 520 hd44780_info()->kp_present = sc->sc_flags & HD_KEYPAD; 521 break; 522 523 524 case HLCD_RESET: 525 /* Reset the LCD. */ 526 error = hd44780_init(sc); 527 break; 528 529 case HLCD_GET_CURSOR_POS: 530 /* Get the current cursor position. */ 531 hd44780_io()->dat = (hd44780_ir_read(sc, en) & 0x7f); 532 break; 533 534 case HLCD_SET_CURSOR_POS: 535 /* Set the cursor position. */ 536 hd44780_ir_write(sc, en, cmd_ddramset(hd44780_io()->dat)); 537 break; 538 539 case HLCD_GETC: 540 /* Get the value at the current cursor position. */ 541 tmp = (hd44780_ir_read(sc, en) & 0x7f); 542 hd44780_ir_write(sc, en, cmd_ddramset(tmp)); 543 hd44780_io()->dat = hd44780_dr_read(sc, en); 544 break; 545 546 case HLCD_PUTC: 547 /* Set the character at the cursor position + advance cursor. */ 548 hd44780_dr_write(sc, en, hd44780_io()->dat); 549 break; 550 551 case HLCD_SHIFT_LEFT: 552 /* Shift display left. */ 553 hd44780_ir_write(sc, en, cmd_shift(1, 0)); 554 break; 555 556 case HLCD_SHIFT_RIGHT: 557 /* Shift display right. */ 558 hd44780_ir_write(sc, en, cmd_shift(1, 1)); 559 break; 560 561 case HLCD_HOME: 562 /* Return home. */ 563 hd44780_ir_write(sc, en, cmd_rethome()); 564 break; 565 566 case HLCD_WRITE: 567 /* Write a string to the LCD virtual area. */ 568 error = hd44780_ddram_io(sc, en, hd44780_io(), HD_DDRAM_WRITE); 569 break; 570 571 case HLCD_READ: 572 /* Read LCD virtual area. */ 573 error = hd44780_ddram_io(sc, en, hd44780_io(), HD_DDRAM_READ); 574 break; 575 576 case HLCD_REDRAW: 577 /* Write to the LCD visible area. */ 578 hd44780_ddram_redraw(sc, en, hd44780_io()); 579 break; 580 581 case HLCD_WRITE_INST: 582 /* Write raw instruction. */ 583 hd44780_ir_write(sc, en, hd44780_io()->dat); 584 break; 585 586 case HLCD_WRITE_DATA: 587 /* Write raw data. */ 588 hd44780_dr_write(sc, en, hd44780_io()->dat); 589 break; 590 591 case HLCD_GET_CHIPNO: 592 /* Get current chip 0 or 1 (top or bottom) */ 593 *(uint8_t *)data = sc->sc_curchip; 594 break; 595 596 case HLCD_SET_CHIPNO: 597 /* Set current chip 0 or 1 (top or bottom) */ 598 sc->sc_curchip = *(uint8_t *)data; 599 break; 600 601 default: 602 error = EINVAL; 603 } 604 605 if (sc->sc_flags & HD_TIMEDOUT) 606 error = EIO; 607 608 return error; 609 } 610 611 /* 612 * Read/write particular area of the LCD screen. 613 */ 614 int 615 hd44780_ddram_io(struct hd44780_chip *sc, uint32_t en, struct hd44780_io *io, 616 uint8_t dir) 617 { 618 uint8_t hi; 619 uint8_t addr; 620 int error = 0; 621 uint8_t i = 0; 622 623 if (io->dat < sc->sc_vcols) { 624 hi = HD_ROW1_ADDR + sc->sc_vcols; 625 addr = HD_ROW1_ADDR + io->dat; 626 for (; (addr < hi) && (i < io->len); addr++, i++) { 627 hd44780_ir_write(sc, en, cmd_ddramset(addr)); 628 if (dir == HD_DDRAM_READ) 629 io->buf[i] = hd44780_dr_read(sc, en); 630 else 631 hd44780_dr_write(sc, en, io->buf[i]); 632 } 633 } 634 if (io->dat < 2 * sc->sc_vcols) { 635 hi = HD_ROW2_ADDR + sc->sc_vcols; 636 if (io->dat >= sc->sc_vcols) 637 addr = HD_ROW2_ADDR + io->dat - sc->sc_vcols; 638 else 639 addr = HD_ROW2_ADDR; 640 for (; (addr < hi) && (i < io->len); addr++, i++) { 641 hd44780_ir_write(sc, en, cmd_ddramset(addr)); 642 if (dir == HD_DDRAM_READ) 643 io->buf[i] = hd44780_dr_read(sc, en); 644 else 645 hd44780_dr_write(sc, en, io->buf[i]); 646 } 647 if (i < io->len) 648 io->len = i; 649 } else { 650 error = EINVAL; 651 } 652 return error; 653 } 654 655 /* 656 * Write to the visible area of the display. 657 */ 658 void 659 hd44780_ddram_redraw(struct hd44780_chip *sc, uint32_t en, 660 struct hd44780_io *io) 661 { 662 uint8_t i; 663 664 hd44780_ir_write(sc, en, cmd_clear()); 665 hd44780_ir_write(sc, en, cmd_rethome()); 666 hd44780_ir_write(sc, en, cmd_ddramset(HD_ROW1_ADDR)); 667 for (i = 0; (i < io->len) && (i < sc->sc_cols); i++) { 668 hd44780_dr_write(sc, en, io->buf[i]); 669 } 670 hd44780_ir_write(sc, en, cmd_ddramset(HD_ROW2_ADDR)); 671 for (; (i < io->len); i++) 672 hd44780_dr_write(sc, en, io->buf[i]); 673 } 674 675 void 676 hd44780_busy_wait(struct hd44780_chip *sc, uint32_t en) 677 { 678 int nloops = 100; 679 680 if (sc->sc_flags & HD_TIMEDOUT) 681 return; 682 683 while (nloops-- && (hd44780_ir_read(sc, en) & BUSY_FLAG) == BUSY_FLAG) 684 continue; 685 686 if (nloops == 0) { 687 sc->sc_flags |= HD_TIMEDOUT; 688 sc->sc_dev_ok = 0; 689 } 690 } 691 692 #if defined(HD44780_STD_WIDE) 693 /* 694 * Standard 8-bit version of 'sc_writereg' (8-bit port, 8-bit access) 695 */ 696 void 697 hd44780_writereg(struct hd44780_chip *sc, uint32_t en, uint32_t reg, 698 uint8_t cmd) 699 { 700 bus_space_tag_t iot = sc->sc_iot; 701 bus_space_handle_t ioh; 702 703 if (sc->sc_dev_ok == 0) 704 return; 705 706 if (reg == 0) 707 ioh = sc->sc_ioir; 708 else 709 ioh = sc->sc_iodr; 710 711 bus_space_write_1(iot, ioh, 0x00, cmd); 712 delay(HD_TIMEOUT_NORMAL); 713 } 714 715 /* 716 * Standard 8-bit version of 'sc_readreg' (8-bit port, 8-bit access) 717 */ 718 uint8_t 719 hd44780_readreg(struct hd44780_chip *sc, uint32_t en, uint32_t reg) 720 { 721 bus_space_tag_t iot = sc->sc_iot; 722 bus_space_handle_t ioh; 723 724 if (sc->sc_dev_ok == 0) 725 return; 726 727 if (reg == 0) 728 ioh = sc->sc_ioir; 729 else 730 ioh = sc->sc_iodr; 731 732 delay(HD_TIMEOUT_NORMAL); 733 return bus_space_read_1(iot, ioh, 0x00); 734 } 735 #elif defined(HD44780_STD_SHORT) 736 /* 737 * Standard 4-bit version of 'sc_writereg' (4-bit port, 8-bit access) 738 */ 739 void 740 hd44780_writereg(struct hd44780_chip *sc, uint32_t en, uint32_t reg, 741 uint8_t cmd) 742 { 743 bus_space_tag_t iot = sc->sc_iot; 744 bus_space_handle_t ioh; 745 746 if (sc->sc_dev_ok == 0) 747 return; 748 749 if (reg == 0) 750 ioh = sc->sc_ioir; 751 else 752 ioh = sc->sc_iodr; 753 754 bus_space_write_1(iot, ioh, 0x00, hi_bits(cmd)); 755 if (sc->sc_flags & HD_UP) 756 bus_space_write_1(iot, ioh, 0x00, lo_bits(cmd)); 757 delay(HD_TIMEOUT_NORMAL); 758 } 759 760 /* 761 * Standard 4-bit version of 'sc_readreg' (4-bit port, 8-bit access) 762 */ 763 uint8_t 764 hd44780_readreg(struct hd44780_chip *sc, uint32_t en, uint32_t reg) 765 { 766 bus_space_tag_t iot = sc->sc_iot; 767 bus_space_handle_t ioh; 768 uint8_t rd, dat; 769 770 if (sc->sc_dev_ok == 0) 771 return; 772 773 if (reg == 0) 774 ioh = sc->sc_ioir; 775 else 776 ioh = sc->sc_iodr; 777 778 rd = bus_space_read_1(iot, ioh, 0x00); 779 dat = (rd & 0x0f) << 4; 780 rd = bus_space_read_1(iot, ioh, 0x00); 781 return (dat | (rd & 0x0f)); 782 } 783 #endif 784