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