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