adb_kbd.c revision 184299
1169691Skan/*- 2169691Skan * Copyright (C) 2008 Nathan Whitehorn 3169691Skan * All rights reserved. 4169691Skan * 5169691Skan * Redistribution and use in source and binary forms, with or without 6169691Skan * modification, are permitted provided that the following conditions 7169691Skan * are met: 8169691Skan * 1. Redistributions of source code must retain the above copyright 9169691Skan * notice, this list of conditions and the following disclaimer. 10169691Skan * 2. Redistributions in binary form must reproduce the above copyright 11169691Skan * notice, this list of conditions and the following disclaimer in the 12169691Skan * documentation and/or other materials provided with the distribution. 13169691Skan * 14169691Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15169691Skan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16169691Skan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17169691Skan * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18169691Skan * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19169691Skan * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20169691Skan * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21169691Skan * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22169691Skan * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23169691Skan * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24169691Skan * 25169691Skan * $FreeBSD: head/sys/dev/adb/adb_kbd.c 184299 2008-10-26 19:37:38Z nwhitehorn $ 26169691Skan */ 27169691Skan 28169691Skan#include <sys/cdefs.h> 29169691Skan#include <sys/param.h> 30169691Skan#include <sys/systm.h> 31169691Skan#include <sys/module.h> 32169691Skan#include <sys/bus.h> 33169691Skan#include <sys/conf.h> 34169691Skan#include <sys/kbio.h> 35169691Skan#include <sys/condvar.h> 36169691Skan#include <sys/callout.h> 37169691Skan#include <sys/kernel.h> 38169691Skan 39169691Skan#include <machine/bus.h> 40169691Skan 41169691Skan#include "opt_kbd.h" 42169691Skan#include <dev/kbd/kbdreg.h> 43169691Skan#include <dev/kbd/kbdtables.h> 44169691Skan 45169691Skan#include <vm/vm.h> 46169691Skan#include <vm/pmap.h> 47169691Skan 48169691Skan#include "adb.h" 49169691Skan 50169691Skan#define KBD_DRIVER_NAME "akbd" 51169691Skan 52169691Skan#define AKBD_EMULATE_ATKBD 1 53169691Skan 54169691Skanstatic int adb_kbd_probe(device_t dev); 55169691Skanstatic int adb_kbd_attach(device_t dev); 56169691Skanstatic int adb_kbd_detach(device_t dev); 57169691Skanstatic void akbd_repeat(void *xsc); 58169691Skan 59169691Skanstatic u_int adb_kbd_receive_packet(device_t dev, u_char status, 60169691Skan u_char command, u_char reg, int len, u_char *data); 61169691Skan 62169691Skanstruct adb_kbd_softc { 63169691Skan keyboard_t sc_kbd; 64169691Skan 65169691Skan device_t sc_dev; 66169691Skan struct mtx sc_mutex; 67169691Skan struct cv sc_cv; 68169691Skan 69169691Skan int sc_mode; 70169691Skan int sc_state; 71169691Skan 72169691Skan int have_led_control; 73169691Skan 74169691Skan uint8_t buffer[8]; 75169691Skan volatile int buffers; 76169691Skan 77169691Skan struct callout sc_repeater; 78169691Skan int sc_repeatstart; 79169691Skan int sc_repeatcontinue; 80169691Skan uint8_t last_press; 81169691Skan}; 82169691Skan 83169691Skanstatic device_method_t adb_kbd_methods[] = { 84169691Skan /* Device interface */ 85169691Skan DEVMETHOD(device_probe, adb_kbd_probe), 86169691Skan DEVMETHOD(device_attach, adb_kbd_attach), 87169691Skan DEVMETHOD(device_detach, adb_kbd_detach), 88169691Skan DEVMETHOD(device_shutdown, bus_generic_shutdown), 89169691Skan DEVMETHOD(device_suspend, bus_generic_suspend), 90169691Skan DEVMETHOD(device_resume, bus_generic_resume), 91169691Skan 92169691Skan /* ADB interface */ 93169691Skan DEVMETHOD(adb_receive_packet, adb_kbd_receive_packet), 94169691Skan 95169691Skan { 0, 0 } 96169691Skan}; 97169691Skan 98169691Skanstatic driver_t adb_kbd_driver = { 99169691Skan "akbd", 100169691Skan adb_kbd_methods, 101169691Skan sizeof(struct adb_kbd_softc), 102169691Skan}; 103169691Skan 104169691Skanstatic devclass_t adb_kbd_devclass; 105169691Skan 106169691SkanDRIVER_MODULE(akbd, adb, adb_kbd_driver, adb_kbd_devclass, 0, 0); 107169691Skan 108169691Skanstatic const uint8_t adb_to_at_scancode_map[128] = { 30, 31, 32, 33, 35, 34, 109169691Skan 44, 45, 46, 47, 0, 48, 16, 17, 18, 19, 21, 20, 2, 3, 4, 5, 7, 6, 13, 110169691Skan 10, 8, 12, 9, 11, 27, 24, 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43, 111169691Skan 51, 53, 49, 50, 52, 15, 57, 41, 14, 0, 1, 29, 0, 42, 58, 56, 97, 98, 112169691Skan 100, 95, 0, 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 91, 89, 0, 74, 13, 0, 113169691Skan 0, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73, 0, 0, 0, 63, 64, 65, 61, 114169691Skan 66, 67, 0, 87, 0, 105, 0, 70, 0, 68, 0, 88, 0, 107, 102, 94, 96, 103, 115169691Skan 62, 99, 60, 101, 59, 54, 93, 90, 0, 0 }; 116169691Skan 117169691Skan/* keyboard driver declaration */ 118169691Skanstatic int akbd_configure(int flags); 119169691Skanstatic kbd_probe_t akbd_probe; 120169691Skanstatic kbd_init_t akbd_init; 121169691Skanstatic kbd_term_t akbd_term; 122169691Skanstatic kbd_intr_t akbd_interrupt; 123169691Skanstatic kbd_test_if_t akbd_test_if; 124169691Skanstatic kbd_enable_t akbd_enable; 125169691Skanstatic kbd_disable_t akbd_disable; 126169691Skanstatic kbd_read_t akbd_read; 127169691Skanstatic kbd_check_t akbd_check; 128169691Skanstatic kbd_read_char_t akbd_read_char; 129169691Skanstatic kbd_check_char_t akbd_check_char; 130169691Skanstatic kbd_ioctl_t akbd_ioctl; 131169691Skanstatic kbd_lock_t akbd_lock; 132169691Skanstatic kbd_clear_state_t akbd_clear_state; 133169691Skanstatic kbd_get_state_t akbd_get_state; 134169691Skanstatic kbd_set_state_t akbd_set_state; 135169691Skanstatic kbd_poll_mode_t akbd_poll; 136169691Skan 137169691Skankeyboard_switch_t akbdsw = { 138169691Skan akbd_probe, 139169691Skan akbd_init, 140169691Skan akbd_term, 141169691Skan akbd_interrupt, 142169691Skan akbd_test_if, 143169691Skan akbd_enable, 144169691Skan akbd_disable, 145169691Skan akbd_read, 146169691Skan akbd_check, 147169691Skan akbd_read_char, 148169691Skan akbd_check_char, 149169691Skan akbd_ioctl, 150169691Skan akbd_lock, 151169691Skan akbd_clear_state, 152169691Skan akbd_get_state, 153169691Skan akbd_set_state, 154169691Skan genkbd_get_fkeystr, 155169691Skan akbd_poll, 156169691Skan genkbd_diag, 157169691Skan}; 158169691Skan 159169691SkanKEYBOARD_DRIVER(akbd, akbdsw, akbd_configure); 160169691Skan 161169691Skanstatic int 162adb_kbd_probe(device_t dev) 163{ 164 uint8_t type; 165 166 type = adb_get_device_type(dev); 167 168 if (type != ADB_DEVICE_KEYBOARD) 169 return (ENXIO); 170 171 switch(adb_get_device_handler(dev)) { 172 case 1: 173 device_set_desc(dev,"Apple Standard Keyboard"); 174 break; 175 case 2: 176 device_set_desc(dev,"Apple Extended Keyboard"); 177 break; 178 case 4: 179 device_set_desc(dev,"Apple ISO Keyboard"); 180 break; 181 case 5: 182 device_set_desc(dev,"Apple Extended ISO Keyboard"); 183 break; 184 case 8: 185 device_set_desc(dev,"Apple Keyboard II"); 186 break; 187 case 9: 188 device_set_desc(dev,"Apple ISO Keyboard II"); 189 break; 190 case 12: 191 device_set_desc(dev,"PowerBook Keyboard"); 192 break; 193 case 13: 194 device_set_desc(dev,"PowerBook ISO Keyboard"); 195 break; 196 case 24: 197 device_set_desc(dev,"PowerBook Extended Keyboard"); 198 break; 199 case 27: 200 device_set_desc(dev,"Apple Design Keyboard"); 201 break; 202 case 195: 203 device_set_desc(dev,"PowerBook G3 Keyboard"); 204 break; 205 case 196: 206 device_set_desc(dev,"iBook Keyboard"); 207 break; 208 default: 209 device_set_desc(dev,"ADB Keyboard"); 210 break; 211 } 212 213 return (0); 214} 215 216static int 217ms_to_ticks(int ms) 218{ 219 if (hz > 1000) 220 return ms*(hz/1000); 221 222 return ms/(1000/hz); 223} 224 225static int 226adb_kbd_attach(device_t dev) 227{ 228 struct adb_kbd_softc *sc; 229 keyboard_switch_t *sw; 230 231 sw = kbd_get_switch(KBD_DRIVER_NAME); 232 if (sw == NULL) { 233 return ENXIO; 234 } 235 236 sc = device_get_softc(dev); 237 sc->sc_dev = dev; 238 sc->sc_mode = K_RAW; 239 sc->sc_state = 0; 240 sc->have_led_control = 0; 241 sc->buffers = 0; 242 243 /* Try stepping forward to the extended keyboard protocol */ 244 adb_set_device_handler(dev,3); 245 246 mtx_init(&sc->sc_mutex,KBD_DRIVER_NAME,MTX_DEF,0); 247 cv_init(&sc->sc_cv,KBD_DRIVER_NAME); 248 callout_init(&sc->sc_repeater, 0); 249 250#ifdef AKBD_EMULATE_ATKBD 251 kbd_init_struct(&sc->sc_kbd, KBD_DRIVER_NAME, KB_101, 0, 0, 0, 0); 252 kbd_set_maps(&sc->sc_kbd, &key_map, &accent_map, fkey_tab, 253 sizeof(fkey_tab) / sizeof(fkey_tab[0])); 254#else 255 #error ADB raw mode not implemented 256#endif 257 258 KBD_FOUND_DEVICE(&sc->sc_kbd); 259 KBD_PROBE_DONE(&sc->sc_kbd); 260 KBD_INIT_DONE(&sc->sc_kbd); 261 KBD_CONFIG_DONE(&sc->sc_kbd); 262 263 (*sw->enable)(&sc->sc_kbd); 264 265 kbd_register(&sc->sc_kbd); 266 267#ifdef KBD_INSTALL_CDEV 268 if (kbd_attach(&sc->sc_kbd)) { 269 adb_kbd_detach(dev); 270 return ENXIO; 271 } 272#endif 273 274 adb_set_autopoll(dev,1); 275 276 /* Check (asynchronously) if we can read out the LED state from 277 this keyboard by reading the key state register */ 278 adb_send_packet(dev,ADB_COMMAND_TALK,2,0,NULL); 279 280 return (0); 281} 282 283static int 284adb_kbd_detach(device_t dev) 285{ 286 struct adb_kbd_softc *sc; 287 keyboard_t *kbd; 288 289 sc = device_get_softc(dev); 290 291 adb_set_autopoll(dev,0); 292 callout_stop(&sc->sc_repeater); 293 294 mtx_lock(&sc->sc_mutex); 295 296 kbd = kbd_get_keyboard(kbd_find_keyboard(KBD_DRIVER_NAME, 297 device_get_unit(dev))); 298 299 kbdd_disable(kbd); 300 301#ifdef KBD_INSTALL_CDEV 302 kbd_detach(kbd); 303#endif 304 305 kbdd_term(kbd); 306 307 mtx_unlock(&sc->sc_mutex); 308 309 mtx_destroy(&sc->sc_mutex); 310 cv_destroy(&sc->sc_cv); 311 312 return (0); 313} 314 315static u_int 316adb_kbd_receive_packet(device_t dev, u_char status, 317 u_char command, u_char reg, int len, u_char *data) 318{ 319 struct adb_kbd_softc *sc; 320 321 sc = device_get_softc(dev); 322 323 if (command != ADB_COMMAND_TALK) 324 return 0; 325 326 if (reg == 2 && len == 2) { 327 sc->have_led_control = 1; 328 return 0; 329 } 330 331 if (reg != 0 || len != 2) 332 return (0); 333 334 mtx_lock(&sc->sc_mutex); 335 if ((data[0] & 0x7f) == 57 && sc->buffers < 7) { 336 /* Fake the down/up cycle for caps lock */ 337 sc->buffer[sc->buffers++] = data[0] & 0x7f; 338 sc->buffer[sc->buffers++] = (data[0] & 0x7f) | (1 << 7); 339 } else { 340 sc->buffer[sc->buffers++] = data[0]; 341 } 342 343 if (sc->buffer[sc->buffers-1] < 0xff) 344 sc->last_press = sc->buffer[sc->buffers-1]; 345 346 if ((data[1] & 0x7f) == 57 && sc->buffers < 7) { 347 /* Fake the down/up cycle for caps lock */ 348 sc->buffer[sc->buffers++] = data[1] & 0x7f; 349 sc->buffer[sc->buffers++] = (data[1] & 0x7f) | (1 << 7); 350 } else { 351 sc->buffer[sc->buffers++] = data[1]; 352 } 353 354 if (sc->buffer[sc->buffers-1] < 0xff) 355 sc->last_press = sc->buffer[sc->buffers-1]; 356 357 /* Stop any existing key repeating */ 358 callout_stop(&sc->sc_repeater); 359 360 /* Schedule a repeat callback on keydown */ 361 if (!(sc->last_press & (1 << 7))) { 362 callout_reset(&sc->sc_repeater, 363 ms_to_ticks(sc->sc_kbd.kb_delay1), akbd_repeat, sc); 364 } 365 mtx_unlock(&sc->sc_mutex); 366 367 cv_broadcast(&sc->sc_cv); 368 369 if (KBD_IS_ACTIVE(&sc->sc_kbd) && KBD_IS_BUSY(&sc->sc_kbd)) { 370 sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd, 371 KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg); 372 } 373 374 return (0); 375} 376 377static void 378akbd_repeat(void *xsc) { 379 struct adb_kbd_softc *sc = xsc; 380 int notify_kbd = 0; 381 382 /* Fake an up/down key repeat so long as we have the 383 free buffers */ 384 mtx_lock(&sc->sc_mutex); 385 if (sc->buffers < 7) { 386 sc->buffer[sc->buffers++] = sc->last_press | (1 << 7); 387 sc->buffer[sc->buffers++] = sc->last_press; 388 389 notify_kbd = 1; 390 } 391 mtx_unlock(&sc->sc_mutex); 392 393 if (notify_kbd && KBD_IS_ACTIVE(&sc->sc_kbd) 394 && KBD_IS_BUSY(&sc->sc_kbd)) { 395 sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd, 396 KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg); 397 } 398 399 /* Reschedule the callout */ 400 callout_reset(&sc->sc_repeater, ms_to_ticks(sc->sc_kbd.kb_delay2), 401 akbd_repeat, sc); 402} 403 404static int 405akbd_configure(int flags) 406{ 407 return 0; 408} 409 410static int 411akbd_probe(int unit, void *arg, int flags) 412{ 413 return 0; 414} 415 416static int 417akbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 418{ 419 return 0; 420} 421 422static int 423akbd_term(keyboard_t *kbd) 424{ 425 return 0; 426} 427 428static int 429akbd_interrupt(keyboard_t *kbd, void *arg) 430{ 431 return 0; 432} 433 434static int 435akbd_test_if(keyboard_t *kbd) 436{ 437 return 0; 438} 439 440static int 441akbd_enable(keyboard_t *kbd) 442{ 443 KBD_ACTIVATE(kbd); 444 return (0); 445} 446 447static int 448akbd_disable(keyboard_t *kbd) 449{ 450 struct adb_kbd_softc *sc; 451 sc = (struct adb_kbd_softc *)(kbd); 452 453 callout_stop(&sc->sc_repeater); 454 KBD_DEACTIVATE(kbd); 455 return (0); 456} 457 458static int 459akbd_read(keyboard_t *kbd, int wait) 460{ 461 return (0); 462} 463 464static int 465akbd_check(keyboard_t *kbd) 466{ 467 struct adb_kbd_softc *sc; 468 469 if (!KBD_IS_ACTIVE(kbd)) 470 return (FALSE); 471 472 sc = (struct adb_kbd_softc *)(kbd); 473 474 mtx_lock(&sc->sc_mutex); 475 if (sc->buffers > 0) { 476 mtx_unlock(&sc->sc_mutex); 477 return (TRUE); 478 } 479 mtx_unlock(&sc->sc_mutex); 480 481 return (FALSE); 482} 483 484static u_int 485akbd_read_char(keyboard_t *kbd, int wait) 486{ 487 struct adb_kbd_softc *sc; 488 uint8_t adb_code, final_scancode; 489 int i; 490 491 sc = (struct adb_kbd_softc *)(kbd); 492 493 mtx_lock(&sc->sc_mutex); 494 if (!sc->buffers && wait) 495 cv_wait(&sc->sc_cv,&sc->sc_mutex); 496 497 if (!sc->buffers) { 498 mtx_unlock(&sc->sc_mutex); 499 return (0); 500 } 501 502 adb_code = sc->buffer[0]; 503 504 for (i = 1; i < sc->buffers; i++) 505 sc->buffer[i-1] = sc->buffer[i]; 506 507 sc->buffers--; 508 mtx_unlock(&sc->sc_mutex); 509 510 #ifdef AKBD_EMULATE_ATKBD 511 final_scancode = adb_to_at_scancode_map[adb_code & 0x7f]; 512 final_scancode |= adb_code & 0x80; 513 #else 514 final_scancode = adb_code; 515 #endif 516 517 return (final_scancode); 518} 519 520static int 521akbd_check_char(keyboard_t *kbd) 522{ 523 if (!KBD_IS_ACTIVE(kbd)) 524 return (FALSE); 525 526 return (akbd_check(kbd)); 527} 528 529static int 530set_typematic(keyboard_t *kbd, int code) 531{ 532 /* These numbers are in microseconds, so convert to ticks */ 533 534 static int delays[] = { 250, 500, 750, 1000 }; 535 static int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63, 536 68, 76, 84, 92, 100, 110, 118, 126, 537 136, 152, 168, 184, 200, 220, 236, 252, 538 272, 304, 336, 368, 400, 440, 472, 504 }; 539 540 if (code & ~0x7f) 541 return EINVAL; 542 kbd->kb_delay1 = delays[(code >> 5) & 3]; 543 kbd->kb_delay2 = rates[code & 0x1f]; 544 return 0; 545} 546 547static int akbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t data) 548{ 549 struct adb_kbd_softc *sc; 550 uint16_t r2; 551 int error; 552 553 sc = (struct adb_kbd_softc *)(kbd); 554 error = 0; 555 556 switch (cmd) { 557 case KDGKBMODE: 558 *(int *)data = sc->sc_mode; 559 break; 560 case KDSKBMODE: 561 switch (*(int *)data) { 562 case K_XLATE: 563 if (sc->sc_mode != K_XLATE) { 564 /* make lock key state and LED state match */ 565 sc->sc_state &= ~LOCK_MASK; 566 sc->sc_state |= KBD_LED_VAL(kbd); 567 } 568 /* FALLTHROUGH */ 569 case K_RAW: 570 case K_CODE: 571 if (sc->sc_mode != *(int *)data) 572 sc->sc_mode = *(int *)data; 573 break; 574 default: 575 error = EINVAL; 576 break; 577 } 578 579 break; 580 581 case KDGETLED: 582 *(int *)data = KBD_LED_VAL(kbd); 583 break; 584 585 case KDSKBSTATE: 586 if (*(int *)data & ~LOCK_MASK) { 587 error = EINVAL; 588 break; 589 } 590 sc->sc_state &= ~LOCK_MASK; 591 sc->sc_state |= *(int *)data; 592 593 /* FALLTHROUGH */ 594 595 case KDSETLED: 596 KBD_LED_VAL(kbd) = *(int *)data; 597 598 if (!sc->have_led_control) 599 break; 600 601 r2 = (~0 & 0x04) | 3; 602 603 if (*(int *)data & NLKED) 604 r2 &= ~1; 605 if (*(int *)data & CLKED) 606 r2 &= ~2; 607 if (*(int *)data & SLKED) 608 r2 &= ~4; 609 610 adb_send_packet(sc->sc_dev,ADB_COMMAND_LISTEN,2, 611 sizeof(uint16_t),(u_char *)&r2); 612 613 break; 614 615 case KDGKBSTATE: 616 *(int *)data = sc->sc_state & LOCK_MASK; 617 break; 618 619 case KDSETREPEAT: 620 if (!KBD_HAS_DEVICE(kbd)) 621 return 0; 622 if (((int *)data)[1] < 0) 623 return EINVAL; 624 if (((int *)data)[0] < 0) 625 return EINVAL; 626 else if (((int *)data)[0] == 0) /* fastest possible value */ 627 kbd->kb_delay1 = 200; 628 else 629 kbd->kb_delay1 = ((int *)data)[0]; 630 kbd->kb_delay2 = ((int *)data)[1]; 631 632 break; 633 634 case KDSETRAD: 635 error = set_typematic(kbd, *(int *)data); 636 break; 637 638 case PIO_KEYMAP: 639 case PIO_KEYMAPENT: 640 case PIO_DEADKEYMAP: 641 default: 642 return (genkbd_commonioctl(kbd, cmd, data)); 643 } 644 645 return (error); 646} 647 648static int akbd_lock(keyboard_t *kbd, int lock) 649{ 650 return (0); 651} 652 653static void akbd_clear_state(keyboard_t *kbd) 654{ 655} 656 657static int akbd_get_state(keyboard_t *kbd, void *buf, size_t len) 658{ 659 return (0); 660} 661 662static int akbd_set_state(keyboard_t *kbd, void *buf, size_t len) 663{ 664 return (0); 665} 666 667static int akbd_poll(keyboard_t *kbd, int on) 668{ 669 return (0); 670} 671 672static int 673akbd_modevent(module_t mod, int type, void *data) 674{ 675 switch (type) { 676 case MOD_LOAD: 677 kbd_add_driver(&akbd_kbd_driver); 678 break; 679 680 case MOD_UNLOAD: 681 kbd_delete_driver(&akbd_kbd_driver); 682 break; 683 684 default: 685 return (EOPNOTSUPP); 686 } 687 688 return (0); 689} 690 691DEV_MODULE(akbd, akbd_modevent, NULL); 692 693