1 // SPDX-License-Identifier: GPL-2.0+ 2 // Driver to instantiate Chromebook i2c/smbus devices. 3 // 4 // Copyright (C) 2012 Google, Inc. 5 // Author: Benson Leung <bleung@chromium.org> 6 7 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 8 9 #include <linux/dmi.h> 10 #include <linux/i2c.h> 11 #include <linux/input.h> 12 #include <linux/interrupt.h> 13 #include <linux/ioport.h> 14 #include <linux/module.h> 15 #include <linux/pci.h> 16 #include <linux/platform_device.h> 17 #include <linux/property.h> 18 19 #define ATMEL_TP_I2C_ADDR 0x4b 20 #define ATMEL_TP_I2C_BL_ADDR 0x25 21 #define ATMEL_TS_I2C_ADDR 0x4a 22 #define ATMEL_TS_I2C_BL_ADDR 0x26 23 #define CYAPA_TP_I2C_ADDR 0x67 24 #define ELAN_TP_I2C_ADDR 0x15 25 #define ISL_ALS_I2C_ADDR 0x44 26 #define TAOS_ALS_I2C_ADDR 0x29 27 28 static const char *i2c_adapter_names[] = { 29 "SMBus I801 adapter", 30 "i915 gmbus vga", 31 "i915 gmbus panel", 32 "Synopsys DesignWare I2C adapter", 33 }; 34 35 /* Keep this enum consistent with i2c_adapter_names */ 36 enum i2c_adapter_type { 37 I2C_ADAPTER_SMBUS = 0, 38 I2C_ADAPTER_VGADDC, 39 I2C_ADAPTER_PANEL, 40 I2C_ADAPTER_DESIGNWARE, 41 }; 42 43 struct i2c_peripheral { 44 struct i2c_board_info board_info; 45 unsigned short alt_addr; 46 47 const char *dmi_name; 48 unsigned long irqflags; 49 struct resource irq_resource; 50 51 enum i2c_adapter_type type; 52 u32 pci_devid; 53 54 struct i2c_client *client; 55 }; 56 57 struct chromeos_laptop { 58 /* 59 * Note that we can't mark this pointer as const because 60 * i2c_new_probed_device() changes passed in I2C board info, so. 61 */ 62 struct i2c_peripheral *i2c_peripherals; 63 unsigned int num_i2c_peripherals; 64 }; 65 66 static const struct chromeos_laptop *cros_laptop; 67 68 static struct i2c_client * 69 chromes_laptop_instantiate_i2c_device(struct i2c_adapter *adapter, 70 struct i2c_board_info *info, 71 unsigned short alt_addr) 72 { 73 const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END }; 74 struct i2c_client *client; 75 76 /* 77 * Add the i2c device. If we can't detect it at the primary 78 * address we scan secondary addresses. In any case the client 79 * structure gets assigned primary address. 80 */ 81 client = i2c_new_probed_device(adapter, info, addr_list, NULL); 82 if (!client && alt_addr) { 83 struct i2c_board_info dummy_info = { 84 I2C_BOARD_INFO("dummy", info->addr), 85 }; 86 const unsigned short alt_addr_list[] = { 87 alt_addr, I2C_CLIENT_END 88 }; 89 struct i2c_client *dummy; 90 91 dummy = i2c_new_probed_device(adapter, &dummy_info, 92 alt_addr_list, NULL); 93 if (dummy) { 94 pr_debug("%d-%02x is probed at %02x\n", 95 adapter->nr, info->addr, dummy->addr); 96 i2c_unregister_device(dummy); 97 client = i2c_new_device(adapter, info); 98 } 99 } 100 101 if (!client) 102 pr_debug("failed to register device %d-%02x\n", 103 adapter->nr, info->addr); 104 else 105 pr_debug("added i2c device %d-%02x\n", 106 adapter->nr, info->addr); 107 108 return client; 109 } 110 111 static bool chromeos_laptop_match_adapter_devid(struct device *dev, u32 devid) 112 { 113 struct pci_dev *pdev; 114 115 if (!dev_is_pci(dev)) 116 return false; 117 118 pdev = to_pci_dev(dev); 119 return devid == PCI_DEVID(pdev->bus->number, pdev->devfn); 120 } 121 122 static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter) 123 { 124 struct i2c_peripheral *i2c_dev; 125 int i; 126 127 for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) { 128 i2c_dev = &cros_laptop->i2c_peripherals[i]; 129 130 /* Skip devices already created */ 131 if (i2c_dev->client) 132 continue; 133 134 if (strncmp(adapter->name, i2c_adapter_names[i2c_dev->type], 135 strlen(i2c_adapter_names[i2c_dev->type]))) 136 continue; 137 138 if (i2c_dev->pci_devid && 139 !chromeos_laptop_match_adapter_devid(adapter->dev.parent, 140 i2c_dev->pci_devid)) { 141 continue; 142 } 143 144 i2c_dev->client = 145 chromes_laptop_instantiate_i2c_device(adapter, 146 &i2c_dev->board_info, 147 i2c_dev->alt_addr); 148 } 149 } 150 151 static void chromeos_laptop_detach_i2c_client(struct i2c_client *client) 152 { 153 struct i2c_peripheral *i2c_dev; 154 int i; 155 156 for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) { 157 i2c_dev = &cros_laptop->i2c_peripherals[i]; 158 159 if (i2c_dev->client == client) 160 i2c_dev->client = NULL; 161 } 162 } 163 164 static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb, 165 unsigned long action, void *data) 166 { 167 struct device *dev = data; 168 169 switch (action) { 170 case BUS_NOTIFY_ADD_DEVICE: 171 if (dev->type == &i2c_adapter_type) 172 chromeos_laptop_check_adapter(to_i2c_adapter(dev)); 173 break; 174 175 case BUS_NOTIFY_REMOVED_DEVICE: 176 if (dev->type == &i2c_client_type) 177 chromeos_laptop_detach_i2c_client(to_i2c_client(dev)); 178 break; 179 } 180 181 return 0; 182 } 183 184 static struct notifier_block chromeos_laptop_i2c_notifier = { 185 .notifier_call = chromeos_laptop_i2c_notifier_call, 186 }; 187 188 #define DECLARE_CROS_LAPTOP(_name) \ 189 static const struct chromeos_laptop _name __initconst = { \ 190 .i2c_peripherals = _name##_peripherals, \ 191 .num_i2c_peripherals = ARRAY_SIZE(_name##_peripherals), \ 192 } 193 194 static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = { 195 /* Touchpad. */ 196 { 197 .board_info = { 198 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), 199 .flags = I2C_CLIENT_WAKE, 200 }, 201 .dmi_name = "trackpad", 202 .type = I2C_ADAPTER_SMBUS, 203 }, 204 /* Light Sensor. */ 205 { 206 .board_info = { 207 I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR), 208 }, 209 .dmi_name = "lightsensor", 210 .type = I2C_ADAPTER_SMBUS, 211 }, 212 }; 213 DECLARE_CROS_LAPTOP(samsung_series_5_550); 214 215 static struct i2c_peripheral samsung_series_5_peripherals[] __initdata = { 216 /* Light Sensor. */ 217 { 218 .board_info = { 219 I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR), 220 }, 221 .type = I2C_ADAPTER_SMBUS, 222 }, 223 }; 224 DECLARE_CROS_LAPTOP(samsung_series_5); 225 226 static const int chromebook_pixel_tp_keys[] __initconst = { 227 KEY_RESERVED, 228 KEY_RESERVED, 229 KEY_RESERVED, 230 KEY_RESERVED, 231 KEY_RESERVED, 232 BTN_LEFT 233 }; 234 235 static const struct property_entry 236 chromebook_pixel_trackpad_props[] __initconst = { 237 PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys), 238 { } 239 }; 240 241 static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = { 242 /* Touch Screen. */ 243 { 244 .board_info = { 245 I2C_BOARD_INFO("atmel_mxt_ts", 246 ATMEL_TS_I2C_ADDR), 247 .flags = I2C_CLIENT_WAKE, 248 }, 249 .dmi_name = "touchscreen", 250 .irqflags = IRQF_TRIGGER_FALLING, 251 .type = I2C_ADAPTER_PANEL, 252 .alt_addr = ATMEL_TS_I2C_BL_ADDR, 253 }, 254 /* Touchpad. */ 255 { 256 .board_info = { 257 I2C_BOARD_INFO("atmel_mxt_tp", 258 ATMEL_TP_I2C_ADDR), 259 .properties = 260 chromebook_pixel_trackpad_props, 261 .flags = I2C_CLIENT_WAKE, 262 }, 263 .dmi_name = "trackpad", 264 .irqflags = IRQF_TRIGGER_FALLING, 265 .type = I2C_ADAPTER_VGADDC, 266 .alt_addr = ATMEL_TP_I2C_BL_ADDR, 267 }, 268 /* Light Sensor. */ 269 { 270 .board_info = { 271 I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR), 272 }, 273 .dmi_name = "lightsensor", 274 .type = I2C_ADAPTER_PANEL, 275 }, 276 }; 277 DECLARE_CROS_LAPTOP(chromebook_pixel); 278 279 static struct i2c_peripheral hp_chromebook_14_peripherals[] __initdata = { 280 /* Touchpad. */ 281 { 282 .board_info = { 283 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), 284 .flags = I2C_CLIENT_WAKE, 285 }, 286 .dmi_name = "trackpad", 287 .type = I2C_ADAPTER_DESIGNWARE, 288 }, 289 }; 290 DECLARE_CROS_LAPTOP(hp_chromebook_14); 291 292 static struct i2c_peripheral dell_chromebook_11_peripherals[] __initdata = { 293 /* Touchpad. */ 294 { 295 .board_info = { 296 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), 297 .flags = I2C_CLIENT_WAKE, 298 }, 299 .dmi_name = "trackpad", 300 .type = I2C_ADAPTER_DESIGNWARE, 301 }, 302 /* Elan Touchpad option. */ 303 { 304 .board_info = { 305 I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR), 306 .flags = I2C_CLIENT_WAKE, 307 }, 308 .dmi_name = "trackpad", 309 .type = I2C_ADAPTER_DESIGNWARE, 310 }, 311 }; 312 DECLARE_CROS_LAPTOP(dell_chromebook_11); 313 314 static struct i2c_peripheral toshiba_cb35_peripherals[] __initdata = { 315 /* Touchpad. */ 316 { 317 .board_info = { 318 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), 319 .flags = I2C_CLIENT_WAKE, 320 }, 321 .dmi_name = "trackpad", 322 .type = I2C_ADAPTER_DESIGNWARE, 323 }, 324 }; 325 DECLARE_CROS_LAPTOP(toshiba_cb35); 326 327 static struct i2c_peripheral acer_c7_chromebook_peripherals[] __initdata = { 328 /* Touchpad. */ 329 { 330 .board_info = { 331 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), 332 .flags = I2C_CLIENT_WAKE, 333 }, 334 .dmi_name = "trackpad", 335 .type = I2C_ADAPTER_SMBUS, 336 }, 337 }; 338 DECLARE_CROS_LAPTOP(acer_c7_chromebook); 339 340 static struct i2c_peripheral acer_ac700_peripherals[] __initdata = { 341 /* Light Sensor. */ 342 { 343 .board_info = { 344 I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR), 345 }, 346 .type = I2C_ADAPTER_SMBUS, 347 }, 348 }; 349 DECLARE_CROS_LAPTOP(acer_ac700); 350 351 static struct i2c_peripheral acer_c720_peripherals[] __initdata = { 352 /* Touchscreen. */ 353 { 354 .board_info = { 355 I2C_BOARD_INFO("atmel_mxt_ts", 356 ATMEL_TS_I2C_ADDR), 357 .flags = I2C_CLIENT_WAKE, 358 }, 359 .dmi_name = "touchscreen", 360 .irqflags = IRQF_TRIGGER_FALLING, 361 .type = I2C_ADAPTER_DESIGNWARE, 362 .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)), 363 .alt_addr = ATMEL_TS_I2C_BL_ADDR, 364 }, 365 /* Touchpad. */ 366 { 367 .board_info = { 368 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), 369 .flags = I2C_CLIENT_WAKE, 370 }, 371 .dmi_name = "trackpad", 372 .type = I2C_ADAPTER_DESIGNWARE, 373 .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)), 374 }, 375 /* Elan Touchpad option. */ 376 { 377 .board_info = { 378 I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR), 379 .flags = I2C_CLIENT_WAKE, 380 }, 381 .dmi_name = "trackpad", 382 .type = I2C_ADAPTER_DESIGNWARE, 383 .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)), 384 }, 385 /* Light Sensor. */ 386 { 387 .board_info = { 388 I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR), 389 }, 390 .dmi_name = "lightsensor", 391 .type = I2C_ADAPTER_DESIGNWARE, 392 .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)), 393 }, 394 }; 395 DECLARE_CROS_LAPTOP(acer_c720); 396 397 static struct i2c_peripheral 398 hp_pavilion_14_chromebook_peripherals[] __initdata = { 399 /* Touchpad. */ 400 { 401 .board_info = { 402 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), 403 .flags = I2C_CLIENT_WAKE, 404 }, 405 .dmi_name = "trackpad", 406 .type = I2C_ADAPTER_SMBUS, 407 }, 408 }; 409 DECLARE_CROS_LAPTOP(hp_pavilion_14_chromebook); 410 411 static struct i2c_peripheral cr48_peripherals[] __initdata = { 412 /* Light Sensor. */ 413 { 414 .board_info = { 415 I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR), 416 }, 417 .type = I2C_ADAPTER_SMBUS, 418 }, 419 }; 420 DECLARE_CROS_LAPTOP(cr48); 421 422 static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { 423 { 424 .ident = "Samsung Series 5 550", 425 .matches = { 426 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"), 427 DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"), 428 }, 429 .driver_data = (void *)&samsung_series_5_550, 430 }, 431 { 432 .ident = "Samsung Series 5", 433 .matches = { 434 DMI_MATCH(DMI_PRODUCT_NAME, "Alex"), 435 }, 436 .driver_data = (void *)&samsung_series_5, 437 }, 438 { 439 .ident = "Chromebook Pixel", 440 .matches = { 441 DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), 442 DMI_MATCH(DMI_PRODUCT_NAME, "Link"), 443 }, 444 .driver_data = (void *)&chromebook_pixel, 445 }, 446 { 447 .ident = "Wolf", 448 .matches = { 449 DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), 450 DMI_MATCH(DMI_PRODUCT_NAME, "Wolf"), 451 }, 452 .driver_data = (void *)&dell_chromebook_11, 453 }, 454 { 455 .ident = "HP Chromebook 14", 456 .matches = { 457 DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), 458 DMI_MATCH(DMI_PRODUCT_NAME, "Falco"), 459 }, 460 .driver_data = (void *)&hp_chromebook_14, 461 }, 462 { 463 .ident = "Toshiba CB35", 464 .matches = { 465 DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), 466 DMI_MATCH(DMI_PRODUCT_NAME, "Leon"), 467 }, 468 .driver_data = (void *)&toshiba_cb35, 469 }, 470 { 471 .ident = "Acer C7 Chromebook", 472 .matches = { 473 DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"), 474 }, 475 .driver_data = (void *)&acer_c7_chromebook, 476 }, 477 { 478 .ident = "Acer AC700", 479 .matches = { 480 DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"), 481 }, 482 .driver_data = (void *)&acer_ac700, 483 }, 484 { 485 .ident = "Acer C720", 486 .matches = { 487 DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"), 488 }, 489 .driver_data = (void *)&acer_c720, 490 }, 491 { 492 .ident = "HP Pavilion 14 Chromebook", 493 .matches = { 494 DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"), 495 }, 496 .driver_data = (void *)&hp_pavilion_14_chromebook, 497 }, 498 { 499 .ident = "Cr-48", 500 .matches = { 501 DMI_MATCH(DMI_PRODUCT_NAME, "Mario"), 502 }, 503 .driver_data = (void *)&cr48, 504 }, 505 { } 506 }; 507 MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table); 508 509 static int __init chromeos_laptop_scan_adapter(struct device *dev, void *data) 510 { 511 struct i2c_adapter *adapter; 512 513 adapter = i2c_verify_adapter(dev); 514 if (adapter) 515 chromeos_laptop_check_adapter(adapter); 516 517 return 0; 518 } 519 520 static int __init chromeos_laptop_get_irq_from_dmi(const char *dmi_name) 521 { 522 const struct dmi_device *dmi_dev; 523 const struct dmi_dev_onboard *dev_data; 524 525 dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, dmi_name, NULL); 526 if (!dmi_dev) { 527 pr_err("failed to find DMI device '%s'\n", dmi_name); 528 return -ENOENT; 529 } 530 531 dev_data = dmi_dev->device_data; 532 if (!dev_data) { 533 pr_err("failed to get data from DMI for '%s'\n", dmi_name); 534 return -EINVAL; 535 } 536 537 return dev_data->instance; 538 } 539 540 static int __init chromeos_laptop_setup_irq(struct i2c_peripheral *i2c_dev) 541 { 542 int irq; 543 544 if (i2c_dev->dmi_name) { 545 irq = chromeos_laptop_get_irq_from_dmi(i2c_dev->dmi_name); 546 if (irq < 0) 547 return irq; 548 549 i2c_dev->irq_resource = (struct resource) 550 DEFINE_RES_NAMED(irq, 1, NULL, 551 IORESOURCE_IRQ | i2c_dev->irqflags); 552 i2c_dev->board_info.resources = &i2c_dev->irq_resource; 553 i2c_dev->board_info.num_resources = 1; 554 } 555 556 return 0; 557 } 558 559 static struct chromeos_laptop * __init 560 chromeos_laptop_prepare(const struct chromeos_laptop *src) 561 { 562 struct chromeos_laptop *cros_laptop; 563 struct i2c_peripheral *i2c_dev; 564 struct i2c_board_info *info; 565 int error; 566 int i; 567 568 cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL); 569 if (!cros_laptop) 570 return ERR_PTR(-ENOMEM); 571 572 cros_laptop->i2c_peripherals = kmemdup(src->i2c_peripherals, 573 src->num_i2c_peripherals * 574 sizeof(*src->i2c_peripherals), 575 GFP_KERNEL); 576 if (!cros_laptop->i2c_peripherals) { 577 error = -ENOMEM; 578 goto err_free_cros_laptop; 579 } 580 581 cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals; 582 583 for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) { 584 i2c_dev = &cros_laptop->i2c_peripherals[i]; 585 info = &i2c_dev->board_info; 586 587 error = chromeos_laptop_setup_irq(i2c_dev); 588 if (error) 589 goto err_destroy_cros_peripherals; 590 591 /* We need to deep-copy properties */ 592 if (info->properties) { 593 info->properties = 594 property_entries_dup(info->properties); 595 if (IS_ERR(info->properties)) { 596 error = PTR_ERR(info->properties); 597 goto err_destroy_cros_peripherals; 598 } 599 } 600 } 601 602 return cros_laptop; 603 604 err_destroy_cros_peripherals: 605 while (--i >= 0) { 606 i2c_dev = &cros_laptop->i2c_peripherals[i]; 607 info = &i2c_dev->board_info; 608 if (info->properties) 609 property_entries_free(info->properties); 610 } 611 kfree(cros_laptop->i2c_peripherals); 612 err_free_cros_laptop: 613 kfree(cros_laptop); 614 return ERR_PTR(error); 615 } 616 617 static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop) 618 { 619 struct i2c_peripheral *i2c_dev; 620 struct i2c_board_info *info; 621 int i; 622 623 for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) { 624 i2c_dev = &cros_laptop->i2c_peripherals[i]; 625 info = &i2c_dev->board_info; 626 627 if (i2c_dev->client) 628 i2c_unregister_device(i2c_dev->client); 629 630 if (info->properties) 631 property_entries_free(info->properties); 632 } 633 634 kfree(cros_laptop->i2c_peripherals); 635 kfree(cros_laptop); 636 } 637 638 static int __init chromeos_laptop_init(void) 639 { 640 const struct dmi_system_id *dmi_id; 641 int error; 642 643 dmi_id = dmi_first_match(chromeos_laptop_dmi_table); 644 if (!dmi_id) { 645 pr_debug("unsupported system\n"); 646 return -ENODEV; 647 } 648 649 pr_debug("DMI Matched %s\n", dmi_id->ident); 650 651 cros_laptop = chromeos_laptop_prepare((void *)dmi_id->driver_data); 652 if (IS_ERR(cros_laptop)) 653 return PTR_ERR(cros_laptop); 654 655 error = bus_register_notifier(&i2c_bus_type, 656 &chromeos_laptop_i2c_notifier); 657 if (error) { 658 pr_err("failed to register i2c bus notifier: %d\n", error); 659 chromeos_laptop_destroy(cros_laptop); 660 return error; 661 } 662 663 /* 664 * Scan adapters that have been registered before we installed 665 * the notifier to make sure we do not miss any devices. 666 */ 667 i2c_for_each_dev(NULL, chromeos_laptop_scan_adapter); 668 669 return 0; 670 } 671 672 static void __exit chromeos_laptop_exit(void) 673 { 674 bus_unregister_notifier(&i2c_bus_type, &chromeos_laptop_i2c_notifier); 675 chromeos_laptop_destroy(cros_laptop); 676 } 677 678 module_init(chromeos_laptop_init); 679 module_exit(chromeos_laptop_exit); 680 681 MODULE_DESCRIPTION("Chrome OS Laptop driver"); 682 MODULE_AUTHOR("Benson Leung <bleung@chromium.org>"); 683 MODULE_LICENSE("GPL"); 684