Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  *  boot.c - Architecture-Specific Low-Level ACPI Boot Support
  3.  *
  4.  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
  5.  *  Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
  6.  *
  7.  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  8.  *
  9.  *  This program is free software; you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public License as published by
  11.  *  the Free Software Foundation; either version 2 of the License, or
  12.  *  (at your option) any later version.
  13.  *
  14.  *  This program is distributed in the hope that it will be useful,
  15.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *  GNU General Public License for more details.
  18.  *
  19.  *  You should have received a copy of the GNU General Public License
  20.  *  along with this program; if not, write to the Free Software
  21.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22.  *
  23.  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  24.  */
  25.  
  26. #include <linux/init.h>
  27. #include <linux/acpi.h>
  28. #include <linux/module.h>
  29. #include <linux/dmi.h>
  30. #include <linux/pci.h>
  31.  
  32. static inline void outb(u8 v, u16 port)
  33. {
  34.         asm volatile("outb %0,%1" : : "a" (v), "dN" (port));
  35. }
  36. static inline u8 inb(u16 port)
  37. {
  38.         u8 v;
  39.         asm volatile("inb %1,%0" : "=a" (v) : "dN" (port));
  40.         return v;
  41. }
  42.  
  43.  
  44. static int __initdata acpi_force = 0;
  45. int acpi_disabled;
  46. EXPORT_SYMBOL(acpi_disabled);
  47.  
  48. #ifdef  CONFIG_X86_64
  49. # include <asm/proto.h>
  50. #endif                          /* X86 */
  51.  
  52. #define PREFIX                  "ACPI: "
  53.  
  54. int acpi_noirq;                         /* skip ACPI IRQ initialization */
  55. int acpi_pci_disabled;          /* skip ACPI PCI scan and IRQ initialization */
  56. EXPORT_SYMBOL(acpi_pci_disabled);
  57.  
  58. int acpi_ioapic;
  59. int acpi_strict;
  60. u8 acpi_sci_flags __initdata;
  61. /*
  62.  * acpi_pic_sci_set_trigger()
  63.  *
  64.  * use ELCR to set PIC-mode trigger type for SCI
  65.  *
  66.  * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
  67.  * it may require Edge Trigger -- use "acpi_sci=edge"
  68.  *
  69.  * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
  70.  * for the 8259 PIC.  bit[n] = 1 means irq[n] is Level, otherwise Edge.
  71.  * ECLR1 is IRQs 0-7 (IRQ 0, 1, 2 must be 0)
  72.  * ECLR2 is IRQs 8-15 (IRQ 8, 13 must be 0)
  73.  */
  74.  
  75. void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
  76. {
  77.         unsigned int mask = 1 << irq;
  78.         unsigned int old, new;
  79.  
  80.         /* Real old ELCR mask */
  81. //      old = inb(0x4d0) | (inb(0x4d1) << 8);
  82.  
  83.         /*
  84.          * If we use ACPI to set PCI IRQs, then we should clear ELCR
  85.          * since we will set it correctly as we enable the PCI irq
  86.          * routing.
  87.          */
  88.         new = acpi_noirq ? old : 0;
  89.  
  90.         /*
  91.          * Update SCI information in the ELCR, it isn't in the PCI
  92.          * routing tables..
  93.          */
  94.         switch (trigger) {
  95.         case 1:         /* Edge - clear */
  96.                 new &= ~mask;
  97.                 break;
  98.         case 3:         /* Level - set */
  99.                 new |= mask;
  100.                 break;
  101.         }
  102.  
  103.         if (old == new)
  104.                 return;
  105.  
  106.         printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old);
  107. //      outb(new, 0x4d0);
  108. //      outb(new >> 8, 0x4d1);
  109. }
  110.  
  111. static int __init acpi_parse_sbf(struct acpi_table_header *table)
  112. {
  113.         struct acpi_table_boot *sb = (struct acpi_table_boot *)table;
  114.  
  115.         sbf_port = sb->cmos_index;      /* Save CMOS port */
  116.  
  117.         return 0;
  118. }
  119.  
  120. #ifdef CONFIG_HPET_TIMER
  121. #include <asm/hpet.h>
  122.  
  123. static struct resource *hpet_res __initdata;
  124.  
  125. static int __init acpi_parse_hpet(struct acpi_table_header *table)
  126. {
  127.         struct acpi_table_hpet *hpet_tbl = (struct acpi_table_hpet *)table;
  128.  
  129.         if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) {
  130.                 printk(KERN_WARNING PREFIX "HPET timers must be located in "
  131.                        "memory.\n");
  132.                 return -1;
  133.         }
  134.  
  135.         hpet_address = hpet_tbl->address.address;
  136.         hpet_blockid = hpet_tbl->sequence;
  137.  
  138.         /*
  139.          * Some broken BIOSes advertise HPET at 0x0. We really do not
  140.          * want to allocate a resource there.
  141.          */
  142.         if (!hpet_address) {
  143.                 printk(KERN_WARNING PREFIX
  144.                        "HPET id: %#x base: %#lx is invalid\n",
  145.                        hpet_tbl->id, hpet_address);
  146.                 return 0;
  147.         }
  148. #ifdef CONFIG_X86_64
  149.         /*
  150.          * Some even more broken BIOSes advertise HPET at
  151.          * 0xfed0000000000000 instead of 0xfed00000. Fix it up and add
  152.          * some noise:
  153.          */
  154.         if (hpet_address == 0xfed0000000000000UL) {
  155.                 if (!hpet_force_user) {
  156.                         printk(KERN_WARNING PREFIX "HPET id: %#x "
  157.                                "base: 0xfed0000000000000 is bogus\n "
  158.                                "try hpet=force on the kernel command line to "
  159.                                "fix it up to 0xfed00000.\n", hpet_tbl->id);
  160.                         hpet_address = 0;
  161.                         return 0;
  162.                 }
  163.                 printk(KERN_WARNING PREFIX
  164.                        "HPET id: %#x base: 0xfed0000000000000 fixed up "
  165.                        "to 0xfed00000.\n", hpet_tbl->id);
  166.                 hpet_address >>= 32;
  167.         }
  168. #endif
  169.         printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
  170.                hpet_tbl->id, hpet_address);
  171.  
  172.         /*
  173.          * Allocate and initialize the HPET firmware resource for adding into
  174.          * the resource tree during the lateinit timeframe.
  175.          */
  176. #define HPET_RESOURCE_NAME_SIZE 9
  177.         hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE);
  178.  
  179.         hpet_res->name = (void *)&hpet_res[1];
  180.         hpet_res->flags = IORESOURCE_MEM;
  181.         snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, "HPET %u",
  182.                  hpet_tbl->sequence);
  183.  
  184.         hpet_res->start = hpet_address;
  185.         hpet_res->end = hpet_address + (1 * 1024) - 1;
  186.  
  187.         return 0;
  188. }
  189.  
  190. /*
  191.  * hpet_insert_resource inserts the HPET resources used into the resource
  192.  * tree.
  193.  */
  194. static __init int hpet_insert_resource(void)
  195. {
  196.         if (!hpet_res)
  197.                 return 1;
  198.  
  199.         return insert_resource(&iomem_resource, hpet_res);
  200. }
  201.  
  202. late_initcall(hpet_insert_resource);
  203.  
  204. #else
  205. #define acpi_parse_hpet NULL
  206. #endif
  207.  
  208. static int __init acpi_parse_fadt(struct acpi_table_header *table)
  209. {
  210.  
  211. #ifdef CONFIG_X86_PM_TIMER
  212.         /* detect the location of the ACPI PM Timer */
  213.         if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
  214.                 /* FADT rev. 2 */
  215.                 if (acpi_gbl_FADT.xpm_timer_block.space_id !=
  216.                     ACPI_ADR_SPACE_SYSTEM_IO)
  217.                         return 0;
  218.  
  219.                 pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address;
  220.                 /*
  221.                  * "X" fields are optional extensions to the original V1.0
  222.                  * fields, so we must selectively expand V1.0 fields if the
  223.                  * corresponding X field is zero.
  224.                  */
  225.                 if (!pmtmr_ioport)
  226.                         pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
  227.         } else {
  228.                 /* FADT rev. 1 */
  229.                 pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
  230.         }
  231.         if (pmtmr_ioport)
  232.                 printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n",
  233.                        pmtmr_ioport);
  234. #endif
  235.         return 0;
  236. }
  237.  
  238.  
  239. #ifdef  CONFIG_X86_IO_APIC
  240. #else
  241. static inline int acpi_parse_madt_ioapic_entries(void)
  242. {
  243.         return -1;
  244. }
  245. #endif  /* !CONFIG_X86_IO_APIC */
  246.  
  247. static void __init early_acpi_process_madt(void)
  248. {
  249. #ifdef CONFIG_X86_LOCAL_APIC
  250.         int error;
  251.  
  252.         if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
  253.  
  254.                 /*
  255.                  * Parse MADT LAPIC entries
  256.                  */
  257.                 error = early_acpi_parse_madt_lapic_addr_ovr();
  258.                 if (!error) {
  259.                         acpi_lapic = 1;
  260.                         smp_found_config = 1;
  261.                 }
  262.                 if (error == -EINVAL) {
  263.                         /*
  264.                          * Dell Precision Workstation 410, 610 come here.
  265.                          */
  266.                         printk(KERN_ERR PREFIX
  267.                                "Invalid BIOS MADT, disabling ACPI\n");
  268.                         disable_acpi();
  269.                 }
  270.         }
  271. #endif
  272. }
  273.  
  274. static void __init acpi_process_madt(void)
  275. {
  276. #ifdef CONFIG_X86_LOCAL_APIC
  277.         int error;
  278.  
  279.         if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
  280.  
  281.                 /*
  282.                  * Parse MADT LAPIC entries
  283.                  */
  284.                 error = acpi_parse_madt_lapic_entries();
  285.                 if (!error) {
  286.                         acpi_lapic = 1;
  287.  
  288.                         /*
  289.                          * Parse MADT IO-APIC entries
  290.                          */
  291.                         mutex_lock(&acpi_ioapic_lock);
  292.                         error = acpi_parse_madt_ioapic_entries();
  293.                         mutex_unlock(&acpi_ioapic_lock);
  294.                         if (!error) {
  295.                                 acpi_set_irq_model_ioapic();
  296.  
  297.                                 smp_found_config = 1;
  298.                         }
  299.                 }
  300.                 if (error == -EINVAL) {
  301.                         /*
  302.                          * Dell Precision Workstation 410, 610 come here.
  303.                          */
  304.                         printk(KERN_ERR PREFIX
  305.                                "Invalid BIOS MADT, disabling ACPI\n");
  306.                         disable_acpi();
  307.                 }
  308.         } else {
  309.                 /*
  310.                  * ACPI found no MADT, and so ACPI wants UP PIC mode.
  311.                  * In the event an MPS table was found, forget it.
  312.                  * Boot with "acpi=off" to use MPS on such a system.
  313.                  */
  314.                 if (smp_found_config) {
  315.                         printk(KERN_WARNING PREFIX
  316.                                 "No APIC-table, disabling MPS\n");
  317.                         smp_found_config = 0;
  318.                 }
  319.         }
  320.  
  321.         /*
  322.          * ACPI supports both logical (e.g. Hyper-Threading) and physical
  323.          * processors, where MPS only supports physical.
  324.          */
  325.         if (acpi_lapic && acpi_ioapic)
  326.                 printk(KERN_INFO "Using ACPI (MADT) for SMP configuration "
  327.                        "information\n");
  328.         else if (acpi_lapic)
  329.                 printk(KERN_INFO "Using ACPI for processor (LAPIC) "
  330.                        "configuration information\n");
  331. #endif
  332.         return;
  333. }
  334.  
  335. static int __init disable_acpi_irq(const struct dmi_system_id *d)
  336. {
  337.         if (!acpi_force) {
  338.                 printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n",
  339.                        d->ident);
  340.                 acpi_noirq_set();
  341.         }
  342.         return 0;
  343. }
  344.  
  345. static int __init disable_acpi_pci(const struct dmi_system_id *d)
  346. {
  347.         if (!acpi_force) {
  348.                 printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n",
  349.                        d->ident);
  350.                 acpi_disable_pci();
  351.         }
  352.         return 0;
  353. }
  354.  
  355. static int __init dmi_disable_acpi(const struct dmi_system_id *d)
  356. {
  357.         if (!acpi_force) {
  358.                 printk(KERN_NOTICE "%s detected: acpi off\n", d->ident);
  359.                 disable_acpi();
  360.         } else {
  361.                 printk(KERN_NOTICE
  362.                        "Warning: DMI blacklist says broken, but acpi forced\n");
  363.         }
  364.         return 0;
  365. }
  366.  
  367. /*
  368.  * Force ignoring BIOS IRQ0 override
  369.  */
  370. static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
  371. {
  372.         if (!acpi_skip_timer_override) {
  373.                 pr_notice("%s detected: Ignoring BIOS IRQ0 override\n",
  374.                         d->ident);
  375.                 acpi_skip_timer_override = 1;
  376.         }
  377.         return 0;
  378. }
  379.  
  380. /*
  381.  * If your system is blacklisted here, but you find that acpi=force
  382.  * works for you, please contact linux-acpi@vger.kernel.org
  383.  */
  384. static struct dmi_system_id __initdata acpi_dmi_table[] = {
  385.         /*
  386.          * Boxes that need ACPI disabled
  387.          */
  388.         {
  389.          .callback = dmi_disable_acpi,
  390.          .ident = "IBM Thinkpad",
  391.          .matches = {
  392.                      DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
  393.                      DMI_MATCH(DMI_BOARD_NAME, "2629H1G"),
  394.                      },
  395.          },
  396.  
  397.         /*
  398.          * Boxes that need ACPI PCI IRQ routing disabled
  399.          */
  400.         {
  401.          .callback = disable_acpi_irq,
  402.          .ident = "ASUS A7V",
  403.          .matches = {
  404.                      DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
  405.                      DMI_MATCH(DMI_BOARD_NAME, "<A7V>"),
  406.                      /* newer BIOS, Revision 1011, does work */
  407.                      DMI_MATCH(DMI_BIOS_VERSION,
  408.                                "ASUS A7V ACPI BIOS Revision 1007"),
  409.                      },
  410.          },
  411.         {
  412.                 /*
  413.                  * Latest BIOS for IBM 600E (1.16) has bad pcinum
  414.                  * for LPC bridge, which is needed for the PCI
  415.                  * interrupt links to work. DSDT fix is in bug 5966.
  416.                  * 2645, 2646 model numbers are shared with 600/600E/600X
  417.                  */
  418.          .callback = disable_acpi_irq,
  419.          .ident = "IBM Thinkpad 600 Series 2645",
  420.          .matches = {
  421.                      DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
  422.                      DMI_MATCH(DMI_BOARD_NAME, "2645"),
  423.                      },
  424.          },
  425.         {
  426.          .callback = disable_acpi_irq,
  427.          .ident = "IBM Thinkpad 600 Series 2646",
  428.          .matches = {
  429.                      DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
  430.                      DMI_MATCH(DMI_BOARD_NAME, "2646"),
  431.                      },
  432.          },
  433.         /*
  434.          * Boxes that need ACPI PCI IRQ routing and PCI scan disabled
  435.          */
  436.         {                       /* _BBN 0 bug */
  437.          .callback = disable_acpi_pci,
  438.          .ident = "ASUS PR-DLS",
  439.          .matches = {
  440.                      DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
  441.                      DMI_MATCH(DMI_BOARD_NAME, "PR-DLS"),
  442.                      DMI_MATCH(DMI_BIOS_VERSION,
  443.                                "ASUS PR-DLS ACPI BIOS Revision 1010"),
  444.                      DMI_MATCH(DMI_BIOS_DATE, "03/21/2003")
  445.                      },
  446.          },
  447.         {
  448.          .callback = disable_acpi_pci,
  449.          .ident = "Acer TravelMate 36x Laptop",
  450.          .matches = {
  451.                      DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
  452.                      DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
  453.                      },
  454.          },
  455.         {}
  456. };
  457.  
  458. /* second table for DMI checks that should run after early-quirks */
  459. static struct dmi_system_id __initdata acpi_dmi_table_late[] = {
  460.         /*
  461.          * HP laptops which use a DSDT reporting as HP/SB400/10000,
  462.          * which includes some code which overrides all temperature
  463.          * trip points to 16C if the INTIN2 input of the I/O APIC
  464.          * is enabled.  This input is incorrectly designated the
  465.          * ISA IRQ 0 via an interrupt source override even though
  466.          * it is wired to the output of the master 8259A and INTIN0
  467.          * is not connected at all.  Force ignoring BIOS IRQ0
  468.          * override in that cases.
  469.          */
  470.         {
  471.          .callback = dmi_ignore_irq0_timer_override,
  472.          .ident = "HP nx6115 laptop",
  473.          .matches = {
  474.                      DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
  475.                      DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6115"),
  476.                      },
  477.          },
  478.         {
  479.          .callback = dmi_ignore_irq0_timer_override,
  480.          .ident = "HP NX6125 laptop",
  481.          .matches = {
  482.                      DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
  483.                      DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6125"),
  484.                      },
  485.          },
  486.         {
  487.          .callback = dmi_ignore_irq0_timer_override,
  488.          .ident = "HP NX6325 laptop",
  489.          .matches = {
  490.                      DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
  491.                      DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
  492.                      },
  493.          },
  494.         {
  495.          .callback = dmi_ignore_irq0_timer_override,
  496.          .ident = "HP 6715b laptop",
  497.          .matches = {
  498.                      DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
  499.                      DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6715b"),
  500.                      },
  501.          },
  502.         {
  503.          .callback = dmi_ignore_irq0_timer_override,
  504.          .ident = "FUJITSU SIEMENS",
  505.          .matches = {
  506.                      DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  507.                      DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"),
  508.                      },
  509.          },
  510.         {}
  511. };
  512.  
  513. /*
  514.  * acpi_boot_table_init() and acpi_boot_init()
  515.  *  called from setup_arch(), always.
  516.  *      1. checksums all tables
  517.  *      2. enumerates lapics
  518.  *      3. enumerates io-apics
  519.  *
  520.  * acpi_table_init() is separate to allow reading SRAT without
  521.  * other side effects.
  522.  *
  523.  * side effects of acpi_boot_init:
  524.  *      acpi_lapic = 1 if LAPIC found
  525.  *      acpi_ioapic = 1 if IOAPIC found
  526.  *      if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
  527.  *      if acpi_blacklisted() acpi_disabled = 1;
  528.  *      acpi_irq_model=...
  529.  *      ...
  530.  */
  531.  
  532. void __init acpi_boot_table_init(void)
  533. {
  534.         dmi_check_system(acpi_dmi_table);
  535.  
  536.         /*
  537.          * If acpi_disabled, bail out
  538.          */
  539.         if (acpi_disabled)
  540.                 return;
  541.  
  542.         /*
  543.          * Initialize the ACPI boot-time table parser.
  544.          */
  545.         if (acpi_table_init()) {
  546.                 disable_acpi();
  547.                 return;
  548.         }
  549.  
  550.         acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
  551.  
  552.         /*
  553.          * blacklist may disable ACPI entirely
  554.          */
  555.         if (acpi_blacklisted()) {
  556.                 if (acpi_force) {
  557.                         printk(KERN_WARNING PREFIX "acpi=force override\n");
  558.                 } else {
  559.                         printk(KERN_WARNING PREFIX "Disabling ACPI support\n");
  560.                         disable_acpi();
  561.                         return;
  562.                 }
  563.         }
  564. }
  565.  
  566. int __init early_acpi_boot_init(void)
  567. {
  568.         /*
  569.          * If acpi_disabled, bail out
  570.          */
  571.         if (acpi_disabled)
  572.                 return 1;
  573.  
  574.         /*
  575.          * Process the Multiple APIC Description Table (MADT), if present
  576.          */
  577.         early_acpi_process_madt();
  578.  
  579.         /*
  580.          * Hardware-reduced ACPI mode initialization:
  581.          */
  582. //      acpi_reduced_hw_init();
  583.  
  584.         return 0;
  585. }
  586.  
  587. int __init acpi_boot_init(void)
  588. {
  589.         /* those are executed after early-quirks are executed */
  590.         dmi_check_system(acpi_dmi_table_late);
  591.  
  592.         /*
  593.          * If acpi_disabled, bail out
  594.          */
  595.         if (acpi_disabled)
  596.                 return 1;
  597.  
  598. //      acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
  599.  
  600.         /*
  601.          * set sci_int and PM timer address
  602.          */
  603.         acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt);
  604.  
  605.         /*
  606.          * Process the Multiple APIC Description Table (MADT), if present
  607.          */
  608.         acpi_process_madt();
  609.  
  610.         acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
  611.  
  612. //      if (!acpi_noirq)
  613. //              x86_init.pci.init = pci_acpi_init;
  614.  
  615.         return 0;
  616. }
  617.