1 /* $NetBSD: hd44780_subr.c,v 1.21 2010/11/13 13:52:01 uebayasi 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.21 2010/11/13 13:52:01 uebayasi 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 int hd44780_init(struct hd44780_chip *sc) 397 { 398 int ret; 399 400 ret = hd44780_chipinit(sc, 0); 401 if (ret != 0 || !(sc->sc_flags & HD_MULTICHIP)) 402 return ret; 403 else 404 return hd44780_chipinit(sc, 1); 405 } 406 407 /* 408 * Initialize 4-bit or 8-bit connected device. 409 */ 410 int 411 hd44780_chipinit(struct hd44780_chip *sc, uint32_t en) 412 { 413 uint8_t cmd, dat; 414 415 sc->sc_flags &= ~(HD_TIMEDOUT|HD_UP); 416 sc->sc_dev_ok = 1; 417 418 cmd = cmd_init(sc->sc_flags & HD_8BIT); 419 hd44780_ir_write(sc, en, cmd); 420 delay(HD_TIMEOUT_LONG); 421 hd44780_ir_write(sc, en, cmd); 422 hd44780_ir_write(sc, en, cmd); 423 424 cmd = cmd_funcset( 425 sc->sc_flags & HD_8BIT, 426 sc->sc_flags & HD_MULTILINE, 427 sc->sc_flags & HD_BIGFONT); 428 429 if ((sc->sc_flags & HD_8BIT) == 0) 430 hd44780_ir_write(sc, en, cmd); 431 432 sc->sc_flags |= HD_UP; 433 434 hd44780_ir_write(sc, en, cmd); 435 hd44780_ir_write(sc, en, cmd_dispctl(0, 0, 0)); 436 hd44780_ir_write(sc, en, cmd_clear()); 437 hd44780_ir_write(sc, en, cmd_modset(1, 0)); 438 439 if (sc->sc_flags & HD_TIMEDOUT) { 440 sc->sc_flags &= ~HD_UP; 441 return EIO; 442 } 443 444 /* Turn display on and clear it. */ 445 hd44780_ir_write(sc, en, cmd_clear()); 446 hd44780_ir_write(sc, en, cmd_dispctl(1, 0, 0)); 447 448 /* Attempt a simple probe for presence */ 449 hd44780_ir_write(sc, en, cmd_ddramset(0x5)); 450 hd44780_ir_write(sc, en, cmd_shift(0, 1)); 451 hd44780_busy_wait(sc, en); 452 if ((dat = hd44780_ir_read(sc, en) & 0x7f) != 0x6) { 453 sc->sc_dev_ok = 0; 454 sc->sc_flags &= ~HD_UP; 455 return EIO; 456 } 457 hd44780_ir_write(sc, en, cmd_ddramset(0)); 458 459 return 0; 460 } 461 462 /* 463 * Standard hd44780 ioctl() functions. 464 */ 465 int 466 hd44780_ioctl_subr(struct hd44780_chip *sc, u_long cmd, void *data) 467 { 468 uint8_t tmp; 469 int error = 0; 470 uint32_t en = sc->sc_curchip; 471 472 #define hd44780_io() ((struct hd44780_io *)data) 473 #define hd44780_info() ((struct hd44780_info *)data) 474 #define hd44780_ctrl() ((struct hd44780_dispctl *)data) 475 476 switch (cmd) { 477 case HLCD_CLEAR: 478 /* Clear the LCD. */ 479 hd44780_ir_write(sc, en, cmd_clear()); 480 break; 481 482 case HLCD_CURSOR_LEFT: 483 /* Move the cursor one position to the left. */ 484 hd44780_ir_write(sc, en, cmd_shift(0, 0)); 485 break; 486 487 case HLCD_CURSOR_RIGHT: 488 /* Move the cursor one position to the right. */ 489 hd44780_ir_write(sc, en, cmd_shift(0, 1)); 490 break; 491 492 case HLCD_DISPCTL: 493 /* Control the LCD. */ 494 hd44780_ir_write(sc, en, cmd_dispctl( 495 hd44780_ctrl()->display_on, 496 hd44780_ctrl()->cursor_on, 497 hd44780_ctrl()->blink_on)); 498 break; 499 500 case HLCD_GET_INFO: 501 /* Get LCD configuration. */ 502 hd44780_info()->lines 503 = (sc->sc_flags & HD_MULTILINE) ? 2 : 1; 504 if (sc->sc_flags & HD_MULTICHIP) 505 hd44780_info()->lines *= 2; 506 hd44780_info()->phys_rows = sc->sc_cols; 507 hd44780_info()->virt_rows = sc->sc_vcols; 508 hd44780_info()->is_wide = sc->sc_flags & HD_8BIT; 509 hd44780_info()->is_bigfont = sc->sc_flags & HD_BIGFONT; 510 hd44780_info()->kp_present = sc->sc_flags & HD_KEYPAD; 511 break; 512 513 514 case HLCD_RESET: 515 /* Reset the LCD. */ 516 error = hd44780_init(sc); 517 break; 518 519 case HLCD_GET_CURSOR_POS: 520 /* Get the current cursor position. */ 521 hd44780_io()->dat = (hd44780_ir_read(sc, en) & 0x7f); 522 break; 523 524 case HLCD_SET_CURSOR_POS: 525 /* Set the cursor position. */ 526 hd44780_ir_write(sc, en, cmd_ddramset(hd44780_io()->dat)); 527 break; 528 529 case HLCD_GETC: 530 /* Get the value at the current cursor position. */ 531 tmp = (hd44780_ir_read(sc, en) & 0x7f); 532 hd44780_ir_write(sc, en, cmd_ddramset(tmp)); 533 hd44780_io()->dat = hd44780_dr_read(sc, en); 534 break; 535 536 case HLCD_PUTC: 537 /* Set the character at the cursor position + advance cursor. */ 538 hd44780_dr_write(sc, en, hd44780_io()->dat); 539 break; 540 541 case HLCD_SHIFT_LEFT: 542 /* Shift display left. */ 543 hd44780_ir_write(sc, en, cmd_shift(1, 0)); 544 break; 545 546 case HLCD_SHIFT_RIGHT: 547 /* Shift display right. */ 548 hd44780_ir_write(sc, en, cmd_shift(1, 1)); 549 break; 550 551 case HLCD_HOME: 552 /* Return home. */ 553 hd44780_ir_write(sc, en, cmd_rethome()); 554 break; 555 556 case HLCD_WRITE: 557 /* Write a string to the LCD virtual area. */ 558 error = hd44780_ddram_io(sc, en, hd44780_io(), HD_DDRAM_WRITE); 559 break; 560 561 case HLCD_READ: 562 /* Read LCD virtual area. */ 563 error = hd44780_ddram_io(sc, en, hd44780_io(), HD_DDRAM_READ); 564 break; 565 566 case HLCD_REDRAW: 567 /* Write to the LCD visible area. */ 568 hd44780_ddram_redraw(sc, en, hd44780_io()); 569 break; 570 571 case HLCD_WRITE_INST: 572 /* Write raw instruction. */ 573 hd44780_ir_write(sc, en, hd44780_io()->dat); 574 break; 575 576 case HLCD_WRITE_DATA: 577 /* Write raw data. */ 578 hd44780_dr_write(sc, en, hd44780_io()->dat); 579 break; 580 581 case HLCD_GET_CHIPNO: 582 /* Get current chip 0 or 1 (top or bottom) */ 583 *(uint8_t *)data = sc->sc_curchip; 584 break; 585 586 case HLCD_SET_CHIPNO: 587 /* Set current chip 0 or 1 (top or bottom) */ 588 sc->sc_curchip = *(uint8_t *)data; 589 break; 590 591 default: 592 error = EINVAL; 593 } 594 595 if (sc->sc_flags & HD_TIMEDOUT) 596 error = EIO; 597 598 return error; 599 } 600 601 /* 602 * Read/write particular area of the LCD screen. 603 */ 604 int 605 hd44780_ddram_io(struct hd44780_chip *sc, uint32_t en, struct hd44780_io *io, 606 uint8_t dir) 607 { 608 uint8_t hi; 609 uint8_t addr; 610 int error = 0; 611 uint8_t i = 0; 612 613 if (io->dat < sc->sc_vcols) { 614 hi = HD_ROW1_ADDR + sc->sc_vcols; 615 addr = HD_ROW1_ADDR + io->dat; 616 for (; (addr < hi) && (i < io->len); addr++, i++) { 617 hd44780_ir_write(sc, en, cmd_ddramset(addr)); 618 if (dir == HD_DDRAM_READ) 619 io->buf[i] = hd44780_dr_read(sc, en); 620 else 621 hd44780_dr_write(sc, en, io->buf[i]); 622 } 623 } 624 if (io->dat < 2 * sc->sc_vcols) { 625 hi = HD_ROW2_ADDR + sc->sc_vcols; 626 if (io->dat >= sc->sc_vcols) 627 addr = HD_ROW2_ADDR + io->dat - sc->sc_vcols; 628 else 629 addr = HD_ROW2_ADDR; 630 for (; (addr < hi) && (i < io->len); addr++, i++) { 631 hd44780_ir_write(sc, en, cmd_ddramset(addr)); 632 if (dir == HD_DDRAM_READ) 633 io->buf[i] = hd44780_dr_read(sc, en); 634 else 635 hd44780_dr_write(sc, en, io->buf[i]); 636 } 637 if (i < io->len) 638 io->len = i; 639 } else { 640 error = EINVAL; 641 } 642 return error; 643 } 644 645 /* 646 * Write to the visible area of the display. 647 */ 648 void 649 hd44780_ddram_redraw(struct hd44780_chip *sc, uint32_t en, 650 struct hd44780_io *io) 651 { 652 uint8_t i; 653 654 hd44780_ir_write(sc, en, cmd_clear()); 655 hd44780_ir_write(sc, en, cmd_rethome()); 656 hd44780_ir_write(sc, en, cmd_ddramset(HD_ROW1_ADDR)); 657 for (i = 0; (i < io->len) && (i < sc->sc_cols); i++) { 658 hd44780_dr_write(sc, en, io->buf[i]); 659 } 660 hd44780_ir_write(sc, en, cmd_ddramset(HD_ROW2_ADDR)); 661 for (; (i < io->len); i++) 662 hd44780_dr_write(sc, en, io->buf[i]); 663 } 664 665 void 666 hd44780_busy_wait(struct hd44780_chip *sc, uint32_t en) 667 { 668 int nloops = 100; 669 670 if (sc->sc_flags & HD_TIMEDOUT) 671 return; 672 673 while (nloops-- && (hd44780_ir_read(sc, en) & BUSY_FLAG) == BUSY_FLAG) 674 continue; 675 676 if (nloops == 0) { 677 sc->sc_flags |= HD_TIMEDOUT; 678 sc->sc_dev_ok = 0; 679 } 680 } 681 682 #if defined(HD44780_STD_WIDE) 683 /* 684 * Standard 8-bit version of 'sc_writereg' (8-bit port, 8-bit access) 685 */ 686 void 687 hd44780_writereg(struct hd44780_chip *sc, uint32_t en, uint32_t reg, 688 uint8_t cmd) 689 { 690 bus_space_tag_t iot = sc->sc_iot; 691 bus_space_handle_t ioh; 692 693 if (sc->sc_dev_ok == 0) 694 return; 695 696 if (reg == 0) 697 ioh = sc->sc_ioir; 698 else 699 ioh = sc->sc_iodr; 700 701 bus_space_write_1(iot, ioh, 0x00, cmd); 702 delay(HD_TIMEOUT_NORMAL); 703 } 704 705 /* 706 * Standard 8-bit version of 'sc_readreg' (8-bit port, 8-bit access) 707 */ 708 uint8_t 709 hd44780_readreg(struct hd44780_chip *sc, uint32_t en, uint32_t reg) 710 { 711 bus_space_tag_t iot = sc->sc_iot; 712 bus_space_handle_t ioh; 713 714 if (sc->sc_dev_ok == 0) 715 return; 716 717 if (reg == 0) 718 ioh = sc->sc_ioir; 719 else 720 ioh = sc->sc_iodr; 721 722 delay(HD_TIMEOUT_NORMAL); 723 return bus_space_read_1(iot, ioh, 0x00); 724 } 725 #elif defined(HD44780_STD_SHORT) 726 /* 727 * Standard 4-bit version of 'sc_writereg' (4-bit port, 8-bit access) 728 */ 729 void 730 hd44780_writereg(struct hd44780_chip *sc, uint32_t en, uint32_t reg, 731 uint8_t cmd) 732 { 733 bus_space_tag_t iot = sc->sc_iot; 734 bus_space_handle_t ioh; 735 736 if (sc->sc_dev_ok == 0) 737 return; 738 739 if (reg == 0) 740 ioh = sc->sc_ioir; 741 else 742 ioh = sc->sc_iodr; 743 744 bus_space_write_1(iot, ioh, 0x00, hi_bits(cmd)); 745 if (sc->sc_flags & HD_UP) 746 bus_space_write_1(iot, ioh, 0x00, lo_bits(cmd)); 747 delay(HD_TIMEOUT_NORMAL); 748 } 749 750 /* 751 * Standard 4-bit version of 'sc_readreg' (4-bit port, 8-bit access) 752 */ 753 uint8_t 754 hd44780_readreg(struct hd44780_chip *sc, uint32_t en, uint32_t reg) 755 { 756 bus_space_tag_t iot = sc->sc_iot; 757 bus_space_handle_t ioh; 758 uint8_t rd, dat; 759 760 if (sc->sc_dev_ok == 0) 761 return; 762 763 if (reg == 0) 764 ioh = sc->sc_ioir; 765 else 766 ioh = sc->sc_iodr; 767 768 rd = bus_space_read_1(iot, ioh, 0x00); 769 dat = (rd & 0x0f) << 4; 770 rd = bus_space_read_1(iot, ioh, 0x00); 771 return (dat | (rd & 0x0f)); 772 } 773 #endif 774