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