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