diff options
author | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 08:45:01 (GMT) |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 08:45:01 (GMT) |
commit | 91550f715b7f7707b5ab5b9b0cd455bda8505954 (patch) | |
tree | 252b23d87eb62562f16e95d24761f03a9d82ede0 | |
parent | 51e22e7a05c1c6f2e38ac7459d3404e32e543b75 (diff) | |
download | linux-91550f715b7f7707b5ab5b9b0cd455bda8505954.tar.xz |
sh: Kill off the rest of the legacy rtc mess.
With the new RTC class driver, we can get rid of most of the
old left over cruft.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r-- | arch/sh/Kconfig | 13 | ||||
-rw-r--r-- | arch/sh/boards/snapgear/rtc.c | 27 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/Makefile | 1 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/irq/ipr.c | 2 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/rtc.c | 128 | ||||
-rw-r--r-- | arch/sh/kernel/time.c | 41 | ||||
-rw-r--r-- | drivers/char/Kconfig | 2 | ||||
-rw-r--r-- | include/asm-sh/mc146818rtc.h | 169 | ||||
-rw-r--r-- | include/asm-sh/rtc.h | 21 |
9 files changed, 23 insertions, 381 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 5bec3af..c7e3596 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -296,19 +296,6 @@ config CPU_LITTLE_ENDIAN endian byte order. These modes require different kernels. Say Y if your machine is little endian, N if it's a big endian machine. -# The SH7750 RTC module is disabled in the Dreamcast -config SH_RTC - bool - depends on !SH_DREAMCAST && !SH_SATURN && !SH_7300_SOLUTION_ENGINE && \ - !SH_73180_SOLUTION_ENGINE && !SH_LANDISK && \ - !SH_R7780RP && !SH_SHMIN - default y - help - Selecting this option will allow the Linux kernel to emulate - PC's RTC. - - If unsure, say N. - config SH_FPU bool "FPU support" depends on !CPU_SH3 diff --git a/arch/sh/boards/snapgear/rtc.c b/arch/sh/boards/snapgear/rtc.c index 722479d..1659fdd 100644 --- a/arch/sh/boards/snapgear/rtc.c +++ b/arch/sh/boards/snapgear/rtc.c @@ -19,9 +19,7 @@ #include <linux/mc146818rtc.h> #include <asm/io.h> -/****************************************************************************/ - -static int use_ds1302 = 0; +static int use_ds1302; /****************************************************************************/ /* @@ -79,10 +77,6 @@ static unsigned int ds1302_readbyte(unsigned int addr) unsigned int val; unsigned long flags; -#if 0 - printk("SnapGear RTC: ds1302_readbyte(addr=%x)\n", addr); -#endif - local_irq_save(flags); set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK); set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); @@ -101,10 +95,6 @@ static void ds1302_writebyte(unsigned int addr, unsigned int val) { unsigned long flags; -#if 0 - printk("SnapGear RTC: ds1302_writebyte(addr=%x)\n", addr); -#endif - local_irq_save(flags); set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK); set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); @@ -167,9 +157,6 @@ void __init secureedge5410_rtc_init(void) if (use_ds1302) { rtc_sh_get_time = snapgear_rtc_gettimeofday; rtc_sh_set_time = snapgear_rtc_settimeofday; - } else { - rtc_sh_get_time = sh_rtc_gettimeofday; - rtc_sh_set_time = sh_rtc_settimeofday; } printk("SnapGear RTC: using %s rtc.\n", use_ds1302 ? "ds1302" : "internal"); @@ -184,10 +171,8 @@ void snapgear_rtc_gettimeofday(struct timespec *ts) { unsigned int sec, min, hr, day, mon, yr; - if (!use_ds1302) { - sh_rtc_gettimeofday(ts); + if (!use_ds1302) return; - } sec = bcd2int(ds1302_readbyte(RTC_ADDR_SEC)); min = bcd2int(ds1302_readbyte(RTC_ADDR_MIN)); @@ -228,7 +213,7 @@ int snapgear_rtc_settimeofday(const time_t secs) unsigned long nowtime; if (!use_ds1302) - return sh_rtc_settimeofday(secs); + return 0; /* * This is called direct from the kernel timer handling code. @@ -237,10 +222,6 @@ int snapgear_rtc_settimeofday(const time_t secs) nowtime = secs; -#if 1 - printk("SnapGear RTC: snapgear_rtc_settimeofday(nowtime=%ld)\n", nowtime); -#endif - /* STOP RTC */ ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80); @@ -326,5 +307,3 @@ void secureedge5410_cmos_write(unsigned char val, int addr) default: break; } } - -/****************************************************************************/ diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile index 59d5b74..fb5dac0 100644 --- a/arch/sh/kernel/cpu/Makefile +++ b/arch/sh/kernel/cpu/Makefile @@ -8,6 +8,5 @@ obj-$(CONFIG_CPU_SH2) += sh2/ obj-$(CONFIG_CPU_SH3) += sh3/ obj-$(CONFIG_CPU_SH4) += sh4/ -obj-$(CONFIG_SH_RTC) += rtc.o obj-$(CONFIG_UBC_WAKEUP) += ubc.o obj-$(CONFIG_SH_ADC) += adc.o diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c index d2b715a..00edee9 100644 --- a/arch/sh/kernel/cpu/irq/ipr.c +++ b/arch/sh/kernel/cpu/irq/ipr.c @@ -124,7 +124,7 @@ void __init init_IRQ(void) #ifndef CONFIG_CPU_SUBTYPE_SH7780 make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY); make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY); -#if defined(CONFIG_SH_RTC) +#ifdef RTC_IRQ make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); #endif diff --git a/arch/sh/kernel/cpu/rtc.c b/arch/sh/kernel/cpu/rtc.c deleted file mode 100644 index 4304cf7..0000000 --- a/arch/sh/kernel/cpu/rtc.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * linux/arch/sh/kernel/rtc.c -- SH3 / SH4 on-chip RTC support - * - * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> - * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka - */ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/time.h> -#include <linux/bcd.h> -#include <asm/io.h> -#include <asm/rtc.h> - -void sh_rtc_gettimeofday(struct timespec *ts) -{ - unsigned int sec128, sec, sec2, min, hr, wk, day, mon, yr, yr100, cf_bit; - unsigned long flags; - - again: - do { - local_irq_save(flags); - ctrl_outb(0, RCR1); /* Clear CF-bit */ - sec128 = ctrl_inb(R64CNT); - sec = ctrl_inb(RSECCNT); - min = ctrl_inb(RMINCNT); - hr = ctrl_inb(RHRCNT); - wk = ctrl_inb(RWKCNT); - day = ctrl_inb(RDAYCNT); - mon = ctrl_inb(RMONCNT); -#if defined(CONFIG_CPU_SH4) - yr = ctrl_inw(RYRCNT); - yr100 = (yr >> 8); - yr &= 0xff; -#else - yr = ctrl_inb(RYRCNT); - yr100 = (yr == 0x99) ? 0x19 : 0x20; -#endif - sec2 = ctrl_inb(R64CNT); - cf_bit = ctrl_inb(RCR1) & RCR1_CF; - local_irq_restore(flags); - } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0); - - BCD_TO_BIN(yr100); - BCD_TO_BIN(yr); - BCD_TO_BIN(mon); - BCD_TO_BIN(day); - BCD_TO_BIN(hr); - BCD_TO_BIN(min); - BCD_TO_BIN(sec); - - if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 || - hr > 23 || min > 59 || sec > 59) { - printk(KERN_ERR - "SH RTC: invalid value, resetting to 1 Jan 2000\n"); - local_irq_save(flags); - ctrl_outb(RCR2_RESET, RCR2); /* Reset & Stop */ - ctrl_outb(0, RSECCNT); - ctrl_outb(0, RMINCNT); - ctrl_outb(0, RHRCNT); - ctrl_outb(6, RWKCNT); - ctrl_outb(1, RDAYCNT); - ctrl_outb(1, RMONCNT); -#if defined(CONFIG_CPU_SH4) - ctrl_outw(0x2000, RYRCNT); -#else - ctrl_outb(0, RYRCNT); -#endif - ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start */ - goto again; - } - -#if RTC_BIT_INVERTED != 0 - if ((sec128 & RTC_BIT_INVERTED)) - sec--; -#endif - - ts->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec); - ts->tv_nsec = ((sec128 * 1000000) / 128) * 1000; -} - -/* - * Changed to only care about tv_sec, and not the full timespec struct - * (i.e. tv_nsec). It can easily be switched to timespec for future cpus - * that support setting usec or nsec RTC values. - */ -int sh_rtc_settimeofday(const time_t secs) -{ - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - unsigned long flags; - - local_irq_save(flags); - ctrl_outb(RCR2_RESET, RCR2); /* Reset pre-scaler & stop RTC */ - - cmos_minutes = ctrl_inb(RMINCNT); - BCD_TO_BIN(cmos_minutes); - - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes - */ - real_seconds = secs % 60; - real_minutes = secs / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - BIN_TO_BCD(real_seconds); - BIN_TO_BCD(real_minutes); - ctrl_outb(real_seconds, RSECCNT); - ctrl_outb(real_minutes, RMINCNT); - } else { - printk(KERN_WARNING - "set_rtc_time: can't update from %d to %d\n", - cmos_minutes, real_minutes); - retval = -1; - } - - ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */ - local_irq_restore(flags); - - return retval; -} diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 8acd70b..149d971 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -3,13 +3,12 @@ * * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> - * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt + * Copyright (C) 2002 - 2006 Paul Mundt * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> * * Some code taken from i386 version. * Copyright (C) 1991, 1992, 1995 Linus Torvalds */ - #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -26,15 +25,20 @@ struct sys_timer *sys_timer; DEFINE_SPINLOCK(rtc_lock); EXPORT_SYMBOL(rtc_lock); -/* XXX: Can we initialize this in a routine somewhere? Dreamcast doesn't want - * these routines anywhere... */ -#ifdef CONFIG_SH_RTC -void (*rtc_sh_get_time)(struct timespec *) = sh_rtc_gettimeofday; -int (*rtc_sh_set_time)(const time_t) = sh_rtc_settimeofday; -#else -void (*rtc_sh_get_time)(struct timespec *); -int (*rtc_sh_set_time)(const time_t); -#endif +/* Dummy RTC ops */ +static void null_rtc_get_time(struct timespec *tv) +{ + tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0); + tv->tv_nsec = 0; +} + +static int null_rtc_set_time(const time_t secs) +{ + return 0; +} + +void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time; +int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time; /* * Scheduler clock - returns current time in nanosec units. @@ -70,7 +74,6 @@ void do_gettimeofday(struct timeval *tv) tv->tv_sec = sec; tv->tv_usec = usec; } - EXPORT_SYMBOL(do_gettimeofday); int do_settimeofday(struct timespec *tv) @@ -103,7 +106,6 @@ int do_settimeofday(struct timespec *tv) return 0; } - EXPORT_SYMBOL(do_settimeofday); /* last time the RTC clock got updated */ @@ -181,7 +183,6 @@ static int __init timer_init_sysfs(void) sys_timer->dev.cls = &timer_sysclass; return sysdev_register(&sys_timer->dev); } - device_initcall(timer_init_sysfs); void (*board_time_init)(void); @@ -193,15 +194,9 @@ void __init time_init(void) clk_init(); - if (rtc_sh_get_time) { - rtc_sh_get_time(&xtime); - } else { - xtime.tv_sec = mktime(2000, 1, 1, 0, 0, 0); - xtime.tv_nsec = 0; - } - - set_normalized_timespec(&wall_to_monotonic, - -xtime.tv_sec, -xtime.tv_nsec); + rtc_sh_get_time(&xtime); + set_normalized_timespec(&wall_to_monotonic, + -xtime.tv_sec, -xtime.tv_nsec); /* * Find the timer to use as the system timer, it will be diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 52ea94b..7f0d323 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -739,7 +739,7 @@ config NVRAM config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM + depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you diff --git a/include/asm-sh/mc146818rtc.h b/include/asm-sh/mc146818rtc.h index adc6e67..0aee96a 100644 --- a/include/asm-sh/mc146818rtc.h +++ b/include/asm-sh/mc146818rtc.h @@ -4,173 +4,4 @@ #ifndef _ASM_MC146818RTC_H #define _ASM_MC146818RTC_H -#ifdef CONFIG_SH_MPC1211 -#undef _ASM_MC146818RTC_H -#undef RTC_IRQ -#include <asm/mpc1211/mc146818rtc.h> -#else - -#include <asm/rtc.h> - -#define RTC_ALWAYS_BCD 1 - -/* FIXME:RTC Interrupt feature is not implemented yet. */ -#undef RTC_IRQ -#define RTC_IRQ 0 - -#if defined(CONFIG_CPU_SH3) -#define RTC_PORT(n) (R64CNT+(n)*2) -#define CMOS_READ(addr) __CMOS_READ(addr,b) -#define CMOS_WRITE(val,addr) __CMOS_WRITE(val,addr,b) - -#elif defined(CONFIG_SH_SECUREEDGE5410) -#include <asm/snapgear.h> - -#define RTC_PORT(n) SECUREEDGE_IOPORT_ADDR -#define CMOS_READ(addr) secureedge5410_cmos_read(addr) -#define CMOS_WRITE(val,addr) secureedge5410_cmos_write(val,addr) -extern unsigned char secureedge5410_cmos_read(int addr); -extern void secureedge5410_cmos_write(unsigned char val, int addr); - -#elif defined(CONFIG_CPU_SH4) -#define RTC_PORT(n) (R64CNT+(n)*4) -#define CMOS_READ(addr) __CMOS_READ(addr,w) -#define CMOS_WRITE(val,addr) __CMOS_WRITE(val,addr,w) -#endif - -#define __CMOS_READ(addr, s) ({ \ - unsigned char val=0, rcr1, rcr2, r64cnt, retry; \ - switch(addr) { \ - case RTC_SECONDS: \ - val = ctrl_inb(RSECCNT); \ - break; \ - case RTC_SECONDS_ALARM: \ - val = ctrl_inb(RSECAR); \ - break; \ - case RTC_MINUTES: \ - val = ctrl_inb(RMINCNT); \ - break; \ - case RTC_MINUTES_ALARM: \ - val = ctrl_inb(RMINAR); \ - break; \ - case RTC_HOURS: \ - val = ctrl_inb(RHRCNT); \ - break; \ - case RTC_HOURS_ALARM: \ - val = ctrl_inb(RHRAR); \ - break; \ - case RTC_DAY_OF_WEEK: \ - val = ctrl_inb(RWKCNT); \ - break; \ - case RTC_DAY_OF_MONTH: \ - val = ctrl_inb(RDAYCNT); \ - break; \ - case RTC_MONTH: \ - val = ctrl_inb(RMONCNT); \ - break; \ - case RTC_YEAR: \ - val = ctrl_in##s(RYRCNT); \ - break; \ - case RTC_REG_A: /* RTC_FREQ_SELECT */ \ - rcr2 = ctrl_inb(RCR2); \ - val = (rcr2 & RCR2_PESMASK) >> 4; \ - rcr1 = ctrl_inb(RCR1); \ - rcr1 = (rcr1 & (RCR1_CIE | RCR1_AIE)) | RCR1_AF;\ - retry = 0; \ - do { \ - ctrl_outb(rcr1, RCR1); /* clear CF */ \ - r64cnt = ctrl_inb(R64CNT); \ - } while((ctrl_inb(RCR1) & RCR1_CF) && retry++ < 1000);\ - r64cnt ^= RTC_BIT_INVERTED; \ - if(r64cnt == 0x7f || r64cnt == 0) \ - val |= RTC_UIP; \ - break; \ - case RTC_REG_B: /* RTC_CONTROL */ \ - rcr1 = ctrl_inb(RCR1); \ - rcr2 = ctrl_inb(RCR2); \ - if(rcr1 & RCR1_CIE) val |= RTC_UIE; \ - if(rcr1 & RCR1_AIE) val |= RTC_AIE; \ - if(rcr2 & RCR2_PESMASK) val |= RTC_PIE; \ - if(!(rcr2 & RCR2_START))val |= RTC_SET; \ - val |= RTC_24H; \ - break; \ - case RTC_REG_C: /* RTC_INTR_FLAGS */ \ - rcr1 = ctrl_inb(RCR1); \ - rcr1 &= ~(RCR1_CF | RCR1_AF); \ - ctrl_outb(rcr1, RCR1); \ - rcr2 = ctrl_inb(RCR2); \ - rcr2 &= ~RCR2_PEF; \ - ctrl_outb(rcr2, RCR2); \ - break; \ - case RTC_REG_D: /* RTC_VALID */ \ - /* Always valid ... */ \ - val = RTC_VRT; \ - break; \ - default: \ - break; \ - } \ - val; \ -}) - -#define __CMOS_WRITE(val, addr, s) ({ \ - unsigned char rcr1,rcr2; \ - switch(addr) { \ - case RTC_SECONDS: \ - ctrl_outb(val, RSECCNT); \ - break; \ - case RTC_SECONDS_ALARM: \ - ctrl_outb(val, RSECAR); \ - break; \ - case RTC_MINUTES: \ - ctrl_outb(val, RMINCNT); \ - break; \ - case RTC_MINUTES_ALARM: \ - ctrl_outb(val, RMINAR); \ - break; \ - case RTC_HOURS: \ - ctrl_outb(val, RHRCNT); \ - break; \ - case RTC_HOURS_ALARM: \ - ctrl_outb(val, RHRAR); \ - break; \ - case RTC_DAY_OF_WEEK: \ - ctrl_outb(val, RWKCNT); \ - break; \ - case RTC_DAY_OF_MONTH: \ - ctrl_outb(val, RDAYCNT); \ - break; \ - case RTC_MONTH: \ - ctrl_outb(val, RMONCNT); \ - break; \ - case RTC_YEAR: \ - ctrl_out##s((ctrl_in##s(RYRCNT) & 0xff00) | (val & 0xff), RYRCNT);\ - break; \ - case RTC_REG_A: /* RTC_FREQ_SELECT */ \ - rcr2 = ctrl_inb(RCR2); \ - if((val & RTC_DIV_CTL) == RTC_DIV_RESET2) \ - rcr2 |= RCR2_RESET; \ - ctrl_outb(rcr2, RCR2); \ - break; \ - case RTC_REG_B: /* RTC_CONTROL */ \ - rcr1 = (ctrl_inb(RCR1) & 0x99) | RCR1_AF; \ - if(val & RTC_AIE) rcr1 |= RCR1_AIE; \ - else rcr1 &= ~RCR1_AIE; \ - if(val & RTC_UIE) rcr1 |= RCR1_CIE; \ - else rcr1 &= ~RCR1_CIE; \ - ctrl_outb(rcr1, RCR1); \ - rcr2 = ctrl_inb(RCR2); \ - if(val & RTC_SET) rcr2 &= ~RCR2_START; \ - else rcr2 |= RCR2_START; \ - ctrl_outb(rcr2, RCR2); \ - break; \ - case RTC_REG_C: /* RTC_INTR_FLAGS */ \ - break; \ - case RTC_REG_D: /* RTC_VALID */ \ - break; \ - default: \ - break; \ - } \ -}) - -#endif /* CONFIG_SH_MPC1211 */ #endif /* _ASM_MC146818RTC_H */ diff --git a/include/asm-sh/rtc.h b/include/asm-sh/rtc.h index 4c7be85..91aacc9 100644 --- a/include/asm-sh/rtc.h +++ b/include/asm-sh/rtc.h @@ -1,29 +1,8 @@ #ifndef _ASM_RTC_H #define _ASM_RTC_H -#ifdef __KERNEL__ -#include <asm/machvec.h> -#include <asm/cpu/rtc.h> - -extern void sh_rtc_gettimeofday(struct timespec *ts); -extern int sh_rtc_settimeofday(const time_t secs); extern void (*board_time_init)(void); extern void (*rtc_sh_get_time)(struct timespec *); extern int (*rtc_sh_set_time)(const time_t); -/* RCR1 Bits */ -#define RCR1_CF 0x80 /* Carry Flag */ -#define RCR1_CIE 0x10 /* Carry Interrupt Enable */ -#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */ -#define RCR1_AF 0x01 /* Alarm Flag */ - -/* RCR2 Bits */ -#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */ -#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */ -#define RCR2_RTCEN 0x08 /* ENable RTC */ -#define RCR2_ADJ 0x04 /* ADJustment (30-second) */ -#define RCR2_RESET 0x02 /* Reset bit */ -#define RCR2_START 0x01 /* Start bit */ - -#endif /* __KERNEL__ */ #endif /* _ASM_RTC_H */ |