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