aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRod Whitby <rod@whitby.id.au>2006-01-04 11:53:06 +0000
committerOpenEmbedded Project <openembedded-devel@lists.openembedded.org>2006-01-04 11:53:06 +0000
commita0f5ebe8b09c775bccef4dcb663f5bd47446e61c (patch)
treebf0d2d9d422520786ef6d6830776e1dca079af7b
parentc435f0f5b01e8df3a0a3a567077741b1f8d4be04 (diff)
downloadopenembedded-a0f5ebe8b09c775bccef4dcb663f5bd47446e61c.tar.gz
nas100d-kernel: Corrected the location of the mac address in the RedBoot config partition, merged the two nas100d patches (sent upstream), updated patchsets to match 2.6.15, removed some patches, and combined some others.
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/00-memory-h-page-shift.patch74
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/01-i2c-ixp4xx.patch29
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/40-rtc-class.patch2719
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/50-nas100d-arch.patch398
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/55-nas100d-arch.patch395
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/85-timer.patch246
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/90-ixp4xx-nslu2.patch132
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/91-maclist.patch377
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/92-nas100d-maclist.patch72
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/anonymiser.patch22
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/nas100d-pci.c87
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/nas100d-power.c92
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/nas100d-setup.c132
-rw-r--r--packages/linux/nas100d-kernel/2.6.15/nas100d.h75
-rw-r--r--packages/linux/nas100d-kernel_2.6.15.bb34
15 files changed, 3915 insertions, 969 deletions
diff --git a/packages/linux/nas100d-kernel/2.6.15/00-memory-h-page-shift.patch b/packages/linux/nas100d-kernel/2.6.15/00-memory-h-page-shift.patch
index 29b048e27a..4ec8f0475f 100644
--- a/packages/linux/nas100d-kernel/2.6.15/00-memory-h-page-shift.patch
+++ b/packages/linux/nas100d-kernel/2.6.15/00-memory-h-page-shift.patch
@@ -1,10 +1,68 @@
---- linux-2.6.15/include/asm-arm/arch-ixp4xx/memory.h 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.15/include/asm-arm/arch-ixp4xx/memory.h 1970-01-01 00:00:00.000000000 +0000
-@@ -8,6 +8,7 @@
- #define __ASM_ARCH_MEMORY_H
+--- linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/memory.h~ 2005-12-30 05:18:27.000000000 +1030
++++ linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/memory.h 2005-12-30 05:36:04.000000000 +1030
+@@ -16,31 +16,10 @@
- #include <asm/sizes.h>
-+#include <asm/page.h>
+ #ifndef __ASSEMBLY__
- /*
- * Physical DRAM offset.
+-/*
+- * Only first 64MB of memory can be accessed via PCI.
+- * We use GFP_DMA to allocate safe buffers to do map/unmap.
+- * This is really ugly and we need a better way of specifying
+- * DMA-capable regions of memory.
+- */
+-static inline void __arch_adjust_zones(int node, unsigned long *zone_size,
+- unsigned long *zhole_size)
+-{
+- unsigned int sz = SZ_64M >> PAGE_SHIFT;
+-
+- /*
+- * Only adjust if > 64M on current system
+- */
+- if (node || (zone_size[0] <= sz))
+- return;
+-
+- zone_size[1] = zone_size[0] - sz;
+- zone_size[0] = sz;
+- zhole_size[1] = zhole_size[0];
+- zhole_size[0] = 0;
+-}
++void ixp4xx_adjust_zones(int node, unsigned long *size, unsigned long *holes);
+
+ #define arch_adjust_zones(node, size, holes) \
+- __arch_adjust_zones(node, size, holes)
++ ixp4xx_adjust_zones(node, size, holes)
+
+ #define ISA_DMA_THRESHOLD (SZ_64M - 1)
+
+--- linux-2.6.15-rc7/arch/arm/mach-ixp4xx/common-pci.c~ 2005-12-30 05:16:03.000000000 +1030
++++ linux-2.6.15-rc7/arch/arm/mach-ixp4xx/common-pci.c 2005-12-30 05:43:55.000000000 +1030
+@@ -341,6 +341,29 @@ int dma_needs_bounce(struct device *dev,
+ return (dev->bus == &pci_bus_type ) && ((dma_addr + size) >= SZ_64M);
+ }
+
++/*
++ * Only first 64MB of memory can be accessed via PCI.
++ * We use GFP_DMA to allocate safe buffers to do map/unmap.
++ * This is really ugly and we need a better way of specifying
++ * DMA-capable regions of memory.
++ */
++void __init ixp4xx_adjust_zones(int node, unsigned long *zone_size,
++ unsigned long *zhole_size)
++{
++ unsigned int sz = SZ_64M >> PAGE_SHIFT;
++
++ /*
++ * Only adjust if > 64M on current system
++ */
++ if (node || (zone_size[0] <= sz))
++ return;
++
++ zone_size[1] = zone_size[0] - sz;
++ zone_size[0] = sz;
++ zhole_size[1] = zhole_size[0];
++ zhole_size[0] = 0;
++}
++
+ void __init ixp4xx_pci_preinit(void)
+ {
+ unsigned long processor_id;
diff --git a/packages/linux/nas100d-kernel/2.6.15/01-i2c-ixp4xx.patch b/packages/linux/nas100d-kernel/2.6.15/01-i2c-ixp4xx.patch
deleted file mode 100644
index 16426bdee6..0000000000
--- a/packages/linux/nas100d-kernel/2.6.15/01-i2c-ixp4xx.patch
+++ /dev/null
@@ -1,29 +0,0 @@
---- linux-2.6.15/drivers/i2c/busses/i2c-ixp4xx.c 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.15/drivers/i2c/busses/i2c-ixp4xx.c 1970-01-01 00:00:00.000000000 +0000
-@@ -35,7 +35,7 @@
-
- #include <asm/hardware.h> /* Pick up IXP4xx-specific bits */
-
--static struct device_driver ixp4xx_i2c_driver;
-+static struct platform_driver ixp4xx_i2c_driver;
-
- static inline int ixp4xx_scl_pin(void *data)
- {
-@@ -128,7 +128,7 @@ static int ixp4xx_i2c_probe(struct platf
- drv_data->algo_data.timeout = 100;
-
- drv_data->adapter.id = I2C_HW_B_IXP4XX;
-- strlcpy(drv_data->adapter.name, ixp4xx_i2c_driver.name,
-+ strlcpy(drv_data->adapter.name, ixp4xx_i2c_driver.driver.name,
- I2C_NAME_SIZE);
- drv_data->adapter.algo_data = &drv_data->algo_data;
-
-@@ -140,7 +140,7 @@ static int ixp4xx_i2c_probe(struct platf
- gpio_line_set(gpio->sda_pin, 0);
-
- if ((err = i2c_bit_add_bus(&drv_data->adapter) != 0)) {
-- printk(KERN_ERR "ERROR: Could not install %s\n", dev->bus_id);
-+ printk(KERN_ERR "ERROR: Could not install %s\n", ixp4xx_i2c_driver.driver.name);
-
- kfree(drv_data);
- return err;
diff --git a/packages/linux/nas100d-kernel/2.6.15/40-rtc-class.patch b/packages/linux/nas100d-kernel/2.6.15/40-rtc-class.patch
new file mode 100644
index 0000000000..feea3f2f8b
--- /dev/null
+++ b/packages/linux/nas100d-kernel/2.6.15/40-rtc-class.patch
@@ -0,0 +1,2719 @@
+--- linux-nslu2.orig/include/linux/rtc.h 2006-01-03 15:31:18.000000000 +0100
++++ linux-nslu2/include/linux/rtc.h 2006-01-03 15:34:24.000000000 +0100
+@@ -91,8 +91,81 @@ struct rtc_pll_info {
+ #define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */
+ #define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */
+
++/* interrupt flags */
++#define RTC_IRQF 0x80 /* any of the following is active */
++#define RTC_PF 0x40
++#define RTC_AF 0x20
++#define RTC_UF 0x10
++
+ #ifdef __KERNEL__
+
++#include <linux/device.h>
++#include <linux/seq_file.h>
++#include <linux/cdev.h>
++#include <linux/poll.h>
++
++struct rtc_class_ops {
++ int (*open)(struct device *);
++ void (*release)(struct device *);
++ int (*ioctl)(struct device *, unsigned int, unsigned long);
++ int (*read_time)(struct device *, struct rtc_time *);
++ int (*set_time)(struct device *, struct rtc_time *);
++ int (*read_alarm)(struct device *, struct rtc_wkalrm *);
++ int (*set_alarm)(struct device *, struct rtc_wkalrm *);
++ int (*proc)(struct device *, struct seq_file *);
++ int (*set_mmss)(struct device *, unsigned long secs);
++ int (*irq_set_state)(struct device *, int enabled);
++ int (*irq_set_freq)(struct device *, int freq);
++};
++
++#define RTC_DEVICE_NAME_SIZE 20
++struct rtc_task;
++
++struct rtc_device
++{
++ int id;
++ struct module *owner;
++ struct rw_semaphore lock;
++ struct class_device class_dev;
++ struct rtc_class_ops *ops;
++ char name[RTC_DEVICE_NAME_SIZE];
++
++ struct cdev char_dev;
++ struct semaphore char_sem;
++
++ unsigned long irq_data;
++ spinlock_t irq_lock;
++ wait_queue_head_t irq_queue;
++ struct fasync_struct *async_queue;
++
++ spinlock_t irq_task_lock;
++ struct rtc_task *irq_task;
++ int irq_freq;
++};
++#define to_rtc_device(d) container_of(d, struct rtc_device, class_dev)
++
++extern struct rtc_device *rtc_device_register(char *name,
++ struct device *dev,
++ struct rtc_class_ops *ops,
++ struct module *owner);
++extern void rtc_device_unregister(struct rtc_device *rdev);
++extern int rtc_interface_register(struct class_interface *intf);
++
++
++extern int rtc_month_days(unsigned int month, unsigned int year);
++extern int rtc_valid_tm(struct rtc_time *tm);
++extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
++extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
++
++extern int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm);
++extern int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm);
++extern int rtc_read_alarm(struct class_device *class_dev,
++ struct rtc_wkalrm *alrm);
++extern int rtc_set_alarm(struct class_device *class_dev,
++ struct rtc_wkalrm *alrm);
++extern void rtc_update_irq(struct class_device *class_dev,
++ unsigned long num, unsigned long events);
++
+ typedef struct rtc_task {
+ void (*func)(void *private_data);
+ void *private_data;
+--- linux-nslu2.orig/drivers/Kconfig 2006-01-03 15:31:19.000000000 +0100
++++ linux-nslu2/drivers/Kconfig 2006-01-04 01:27:31.000000000 +0100
+@@ -66,4 +66,6 @@ source "drivers/infiniband/Kconfig"
+
+ source "drivers/sn/Kconfig"
+
++source "drivers/rtc/Kconfig"
++
+ endmenu
+--- linux-nslu2.orig/drivers/Makefile 2006-01-03 15:33:32.000000000 +0100
++++ linux-nslu2/drivers/Makefile 2006-01-04 01:27:31.000000000 +0100
+@@ -54,6 +54,7 @@ obj-$(CONFIG_USB_GADGET) += usb/gadget/
+ obj-$(CONFIG_GAMEPORT) += input/gameport/
+ obj-$(CONFIG_INPUT) += input/
+ obj-$(CONFIG_I2O) += message/
++obj-y += rtc/
+ obj-$(CONFIG_I2C) += i2c/
+ obj-$(CONFIG_W1) += w1/
+ obj-$(CONFIG_HWMON) += hwmon/
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/class.c 2006-01-03 15:45:19.000000000 +0100
+@@ -0,0 +1,141 @@
++/*
++ * RTC subsystem, base class
++ *
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * class skeleton from drivers/hwmon/hwmon.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++*/
++
++#include <linux/module.h>
++#include <linux/rtc.h>
++#include <linux/kdev_t.h>
++#include <linux/idr.h>
++
++static DEFINE_IDR(rtc_idr);
++static DECLARE_MUTEX(idr_lock);
++struct class *rtc_class;
++
++static void rtc_device_release(struct class_device *class_dev)
++{
++ struct rtc_device *rtc = to_rtc_device(class_dev);
++ down(&idr_lock);
++ idr_remove(&rtc_idr, rtc->id);
++ up(&idr_lock);
++ kfree(rtc);
++}
++
++/**
++ * rtc_device_register - register w/ RTC class
++ * @dev: the device to register
++ *
++ * rtc_device_unregister() must be called when the class device is no
++ * longer needed.
++ *
++ * Returns the pointer to the new struct class device.
++ */
++struct rtc_device *rtc_device_register(char *name, struct device *dev,
++ struct rtc_class_ops *ops,
++ struct module *owner)
++{
++ struct rtc_device *rtc;
++ int id, err;
++
++ if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
++ err = -ENOMEM;
++ goto exit;
++ }
++
++
++ down(&idr_lock);
++ err = idr_get_new(&rtc_idr, NULL, &id);
++ up(&idr_lock);
++
++ if (err < 0)
++ goto exit;
++
++ id = id & MAX_ID_MASK;
++
++ if ((rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL)) == NULL) {
++ err = -ENOMEM;
++ goto exit_idr;
++ }
++
++ rtc->id = id;
++ rtc->ops = ops;
++ rtc->owner = owner;
++ rtc->class_dev.dev = dev;
++ rtc->class_dev.class = rtc_class;
++ rtc->class_dev.release = rtc_device_release;
++
++ init_rwsem(&rtc->lock);
++ spin_lock_init(&rtc->irq_lock);
++ spin_lock_init(&rtc->irq_task_lock);
++
++ strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
++ snprintf(rtc->class_dev.class_id, BUS_ID_SIZE, "rtc%d", id);
++
++ if ((err = class_device_register(&rtc->class_dev)))
++ goto exit_kfree;
++
++ dev_info(dev, "rtc core: registered %s as %s\n",
++ rtc->name, rtc->class_dev.class_id);
++
++ return rtc;
++
++exit_kfree:
++ kfree(rtc);
++
++exit_idr:
++ idr_remove(&rtc_idr, id);
++
++exit:
++ return ERR_PTR(err);
++}
++EXPORT_SYMBOL_GPL(rtc_device_register);
++
++
++/**
++ * rtc_device_unregister - removes the previously registered RTC class device
++ *
++ * @rtc: the RTC class device to destroy
++ */
++void rtc_device_unregister(struct rtc_device *rtc)
++{
++ down_write(&rtc->lock);
++ class_device_unregister(&rtc->class_dev);
++}
++EXPORT_SYMBOL_GPL(rtc_device_unregister);
++
++int rtc_interface_register(struct class_interface *intf)
++{
++ intf->class = rtc_class;
++ return class_interface_register(intf);
++}
++EXPORT_SYMBOL_GPL(rtc_interface_register);
++
++static int __init rtc_init(void)
++{
++ rtc_class = class_create(THIS_MODULE, "rtc");
++ if (IS_ERR(rtc_class)) {
++ printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
++ return PTR_ERR(rtc_class);
++ }
++ return 0;
++}
++
++static void __exit rtc_exit(void)
++{
++ class_destroy(rtc_class);
++}
++
++module_init(rtc_init);
++module_exit(rtc_exit);
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towerteh.it>");
++MODULE_DESCRIPTION("RTC class support");
++MODULE_LICENSE("GPL");
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/Kconfig 2006-01-04 01:27:21.000000000 +0100
+@@ -0,0 +1,93 @@
++#
++# RTC class/drivers configuration
++#
++
++menu "Real Time Clock"
++
++config RTC_CLASS
++ tristate "RTC class"
++ depends on EXPERIMENTAL
++ default y
++ help
++ Generic RTC class support. If you say yes here, you will
++ be allowed to plug one or more RTCs to your system. You will
++ probably want to enable one of more of the interfaces below.
++
++ This driver can also be built as a module. If so, the module
++ will be called rtc-class.
++
++comment "RTC interfaces"
++ depends on RTC_CLASS
++
++config RTC_INTF_SYSFS
++ tristate "sysfs"
++ depends on RTC_CLASS && SYSFS
++ default RTC_CLASS
++ help
++ Say yes here if you want to use your RTC using the sysfs
++ interface, /sys/class/rtc/rtcX .
++
++ This driver can also be built as a module. If so, the module
++ will be called rtc-sysfs.
++
++config RTC_INTF_PROC
++ tristate "proc"
++ depends on RTC_CLASS && PROC_FS
++ default RTC_CLASS
++ help
++ Say yes here if you want to use your RTC using the proc
++ interface, /proc/driver/rtc .
++
++ This driver can also be built as a module. If so, the module
++ will be called rtc-proc.
++
++config RTC_INTF_DEV
++ tristate "dev"
++ depends on RTC_CLASS
++ default RTC_CLASS
++ help
++ Say yes here if you want to use your RTC using the dev
++ interface, /dev/rtc .
++
++ This driver can also be built as a module. If so, the module
++ will be called rtc-dev.
++
++comment "RTC drivers"
++ depends on RTC_CLASS
++
++config RTC_DRV_X1205
++ tristate "Xicor/Intersil X1205 RTC chip"
++ depends on RTC_CLASS && I2C
++ help
++ If you say yes here you get support for the
++ Xicor/Intersil X1205 RTC chip.
++
++ This driver can also be built as a module. If so, the module
++ will be called rtc-x1205.
++
++config RTC_DRV_DS1672
++ tristate "Dallas/Maxim DS1672"
++ depends on RTC_CLASS && I2C
++ help
++ If you say yes here you get support for the
++ Dallas/Maxim DS1672 timekeeping chip.
++
++ This driver can also be built as a module. If so, the module
++ will be called rtc-ds1672.
++
++config RTC_DRV_TEST
++ tristate "Test driver/device"
++ depends on RTC_CLASS
++ help
++ If you say yes here you get support for the
++ RTC test driver. It's a software RTC which can be
++ used to test the RTC subsystem APIs. It gets
++ the time from the system clock.
++ You want this driver only if you are doing development
++ on the RTC subsystem. Please read the source code
++ for further details.
++
++ This driver can also be built as a module. If so, the module
++ will be called rtc-test.
++
++endmenu
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/Makefile 2006-01-04 01:27:21.000000000 +0100
+@@ -0,0 +1,15 @@
++#
++# Makefile for RTC class/drivers.
++#
++
++obj-y += utils.o
++obj-$(CONFIG_RTC_CLASS) += rtc-core.o
++rtc-core-y := class.o interface.o
++obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
++obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
++obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
++
++obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
++obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
++obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
++
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/interface.c 2006-01-03 15:34:24.000000000 +0100
+@@ -0,0 +1,189 @@
++/*
++ * RTC subsystem, interface functions
++ *
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * based on arch/arm/common/rtctime.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++*/
++
++#include <linux/rtc.h>
++
++extern struct class *rtc_class;
++
++int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm)
++{
++ int err = -EINVAL;
++ struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
++
++ if (ops->read_time) {
++ memset(tm, 0, sizeof(struct rtc_time));
++ err = ops->read_time(class_dev->dev, tm);
++ }
++ return err;
++}
++EXPORT_SYMBOL(rtc_read_time);
++
++int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm)
++{
++ int err;
++ struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
++
++ err = rtc_valid_tm(tm);
++ if (err == 0 && ops->set_time)
++ err = ops->set_time(class_dev->dev, tm);
++
++ return err;
++}
++EXPORT_SYMBOL(rtc_set_time);
++
++int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
++{
++ struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
++ int err = -EINVAL;
++
++ if (ops->read_alarm) {
++ memset(alarm, 0, sizeof(struct rtc_wkalrm));
++ err = ops->read_alarm(class_dev->dev, alarm);
++ }
++ return err;
++}
++EXPORT_SYMBOL(rtc_read_alarm);
++
++int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
++{
++ int err = -EINVAL;
++ struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
++
++ if (ops->set_alarm)
++ err = ops->set_alarm(class_dev->dev, alarm);
++ return err;
++}
++EXPORT_SYMBOL(rtc_set_alarm);
++
++void rtc_update_irq(struct class_device *class_dev,
++ unsigned long num, unsigned long events)
++{
++ struct rtc_device *rtc = to_rtc_device(class_dev);
++
++ spin_lock(&rtc->irq_lock);
++ rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
++ spin_unlock(&rtc->irq_lock);
++
++ spin_lock(&rtc->irq_task_lock);
++ if (rtc->irq_task)
++ rtc->irq_task->func(rtc->irq_task->private_data);
++ spin_unlock(&rtc->irq_task_lock);
++
++ wake_up_interruptible(&rtc->irq_queue);
++ kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
++}
++EXPORT_SYMBOL(rtc_update_irq);
++
++struct class_device *rtc_open(char *name)
++{
++ struct class_device *class_dev = NULL,
++ *class_dev_tmp;
++
++ down(&rtc_class->sem);
++ list_for_each_entry(class_dev_tmp, &rtc_class->children, node) {
++ if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) {
++ class_dev = class_dev_tmp;
++ break;
++ }
++ }
++ up(&rtc_class->sem);
++
++ return class_dev;
++}
++EXPORT_SYMBOL(rtc_open);
++
++void rtc_close(struct class_device *class_dev)
++{
++}
++EXPORT_SYMBOL(rtc_close);
++
++int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task)
++{
++ int retval = -EBUSY;
++ struct rtc_device *rtc = to_rtc_device(class_dev);
++
++ if (task == NULL || task->func == NULL)
++ return -EINVAL;
++
++ spin_lock(&rtc->irq_task_lock);
++ if (rtc->irq_task == NULL) {
++ rtc->irq_task = task;
++ retval = 0;
++ }
++ spin_unlock(&rtc->irq_task_lock);
++
++ return retval;
++}
++EXPORT_SYMBOL(rtc_irq_register);
++
++void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task)
++{
++ struct rtc_device *rtc = to_rtc_device(class_dev);
++
++ spin_lock(&rtc->irq_task_lock);
++ if (rtc->irq_task == task)
++ rtc->irq_task = NULL;
++ spin_unlock(&rtc->irq_task_lock);
++}
++EXPORT_SYMBOL(rtc_irq_unregister);
++
++int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled)
++{
++ int err = 0;
++ unsigned long flags;
++ struct rtc_device *rtc = to_rtc_device(class_dev);
++
++ spin_lock_irqsave(&rtc->irq_task_lock, flags);
++ if (rtc->irq_task != task)
++ err = -ENXIO;
++ spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
++
++ if (err == 0)
++ err = rtc->ops->irq_set_state(class_dev->dev, enabled);
++
++ return err;
++}
++EXPORT_SYMBOL(rtc_irq_set_state);
++
++int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
++{
++ int err = 0, tmp = 0;
++ unsigned long flags;
++ struct rtc_device *rtc = to_rtc_device(class_dev);
++
++ /* allowed range is 2-8192 */
++ if (freq < 2 || freq > 8192)
++ return -EINVAL;
++
++/* if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
++ return -EACCES;
++*/
++ /* check if freq is a power of 2 */
++ while (freq > (1 << tmp))
++ tmp++;
++
++ if (freq != (1 << tmp))
++ return -EINVAL;
++
++ spin_lock_irqsave(&rtc->irq_task_lock, flags);
++ if (rtc->irq_task != task)
++ err = -ENXIO;
++ spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
++
++ if (err == 0) {
++ if ((err = rtc->ops->irq_set_freq(class_dev->dev, freq)) == 0)
++ rtc->irq_freq = freq;
++ }
++ return err;
++
++}
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/utils.c 2006-01-03 15:34:24.000000000 +0100
+@@ -0,0 +1,97 @@
++/*
++ * RTC subsystem, utility functions
++ *
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * based on arch/arm/common/rtctime.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++*/
++
++#include <linux/rtc.h>
++
++static const unsigned char rtc_days_in_month[] = {
++ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
++};
++
++#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
++#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
++
++int rtc_month_days(unsigned int month, unsigned int year)
++{
++ return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1);
++}
++EXPORT_SYMBOL(rtc_month_days);
++
++/*
++ * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
++ */
++void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
++{
++ int days, month, year;
++
++ days = time / 86400;
++ time -= days * 86400;
++
++ tm->tm_wday = (days + 4) % 7;
++
++ year = 1970 + days / 365;
++ days -= (year - 1970) * 365
++ + LEAPS_THRU_END_OF(year - 1)
++ - LEAPS_THRU_END_OF(1970 - 1);
++ if (days < 0) {
++ year -= 1;
++ days += 365 + LEAP_YEAR(year);
++ }
++ tm->tm_year = year - 1900;
++ tm->tm_yday = days + 1;
++
++ for (month = 0; month < 11; month++) {
++ int newdays;
++
++ newdays = days - rtc_month_days(month, year);
++ if (newdays < 0)
++ break;
++ days = newdays;
++ }
++ tm->tm_mon = month;
++ tm->tm_mday = days + 1;
++
++ tm->tm_hour = time / 3600;
++ time -= tm->tm_hour * 3600;
++ tm->tm_min = time / 60;
++ tm->tm_sec = time - tm->tm_min * 60;
++}
++EXPORT_SYMBOL(rtc_time_to_tm);
++
++/*
++ * Does the rtc_time represent a valid date/time?
++ */
++int rtc_valid_tm(struct rtc_time *tm)
++{
++ if (tm->tm_year < 70 ||
++ tm->tm_mon >= 12 ||
++ tm->tm_mday < 1 ||
++ tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900) ||
++ tm->tm_hour >= 24 ||
++ tm->tm_min >= 60 ||
++ tm->tm_sec >= 60)
++ return -EINVAL;
++
++ return 0;
++}
++EXPORT_SYMBOL(rtc_valid_tm);
++
++/*
++ * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
++ */
++int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
++{
++ *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
++ tm->tm_hour, tm->tm_min, tm->tm_sec);
++ return 0;
++}
++EXPORT_SYMBOL(rtc_tm_to_time);
+--- linux-nslu2.orig/arch/arm/Kconfig 2006-01-04 01:27:04.000000000 +0100
++++ linux-nslu2/arch/arm/Kconfig 2006-01-04 01:27:31.000000000 +0100
+@@ -750,6 +750,8 @@ source "drivers/usb/Kconfig"
+
+ source "drivers/mmc/Kconfig"
+
++source "drivers/rtc/Kconfig"
++
+ endmenu
+
+ source "fs/Kconfig"
+--- linux-nslu2.orig/arch/arm/common/rtctime.c 2006-01-04 01:27:04.000000000 +0100
++++ linux-nslu2/arch/arm/common/rtctime.c 2006-01-04 01:27:09.000000000 +0100
+@@ -40,89 +40,6 @@ static struct rtc_ops *rtc_ops;
+
+ #define rtc_epoch 1900UL
+
+-static const unsigned char days_in_month[] = {
+- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+-};
+-
+-#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
+-#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
+-
+-static int month_days(unsigned int month, unsigned int year)
+-{
+- return days_in_month[month] + (LEAP_YEAR(year) && month == 1);
+-}
+-
+-/*
+- * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
+- */
+-void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
+-{
+- int days, month, year;
+-
+- days = time / 86400;
+- time -= days * 86400;
+-
+- tm->tm_wday = (days + 4) % 7;
+-
+- year = 1970 + days / 365;
+- days -= (year - 1970) * 365
+- + LEAPS_THRU_END_OF(year - 1)
+- - LEAPS_THRU_END_OF(1970 - 1);
+- if (days < 0) {
+- year -= 1;
+- days += 365 + LEAP_YEAR(year);
+- }
+- tm->tm_year = year - 1900;
+- tm->tm_yday = days + 1;
+-
+- for (month = 0; month < 11; month++) {
+- int newdays;
+-
+- newdays = days - month_days(month, year);
+- if (newdays < 0)
+- break;
+- days = newdays;
+- }
+- tm->tm_mon = month;
+- tm->tm_mday = days + 1;
+-
+- tm->tm_hour = time / 3600;
+- time -= tm->tm_hour * 3600;
+- tm->tm_min = time / 60;
+- tm->tm_sec = time - tm->tm_min * 60;
+-}
+-EXPORT_SYMBOL(rtc_time_to_tm);
+-
+-/*
+- * Does the rtc_time represent a valid date/time?
+- */
+-int rtc_valid_tm(struct rtc_time *tm)
+-{
+- if (tm->tm_year < 70 ||
+- tm->tm_mon >= 12 ||
+- tm->tm_mday < 1 ||
+- tm->tm_mday > month_days(tm->tm_mon, tm->tm_year + 1900) ||
+- tm->tm_hour >= 24 ||
+- tm->tm_min >= 60 ||
+- tm->tm_sec >= 60)
+- return -EINVAL;
+-
+- return 0;
+-}
+-EXPORT_SYMBOL(rtc_valid_tm);
+-
+-/*
+- * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
+- */
+-int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
+-{
+- *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+- tm->tm_hour, tm->tm_min, tm->tm_sec);
+-
+- return 0;
+-}
+-EXPORT_SYMBOL(rtc_tm_to_time);
+-
+ /*
+ * Calculate the next alarm time given the requested alarm time mask
+ * and the current time.
+@@ -141,13 +58,13 @@ void rtc_next_alarm_time(struct rtc_time
+ next->tm_sec = alrm->tm_sec;
+ }
+
+-static inline int rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm)
++static inline int rtc_arm_read_time(struct rtc_ops *ops, struct rtc_time *tm)
+ {
+ memset(tm, 0, sizeof(struct rtc_time));
+ return ops->read_time(tm);
+ }
+
+-static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm)
++static inline int rtc_arm_set_time(struct rtc_ops *ops, struct rtc_time *tm)
+ {
+ int ret;
+
+@@ -158,7 +75,7 @@ static inline int rtc_set_time(struct rt
+ return ret;
+ }
+
+-static inline int rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
++static inline int rtc_arm_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
+ {
+ int ret = -EINVAL;
+ if (ops->read_alarm) {
+@@ -168,7 +85,7 @@ static inline int rtc_read_alarm(struct
+ return ret;
+ }
+
+-static inline int rtc_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
++static inline int rtc_arm_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
+ {
+ int ret = -EINVAL;
+ if (ops->set_alarm)
+@@ -256,7 +173,7 @@ static int rtc_ioctl(struct inode *inode
+
+ switch (cmd) {
+ case RTC_ALM_READ:
+- ret = rtc_read_alarm(ops, &alrm);
++ ret = rtc_arm_read_alarm(ops, &alrm);
+ if (ret)
+ break;
+ ret = copy_to_user(uarg, &alrm.time, sizeof(tm));
+@@ -278,11 +195,11 @@ static int rtc_ioctl(struct inode *inode
+ alrm.time.tm_wday = -1;
+ alrm.time.tm_yday = -1;
+ alrm.time.tm_isdst = -1;
+- ret = rtc_set_alarm(ops, &alrm);
++ ret = rtc_arm_set_alarm(ops, &alrm);
+ break;
+
+ case RTC_RD_TIME:
+- ret = rtc_read_time(ops, &tm);
++ ret = rtc_arm_read_time(ops, &tm);
+ if (ret)
+ break;
+ ret = copy_to_user(uarg, &tm, sizeof(tm));
+@@ -300,7 +217,7 @@ static int rtc_ioctl(struct inode *inode
+ ret = -EFAULT;
+ break;
+ }
+- ret = rtc_set_time(ops, &tm);
++ ret = rtc_arm_set_time(ops, &tm);
+ break;
+
+ case RTC_EPOCH_SET:
+@@ -331,11 +248,11 @@ static int rtc_ioctl(struct inode *inode
+ ret = -EFAULT;
+ break;
+ }
+- ret = rtc_set_alarm(ops, &alrm);
++ ret = rtc_arm_set_alarm(ops, &alrm);
+ break;
+
+ case RTC_WKALM_RD:
+- ret = rtc_read_alarm(ops, &alrm);
++ ret = rtc_arm_read_alarm(ops, &alrm);
+ if (ret)
+ break;
+ ret = copy_to_user(uarg, &alrm, sizeof(alrm));
+@@ -425,7 +342,7 @@ static int rtc_read_proc(char *page, cha
+ struct rtc_time tm;
+ char *p = page;
+
+- if (rtc_read_time(ops, &tm) == 0) {
++ if (rtc_arm_read_time(ops, &tm) == 0) {
+ p += sprintf(p,
+ "rtc_time\t: %02d:%02d:%02d\n"
+ "rtc_date\t: %04d-%02d-%02d\n"
+@@ -435,7 +352,7 @@ static int rtc_read_proc(char *page, cha
+ rtc_epoch);
+ }
+
+- if (rtc_read_alarm(ops, &alrm) == 0) {
++ if (rtc_arm_read_alarm(ops, &alrm) == 0) {
+ p += sprintf(p, "alrm_time\t: ");
+ if ((unsigned int)alrm.time.tm_hour <= 24)
+ p += sprintf(p, "%02d:", alrm.time.tm_hour);
+--- linux-nslu2.orig/include/asm-arm/rtc.h 2006-01-04 01:27:04.000000000 +0100
++++ linux-nslu2/include/asm-arm/rtc.h 2006-01-04 01:27:09.000000000 +0100
+@@ -25,9 +25,6 @@ struct rtc_ops {
+ int (*proc)(char *buf);
+ };
+
+-void rtc_time_to_tm(unsigned long, struct rtc_time *);
+-int rtc_tm_to_time(struct rtc_time *, unsigned long *);
+-int rtc_valid_tm(struct rtc_time *);
+ void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *);
+ void rtc_update(unsigned long, unsigned long);
+ int register_rtc(struct rtc_ops *);
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/rtc-sysfs.c 2006-01-04 01:27:12.000000000 +0100
+@@ -0,0 +1,125 @@
++/*
++ * RTC subsystem, sysfs interface
++ *
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++*/
++
++#include <linux/module.h>
++#include <linux/rtc.h>
++
++/* device attributes */
++
++static ssize_t rtc_sysfs_show_name(struct class_device *dev, char *buf)
++{
++ return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
++}
++static CLASS_DEVICE_ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL);
++
++static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf)
++{
++ ssize_t retval = 0;
++ struct rtc_device *rtc = to_rtc_device(dev);
++ struct rtc_time tm;
++
++ if (down_read_trylock(&rtc->lock) == 0)
++ return -ENODEV;
++
++ if (rtc_read_time(dev, &tm) == 0) {
++ retval = sprintf(buf, "%04d-%02d-%02d\n",
++ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
++ }
++
++ up_read(&rtc->lock);
++ return retval;
++}
++static CLASS_DEVICE_ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL);
++
++static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf)
++{
++ ssize_t retval = 0;
++ struct rtc_device *rtc = to_rtc_device(dev);
++ struct rtc_time tm;
++
++ if (down_read_trylock(&rtc->lock) == 0)
++ return -ENODEV;
++
++ if (rtc_read_time(dev, &tm) == 0) {
++ retval = sprintf(buf, "%02d:%02d:%02d\n",
++ tm.tm_hour, tm.tm_min, tm.tm_sec);
++ }
++
++ up_read(&rtc->lock);
++ return retval;
++}
++static CLASS_DEVICE_ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL);
++
++static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf)
++{
++ ssize_t retval = 0;
++ struct rtc_device *rtc = to_rtc_device(dev);
++ struct rtc_time tm;
++
++ if (down_read_trylock(&rtc->lock) == 0)
++ return -ENODEV;
++
++ if (rtc_read_time(dev, &tm) == 0) {
++ unsigned long time;
++ rtc_tm_to_time(&tm, &time);
++ retval = sprintf(buf, "%lu\n", time);
++ }
++
++ up_read(&rtc->lock);
++ return retval;
++}
++static CLASS_DEVICE_ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL);
++
++/* insertion/removal hooks */
++
++static int __devinit rtc_sysfs_add_device(struct class_device *class_dev,
++ struct class_interface *class_intf)
++{
++ class_device_create_file(class_dev, &class_device_attr_name);
++ class_device_create_file(class_dev, &class_device_attr_date);
++ class_device_create_file(class_dev, &class_device_attr_time);
++ class_device_create_file(class_dev, &class_device_attr_since_epoch);
++ dev_info(class_dev->dev, "rtc intf: sysfs\n");
++ return 0;
++}
++
++static void rtc_sysfs_remove_device(struct class_device *class_dev,
++ struct class_interface *class_intf)
++{
++ class_device_remove_file(class_dev, &class_device_attr_name);
++ class_device_remove_file(class_dev, &class_device_attr_date);
++ class_device_remove_file(class_dev, &class_device_attr_time);
++ class_device_remove_file(class_dev, &class_device_attr_since_epoch);
++}
++
++/* interface registration */
++
++struct class_interface rtc_sysfs_interface = {
++ .add = &rtc_sysfs_add_device,
++ .remove = &rtc_sysfs_remove_device,
++};
++
++static int __init rtc_sysfs_init(void)
++{
++ return rtc_interface_register(&rtc_sysfs_interface);
++}
++
++static void __exit rtc_sysfs_exit(void)
++{
++ class_interface_unregister(&rtc_sysfs_interface);
++}
++
++module_init(rtc_sysfs_init);
++module_exit(rtc_sysfs_exit);
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("RTC class sysfs interface");
++MODULE_LICENSE("GPL");
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/rtc-proc.c 2006-01-04 01:27:14.000000000 +0100
+@@ -0,0 +1,158 @@
++/*
++ * RTC subsystem, proc interface
++ *
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * based on arch/arm/common/rtctime.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++*/
++
++#include <linux/module.h>
++#include <linux/rtc.h>
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++
++static struct class_device *rtc_dev = NULL;
++static DECLARE_MUTEX(rtc_sem);
++
++static int rtc_proc_show(struct seq_file *seq, void *offset)
++{
++ struct class_device *class_dev = seq->private;
++ struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
++ struct rtc_wkalrm alrm;
++ struct rtc_time tm;
++
++ if (rtc_read_time(class_dev, &tm) == 0) {
++ seq_printf(seq,
++ "rtc_time\t: %02d:%02d:%02d\n"
++ "rtc_date\t: %04d-%02d-%02d\n",
++ tm.tm_hour, tm.tm_min, tm.tm_sec,
++ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
++ }
++
++ if (rtc_read_alarm(class_dev, &alrm) == 0) {
++ seq_printf(seq, "alrm_time\t: ");
++ if ((unsigned int)alrm.time.tm_hour <= 24)
++ seq_printf(seq, "%02d:", alrm.time.tm_hour);
++ else
++ seq_printf(seq, "**:");
++ if ((unsigned int)alrm.time.tm_min <= 59)
++ seq_printf(seq, "%02d:", alrm.time.tm_min);
++ else
++ seq_printf(seq, "**:");
++ if ((unsigned int)alrm.time.tm_sec <= 59)
++ seq_printf(seq, "%02d\n", alrm.time.tm_sec);
++ else
++ seq_printf(seq, "**\n");
++
++ seq_printf(seq, "alrm_date\t: ");
++ if ((unsigned int)alrm.time.tm_year <= 200)
++ seq_printf(seq, "%04d-", alrm.time.tm_year + 1900);
++ else
++ seq_printf(seq, "****-");
++ if ((unsigned int)alrm.time.tm_mon <= 11)
++ seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
++ else
++ seq_printf(seq, "**-");
++ if ((unsigned int)alrm.time.tm_mday <= 31)
++ seq_printf(seq, "%02d\n", alrm.time.tm_mday);
++ else
++ seq_printf(seq, "**\n");
++ seq_printf(seq, "alrm_wakeup\t: %s\n",
++ alrm.enabled ? "yes" : "no");
++ seq_printf(seq, "alrm_pending\t: %s\n",
++ alrm.pending ? "yes" : "no");
++ }
++
++ if (ops->proc)
++ ops->proc(class_dev->dev, seq);
++
++ return 0;
++}
++
++static int rtc_proc_open(struct inode *inode, struct file *file)
++{
++ struct class_device *class_dev = PDE(inode)->data;
++
++ if (!try_module_get(THIS_MODULE))
++ return -ENODEV;
++
++ return single_open(file, rtc_proc_show, class_dev);
++}
++
++static int rtc_proc_release(struct inode *inode, struct file *file)
++{
++ int res = single_release(inode, file);
++ module_put(THIS_MODULE);
++ return res;
++}
++
++static struct file_operations rtc_proc_fops = {
++ .open = rtc_proc_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = rtc_proc_release,
++};
++
++static int rtc_proc_add_device(struct class_device *class_dev,
++ struct class_interface *class_intf)
++{
++ down(&rtc_sem);
++ if (rtc_dev == NULL) {
++ struct proc_dir_entry *ent;
++
++ rtc_dev = class_dev;
++
++ if ((ent = create_proc_entry("driver/rtc", 0, NULL))) {
++ struct rtc_device *rtc = to_rtc_device(class_dev);
++
++ ent->proc_fops = &rtc_proc_fops;
++ ent->owner = rtc->owner;
++ ent->data = class_dev;
++
++ dev_info(class_dev->dev, "rtc intf: proc\n");
++ }
++ else
++ rtc_dev = NULL;
++ }
++ up(&rtc_sem);
++
++ return 0;
++}
++
++static void rtc_proc_remove_device(struct class_device *class_dev,
++ struct class_interface *class_intf)
++{
++ down(&rtc_sem);
++ if (rtc_dev == class_dev) {
++ remove_proc_entry("driver/rtc", NULL);
++ rtc_dev = NULL;
++ }
++ up(&rtc_sem);
++}
++
++struct class_interface rtc_proc_interface = {
++ .add = &rtc_proc_add_device,
++ .remove = &rtc_proc_remove_device,
++};
++
++static int __init rtc_proc_init(void)
++{
++ return rtc_interface_register(&rtc_proc_interface);
++}
++
++static void __exit rtc_proc_exit(void)
++{
++ class_interface_unregister(&rtc_proc_interface);
++}
++
++module_init(rtc_proc_init);
++module_exit(rtc_proc_exit);
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("RTC class proc interface");
++MODULE_LICENSE("GPL");
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/rtc-dev.c 2006-01-04 01:27:15.000000000 +0100
+@@ -0,0 +1,372 @@
++/*
++ * RTC subsystem, dev interface
++ *
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * based on arch/arm/common/rtctime.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++*/
++
++#include <linux/module.h>
++#include <linux/rtc.h>
++
++static dev_t rtc_devt;
++
++#define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */
++
++static int rtc_dev_open(struct inode *inode, struct file *file)
++{
++ int err;
++ struct rtc_device *rtc = container_of(inode->i_cdev,
++ struct rtc_device, char_dev);
++ struct rtc_class_ops *ops = rtc->ops;
++
++ /* We keep the lock as long as the device is in use
++ * and return immediately if busy
++ */
++ if (down_trylock(&rtc->char_sem))
++ return -EBUSY;
++
++ file->private_data = &rtc->class_dev;
++
++ err = ops->open ? ops->open(rtc->class_dev.dev) : 0;
++ if (err == 0) {
++
++ spin_lock_irq(&rtc->irq_lock);
++ rtc->irq_data = 0;
++ spin_unlock_irq(&rtc->irq_lock);
++
++ return 0;
++ }
++
++ /* something has gone wrong, release the lock */
++ up(&rtc->char_sem);
++ return err;
++}
++
++
++static ssize_t
++rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
++{
++ struct rtc_device *rtc = to_rtc_device(file->private_data);
++
++ DECLARE_WAITQUEUE(wait, current);
++ unsigned long data;
++ ssize_t ret;
++
++ if (count < sizeof(unsigned long))
++ return -EINVAL;
++
++ add_wait_queue(&rtc->irq_queue, &wait);
++ do {
++ __set_current_state(TASK_INTERRUPTIBLE);
++
++ spin_lock_irq(&rtc->irq_lock);
++ data = rtc->irq_data;
++ rtc->irq_data = 0;
++ spin_unlock_irq(&rtc->irq_lock);
++
++ if (data != 0) {
++ ret = 0;
++ break;
++ }
++ if (file->f_flags & O_NONBLOCK) {
++ ret = -EAGAIN;
++ break;
++ }
++ if (signal_pending(current)) {
++ ret = -ERESTARTSYS;
++ break;
++ }
++ schedule();
++ } while (1);
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&rtc->irq_queue, &wait);
++
++ if (ret == 0) {
++ ret = put_user(data, (unsigned long __user *)buf);
++ if (ret == 0)
++ ret = sizeof(unsigned long);
++ }
++ return ret;
++}
++
++static unsigned int rtc_dev_poll(struct file *file, poll_table *wait)
++{
++ struct rtc_device *rtc = to_rtc_device(file->private_data);
++ unsigned long data;
++
++ poll_wait(file, &rtc->irq_queue, wait);
++
++ spin_lock_irq(&rtc->irq_lock);
++ data = rtc->irq_data;
++ spin_unlock_irq(&rtc->irq_lock);
++
++ return data != 0 ? POLLIN | POLLRDNORM : 0;
++}
++
++static int rtc_dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int err = 0;
++ struct class_device *class_dev = file->private_data;
++ struct rtc_device *rtc = to_rtc_device(class_dev);
++ struct rtc_class_ops *ops = rtc->ops;
++ struct rtc_time tm;
++ struct rtc_wkalrm alarm;
++ void __user *uarg = (void __user *) arg;
++
++ /* avoid conflicting IRQ users */
++ if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) {
++ spin_lock(&rtc->irq_task_lock);
++ if (rtc->irq_task)
++ err = -EBUSY;
++ spin_unlock(&rtc->irq_task_lock);
++
++ if (err < 0)
++ return err;
++ }
++
++ /* try the driver's ioctl interface */
++ if (ops->ioctl) {
++ err = ops->ioctl(class_dev->dev, cmd, arg);
++ if (err < 0 && err != -EINVAL)
++ return err;
++ }
++
++ /* if the driver does not provide the ioctl interface
++ * or if that particular ioctl was not implemented
++ * (-EINVAL), we will try to emulate here.
++ */
++
++ switch (cmd) {
++ case RTC_ALM_READ:
++ if ((err = rtc_read_alarm(class_dev, &alarm)) < 0)
++ return err;
++
++ if ((err = copy_to_user(uarg, &alarm.time, sizeof(tm))))
++ return -EFAULT;
++ break;
++
++ case RTC_ALM_SET:
++ if ((err = copy_from_user(&alarm.time, uarg, sizeof(tm))))
++ return -EFAULT;
++
++ alarm.enabled = 0;
++ alarm.pending = 0;
++ alarm.time.tm_mday = -1;
++ alarm.time.tm_mon = -1;
++ alarm.time.tm_year = -1;
++ alarm.time.tm_wday = -1;
++ alarm.time.tm_yday = -1;
++ alarm.time.tm_isdst = -1;
++ err = rtc_set_alarm(class_dev, &alarm);
++ break;
++
++ case RTC_RD_TIME:
++ if ((err = rtc_read_time(class_dev, &tm)) < 0)
++ return err;
++
++ if ((err = copy_to_user(uarg, &tm, sizeof(tm))))
++ return -EFAULT;
++ break;
++
++ case RTC_SET_TIME:
++ if (!capable(CAP_SYS_TIME))
++ return -EACCES;
++
++ if ((err = copy_from_user(&tm, uarg, sizeof(tm))))
++ return -EFAULT;
++
++ err = rtc_set_time(class_dev, &tm);
++ break;
++#if 0
++ case RTC_EPOCH_SET:
++#ifndef rtc_epoch
++ /*
++ * There were no RTC clocks before 1900.
++ */
++ if (arg < 1900) {
++ err = -EINVAL;
++ break;
++ }
++ if (!capable(CAP_SYS_TIME)) {
++ err = -EACCES;
++ break;
++ }
++ rtc_epoch = arg;
++ err = 0;
++#endif
++ break;
++
++ case RTC_EPOCH_READ:
++ err = put_user(rtc_epoch, (unsigned long __user *)uarg);
++ break;
++#endif
++ case RTC_WKALM_SET:
++ if ((err = copy_from_user(&alarm, uarg, sizeof(alarm))))
++ return -EFAULT;
++
++ err = rtc_set_alarm(class_dev, &alarm);
++ break;
++
++ case RTC_WKALM_RD:
++ if ((err = rtc_read_alarm(class_dev, &alarm)) < 0)
++ return err;
++
++ if ((err = copy_to_user(uarg, &alarm, sizeof(alarm))))
++ return -EFAULT;
++ break;
++
++ default:
++ err = -EINVAL;
++ break;
++ }
++
++ return err;
++}
++
++static int rtc_dev_release(struct inode *inode, struct file *file)
++{
++ struct rtc_device *rtc = to_rtc_device(file->private_data);
++
++ if (rtc->ops->release)
++ rtc->ops->release(rtc->class_dev.dev);
++
++ spin_lock_irq(&rtc->irq_lock);
++ rtc->irq_data = 0;
++ spin_unlock_irq(&rtc->irq_lock);
++
++ up(&rtc->char_sem);
++ return 0;
++}
++
++static int rtc_dev_fasync(int fd, struct file *file, int on)
++{
++ struct rtc_device *rtc = to_rtc_device(file->private_data);
++ return fasync_helper(fd, file, on, &rtc->async_queue);
++}
++
++static struct file_operations rtc_dev_fops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .read = rtc_dev_read,
++ .poll = rtc_dev_poll,
++ .ioctl = rtc_dev_ioctl,
++ .open = rtc_dev_open,
++ .release = rtc_dev_release,
++ .fasync = rtc_dev_fasync,
++};
++
++static ssize_t rtc_dev_show_dev(struct class_device *class_dev, char *buf)
++{
++ return print_dev_t(buf, class_dev->devt);
++}
++static CLASS_DEVICE_ATTR(dev, S_IRUGO, rtc_dev_show_dev, NULL);
++
++/* insertion/removal hooks */
++
++static int rtc_dev_add_device(struct class_device *class_dev,
++ struct class_interface *class_intf)
++{
++ struct rtc_device *rtc = to_rtc_device(class_dev);
++
++ if (rtc->id >= RTC_DEV_MAX) {
++ dev_err(class_dev->dev, "too many RTCs\n");
++ return -EINVAL;
++ }
++
++ init_MUTEX(&rtc->char_sem);
++ spin_lock_init(&rtc->irq_lock);
++ init_waitqueue_head(&rtc->irq_queue);
++
++ cdev_init(&rtc->char_dev, &rtc_dev_fops);
++ rtc->char_dev.owner = rtc->owner;
++ class_dev->devt = MKDEV(MAJOR(rtc_devt), rtc->id);
++
++ if (cdev_add(&rtc->char_dev, class_dev->devt, 1)) {
++ cdev_del(&rtc->char_dev);
++
++ dev_err(class_dev->dev,
++ "failed to add char device %d:%d\n",
++ MAJOR(class_dev->devt),
++ MINOR(class_dev->devt));
++
++ class_dev->devt = MKDEV(0, 0);
++ return -ENODEV;
++ }
++
++ class_device_create_file(class_dev, &class_device_attr_dev);
++
++ dev_info(class_dev->dev, "rtc intf: dev (%d:%d)\n",
++ MAJOR(class_dev->devt),
++ MINOR(class_dev->devt));
++
++ kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
++
++ return 0;
++}
++
++static void rtc_dev_remove_device(struct class_device *class_dev,
++ struct class_interface *class_intf)
++{
++ struct rtc_device *rtc = to_rtc_device(class_dev);
++
++ class_device_remove_file(class_dev, &class_device_attr_dev);
++
++ if (MAJOR(class_dev->devt)) {
++ dev_dbg(class_dev->dev, "removing char %d:%d\n",
++ MAJOR(class_dev->devt),
++ MINOR(class_dev->devt));
++ cdev_del(&rtc->char_dev);
++
++ kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE);
++
++ class_dev->devt = MKDEV(0, 0);
++ }
++}
++
++/* interface registration */
++
++struct class_interface rtc_dev_interface = {
++ .add = &rtc_dev_add_device,
++ .remove = &rtc_dev_remove_device,
++};
++
++static int __init rtc_dev_init(void)
++{
++ int err;
++
++ if ((err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc")) < 0) {
++ printk(KERN_ERR "%s: failed to allocate char dev region\n",
++ __FILE__);
++ return err;
++ }
++
++ if ((err = rtc_interface_register(&rtc_dev_interface)) < 0) {
++ printk(KERN_ERR "%s: failed to register the interface\n",
++ __FILE__);
++ unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
++ return err;
++ }
++
++ return 0;
++}
++
++static void __exit rtc_dev_exit(void)
++{
++ class_interface_unregister(&rtc_dev_interface);
++
++ unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
++}
++
++module_init(rtc_dev_init);
++module_exit(rtc_dev_exit);
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("RTC class dev interface");
++MODULE_LICENSE("GPL");
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/rtc-x1205.c 2006-01-04 01:27:17.000000000 +0100
+@@ -0,0 +1,725 @@
++/*
++ * An i2c driver for the Xicor/Intersil X1205 RTC
++ * Copyright 2004 Karen Spearel
++ * Copyright 2005 Alessandro Zummo
++ *
++ * please send all reports to:
++ * kas11 at tampabay dot rr dot com
++ * a dot zummo at towertech dot it
++ *
++ * based on a lot of other RTC drivers.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/i2c.h>
++#include <linux/string.h>
++#include <linux/bcd.h>
++#include <linux/rtc.h>
++#include <linux/delay.h>
++
++#define DRV_VERSION "1.0.5"
++
++/* Addresses to scan: none. This chip is located at
++ * 0x6f and uses a two bytes register addressing.
++ * Two bytes need to be written to read a single register,
++ * while most other chips just require one and take the second
++ * one as the data to be written. To prevent corrupting
++ * unknown chips, the user must explicitely set the probe parameter.
++ */
++
++static unsigned short normal_i2c[] = { I2C_CLIENT_END };
++
++/* Insmod parameters */
++I2C_CLIENT_INSMOD;
++I2C_CLIENT_MODULE_PARM(hctosys,
++ "Set the system time from the hardware clock upon initialization");
++
++/* offsets into CCR area */
++
++#define CCR_SEC 0
++#define CCR_MIN 1
++#define CCR_HOUR 2
++#define CCR_MDAY 3
++#define CCR_MONTH 4
++#define CCR_YEAR 5
++#define CCR_WDAY 6
++#define CCR_Y2K 7
++
++#define X1205_REG_SR 0x3F /* status register */
++#define X1205_REG_Y2K 0x37
++#define X1205_REG_DW 0x36
++#define X1205_REG_YR 0x35
++#define X1205_REG_MO 0x34
++#define X1205_REG_DT 0x33
++#define X1205_REG_HR 0x32
++#define X1205_REG_MN 0x31
++#define X1205_REG_SC 0x30
++#define X1205_REG_DTR 0x13
++#define X1205_REG_ATR 0x12
++#define X1205_REG_INT 0x11
++#define X1205_REG_0 0x10
++#define X1205_REG_Y2K1 0x0F
++#define X1205_REG_DWA1 0x0E
++#define X1205_REG_YRA1 0x0D
++#define X1205_REG_MOA1 0x0C
++#define X1205_REG_DTA1 0x0B
++#define X1205_REG_HRA1 0x0A
++#define X1205_REG_MNA1 0x09
++#define X1205_REG_SCA1 0x08
++#define X1205_REG_Y2K0 0x07
++#define X1205_REG_DWA0 0x06
++#define X1205_REG_YRA0 0x05
++#define X1205_REG_MOA0 0x04
++#define X1205_REG_DTA0 0x03
++#define X1205_REG_HRA0 0x02
++#define X1205_REG_MNA0 0x01
++#define X1205_REG_SCA0 0x00
++
++#define X1205_CCR_BASE 0x30 /* Base address of CCR */
++#define X1205_ALM0_BASE 0x00 /* Base address of ALARM0 */
++
++#define X1205_SR_RTCF 0x01 /* Clock failure */
++#define X1205_SR_WEL 0x02 /* Write Enable Latch */
++#define X1205_SR_RWEL 0x04 /* Register Write Enable */
++
++#define X1205_DTR_DTR0 0x01
++#define X1205_DTR_DTR1 0x02
++#define X1205_DTR_DTR2 0x04
++
++#define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */
++
++/* Prototypes */
++static int x1205_attach(struct i2c_adapter *adapter);
++static int x1205_detach(struct i2c_client *client);
++static int x1205_probe(struct i2c_adapter *adapter, int address, int kind);
++
++static struct i2c_driver x1205_driver = {
++ .owner = THIS_MODULE,
++ .name = "x1205",
++ .flags = I2C_DF_NOTIFY,
++ .attach_adapter = &x1205_attach,
++ .detach_client = &x1205_detach,
++};
++
++/*
++ * In the routines that deal directly with the x1205 hardware, we use
++ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
++ * Epoch is initialized as 2000. Time is set to UTC.
++ */
++static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
++ unsigned char reg_base)
++{
++ unsigned char dt_addr[2] = { 0, reg_base };
++
++ unsigned char buf[8];
++
++ struct i2c_msg msgs[] = {
++ { client->addr, 0, 2, dt_addr }, /* setup read ptr */
++ { client->addr, I2C_M_RD, 8, buf }, /* read date */
++ };
++
++ /* read date registers */
++ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
++ dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
++ return -EIO;
++ }
++
++ dev_dbg(&client->dev,
++ "%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
++ "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
++ __FUNCTION__,
++ buf[0], buf[1], buf[2], buf[3],
++ buf[4], buf[5], buf[6], buf[7]);
++
++ tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
++ tm->tm_min = BCD2BIN(buf[CCR_MIN]);
++ tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
++ tm->tm_mday = BCD2BIN(buf[CCR_MDAY]);
++ tm->tm_mon = BCD2BIN(buf[CCR_MONTH]) - 1; /* mon is 0-11 */
++ tm->tm_year = BCD2BIN(buf[CCR_YEAR])
++ + (BCD2BIN(buf[CCR_Y2K]) * 100) - 1900;
++ tm->tm_wday = buf[CCR_WDAY];
++
++ dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
++ "mday=%d, mon=%d, year=%d, wday=%d\n",
++ __FUNCTION__,
++ tm->tm_sec, tm->tm_min, tm->tm_hour,
++ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
++
++ return 0;
++}
++
++static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
++{
++ static unsigned char sr_addr[2] = { 0, X1205_REG_SR };
++
++ struct i2c_msg msgs[] = {
++ { client->addr, 0, 2, sr_addr }, /* setup read ptr */
++ { client->addr, I2C_M_RD, 1, sr }, /* read status */
++ };
++
++ /* read status register */
++ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
++ dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
++ int datetoo, u8 reg_base)
++{
++ int i, xfer;
++ unsigned char buf[8];
++
++ static const unsigned char wel[3] = { 0, X1205_REG_SR,
++ X1205_SR_WEL };
++
++ static const unsigned char rwel[3] = { 0, X1205_REG_SR,
++ X1205_SR_WEL | X1205_SR_RWEL };
++
++ static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 };
++
++ dev_dbg(&client->dev,
++ "%s: secs=%d, mins=%d, hours=%d\n",
++ __FUNCTION__,
++ tm->tm_sec, tm->tm_min, tm->tm_hour);
++
++ buf[CCR_SEC] = BIN2BCD(tm->tm_sec);
++ buf[CCR_MIN] = BIN2BCD(tm->tm_min);
++
++ /* set hour and 24hr bit */
++ buf[CCR_HOUR] = BIN2BCD(tm->tm_hour) | X1205_HR_MIL;
++
++ /* should we also set the date? */
++ if (datetoo) {
++ dev_dbg(&client->dev,
++ "%s: mday=%d, mon=%d, year=%d, wday=%d\n",
++ __FUNCTION__,
++ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
++
++ buf[CCR_MDAY] = BIN2BCD(tm->tm_mday);
++
++ /* month, 1 - 12 */
++ buf[CCR_MONTH] = BIN2BCD(tm->tm_mon + 1);
++
++ /* year, since the rtc epoch*/
++ buf[CCR_YEAR] = BIN2BCD(tm->tm_year % 100);
++ buf[CCR_WDAY] = tm->tm_wday & 0x07;
++ buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100);
++ }
++
++ /* this sequence is required to unlock the chip */
++ xfer = i2c_master_send(client, wel, 3);
++ if (xfer != 3) {
++ dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer);
++ return -EIO;
++ }
++
++ xfer = i2c_master_send(client, rwel, 3);
++ if (xfer != 3) {
++ dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer);
++ return -EIO;
++ }
++
++ /* write register's data */
++ for (i = 0; i < (datetoo ? 8 : 3); i++) {
++ unsigned char rdata[3] = { 0, reg_base + i, buf[i] };
++
++ xfer = i2c_master_send(client, rdata, 3);
++ if (xfer != 3) {
++ dev_err(&client->dev,
++ "%s: xfer=%d addr=%02x, data=%02x\n",
++ __FUNCTION__,
++ xfer, rdata[1], rdata[2]);
++ return -EIO;
++ }
++ };
++
++ /* disable further writes */
++ xfer = i2c_master_send(client, diswe, 3);
++ if (xfer != 3) {
++ dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int x1205_fix_osc(struct i2c_client *client)
++{
++ int err;
++ struct rtc_time tm;
++
++ tm.tm_hour = 0;
++ tm.tm_min = 0;
++ tm.tm_sec = 0;
++
++ if ((err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE)) < 0)
++ dev_err(&client->dev,
++ "unable to restart the clock\n");
++
++ return err;
++}
++
++static int x1205_get_dtrim(struct i2c_client *client, int *trim)
++{
++ unsigned char dtr;
++ static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR };
++
++ struct i2c_msg msgs[] = {
++ { client->addr, 0, 2, dtr_addr }, /* setup read ptr */
++ { client->addr, I2C_M_RD, 1, &dtr }, /* read dtr */
++ };
++
++ /* read dtr register */
++ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
++ dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
++ return -EIO;
++ }
++
++ dev_dbg(&client->dev, "%s: raw dtr=%x\n", __FUNCTION__, dtr);
++
++ *trim = 0;
++
++ if (dtr & X1205_DTR_DTR0)
++ *trim += 20;
++
++ if (dtr & X1205_DTR_DTR1)
++ *trim += 10;
++
++ if (dtr & X1205_DTR_DTR2)
++ *trim = -*trim;
++
++ return 0;
++}
++
++static int x1205_get_atrim(struct i2c_client *client, int *trim)
++{
++ s8 atr;
++ static unsigned char atr_addr[2] = { 0, X1205_REG_ATR };
++
++ struct i2c_msg msgs[] = {
++ { client->addr, 0, 2, atr_addr }, /* setup read ptr */
++ { client->addr, I2C_M_RD, 1, &atr }, /* read atr */
++ };
++
++ /* read atr register */
++ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
++ dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
++ return -EIO;
++ }
++
++ dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr);
++
++ /* atr is a two's complement value on 6 bits,
++ * perform sign extension. The formula is
++ * Catr = (atr * 0.25pF) + 11.00pF.
++ */
++ if (atr & 0x20)
++ atr |= 0xC0;
++
++ dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr);
++
++ *trim = (atr * 250) + 11000;
++
++ dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim);
++
++ return 0;
++}
++
++static int x1205_hctosys(struct i2c_client *client)
++{
++ int err;
++
++ struct rtc_time tm;
++ struct timespec tv;
++ unsigned char sr;
++
++ if ((err = x1205_get_status(client, &sr)) < 0)
++ return err;
++
++ /* Don't set if we had a power failure */
++ if (sr & X1205_SR_RTCF)
++ return -EINVAL;
++
++ if ((err = x1205_get_datetime(client, &tm, X1205_CCR_BASE)) < 0)
++ return err;
++
++ /* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
++ * whether it stores the most close value or the value with partial
++ * seconds truncated. However, it is important that we use it to store
++ * the truncated value. This is because otherwise it is necessary,
++ * in an rtc sync function, to read both xtime.tv_sec and
++ * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
++ * of >32bits is not possible. So storing the most close value would
++ * slow down the sync API. So here we have the truncated value and
++ * the best guess is to add 0.5s.
++ */
++
++ tv.tv_nsec = NSEC_PER_SEC >> 1;
++
++ rtc_tm_to_time(&tm, &tv.tv_sec);
++
++ do_settimeofday(&tv);
++
++ dev_info(&client->dev,
++ "setting the system clock to %d-%d-%d %d:%d:%d\n",
++ tm.tm_year + 1900, tm.tm_mon + 1,
++ tm.tm_mday, tm.tm_hour, tm.tm_min,
++ tm.tm_sec);
++
++ return 0;
++}
++
++struct x1205_limit
++{
++ unsigned char reg;
++ unsigned char mask;
++ unsigned char min;
++ unsigned char max;
++};
++
++static int x1205_validate_client(struct i2c_client *client)
++{
++ int i, xfer;
++
++ /* Probe array. We will read the register at the specified
++ * address and check if the given bits are zero.
++ */
++ static const unsigned char probe_zero_pattern[] = {
++ /* register, mask */
++ X1205_REG_SR, 0x18,
++ X1205_REG_DTR, 0xF8,
++ X1205_REG_ATR, 0xC0,
++ X1205_REG_INT, 0x18,
++ X1205_REG_0, 0xFF,
++ };
++
++ static const struct x1205_limit probe_limits_pattern[] = {
++ /* register, mask, min, max */
++ { X1205_REG_Y2K, 0xFF, 19, 20 },
++ { X1205_REG_DW, 0xFF, 0, 6 },
++ { X1205_REG_YR, 0xFF, 0, 99 },
++ { X1205_REG_MO, 0xFF, 0, 12 },
++ { X1205_REG_DT, 0xFF, 0, 31 },
++ { X1205_REG_HR, 0x7F, 0, 23 },
++ { X1205_REG_MN, 0xFF, 0, 59 },
++ { X1205_REG_SC, 0xFF, 0, 59 },
++ { X1205_REG_Y2K1, 0xFF, 19, 20 },
++ { X1205_REG_Y2K0, 0xFF, 19, 20 },
++ };
++
++ /* check that registers have bits a 0 where expected */
++ for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) {
++ unsigned char buf;
++
++ unsigned char addr[2] = { 0, probe_zero_pattern[i] };
++
++ struct i2c_msg msgs[2] = {
++ { client->addr, 0, 2, addr },
++ { client->addr, I2C_M_RD, 1, &buf },
++ };
++
++ xfer = i2c_transfer(client->adapter, msgs, 2);
++ if (xfer != 2) {
++ dev_err(&client->adapter->dev,
++ "%s: could not read register %x\n",
++ __FUNCTION__, addr[1]);
++
++ return -EIO;
++ }
++
++ if ((buf & probe_zero_pattern[i+1]) != 0) {
++ dev_err(&client->adapter->dev,
++ "%s: register=%02x, zero pattern=%d, value=%x\n",
++ __FUNCTION__, addr[1], i, buf);
++
++ return -ENODEV;
++ }
++ }
++
++ /* check limits (only registers with bcd values) */
++ for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) {
++ unsigned char reg, value;
++
++ unsigned char addr[2] = { 0, probe_limits_pattern[i].reg };
++
++ struct i2c_msg msgs[2] = {
++ { client->addr, 0, 2, addr },
++ { client->addr, I2C_M_RD, 1, &reg },
++ };
++
++ xfer = i2c_transfer(client->adapter, msgs, 2);
++
++ if (xfer != 2) {
++ dev_err(&client->adapter->dev,
++ "%s: could not read register %x\n",
++ __FUNCTION__, addr[1]);
++
++ return -EIO;
++ }
++
++ value = BCD2BIN(reg & probe_limits_pattern[i].mask);
++
++ if (value > probe_limits_pattern[i].max ||
++ value < probe_limits_pattern[i].min) {
++ dev_dbg(&client->adapter->dev,
++ "%s: register=%x, lim pattern=%d, value=%d\n",
++ __FUNCTION__, addr[1], i, value);
++
++ return -ENODEV;
++ }
++ }
++
++ return 0;
++}
++
++static int x1205_rtc_read_alarm(struct device *dev,
++ struct rtc_wkalrm *alrm)
++{
++ return x1205_get_datetime(to_i2c_client(dev),
++ &alrm->time, X1205_ALM0_BASE);
++}
++
++static int x1205_rtc_set_alarm(struct device *dev,
++ struct rtc_wkalrm *alrm)
++{
++ return x1205_set_datetime(to_i2c_client(dev),
++ &alrm->time, 1, X1205_ALM0_BASE);
++}
++
++static int x1205_rtc_read_time(struct device *dev,
++ struct rtc_time *tm)
++{
++ return x1205_get_datetime(to_i2c_client(dev),
++ tm, X1205_CCR_BASE);
++}
++
++static int x1205_rtc_set_time(struct device *dev,
++ struct rtc_time *tm)
++{
++ return x1205_set_datetime(to_i2c_client(dev),
++ tm, 1, X1205_CCR_BASE);
++}
++
++static int x1205_rtc_set_mmss(struct device *dev, unsigned long secs)
++{
++ int err;
++
++ struct rtc_time new_tm, old_tm;
++
++ if ((err = x1205_rtc_read_time(dev, &old_tm) == 0))
++ return err;
++
++ /* FIXME xtime.tv_nsec = old_tm.tm_sec * 10000000; */
++ new_tm.tm_sec = secs % 60;
++ secs /= 60;
++ new_tm.tm_min = secs % 60;
++ secs /= 60;
++ new_tm.tm_hour = secs % 24;
++
++ /*
++ * avoid writing when we're going to change the day
++ * of the month. We will retry in the next minute.
++ * This basically means that if the RTC must not drift
++ * by more than 1 minute in 11 minutes.
++ */
++ if ((old_tm.tm_hour == 23 && old_tm.tm_min == 59) ||
++ (new_tm.tm_hour == 23 && new_tm.tm_min == 59))
++ return 1;
++
++ return x1205_rtc_set_time(dev, &new_tm);
++}
++
++static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
++{
++ int err, dtrim, atrim;
++
++ seq_printf(seq, "24hr\t\t: yes\n");
++
++ err = x1205_get_dtrim(to_i2c_client(dev), &dtrim);
++ if (err == 0)
++ seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim);
++
++ err = x1205_get_atrim(to_i2c_client(dev), &atrim);
++ if (err == 0)
++ seq_printf(seq, "analog_trim\t: %d.%02d pF\n",
++ atrim / 1000, atrim % 1000);
++ return 0;
++}
++
++static struct rtc_class_ops x1205_rtc_ops = {
++ .proc = x1205_rtc_proc,
++ .read_time = x1205_rtc_read_time,
++ .set_time = x1205_rtc_set_time,
++ .read_alarm = x1205_rtc_read_alarm,
++ .set_alarm = x1205_rtc_set_alarm,
++ .set_mmss = x1205_rtc_set_mmss,
++};
++
++static ssize_t x1205_sysfs_show_atrim(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int atrim;
++
++ if (x1205_get_atrim(to_i2c_client(dev), &atrim) == 0) {
++ return sprintf(buf, "%d.%02d pF\n",
++ atrim / 1000, atrim % 1000); }
++ return 0;
++}
++static DEVICE_ATTR(atrim, S_IRUGO, x1205_sysfs_show_atrim, NULL);
++
++static ssize_t x1205_sysfs_show_dtrim(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int dtrim;
++
++ if (x1205_get_dtrim(to_i2c_client(dev), &dtrim) == 0) {
++ return sprintf(buf, "%d ppm\n", dtrim);
++ }
++ return 0;
++}
++static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL);
++
++
++static int x1205_attach(struct i2c_adapter *adapter)
++{
++ dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
++
++ return i2c_probe(adapter, &addr_data, x1205_probe);
++}
++
++static int x1205_probe(struct i2c_adapter *adapter, int address, int kind)
++{
++ int err = 0;
++ unsigned char sr;
++ struct i2c_client *client;
++ struct rtc_device *rtc;
++
++ dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
++
++ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
++ err = -ENODEV;
++ goto exit;
++ }
++
++ if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
++ err = -ENOMEM;
++ goto exit;
++ }
++
++ /* I2C client */
++ client->addr = address;
++ client->driver = &x1205_driver;
++ client->adapter = adapter;
++
++ strlcpy(client->name, x1205_driver.name, I2C_NAME_SIZE);
++
++ /* Verify the chip is really an X1205 */
++ if (kind < 0) {
++ if (x1205_validate_client(client) < 0) {
++ err = -ENODEV;
++ goto exit_kfree;
++ }
++ }
++
++ /* Inform the i2c layer */
++ if ((err = i2c_attach_client(client)))
++ goto exit_kfree;
++
++ dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
++
++ rtc = rtc_device_register(x1205_driver.name, &client->dev,
++ &x1205_rtc_ops, THIS_MODULE);
++
++ if (IS_ERR(rtc)) {
++ err = PTR_ERR(rtc);
++ dev_err(&client->dev,
++ "unable to register the class device\n");
++ goto exit_detach;
++ }
++
++ i2c_set_clientdata(client, rtc);
++
++ /* Check for power failures and eventualy enable the osc */
++ if ((err = x1205_get_status(client, &sr)) == 0) {
++ if (sr & X1205_SR_RTCF) {
++ dev_err(&client->dev,
++ "power failure detected, "
++ "please set the clock\n");
++ udelay(50);
++ x1205_fix_osc(client);
++ }
++ }
++ else
++ dev_err(&client->dev, "couldn't read status\n");
++
++ /* If requested, set the system time */
++ if (hctosys) {
++ if ((err = x1205_hctosys(client)) < 0)
++ dev_err(&client->dev,
++ "unable to set the system clock\n");
++ }
++
++ device_create_file(&client->dev, &dev_attr_atrim);
++ device_create_file(&client->dev, &dev_attr_dtrim);
++
++ return 0;
++
++exit_detach:
++ i2c_detach_client(client);
++
++exit_kfree:
++ kfree(client);
++
++exit:
++ return err;
++}
++
++static int x1205_detach(struct i2c_client *client)
++{
++ int err;
++ struct rtc_device *rtc = i2c_get_clientdata(client);
++
++ dev_dbg(&client->dev, "%s\n", __FUNCTION__);
++
++ if (rtc)
++ rtc_device_unregister(rtc);
++
++ if ((err = i2c_detach_client(client)))
++ return err;
++
++ kfree(client);
++
++ return 0;
++}
++
++static int __init x1205_init(void)
++{
++ return i2c_add_driver(&x1205_driver);
++}
++
++static void __exit x1205_exit(void)
++{
++ i2c_del_driver(&x1205_driver);
++}
++
++MODULE_AUTHOR(
++ "Karen Spearel <kas11@tampabay.rr.com>, "
++ "Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("Xicor/Intersil X1205 RTC driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++module_init(x1205_init);
++module_exit(x1205_exit);
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/rtc-test.c 2006-01-04 01:27:19.000000000 +0100
+@@ -0,0 +1,189 @@
++/*
++ * An RTC test device/driver
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/rtc.h>
++#include <linux/platform_device.h>
++
++static int test_rtc_read_alarm(struct device *dev,
++ struct rtc_wkalrm *alrm)
++{
++ return 0;
++}
++
++static int test_rtc_set_alarm(struct device *dev,
++ struct rtc_wkalrm *alrm)
++{
++ return 0;
++}
++
++static int test_rtc_read_time(struct device *dev,
++ struct rtc_time *tm)
++{
++ rtc_time_to_tm(get_seconds(), tm);
++ return 0;
++}
++
++static int test_rtc_set_time(struct device *dev,
++ struct rtc_time *tm)
++{
++ return 0;
++}
++
++static int test_rtc_set_mmss(struct device *dev, unsigned long secs)
++{
++ return 0;
++}
++
++static int test_rtc_proc(struct device *dev, struct seq_file *seq)
++{
++ struct platform_device *plat_dev = to_platform_device(dev);
++
++ seq_printf(seq, "24hr\t\t: yes\n");
++ seq_printf(seq, "test\t\t: yes\n");
++ seq_printf(seq, "id\t\t: %d\n", plat_dev->id);
++
++ return 0;
++}
++
++static int test_rtc_ioctl(struct device *dev, unsigned int cmd,
++ unsigned long arg)
++{
++ /* We do support interrupts, they're generated
++ * using the sysfs interface.
++ */
++ switch (cmd) {
++ case RTC_PIE_ON:
++ case RTC_PIE_OFF:
++ case RTC_UIE_ON:
++ case RTC_UIE_OFF:
++ case RTC_AIE_ON:
++ case RTC_AIE_OFF:
++ return 0;
++
++ default:
++ return -EINVAL;
++ }
++}
++
++static struct rtc_class_ops test_rtc_ops = {
++ .proc = test_rtc_proc,
++ .read_time = test_rtc_read_time,
++ .set_time = test_rtc_set_time,
++ .read_alarm = test_rtc_read_alarm,
++ .set_alarm = test_rtc_set_alarm,
++ .set_mmss = test_rtc_set_mmss,
++ .ioctl = test_rtc_ioctl,
++};
++
++static ssize_t test_irq_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%d\n", 42);
++}
++static ssize_t test_irq_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ int retval;
++ struct platform_device *plat_dev = to_platform_device(dev);
++ struct rtc_device *rtc = platform_get_drvdata(plat_dev);
++
++ retval = count;
++ if (strncmp(buf, "tick", 4) == 0)
++ rtc_update_irq(&rtc->class_dev, 1, RTC_PF | RTC_IRQF);
++ else if (strncmp(buf, "alarm", 5) == 0)
++ rtc_update_irq(&rtc->class_dev, 1, RTC_AF | RTC_IRQF);
++ else if (strncmp(buf, "update", 6) == 0)
++ rtc_update_irq(&rtc->class_dev, 1, RTC_UF | RTC_IRQF);
++ else
++ retval = -EINVAL;
++
++ return retval;
++}
++static DEVICE_ATTR(irq, S_IRUGO | S_IWUSR, test_irq_show, test_irq_store);
++
++static int test_probe(struct platform_device *plat_dev)
++{
++ int err;
++ struct rtc_device *rtc = rtc_device_register("test", &plat_dev->dev,
++ &test_rtc_ops, THIS_MODULE);
++ if (IS_ERR(rtc)) {
++ err = PTR_ERR(rtc);
++ dev_err(&plat_dev->dev,
++ "unable to register the class device\n");
++ return err;
++ }
++ device_create_file(&plat_dev->dev, &dev_attr_irq);
++
++ platform_set_drvdata(plat_dev, rtc);
++
++ return 0;
++}
++
++static int test_remove(struct platform_device *plat_dev)
++{
++ struct rtc_device *rtc = platform_get_drvdata(plat_dev);
++
++ rtc_device_unregister(rtc);
++ device_remove_file(&plat_dev->dev, &dev_attr_irq);
++
++ return 0;
++}
++
++static void test_release(struct device * dev)
++{
++}
++
++struct platform_device test_dev_zero = {
++ .name = "rtc-test",
++ .id = 0,
++ .dev.release = test_release,
++};
++
++struct platform_device test_dev_one = {
++ .name = "rtc-test",
++ .id = 1,
++ .dev.release = test_release,
++};
++
++struct platform_driver test_drv = {
++ .probe = test_probe,
++ .remove = test_remove,
++ .driver = {
++ .name = "rtc-test",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init test_init(void)
++{
++ platform_device_register(&test_dev_zero);
++ platform_device_register(&test_dev_one);
++ platform_driver_register(&test_drv);
++
++ return 0;
++}
++
++static void __exit test_exit(void)
++{
++ platform_driver_unregister(&test_drv);
++ platform_device_unregister(&test_dev_zero);
++ platform_device_unregister(&test_dev_one);
++}
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("RTC test driver/device");
++MODULE_LICENSE("GPL");
++
++module_init(test_init);
++module_exit(test_exit);
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/rtc-ds1672.c 2006-01-04 01:27:21.000000000 +0100
+@@ -0,0 +1,266 @@
++/*
++ * An rtc/i2c driver for the Dallas DS1672
++ * Copyright 2005 Alessandro Zummo
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/rtc.h>
++
++#define DRV_VERSION "0.1"
++
++/* Addresses to scan: none. This chip cannot be detected. */
++static unsigned short normal_i2c[] = { I2C_CLIENT_END };
++
++/* Insmod parameters */
++I2C_CLIENT_INSMOD;
++I2C_CLIENT_MODULE_PARM(hctosys,
++ "Set the system time from the hardware clock upon initialization");
++
++/* Registers */
++
++#define DS1672_REG_CNT_BASE 0
++#define DS1672_REG_CONTROL 4
++#define DS1672_REG_TRICKLE 5
++
++
++/* Prototypes */
++static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind);
++
++/*
++ * In the routines that deal directly with the ds1672 hardware, we use
++ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
++ * Epoch is initialized as 2000. Time is set to UTC.
++ */
++static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
++{
++ unsigned long time;
++ unsigned char buf[4];
++
++ dev_dbg(&client->dev,
++ "%s: raw read data - counters=%02x,%02x,%02x,%02x\n"
++ __FUNCTION__,
++ buf[0], buf[1], buf[2], buf[3]);
++
++ time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
++
++ rtc_time_to_tm(time, tm);
++
++ dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
++ "mday=%d, mon=%d, year=%d, wday=%d\n",
++ __FUNCTION__,
++ tm->tm_sec, tm->tm_min, tm->tm_hour,
++ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
++
++ return 0;
++}
++
++static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs)
++{
++ int xfer;
++ unsigned char buf[5];
++
++ buf[0] = DS1672_REG_CNT_BASE;
++ buf[1] = secs & 0x000000FF;
++ buf[2] = (secs & 0x0000FF00) >> 8;
++ buf[3] = (secs & 0x00FF0000) >> 16;
++ buf[4] = (secs & 0xFF000000) >> 24;
++
++ xfer = i2c_master_send(client, buf, 5);
++ if (xfer != 5) {
++ dev_err(&client->dev, "%s: send: %d\n", __FUNCTION__, xfer);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm)
++{
++ unsigned long secs;
++
++ dev_dbg(&client->dev,
++ "%s: secs=%d, mins=%d, hours=%d, ",
++ "mday=%d, mon=%d, year=%d, wday=%d\n",
++ __FUNCTION__,
++ tm->tm_sec, tm->tm_min, tm->tm_hour,
++ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
++
++ rtc_tm_to_time(tm, &secs);
++
++ return ds1672_set_mmss(client, secs);
++}
++
++static int ds1672_hctosys(struct i2c_client *client)
++{
++ int err;
++ struct rtc_time tm;
++ struct timespec tv;
++
++ if ((err = ds1672_get_datetime(client, &tm)) != 0)
++ return err;
++
++ /* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
++ * whether it stores the most close value or the value with partial
++ * seconds truncated. However, it is important that we use it to store
++ * the truncated value. This is because otherwise it is necessary,
++ * in an rtc sync function, to read both xtime.tv_sec and
++ * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
++ * of >32bits is not possible. So storing the most close value would
++ * slow down the sync API. So here we have the truncated value and
++ * the best guess is to add 0.5s.
++ */
++
++ tv.tv_nsec = NSEC_PER_SEC >> 1;
++
++ rtc_tm_to_time(&tm, &tv.tv_sec);
++
++ do_settimeofday(&tv);
++
++ dev_info(&client->dev,
++ "setting the system clock to %d-%02d-%02d %02d:%02d:%02d\n",
++ tm.tm_year + 1900, tm.tm_mon + 1,
++ tm.tm_mday, tm.tm_hour, tm.tm_min,
++ tm.tm_sec);
++
++ return 0;
++}
++
++static int ds1672_rtc_read_time(struct device *dev, struct rtc_time *tm)
++{
++ return ds1672_get_datetime(to_i2c_client(dev), tm);
++}
++
++static int ds1672_rtc_set_time(struct device *dev, struct rtc_time *tm)
++{
++ return ds1672_set_datetime(to_i2c_client(dev), tm);
++}
++
++static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs)
++{
++ return ds1672_set_mmss(to_i2c_client(dev), secs);
++}
++
++static struct rtc_class_ops ds1672_rtc_ops = {
++ .read_time = ds1672_rtc_read_time,
++ .set_time = ds1672_rtc_set_time,
++ .set_mmss = ds1672_rtc_set_mmss,
++};
++
++static int ds1672_attach(struct i2c_adapter *adapter)
++{
++ dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
++
++ return i2c_probe(adapter, &addr_data, ds1672_probe);
++}
++
++static int ds1672_detach(struct i2c_client *client)
++{
++ int err;
++ struct rtc_device *rtc = i2c_get_clientdata(client);
++
++ dev_dbg(&client->dev, "%s\n", __FUNCTION__);
++
++ if (rtc)
++ rtc_device_unregister(rtc);
++
++ if ((err = i2c_detach_client(client)))
++ return err;
++
++ kfree(client);
++
++ return 0;
++}
++
++static struct i2c_driver ds1672_driver = {
++ .owner = THIS_MODULE,
++ .name = "ds1672",
++ .flags = I2C_DF_NOTIFY,
++ .attach_adapter = &ds1672_attach,
++ .detach_client = &ds1672_detach,
++};
++
++static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
++{
++ int err = 0;
++ struct i2c_client *client;
++ struct rtc_device *rtc;
++
++ dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
++
++ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
++ err = -ENODEV;
++ goto exit;
++ }
++
++ if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
++ err = -ENOMEM;
++ goto exit;
++ }
++
++ /* I2C client */
++ client->addr = address;
++ client->driver = &ds1672_driver;
++ client->adapter = adapter;
++
++ strlcpy(client->name, ds1672_driver.name, I2C_NAME_SIZE);
++
++ /* Inform the i2c layer */
++ if ((err = i2c_attach_client(client)))
++ goto exit_kfree;
++
++ dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
++
++ rtc = rtc_device_register(ds1672_driver.name, &client->dev,
++ &ds1672_rtc_ops, THIS_MODULE);
++
++ if (IS_ERR(rtc)) {
++ err = PTR_ERR(rtc);
++ dev_err(&client->dev,
++ "unable to register the class device\n");
++ goto exit_detach;
++ }
++
++ i2c_set_clientdata(client, rtc);
++
++ /* If requested, set the system time */
++ if (hctosys) {
++ if ((err = ds1672_hctosys(client)) < 0)
++ dev_err(&client->dev,
++ "unable to set the system clock\n");
++ }
++
++ return 0;
++
++exit_detach:
++ i2c_detach_client(client);
++
++exit_kfree:
++ kfree(client);
++
++exit:
++ return err;
++}
++
++static int __init ds1672_init(void)
++{
++ return i2c_add_driver(&ds1672_driver);
++}
++
++static void __exit ds1672_exit(void)
++{
++ i2c_del_driver(&ds1672_driver);
++}
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++module_init(ds1672_init);
++module_exit(ds1672_exit);
diff --git a/packages/linux/nas100d-kernel/2.6.15/50-nas100d-arch.patch b/packages/linux/nas100d-kernel/2.6.15/50-nas100d-arch.patch
index eed275fefb..028e50455a 100644
--- a/packages/linux/nas100d-kernel/2.6.15/50-nas100d-arch.patch
+++ b/packages/linux/nas100d-kernel/2.6.15/50-nas100d-arch.patch
@@ -1,11 +1,5 @@
- arch/arm/mach-ixp4xx/Kconfig | 8 ++++++++
- arch/arm/mach-ixp4xx/Makefile | 1 +
- include/asm-arm/arch-ixp4xx/hardware.h | 1 +
- include/asm-arm/arch-ixp4xx/irqs.h | 9 +++++++++
- 4 files changed, 19 insertions(+)
-
---- linux-nas100d.orig/arch/arm/mach-ixp4xx/Kconfig 2005-11-16 22:29:00.000000000 +0100
-+++ linux-nas100d/arch/arm/mach-ixp4xx/Kconfig 2005-11-16 22:29:52.000000000 +0100
+--- linux-2.6.15-rc7/arch/arm/mach-ixp4xx/Kconfig 2005-12-27 22:29:00.000000000 +0100
++++ linux-2.6.15-rc7/arch/arm/mach-ixp4xx/Kconfig 2005-12-27 22:29:52.000000000 +0100
@@ -71,6 +71,14 @@ config ARCH_PRPMC1100
PrPCM1100 Processor Mezanine Module. For more information on
this platform, see <file:Documentation/arm/IXP4xx>.
@@ -21,16 +15,16 @@
#
# Avila and IXDP share the same source for now. Will change in future
#
---- linux-nas100d.orig/arch/arm/mach-ixp4xx/Makefile 2005-11-16 22:29:00.000000000 +0100
-+++ linux-nas100d/arch/arm/mach-ixp4xx/Makefile 2005-11-16 22:30:37.000000000 +0100
+--- linux-2.6.15-rc7/arch/arm/mach-ixp4xx/Makefile 2005-12-27 22:29:00.000000000 +0100
++++ linux-2.6.15-rc7/arch/arm/mach-ixp4xx/Makefile 2005-12-27 22:30:37.000000000 +0100
@@ -9,4 +9,5 @@ obj-$(CONFIG_MACH_IXDPG425) += ixdpg425-
obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o coyote-setup.o
obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o gtwx5715-setup.o
obj-$(CONFIG_MACH_NSLU2) += nslu2-pci.o nslu2-setup.o nslu2-power.o
+obj-$(CONFIG_MACH_NAS100D) += nas100d-pci.o nas100d-setup.o nas100d-power.o
---- linux-nas100d.orig/include/asm-arm/arch-ixp4xx/hardware.h 2005-11-16 22:29:18.000000000 +0100
-+++ linux-nas100d/include/asm-arm/arch-ixp4xx/hardware.h 2005-11-16 22:31:08.000000000 +0100
+--- linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/hardware.h 2005-12-27 22:29:18.000000000 +0100
++++ linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/hardware.h 2005-12-27 22:31:08.000000000 +0100
@@ -45,5 +45,6 @@ extern unsigned int processor_id;
#include "coyote.h"
#include "prpmc1100.h"
@@ -38,8 +32,8 @@
+#include "nas100d.h"
#endif /* _ASM_ARCH_HARDWARE_H */
---- linux-nas100d.orig/include/asm-arm/arch-ixp4xx/irqs.h 2005-11-16 22:29:18.000000000 +0100
-+++ linux-nas100d/include/asm-arm/arch-ixp4xx/irqs.h 2005-11-16 22:29:52.000000000 +0100
+--- linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/irqs.h 2005-12-27 22:29:18.000000000 +0100
++++ linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/irqs.h 2005-12-27 22:29:52.000000000 +0100
@@ -100,4 +100,13 @@
#define IRQ_NSLU2_PCI_INTB IRQ_IXP4XX_GPIO10
#define IRQ_NSLU2_PCI_INTC IRQ_IXP4XX_GPIO9
@@ -47,10 +41,376 @@
+/*
+ * NAS100D board IRQs
+ */
-+#define IRQ_NAS100D_PCI_INTA IRQ_IXP4XX_GPIO11
-+#define IRQ_NAS100D_PCI_INTB IRQ_IXP4XX_GPIO10
-+#define IRQ_NAS100D_PCI_INTC IRQ_IXP4XX_GPIO9
-+#define IRQ_NAS100D_PCI_INTD IRQ_IXP4XX_GPIO8
-+#define IRQ_NAS100D_PCI_INTE IRQ_IXP4XX_GPIO7
++#define IRQ_NAS100D_PCI_INTA IRQ_IXP4XX_GPIO11
++#define IRQ_NAS100D_PCI_INTB IRQ_IXP4XX_GPIO10
++#define IRQ_NAS100D_PCI_INTC IRQ_IXP4XX_GPIO9
++#define IRQ_NAS100D_PCI_INTD IRQ_IXP4XX_GPIO8
++#define IRQ_NAS100D_PCI_INTE IRQ_IXP4XX_GPIO7
+
#endif
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/nas100d.h 2005-11-12 14:24:14.000000000 +0100
+@@ -0,0 +1,75 @@
++/*
++ * include/asm-arm/arch-ixp4xx/nas100d.h
++ *
++ * NAS100D platform specific definitions
++ *
++ * Copyright (c) 2005 Tower Technologies
++ *
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * based on ixdp425.h:
++ * Copyright 2004 (c) MontaVista, Software, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#ifndef __ASM_ARCH_HARDWARE_H__
++#error "Do not include this directly, instead #include <asm/hardware.h>"
++#endif
++
++#define NAS100D_FLASH_BASE IXP4XX_EXP_BUS_CS0_BASE_PHYS
++#define NAS100D_FLASH_SIZE IXP4XX_EXP_BUS_CSX_REGION_SIZE
++
++#define NAS100D_SDA_PIN 6
++#define NAS100D_SCL_PIN 5
++
++/*
++ * NAS100D PCI IRQs
++ */
++#define NAS100D_PCI_MAX_DEV 3
++#define NAS100D_PCI_IRQ_LINES 3
++
++
++/* PCI controller GPIO to IRQ pin mappings */
++#define NAS100D_PCI_INTA_PIN 11
++#define NAS100D_PCI_INTB_PIN 10
++#define NAS100D_PCI_INTC_PIN 9
++#define NAS100D_PCI_INTD_PIN 8
++#define NAS100D_PCI_INTE_PIN 7
++
++/* GPIO */
++
++#define NAS100D_GPIO0 0
++#define NAS100D_GPIO1 1
++#define NAS100D_GPIO2 2
++#define NAS100D_GPIO3 3
++#define NAS100D_GPIO4 4
++#define NAS100D_GPIO5 5
++#define NAS100D_GPIO6 6
++#define NAS100D_GPIO7 7
++#define NAS100D_GPIO8 8
++#define NAS100D_GPIO9 9
++#define NAS100D_GPIO10 10
++#define NAS100D_GPIO11 11
++#define NAS100D_GPIO12 12
++#define NAS100D_GPIO13 13
++#define NAS100D_GPIO14 14
++#define NAS100D_GPIO15 15
++
++
++/* Buttons */
++
++#define NAS100D_PB_GPIO NAS100D_GPIO14
++#define NAS100D_RB_GPIO NAS100D_GPIO4
++#define NAS100D_PO_GPIO NAS100D_GPIO12 /* power off */
++
++#define NAS100D_PB_IRQ IRQ_IXP4XX_GPIO14
++#define NAS100D_RB_IRQ IRQ_IXP4XX_GPIO4
++
++/*
++#define NAS100D_PB_BM (1L << NAS100D_PB_GPIO)
++#define NAS100D_PO_BM (1L << NAS100D_PO_GPIO)
++#define NAS100D_RB_BM (1L << NAS100D_RB_GPIO)
++*/
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15-rc7/arch/arm/mach-ixp4xx/nas100d-pci.c 2005-11-12 14:24:14.000000000 +0100
+@@ -0,0 +1,77 @@
++/*
++ * arch/arm/mach-ixp4xx/nas100d-pci.c
++ *
++ * NAS 100d board-level PCI initialization
++ *
++ * based on ixdp425-pci.c:
++ * Copyright (C) 2002 Intel Corporation.
++ * Copyright (C) 2003-2004 MontaVista Software, Inc.
++ *
++ * Maintainer: http://www.nslu2-linux.org/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++
++#include <asm/mach/pci.h>
++#include <asm/mach-types.h>
++
++void __init nas100d_pci_preinit(void)
++{
++ set_irq_type(IRQ_NAS100D_PCI_INTA, IRQT_LOW);
++ set_irq_type(IRQ_NAS100D_PCI_INTB, IRQT_LOW);
++ set_irq_type(IRQ_NAS100D_PCI_INTC, IRQT_LOW);
++ set_irq_type(IRQ_NAS100D_PCI_INTD, IRQT_LOW);
++ set_irq_type(IRQ_NAS100D_PCI_INTE, IRQT_LOW);
++
++ gpio_line_isr_clear(NAS100D_PCI_INTA_PIN);
++ gpio_line_isr_clear(NAS100D_PCI_INTB_PIN);
++ gpio_line_isr_clear(NAS100D_PCI_INTC_PIN);
++ gpio_line_isr_clear(NAS100D_PCI_INTD_PIN);
++ gpio_line_isr_clear(NAS100D_PCI_INTE_PIN);
++
++ ixp4xx_pci_preinit();
++}
++
++static int __init nas100d_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ static int pci_irq_table[NAS100D_PCI_MAX_DEV][NAS100D_PCI_IRQ_LINES] =
++ {
++ { IRQ_NAS100D_PCI_INTA, -1, -1 },
++ { IRQ_NAS100D_PCI_INTB, -1, -1 },
++ { IRQ_NAS100D_PCI_INTC, IRQ_NAS100D_PCI_INTD, IRQ_NAS100D_PCI_INTE },
++ };
++
++ int irq = -1;
++
++ if (slot >= 1 && slot <= NAS100D_PCI_MAX_DEV &&
++ pin >= 1 && pin <= NAS100D_PCI_IRQ_LINES)
++ irq = pci_irq_table[slot-1][pin-1];
++
++ return irq;
++}
++
++struct hw_pci __initdata nas100d_pci = {
++ .nr_controllers = 1,
++ .preinit = nas100d_pci_preinit,
++ .swizzle = pci_std_swizzle,
++ .setup = ixp4xx_setup,
++ .scan = ixp4xx_scan_bus,
++ .map_irq = nas100d_map_irq,
++};
++
++int __init nas100d_pci_init(void)
++{
++ if (machine_is_nas100d())
++ pci_common_init(&nas100d_pci);
++
++ return 0;
++}
++
++subsys_initcall(nas100d_pci_init);
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15-rc7/arch/arm/mach-ixp4xx/nas100d-power.c 2005-11-12 14:24:14.000000000 +0100
+@@ -0,0 +1,69 @@
++/*
++ * arch/arm/mach-ixp4xx/nas100d-power.c
++ *
++ * NAS 100d Power/Reset driver
++ *
++ * Copyright (C) 2005 Tower Technologies
++ *
++ * based on nas100d-io.c
++ * Copyright (C) 2004 Karen Spearel
++ *
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ * Maintainers: http://www.nslu2-linux.org/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/reboot.h>
++#include <linux/interrupt.h>
++
++#include <asm/mach-types.h>
++
++extern void ctrl_alt_del(void);
++
++static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
++{
++ /* Signal init to do the ctrlaltdel action, this will bypass init if
++ * it hasn't started and do a kernel_restart.
++ */
++ ctrl_alt_del();
++
++ return IRQ_HANDLED;
++}
++
++static int __init nas100d_power_init(void)
++{
++ if (!(machine_is_nas100d()))
++ return 0;
++
++ set_irq_type(NAS100D_RB_IRQ, IRQT_LOW);
++
++ gpio_line_isr_clear(NAS100D_RB_GPIO);
++
++ if (request_irq(NAS100D_RB_IRQ, &nas100d_reset_handler,
++ SA_INTERRUPT, "NAS100D reset button", NULL) < 0) {
++
++ printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
++ NAS100D_RB_IRQ);
++
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static void __exit nas100d_power_exit(void)
++{
++ free_irq(NAS100D_RB_IRQ, NULL);
++}
++
++module_init(nas100d_power_init);
++module_exit(nas100d_power_exit);
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("NAS100D Power/Reset driver");
++MODULE_LICENSE("GPL");
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15-rc7/arch/arm/mach-ixp4xx/nas100d-setup.c 2005-11-12 14:24:14.000000000 +0100
+@@ -0,0 +1,133 @@
++/*
++ * arch/arm/mach-ixp4xx/nas100d-setup.c
++ *
++ * NAS 100d board-setup
++ *
++ * based ixdp425-setup.c:
++ * Copyright (C) 2003-2004 MontaVista Software, Inc.
++ *
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ * Author: Rod Whitby <rod@whitby.id.au>
++ * Maintainers: http://www.nslu2-linux.org/
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/serial.h>
++#include <linux/serial_8250.h>
++
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++static struct flash_platform_data nas100d_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++};
++
++static struct resource nas100d_flash_resource = {
++ .start = NAS100D_FLASH_BASE,
++ .end = NAS100D_FLASH_BASE + NAS100D_FLASH_SIZE,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device nas100d_flash = {
++ .name = "IXP4XX-Flash",
++ .id = 0,
++ .dev.platform_data = &nas100d_flash_data,
++ .num_resources = 1,
++ .resource = &nas100d_flash_resource,
++};
++
++static struct ixp4xx_i2c_pins nas100d_i2c_gpio_pins = {
++ .sda_pin = NAS100D_SDA_PIN,
++ .scl_pin = NAS100D_SCL_PIN,
++};
++
++static struct platform_device nas100d_i2c_controller = {
++ .name = "IXP4XX-I2C",
++ .id = 0,
++ .dev.platform_data = &nas100d_i2c_gpio_pins,
++ .num_resources = 0,
++};
++
++static struct resource nas100d_uart_resources[] = {
++ {
++ .start = IXP4XX_UART1_BASE_PHYS,
++ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = IXP4XX_UART2_BASE_PHYS,
++ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++ .flags = IORESOURCE_MEM,
++ }
++};
++
++static struct plat_serial8250_port nas100d_uart_data[] = {
++ {
++ .mapbase = IXP4XX_UART1_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART1,
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ {
++ .mapbase = IXP4XX_UART2_BASE_PHYS,
++ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++ .irq = IRQ_IXP4XX_UART2,
++ .flags = UPF_BOOT_AUTOCONF,
++ .iotype = UPIO_MEM,
++ .regshift = 2,
++ .uartclk = IXP4XX_UART_XTAL,
++ },
++ { }
++};
++
++static struct platform_device nas100d_uart = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .dev.platform_data = nas100d_uart_data,
++ .num_resources = 2,
++ .resource = nas100d_uart_resources,
++};
++
++static struct platform_device *nas100d_devices[] __initdata = {
++ &nas100d_i2c_controller,
++ &nas100d_flash,
++ &nas100d_uart,
++};
++
++static void nas100d_power_off(void)
++{
++ /* This causes the box to drop the power and go dead. */
++
++ /* enable the pwr cntl gpio */
++ gpio_line_config(NAS100D_PO_GPIO, IXP4XX_GPIO_OUT);
++
++ /* do the deed */
++ gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
++}
++
++static void __init nas100d_init(void)
++{
++ ixp4xx_sys_init();
++
++ pm_power_off = nas100d_power_off;
++
++ platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
++}
++
++MACHINE_START(NAS100D, "Iomega NAS 100d")
++ /* Maintainer: www.nslu2-linux.org */
++ .phys_ram = PHYS_OFFSET,
++ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
++ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
++ .boot_params = 0x00000100,
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .timer = &ixp4xx_timer,
++ .init_machine = nas100d_init,
++MACHINE_END
diff --git a/packages/linux/nas100d-kernel/2.6.15/55-nas100d-arch.patch b/packages/linux/nas100d-kernel/2.6.15/55-nas100d-arch.patch
deleted file mode 100644
index 4b40047a92..0000000000
--- a/packages/linux/nas100d-kernel/2.6.15/55-nas100d-arch.patch
+++ /dev/null
@@ -1,395 +0,0 @@
- arch/arm/mach-ixp4xx/nas100d-pci.c | 77 +++++++++++++++++++
- arch/arm/mach-ixp4xx/nas100d-power.c | 92 +++++++++++++++++++++++
- arch/arm/mach-ixp4xx/nas100d-setup.c | 132 ++++++++++++++++++++++++++++++++++
- drivers/ide/pci/aec62xx.c | 11 ++
- include/asm-arm/arch-ixp4xx/nas100d.h | 75 +++++++++++++++++++
- 5 files changed, 387 insertions(+)
-
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.14/include/asm-arm/arch-ixp4xx/nas100d.h 2005-11-12 14:24:14.000000000 +0100
-@@ -0,0 +1,75 @@
-+/*
-+ * include/asm-arm/arch-ixp4xx/nas100d.h
-+ *
-+ * NAS100D platform specific definitions
-+ *
-+ * Copyright (c) 2005 Tower Technologies
-+ *
-+ * Author: Alessandro Zummo <a.zummo@towertech.it>
-+ *
-+ * based on ixdp425.h:
-+ * Copyright 2004 (c) MontaVista, Software, Inc.
-+ *
-+ * This file is licensed under the terms of the GNU General Public
-+ * License version 2. This program is licensed "as is" without any
-+ * warranty of any kind, whether express or implied.
-+ */
-+
-+#ifndef __ASM_ARCH_HARDWARE_H__
-+#error "Do not include this directly, instead #include <asm/hardware.h>"
-+#endif
-+
-+#define NAS100D_FLASH_BASE IXP4XX_EXP_BUS_CS0_BASE_PHYS
-+#define NAS100D_FLASH_SIZE IXP4XX_EXP_BUS_CSX_REGION_SIZE
-+
-+#define NAS100D_SDA_PIN 6
-+#define NAS100D_SCL_PIN 5
-+
-+/*
-+ * NAS100D PCI IRQs
-+ */
-+#define NAS100D_PCI_MAX_DEV 3
-+#define NAS100D_PCI_IRQ_LINES 3
-+
-+
-+/* PCI controller GPIO to IRQ pin mappings */
-+#define NAS100D_PCI_INTA_PIN 11
-+#define NAS100D_PCI_INTB_PIN 10
-+#define NAS100D_PCI_INTC_PIN 9
-+#define NAS100D_PCI_INTD_PIN 8
-+#define NAS100D_PCI_INTE_PIN 7
-+
-+/* GPIO */
-+
-+#define NAS100D_GPIO0 0
-+#define NAS100D_GPIO1 1
-+#define NAS100D_GPIO2 2
-+#define NAS100D_GPIO3 3
-+#define NAS100D_GPIO4 4
-+#define NAS100D_GPIO5 5
-+#define NAS100D_GPIO6 6
-+#define NAS100D_GPIO7 7
-+#define NAS100D_GPIO8 8
-+#define NAS100D_GPIO9 9
-+#define NAS100D_GPIO10 10
-+#define NAS100D_GPIO11 11
-+#define NAS100D_GPIO12 12
-+#define NAS100D_GPIO13 13
-+#define NAS100D_GPIO14 14
-+#define NAS100D_GPIO15 15
-+
-+
-+/* Buttons */
-+
-+#define NAS100D_PB_GPIO NAS100D_GPIO14
-+#define NAS100D_RB_GPIO NAS100D_GPIO4
-+#define NAS100D_PO_GPIO NAS100D_GPIO12 /* power off */
-+
-+#define NAS100D_PB_IRQ IRQ_IXP4XX_GPIO14
-+#define NAS100D_RB_IRQ IRQ_IXP4XX_GPIO4
-+
-+/*
-+#define NAS100D_PB_BM (1L << NAS100D_PB_GPIO)
-+#define NAS100D_PO_BM (1L << NAS100D_PO_GPIO)
-+#define NAS100D_RB_BM (1L << NAS100D_RB_GPIO)
-+*/
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.14/arch/arm/mach-ixp4xx/nas100d-pci.c 2005-11-12 14:24:14.000000000 +0100
-@@ -0,0 +1,77 @@
-+/*
-+ * arch/arm/mach-ixp4xx/nas100d-pci.c
-+ *
-+ * NAS 100d board-level PCI initialization
-+ *
-+ * based on ixdp425-pci.c:
-+ * Copyright (C) 2002 Intel Corporation.
-+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
-+ *
-+ * Maintainer: http://www.nslu2-linux.org/
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/pci.h>
-+#include <linux/init.h>
-+
-+#include <asm/mach/pci.h>
-+#include <asm/mach-types.h>
-+
-+void __init nas100d_pci_preinit(void)
-+{
-+ set_irq_type(IRQ_NAS100D_PCI_INTA, IRQT_LOW);
-+ set_irq_type(IRQ_NAS100D_PCI_INTB, IRQT_LOW);
-+ set_irq_type(IRQ_NAS100D_PCI_INTC, IRQT_LOW);
-+ set_irq_type(IRQ_NAS100D_PCI_INTD, IRQT_LOW);
-+ set_irq_type(IRQ_NAS100D_PCI_INTE, IRQT_LOW);
-+
-+ gpio_line_isr_clear(NAS100D_PCI_INTA_PIN);
-+ gpio_line_isr_clear(NAS100D_PCI_INTB_PIN);
-+ gpio_line_isr_clear(NAS100D_PCI_INTC_PIN);
-+ gpio_line_isr_clear(NAS100D_PCI_INTD_PIN);
-+ gpio_line_isr_clear(NAS100D_PCI_INTE_PIN);
-+
-+ ixp4xx_pci_preinit();
-+}
-+
-+static int __init nas100d_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-+{
-+ static int pci_irq_table[NAS100D_PCI_MAX_DEV][NAS100D_PCI_IRQ_LINES] =
-+ {
-+ { IRQ_NAS100D_PCI_INTA, -1, -1 },
-+ { IRQ_NAS100D_PCI_INTB, -1, -1 },
-+ { IRQ_NAS100D_PCI_INTC, IRQ_NAS100D_PCI_INTD, IRQ_NAS100D_PCI_INTE },
-+ };
-+
-+ int irq = -1;
-+
-+ if (slot >= 1 && slot <= NAS100D_PCI_MAX_DEV &&
-+ pin >= 1 && pin <= NAS100D_PCI_IRQ_LINES)
-+ irq = pci_irq_table[slot-1][pin-1];
-+
-+ return irq;
-+}
-+
-+struct hw_pci __initdata nas100d_pci = {
-+ .nr_controllers = 1,
-+ .preinit = nas100d_pci_preinit,
-+ .swizzle = pci_std_swizzle,
-+ .setup = ixp4xx_setup,
-+ .scan = ixp4xx_scan_bus,
-+ .map_irq = nas100d_map_irq,
-+};
-+
-+int __init nas100d_pci_init(void)
-+{
-+ if (machine_is_nas100d())
-+ pci_common_init(&nas100d_pci);
-+
-+ return 0;
-+}
-+
-+subsys_initcall(nas100d_pci_init);
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.14/arch/arm/mach-ixp4xx/nas100d-power.c 2005-11-12 14:24:14.000000000 +0100
-@@ -0,0 +1,92 @@
-+/*
-+ * arch/arm/mach-ixp4xx/nas100d-power.c
-+ *
-+ * NAS 100d Power/Reset driver
-+ *
-+ * Copyright (C) 2005 Tower Technologies
-+ *
-+ * based on nas100d-io.c
-+ * Copyright (C) 2004 Karen Spearel
-+ *
-+ * Author: Alessandro Zummo <a.zummo@towertech.it>
-+ * Maintainers: http://www.nslu2-linux.org/
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/reboot.h>
-+#include <linux/interrupt.h>
-+
-+#include <asm/mach-types.h>
-+
-+extern void ctrl_alt_del(void);
-+
-+static irqreturn_t nas100d_power_handler(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ /* Signal init to do the ctrlaltdel action, this will bypass init if
-+ * it hasn't started and do a kernel_restart.
-+ */
-+ ctrl_alt_del();
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ /* This is the paper-clip reset, it shuts the machine down directly.
-+ */
-+ machine_power_off();
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int __init nas100d_power_init(void)
-+{
-+ if (!(machine_is_nas100d()))
-+ return 0;
-+
-+ // *IXP4XX_GPIO_GPISR = 0x20400000; /* read the 2 irqs to clr */
-+
-+ set_irq_type(NAS100D_RB_IRQ, IRQT_LOW);
-+// set_irq_type(NAS100D_PB_IRQ, IRQT_HIGH);
-+
-+ gpio_line_isr_clear(NAS100D_RB_GPIO);
-+// gpio_line_isr_clear(NAS100D_PB_GPIO);
-+
-+ if (request_irq(NAS100D_RB_IRQ, &nas100d_reset_handler,
-+ SA_INTERRUPT, "NAS100D reset button", NULL) < 0) {
-+
-+ printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
-+ NAS100D_RB_IRQ);
-+
-+ return -EIO;
-+ }
-+/*
-+ if (request_irq(NAS100D_PB_IRQ, &nas100d_power_handler,
-+ SA_INTERRUPT, "NAS100D power button", NULL) < 0) {
-+
-+ printk(KERN_DEBUG "Power Button IRQ %d not available\n",
-+ NAS100D_PB_IRQ);
-+
-+ return -EIO;
-+ }
-+*/
-+ return 0;
-+}
-+
-+static void __exit nas100d_power_exit(void)
-+{
-+ free_irq(NAS100D_RB_IRQ, NULL);
-+// free_irq(NAS100D_PB_IRQ, NULL);
-+}
-+
-+module_init(nas100d_power_init);
-+module_exit(nas100d_power_exit);
-+
-+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-+MODULE_DESCRIPTION("NAS100D Power/Reset driver");
-+MODULE_LICENSE("GPL");
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.14/arch/arm/mach-ixp4xx/nas100d-setup.c 2005-11-12 14:24:14.000000000 +0100
-@@ -0,0 +1,132 @@
-+/*
-+ * arch/arm/mach-ixp4xx/nas100d-setup.c
-+ *
-+ * NAS 100d board-setup
-+ *
-+ * based ixdp425-setup.c:
-+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
-+ *
-+ * Author: Mark Rakes <mrakes at mac.com>
-+ * Maintainers: http://www.nslu2-linux.org/
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/serial.h>
-+#include <linux/serial_8250.h>
-+
-+#include <asm/mach-types.h>
-+#include <asm/mach/arch.h>
-+#include <asm/mach/flash.h>
-+
-+static struct flash_platform_data nas100d_flash_data = {
-+ .map_name = "cfi_probe",
-+ .width = 2,
-+};
-+
-+static struct resource nas100d_flash_resource = {
-+ .start = NAS100D_FLASH_BASE,
-+ .end = NAS100D_FLASH_BASE + NAS100D_FLASH_SIZE,
-+ .flags = IORESOURCE_MEM,
-+};
-+
-+static struct platform_device nas100d_flash = {
-+ .name = "IXP4XX-Flash",
-+ .id = 0,
-+ .dev.platform_data = &nas100d_flash_data,
-+ .num_resources = 1,
-+ .resource = &nas100d_flash_resource,
-+};
-+
-+static struct ixp4xx_i2c_pins nas100d_i2c_gpio_pins = {
-+ .sda_pin = NAS100D_SDA_PIN,
-+ .scl_pin = NAS100D_SCL_PIN,
-+};
-+
-+static struct platform_device nas100d_i2c_controller = {
-+ .name = "IXP4XX-I2C",
-+ .id = 0,
-+ .dev.platform_data = &nas100d_i2c_gpio_pins,
-+ .num_resources = 0,
-+};
-+
-+static struct resource nas100d_uart_resources[] = {
-+ {
-+ .start = IXP4XX_UART1_BASE_PHYS,
-+ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
-+ .flags = IORESOURCE_MEM,
-+ },
-+ {
-+ .start = IXP4XX_UART2_BASE_PHYS,
-+ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
-+ .flags = IORESOURCE_MEM,
-+ }
-+};
-+
-+static struct plat_serial8250_port nas100d_uart_data[] = {
-+ {
-+ .mapbase = IXP4XX_UART1_BASE_PHYS,
-+ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
-+ .irq = IRQ_IXP4XX_UART1,
-+ .flags = UPF_BOOT_AUTOCONF,
-+ .iotype = UPIO_MEM,
-+ .regshift = 2,
-+ .uartclk = IXP4XX_UART_XTAL,
-+ },
-+ {
-+ .mapbase = IXP4XX_UART2_BASE_PHYS,
-+ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
-+ .irq = IRQ_IXP4XX_UART2,
-+ .flags = UPF_BOOT_AUTOCONF,
-+ .iotype = UPIO_MEM,
-+ .regshift = 2,
-+ .uartclk = IXP4XX_UART_XTAL,
-+ },
-+ { }
-+};
-+
-+static struct platform_device nas100d_uart = {
-+ .name = "serial8250",
-+ .id = PLAT8250_DEV_PLATFORM,
-+ .dev.platform_data = nas100d_uart_data,
-+ .num_resources = 2,
-+ .resource = nas100d_uart_resources,
-+};
-+
-+static struct platform_device *nas100d_devices[] __initdata = {
-+ &nas100d_i2c_controller,
-+ &nas100d_flash,
-+ &nas100d_uart,
-+};
-+
-+static void nas100d_power_off(void)
-+{
-+ /* This causes the box to drop the power and go dead. */
-+
-+ /* enable the pwr cntl gpio */
-+ gpio_line_config(NAS100D_PO_GPIO, IXP4XX_GPIO_OUT);
-+
-+ /* do the deed */
-+ gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
-+}
-+
-+static void __init nas100d_init(void)
-+{
-+ ixp4xx_sys_init();
-+
-+ pm_power_off = nas100d_power_off;
-+
-+ platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
-+}
-+
-+MACHINE_START(NAS100D, "Iomega NAS 100d")
-+ /* Maintainer: www.nslu2-linux.org */
-+ .phys_ram = PHYS_OFFSET,
-+ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
-+ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
-+ .boot_params = 0x00000100,
-+ .map_io = ixp4xx_map_io,
-+ .init_irq = ixp4xx_init_irq,
-+ .timer = &ixp4xx_timer,
-+ .init_machine = nas100d_init,
-+MACHINE_END
diff --git a/packages/linux/nas100d-kernel/2.6.15/85-timer.patch b/packages/linux/nas100d-kernel/2.6.15/85-timer.patch
new file mode 100644
index 0000000000..e83120ca75
--- /dev/null
+++ b/packages/linux/nas100d-kernel/2.6.15/85-timer.patch
@@ -0,0 +1,246 @@
+--- linux-2.6.15/arch/arm/mach-ixp4xx/common.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/arch/arm/mach-ixp4xx/common.c 1970-01-01 00:00:00.000000000 +0000
+@@ -239,36 +239,165 @@ void __init ixp4xx_init_irq(void)
+ * IXP4xx timer tick
+ * We use OS timer1 on the CPU for the timer tick and the timestamp
+ * counter as a source of real clock ticks to account for missed jiffies.
++ *
++ * 'CLOCK_TICK_RATE' is the nominal number of internal ticks per second,
++ * this is significantly greater than the actual number on any ixp4xx
++ * board. Neither this nor 'LATCH' are required by this code because
++ * the only requirement is to generate HZ timer_tick calls per second.
+ *************************************************************************/
++#if TICK_NSEC * HZ != 1000000000
++ /* This will cause the jiffies to drift unnecessarily. */
++# error CLOCK_TICK_RATE should be a multiple of HZ for this code
++#endif
++
++/* These are the control registers for the interrupt handler, they must
++ * only be read and written by the interrupt handler and by the init
++ * method (which sets them to 0).
++ */
++static volatile u32 last_timer_time;
++static volatile int accumulated_error;
++
++/* Most ixp4xx boards have 66.6666MHz crystals, so default to this, reset
++ * this from the board level code if required. The following variables
++ * must be *written* only by set_board_tick_rate
++ */
++static u32 board_tick_rate;
++static u32 board_tick_per_1000; /* board_tick_rate/1000 */
++static u32 timer_count;
++
++/* The following symbol may be written to change the current tick rate,
++ * it is read by the interrupt handler and used to reload the timer.
++ * The 'real' value (the one in use) is 'board_tick_rate' above.
++ * NOTE: this can be tweaked to match the actual crystal on a particular
++ * machine.
++ */
++volatile u32 ixp4xx_board_tick_rate = 66666600;
++EXPORT_SYMBOL(ixp4xx_board_tick_rate);
++
++/* The set API may run asynchronously in the presence of interrupts,
++ * everything it does it is both atomic and complete (notice that it
++ * doesn't change any of the 'volatile' values). The mathematics in
++ * here require the following values. Changing the board tick rate
++ * implies an unknown error in the current timestamp tick count.
++ */
++#if IXP4XX_OST_RELOAD_MASK != 3 || IXP4XX_OST_ENABLE != 1
++# error unexpected value for timer reload mask
++#endif
++static void set_board_tick_rate(u32 rate) {
++ u32 reload;
++
++ /* Store the two effectively informational rate values, the
++ * error calculation is (rate - count*HZ) (above), and rate
++ * is changed first, this can cause a temporary error which
++ * will be corrected on the next interrupt.
++ */
++ board_tick_rate = rate;
++ board_tick_per_1000 = (rate+500)/1000;
++
++ /* Calculate the correct value to load into the timer countdown
++ * register, the low two bits must be b01 (to enable the timer).
++ * Select the top bits to be as close to the desired value as
++ * possible.
++ *
++ * First find the best value, regardless of the low two bits -
++ * this is the value used in the interrupt calculation even though
++ * it cannot necessarily be set into the register.
++ */
++ timer_count = (rate + (HZ/2))/HZ;
++
++ /* Now the timer_ticks are being generated at this rate, calculate
++ * an appropriate value for the register. This stores a 30 bit
++ * value which gives a period of 4*x+1, we want:
++ *
++ * 4*x+1 = board_tick_rate/HZ
++ *
++ * This needs to be rounded to the closest 4*HZ value:
++ *
++ * x = ((board_tick_rate-HZ) + (4*HZ)/2) / 4*HZ
++ * x = (board_tick_rate+HZ) / (4*HZ);
++ */
++ reload = (board_tick_rate + HZ) / HZ;
++ reload = (reload & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
++ *IXP4XX_OSRT1 = reload;
+
+-static unsigned volatile last_jiffy_time;
++ /* If the clock is drifing, look in syslog: */
++ printk(KERN_INFO "IXP4xx: FREQ=%d COUNT=%d\n", rate, reload);
++}
+
+-#define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC)
++/* This returns the time in timer ticks since the 'last_timer_time'
++ * recorded above. Use this to avoid arithmetic errors because of
++ * the overflow when the timer wraps.
++ */
++static inline u32 ixp4xx_timer_delta(void)
++{
++ return *IXP4XX_OSTS - last_timer_time;
++}
+
+ /* IRQs are disabled before entering here from do_gettimeofday() */
+ static unsigned long ixp4xx_gettimeoffset(void)
+ {
+- u32 elapsed;
+-
+- elapsed = *IXP4XX_OSTS - last_jiffy_time;
++ /* Return the offset of the current time from the last time
++ * timer tick in microseconds. This is only used for the
++ * gettimeofday call.
++ *
++ * The result of this API is at most about 20000 (for a 50Hz
++ * HZ - 20000 uS/tick), the input delta is at most about
++ * 1.3M - 21 bits.
++ */
++ u32 delta = ixp4xx_timer_delta(); /* About 21 bits max */
++ /* return delta * 1000000 / board_tick_rate; */
++ return (delta * 1000 + board_tick_per_1000/2) / board_tick_per_1000;
++}
+
+- return elapsed / CLOCK_TICKS_PER_USEC;
++/* This is the correct adjustment to the counter to compensate for an
++ * error iff timer_count-1 <= exact_count <= timer_count+1
++ */
++static inline int adjustment(int error) {
++ if (error >= HZ)
++ return 1;
++ else if (error <= -HZ)
++ return -1;
++ return 0;
+ }
+
+ static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
++ u32 rate;
++ u32 count;
++ int error;
++
+ write_seqlock(&xtime_lock);
+
+ /* Clear Pending Interrupt by writing '1' to it */
+ *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
+
++ /* If the board tick rate has been changed update the cached
++ * value.
++ */
++ if (ixp4xx_board_tick_rate != board_tick_rate) {
++ set_board_tick_rate(ixp4xx_board_tick_rate);
++ accumulated_error = 0;
++ }
++
+ /*
+ * Catch up with the real idea of time
++ *
++ * board_tick_rate: actual ixp4xx ticks/second, read-only
++ * accumulated_error: aggregate error/tick * HZ, read/write
++ * timer_count: best ixp4xx ticks per timer_tick, read-only
+ */
+- while ((*IXP4XX_OSTS - last_jiffy_time) > LATCH) {
++ rate = board_tick_rate;
++ error = accumulated_error;
++ count = timer_count;
++ do {
++ u32 adjusted_count = count + adjustment(error);
++ if (ixp4xx_timer_delta() < adjusted_count)
++ break;
+ timer_tick(regs);
+- last_jiffy_time += LATCH;
+- }
++ last_timer_time += adjusted_count;
++ error += rate - adjusted_count*HZ;
++ } while (1);
++ accumulated_error = error;
+
+ write_sequnlock(&xtime_lock);
+
+@@ -281,17 +410,30 @@ static struct irqaction ixp4xx_timer_irq
+ .handler = ixp4xx_timer_interrupt,
+ };
+
++u32 ixp4xx_get_board_tick_rate(void) {
++ return board_tick_rate;
++}
++
++EXPORT_SYMBOL(ixp4xx_get_board_tick_rate);
++
++void ixp4xx_set_board_tick_rate(u32 rate) {
++ ixp4xx_board_tick_rate = rate;
++}
++
++EXPORT_SYMBOL(ixp4xx_set_board_tick_rate);
++
+ static void __init ixp4xx_timer_init(void)
+ {
+ /* Clear Pending Interrupt by writing '1' to it */
+ *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
+
+ /* Setup the Timer counter value */
+- *IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
++ set_board_tick_rate(ixp4xx_board_tick_rate);
+
+ /* Reset time-stamp counter */
+ *IXP4XX_OSTS = 0;
+- last_jiffy_time = 0;
++ last_timer_time = 0;
++ accumulated_error = 0;
+
+ /* Connect the interrupt handler and enable the interrupt */
+ setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq);
+@@ -337,4 +479,3 @@ void __init ixp4xx_sys_init(void)
+ ARRAY_SIZE(ixp46x_devices));
+ }
+ }
+-
+--- linux-2.6.15/include/asm-arm/arch-ixp4xx/timex.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/include/asm-arm/arch-ixp4xx/timex.h 1970-01-01 00:00:00.000000000 +0000
+@@ -6,10 +6,23 @@
+ #include <asm/hardware.h>
+
+ /*
+- * We use IXP425 General purpose timer for our timer needs, it runs at
+- * 66.66... MHz. We do a convulted calculation of CLOCK_TICK_RATE b/c the
+- * timer register ignores the bottom 2 bits of the LATCH value.
++ * In linux/timex.h 'LATCH' is defined as CLOCK_TICK_RATE/HZ and
++ * is the number of internal counts per timer interrupt. Thus
++ * CLOCK_TICK_RATE is LATCH*HZ.
++ *
++ * The actual values of these numbers do not matter, because they
++ * are only used to calculate ACTHZ (rate/latch as a 24.8 fixed
++ * point number), so the value here gives a LATCH of 1 and pretty
++ * much guarantees to flush out any off-by-one errors.
++ *
++ * ACTHZ is equal to HZ, because CLOCK_TICK_RATE is a multiple of
++ * HZ, this is checked in the ixp4xx/common.c code.
+ */
+-#define FREQ 66666666
+-#define CLOCK_TICK_RATE (((FREQ / HZ & ~IXP4XX_OST_RELOAD_MASK) + 1) * HZ)
++#define CLOCK_TICK_RATE HZ
+
++/* The following allow the exact board tick rate to be set and
++ * discovered. The value should be exactly twice the frequency
++ * (in Hz) of the onboard crystal.
++ */
++extern u32 ixp4xx_get_board_tick_rate(void);
++extern void ixp4xx_set_board_tick_rate(u32 new_rate);
diff --git a/packages/linux/nas100d-kernel/2.6.15/90-ixp4xx-nslu2.patch b/packages/linux/nas100d-kernel/2.6.15/90-ixp4xx-nslu2.patch
deleted file mode 100644
index c106f7c957..0000000000
--- a/packages/linux/nas100d-kernel/2.6.15/90-ixp4xx-nslu2.patch
+++ /dev/null
@@ -1,132 +0,0 @@
-ixp4xx updates:
- - Handle reads that don't start on a half-word boundary.
- - Make it work when CPU is in little-endian mode.
-
-Signed-off-by: John Bowler <jbowler@acm.org>
-Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
-Signed-off-by: David Vrabel <dvrabel@arcom.com>
-
-Index: linux-2.6-working/drivers/mtd/maps/ixp4xx.c
-===================================================================
---- linux-2.6-working.orig/drivers/mtd/maps/ixp4xx.c 2005-11-16 15:19:34.000000000 +0000
-+++ linux-2.6-working/drivers/mtd/maps/ixp4xx.c 2005-11-16 16:06:54.000000000 +0000
-@@ -34,10 +34,55 @@
-
- #include <linux/reboot.h>
-
-+/*
-+ * Read/write a 16 bit word from flash address 'addr'.
-+ *
-+ * When the cpu is in little-endian mode it swizzles the address lines
-+ * ('address coherency') so we need to undo the swizzling to ensure commands
-+ * and the like end up on the correct flash address.
-+ *
-+ * To further complicate matters, due to the way the expansion bus controller
-+ * handles 32 bit reads, the byte stream ABCD is stored on the flash as:
-+ * D15 D0
-+ * +---+---+
-+ * | A | B | 0
-+ * +---+---+
-+ * | C | D | 2
-+ * +---+---+
-+ * This means that on LE systems each 16 bit word must be swapped. Note that
-+ * this requires CONFIG_MTD_CFI_BE_BYTE_SWAP to be enabled to 'unswap' the CFI
-+ * data and other flash commands which are always in D7-D0.
-+ */
- #ifndef __ARMEB__
-+#ifndef CONFIG_MTD_CFI_BE_BYTE_SWAP
-+# error CONFIG_MTD_CFI_BE_BYTE_SWAP required
-+#endif
-+
-+static inline u16 flash_read16(void __iomem *addr)
-+{
-+ return be16_to_cpu(__raw_readw((void __iomem *)((unsigned long)addr ^ 0x2)));
-+}
-+
-+static inline void flash_write16(u16 d, void __iomem *addr)
-+{
-+ __raw_writew(cpu_to_be16(d), (void __iomem *)((unsigned long)addr ^ 0x2));
-+}
-+
- #define BYTE0(h) ((h) & 0xFF)
- #define BYTE1(h) (((h) >> 8) & 0xFF)
-+
- #else
-+
-+static inline u16 flash_read16(const void __iomem *addr)
-+{
-+ return __raw_readw(addr);
-+}
-+
-+static inline void flash_write16(u16 d, void __iomem *addr)
-+{
-+ __raw_writew(d, addr);
-+}
-+
- #define BYTE0(h) (((h) >> 8) & 0xFF)
- #define BYTE1(h) ((h) & 0xFF)
- #endif
-@@ -45,7 +90,7 @@
- static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs)
- {
- map_word val;
-- val.x[0] = le16_to_cpu(readw(map->virt + ofs));
-+ val.x[0] = flash_read16(map->virt + ofs);
- return val;
- }
-
-@@ -57,19 +102,28 @@
- static void ixp4xx_copy_from(struct map_info *map, void *to,
- unsigned long from, ssize_t len)
- {
-- int i;
- u8 *dest = (u8 *) to;
- void __iomem *src = map->virt + from;
-- u16 data;
-
-- for (i = 0; i < (len / 2); i++) {
-- data = le16_to_cpu(readw(src + 2*i));
-- dest[i * 2] = BYTE0(data);
-- dest[i * 2 + 1] = BYTE1(data);
-+ if (len <= 0)
-+ return;
-+
-+ if (from & 1) {
-+ *dest++ = BYTE1(flash_read16(src));
-+ src++;
-+ --len;
- }
-
-- if (len & 1)
-- dest[len - 1] = BYTE0(le16_to_cpu(readw(src + 2*i)));
-+ while (len >= 2) {
-+ u16 data = flash_read16(src);
-+ *dest++ = BYTE0(data);
-+ *dest++ = BYTE1(data);
-+ src += 2;
-+ len -= 2;
-+ }
-+
-+ if (len > 0)
-+ *dest++ = BYTE0(flash_read16(src));
- }
-
- /*
-@@ -79,7 +133,7 @@
- static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr)
- {
- if (!(adr & 1))
-- writew(cpu_to_le16(d.x[0]), map->virt + adr);
-+ flash_write16(d.x[0], map->virt + adr);
- }
-
- /*
-@@ -87,7 +141,7 @@
- */
- static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)
- {
-- writew(cpu_to_le16(d.x[0]), map->virt + adr);
-+ flash_write16(d.x[0], map->virt + adr);
- }
-
- struct ixp4xx_flash_info {
diff --git a/packages/linux/nas100d-kernel/2.6.15/91-maclist.patch b/packages/linux/nas100d-kernel/2.6.15/91-maclist.patch
new file mode 100644
index 0000000000..27af1ea639
--- /dev/null
+++ b/packages/linux/nas100d-kernel/2.6.15/91-maclist.patch
@@ -0,0 +1,377 @@
+--- linux-2.6.15/include/net/maclist.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/include/net/maclist.h 1970-01-01 00:00:00.000000000 +0000
+@@ -0,0 +1,23 @@
++#ifndef _MACLIST_H
++#define _MACLIST_H 1
++/*
++ * Interfaces to the MAC repository
++ */
++/*
++ * Add a single entry, returns 0 on success else an error
++ * code. Must *not* be called from an interrupt handler.
++ */
++extern int maclist_add(const u8 id_to_add[6]);
++
++/*
++ * Return the current entry count (valid in any context).
++ */
++extern int maclist_count(void);
++
++/*
++ * Return the ID from the n'th entry (valid in any context),
++ * returns 0 on success, -EINVAL if 'n' is out of range.
++ */
++extern int maclist_read(u8 (*buffer_for_id)[6], int index_of_id_to_return);
++
++#endif /*_MACLIST_H*/
+--- linux-2.6.15/drivers/net/maclist.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/maclist.c 1970-01-01 00:00:00.000000000 +0000
+@@ -0,0 +1,314 @@
++/*
++ * drivers/net/maclist.c
++ *
++ * a simple driver to remember ethernet MAC values
++ *
++ * Some Ethernet hardware implementations have no built-in
++ * storage for allocated MAC values - an example is the Intel
++ * IXP420 chip which has support for Ethernet but no defined
++ * way of storing allocated MAC values. With such hardware
++ * different board level implementations store the allocated
++ * MAC (or MACs) in different ways. Rather than put board
++ * level code into a specific Ethernet driver this driver
++ * provides a generally accessible repository for the MACs
++ * which can be written by board level code and read by the
++ * driver.
++ *
++ * The implementation also allows user level programs to
++ * access the MAC information in /proc/net/maclist. This is
++ * useful as it allows user space code to use the MAC if it
++ * is not used by a built-in driver.
++ *
++ * Copyright (C) 2005 John Bowler
++ * Author: John Bowler <jbowler@acm.org>
++ * Maintainers: http://www.nslu2-linux.org/
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * External interfaces:
++ * Interfaces to linux kernel (and modules)
++ * maclist_add: add a single MAC
++ * maclist_count: total number of MACs stored
++ * maclist_read: read a MAC 0..(maclist_count-1)
++ */
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/etherdevice.h>
++#include <linux/proc_fs.h>
++#include <linux/errno.h>
++
++#include <net/maclist.h>
++
++#define MACLIST_NAME "maclist"
++
++MODULE_AUTHOR("John Bowler <jbowler@acm.org>");
++MODULE_DESCRIPTION("MAC list repository");
++MODULE_LICENSE("GPL");
++
++typedef struct maclist_entry {
++ struct maclist_entry *next; /* Linked list, first first */
++ u8 id[6]; /* 6 byte Ethernet MAC */
++} maclist_entry_t;
++
++/* Access to this list is possible at any time - entries in
++ * the list are never destroyed. Modification of the list is
++ * safe only from the init code (i.e. modification must be
++ * single threaded), but read from an interrupt at the same
++ * time is possible and safe.
++ */
++static maclist_entry_t *maclist_list = 0;
++
++/*
++ * External interfaces.
++ *
++ * Add a single entry, returns 0 on success else an error
++ * code. Must be single threaded.
++ */
++int maclist_add(const u8 new_id[6]) {
++ maclist_entry_t *new_entry, **tail;
++
++ if (new_id == 0 || !is_valid_ether_addr(new_id)) {
++ printk(KERN_ERR MACLIST_NAME ": invalid ethernet address\n");
++ return -EINVAL;
++ }
++ new_entry = kmalloc(sizeof *new_entry, GFP_KERNEL);
++ if (new_entry == 0)
++ return -ENOMEM;
++ new_entry->next = 0;
++ memcpy(new_entry->id, new_id, sizeof new_entry->id);
++
++ tail = &maclist_list;
++ while (*tail != 0)
++ tail = &(*tail)->next;
++ *tail = new_entry;
++ return 0;
++}
++EXPORT_SYMBOL(maclist_add);
++
++/*
++ * Return the current entry count (valid in any context).
++ */
++int maclist_count(void) {
++ maclist_entry_t *tail = maclist_list;
++ int count = 0;
++
++ while (tail != 0) {
++ tail = tail->next;
++ ++count;
++ }
++
++ return count;
++}
++EXPORT_SYMBOL(maclist_count);
++
++/*
++ * Return the ID from the n'th entry (valid in any context),
++ * returns 0 on success, -EINVAL if 'n' is out of range.
++ */
++int maclist_read(u8 (*id)[6], int n) {
++ maclist_entry_t *entry = maclist_list;
++
++ while (n > 0 && entry != 0) {
++ --n;
++ entry = entry->next;
++ }
++
++ if (n == 0 && entry != 0) {
++ memcpy(id, entry->id, sizeof *id);
++ return 0;
++ }
++
++ printk(KERN_ERR MACLIST_NAME ": id does not exist\n");
++ return -EINVAL;
++}
++EXPORT_SYMBOL(maclist_read);
++
++/*
++ * Parameter parsing. The option string is a list of MAC
++ * addresses, comma separated. (The parsing really should
++ * be somewhere central...)
++ */
++static int __init maclist_setup(char *param) {
++ int bytes = 0, seen_a_digit = 0;
++ u8 id[6];
++
++ memset(id, 0, sizeof id);
++
++ if (param) do {
++ int digit = -1;
++ switch (*param) {
++ case '0': digit = 0; break;
++ case '1': digit = 1; break;
++ case '2': digit = 2; break;
++ case '3': digit = 3; break;
++ case '4': digit = 4; break;
++ case '5': digit = 5; break;
++ case '6': digit = 6; break;
++ case '7': digit = 7; break;
++ case '8': digit = 8; break;
++ case '9': digit = 9; break;
++ case 'a': case 'A': digit = 10; break;
++ case 'b': case 'B': digit = 11; break;
++ case 'c': case 'C': digit = 12; break;
++ case 'd': case 'D': digit = 13; break;
++ case 'e': case 'E': digit = 14; break;
++ case 'f': case 'F': digit = 15; break;
++ case ':':
++ if (seen_a_digit)
++ bytes = (bytes+1) & ~1;
++ else
++ bytes += 2; /* i.e. ff::ff is ff:00:ff */
++ seen_a_digit = 0;
++ break;
++ case 0:
++ if (bytes == 0) /* nothing new seen so far */
++ return 0;
++ /*fall through*/
++ case ',': case ';':
++ if (bytes > 0)
++ bytes = 12; /* i.e. all trailing bytes 0 */
++ break;
++ default:
++ printk(KERN_ERR MACLIST_NAME ": invalid character <%c[%d]>\n",
++ *param, *param);
++ return -EINVAL;
++ }
++
++ if (digit >= 0) {
++ id[bytes>>1] = (id[bytes>>1] << 4) + digit; break;
++ ++bytes;
++ seen_a_digit = 1;
++ }
++
++ if (bytes >= 12) {
++ int rc = maclist_add(id);
++ if (rc)
++ return rc;
++ bytes = 0;
++ seen_a_digit = 0;
++ memset(id, 0, sizeof id);
++ if (*param == 0)
++ return 0;
++ }
++ ++param;
++ } while (1);
++
++ return 0;
++}
++
++/*
++ * procfs support, if compiled in.
++ */
++#ifdef CONFIG_PROC_FS
++/*
++ * Character device read
++ */
++static int maclist_getchar(off_t n) {
++ static char xdigit[16] = "0123456789abcdef";
++ maclist_entry_t *head = maclist_list;
++ int b;
++
++ do {
++ if (head == 0)
++ return -1;
++ if (n < 18)
++ break;
++ head = head->next;
++ n -= 18;
++ } while (1);
++
++ if (n == 17)
++ return '\n';
++
++ b = n/3;
++ switch (n - b*3) {
++ case 0: return xdigit[head->id[b] >> 4];
++ case 1: return xdigit[head->id[b] & 0xf];
++ default: return ':';
++ }
++}
++
++/*
++ * The extensively undocumented proc_read_t callback is implemented here.
++ * Go look in fs/proc/generic.c:
++ *
++ * Prototype:
++ * int f(char *buffer, char **start, off_t offset,
++ * int count, int *peof, void *dat)
++ *
++ * Assume that the buffer is "count" bytes in size.
++ *
++ * 2) Set *start = an address within the buffer.
++ * Put the data of the requested offset at *start.
++ * Return the number of bytes of data placed there.
++ * If this number is greater than zero and you
++ * didn't signal eof and the reader is prepared to
++ * take more data you will be called again with the
++ * requested offset advanced by the number of bytes
++ * absorbed.
++ */
++static int maclist_proc_read(char *buffer, char **start, off_t offset,
++ int count, int *peof, void *dat) {
++ int total;
++
++ *start = buffer;
++ total = 0;
++
++ while (total < count) {
++ int ch = maclist_getchar(offset++);
++ if (ch == -1) {
++ *peof = 1;
++ break;
++ }
++ *buffer++ = ch;
++ ++total;
++ }
++
++ return total;
++}
++#endif
++
++/*
++ * Finally, the init/exit functions.
++ */
++static void __exit maclist_exit(void)
++{
++ maclist_entry_t *list;
++
++ remove_proc_entry(MACLIST_NAME, proc_net);
++
++ list = maclist_list;
++ maclist_list = 0;
++
++ while (list != 0) {
++ maclist_entry_t *head = list;
++ list = head->next;
++ kfree(head);
++ }
++}
++
++#ifdef MODULE
++static char ids[256];
++module_param_string(ids, ids, sizeof ids, 0);
++MODULE_PARM_DESC(ids, "comma separated list of MAC ids\n");
++#else
++__setup("maclist_ids=", maclist_setup);
++#endif
++
++static int __init maclist_init(void)
++{
++# ifdef MODULE
++ if (ids[0])
++ maclist_setup(ids);
++# endif
++
++ /* Ignore failure, the module will still work. */
++ (void)create_proc_read_entry(MACLIST_NAME, S_IRUGO, proc_net, maclist_proc_read, NULL);
++
++ return 0;
++}
++
++module_init(maclist_init);
++module_exit(maclist_exit);
+--- linux-2.6.15/drivers/net/Makefile 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/Makefile 1970-01-01 00:00:00.000000000 +0000
+@@ -70,6 +70,7 @@ obj-$(CONFIG_RIONET) += rionet.o
+ # end link order section
+ #
+
++obj-$(CONFIG_MACLIST) += maclist.o
+ obj-$(CONFIG_MII) += mii.o
+ obj-$(CONFIG_PHYLIB) += phy/
+
+--- linux-2.6.15/drivers/net/Kconfig 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/Kconfig 1970-01-01 00:00:00.000000000 +0000
+@@ -166,6 +166,21 @@ config NET_ETHERNET
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Ethernet network cards. If unsure, say N.
+
++config MACLIST
++ tristate "Ethernet MAC repository"
++ depends on NET_ETHERNET
++ help
++ Some ethernet controllers have no built-in way of obtaining an
++ appropriate Ethernet MAC address. Such controllers have to be
++ initialised in a board-specific way, depending on how the allocated
++ MAC is stored. The MAC repository provides a set of APIs and a
++ proc entry (/proc/net/maclist) to store MAC values from the board
++ so that such drivers can obtain a MAC address without board-specific
++ code. You do not need to enable this device - it will be selected
++ automatically by any device which requires it. It is only useful
++ to enable it manually when building a device driver independently
++ of the kernel build.
++
+ config MII
+ tristate "Generic Media Independent Interface device support"
+ depends on NET_ETHERNET
diff --git a/packages/linux/nas100d-kernel/2.6.15/92-nas100d-maclist.patch b/packages/linux/nas100d-kernel/2.6.15/92-nas100d-maclist.patch
new file mode 100644
index 0000000000..3143850b22
--- /dev/null
+++ b/packages/linux/nas100d-kernel/2.6.15/92-nas100d-maclist.patch
@@ -0,0 +1,72 @@
+--- linux-2.6.15/arch/arm/mach-ixp4xx/Kconfig 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/arch/arm/mach-ixp4xx/Kconfig 1970-01-01 00:00:00.000000000 +0000
+@@ -74,6 +74,7 @@ comment "IXP4xx Platforms"
+ config MACH_NAS100D
+ bool
+ prompt "NAS100D"
++ select MACLIST
+ help
+ Say 'Y' here if you want your kernel to support Iomega's
+ NAS 100d device. For more information on this platform,
+--- linux-2.6.15/arch/arm/mach-ixp4xx/nas100d-setup.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/arch/arm/mach-ixp4xx/nas100d-setup.c 1970-01-01 00:00:00.000000000 +0000
+@@ -14,11 +14,14 @@
+ #include <linux/kernel.h>
+ #include <linux/serial.h>
+ #include <linux/serial_8250.h>
++#include <linux/mtd/mtd.h>
+
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+ #include <asm/mach/flash.h>
+
++#include <net/maclist.h>
++
+ static struct flash_platform_data nas100d_flash_data = {
+ .map_name = "cfi_probe",
+ .width = 2,
+@@ -110,8 +113,44 @@
+ gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
+ }
+
++/*
++ * When the RedBoot config partition is added the MAC address is read from
++ * it.
++ */
++void flash_add(struct mtd_info *mtd) {
++ if (strcmp(mtd->name, "RedBoot config") == 0) {
++ size_t retlen;
++ u_char mac[6];
++
++ /* The MAC is at a known offset... */
++ if (mtd->read(mtd, 0x0FD8, 6, &retlen, mac) == 0 && retlen == 6) {
++ printk(KERN_INFO "NAS100D MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
++ maclist_add(mac);
++ } else {
++ printk(KERN_ERR "NAS100D MAC: read failed\n");
++ }
++ }
++}
++
++/*
++ * Nothing to do on remove at present.
++ */
++void flash_remove(struct mtd_info *mtd) {
++}
++
++struct mtd_notifier flash_notifier = {
++ .add = flash_add,
++ .remove = flash_remove,
++};
++
+ static void __init nas100d_init(void)
+ {
++ /* The flash has an ethernet MAC embedded in it which we need,
++ * that is all this notifier does.
++ */
++ register_mtd_user(&flash_notifier);
++
+ ixp4xx_sys_init();
+
+ pm_power_off = nas100d_power_off;
diff --git a/packages/linux/nas100d-kernel/2.6.15/anonymiser.patch b/packages/linux/nas100d-kernel/2.6.15/anonymiser.patch
new file mode 100644
index 0000000000..3384b15fe2
--- /dev/null
+++ b/packages/linux/nas100d-kernel/2.6.15/anonymiser.patch
@@ -0,0 +1,22 @@
+--- linux-2.6.11.2/scripts/mkcompile_h.orig 2005-05-07 05:27:02.440000000 +0000
++++ linux-2.6.11.2/scripts/mkcompile_h 2005-05-07 05:28:30.360000000 +0000
+@@ -43,16 +43,9 @@
+ echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
+
+ echo \#define LINUX_COMPILE_TIME \"`LC_ALL=C LANG=C date +%T`\"
+- echo \#define LINUX_COMPILE_BY \"`whoami`\"
+- echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\"
+-
+- if [ -x /bin/dnsdomainname ]; then
+- echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname | $UTS_TRUNCATE`\"
+- elif [ -x /bin/domainname ]; then
+- echo \#define LINUX_COMPILE_DOMAIN \"`domainname | $UTS_TRUNCATE`\"
+- else
+- echo \#define LINUX_COMPILE_DOMAIN
+- fi
++ echo \#define LINUX_COMPILE_BY \"openslug\"
++ echo \#define LINUX_COMPILE_HOST \"openslug.org\"
++ echo \#define LINUX_COMPILE_DOMAIN \"openslug.org\"
+
+ echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\"
+ ) > .tmpcompile
diff --git a/packages/linux/nas100d-kernel/2.6.15/nas100d-pci.c b/packages/linux/nas100d-kernel/2.6.15/nas100d-pci.c
deleted file mode 100644
index 1f934068e9..0000000000
--- a/packages/linux/nas100d-kernel/2.6.15/nas100d-pci.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/nas100d-pci.c
- *
- * NAS 100d board-level PCI initialization
- *
- * based on ixdp425-pci.c:
- * Copyright (C) 2002 Intel Corporation.
- * Copyright (C) 2003-2004 MontaVista Software, Inc.
- *
- * Maintainer: http://www.nslu2-linux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/config.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/mach/pci.h>
-#include <asm/mach-types.h>
-
-void __init nas100d_pci_preinit(void)
-{
- set_irq_type(IRQ_NAS100D_PCI_INTA, IRQT_LOW);
- set_irq_type(IRQ_NAS100D_PCI_INTB, IRQT_LOW);
- set_irq_type(IRQ_NAS100D_PCI_INTC, IRQT_LOW);
- set_irq_type(IRQ_NAS100D_PCI_INTD, IRQT_LOW);
- set_irq_type(IRQ_NAS100D_PCI_INTE, IRQT_LOW);
-
- gpio_line_isr_clear(NAS100D_PCI_INTA_PIN);
- gpio_line_isr_clear(NAS100D_PCI_INTB_PIN);
- gpio_line_isr_clear(NAS100D_PCI_INTC_PIN);
- gpio_line_isr_clear(NAS100D_PCI_INTD_PIN);
- gpio_line_isr_clear(NAS100D_PCI_INTE_PIN);
-
- ixp4xx_pci_preinit();
-}
-
-static int __init nas100d_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
- if (slot < 1 || slot > 3 || pin < 1 || pin > 3)
- return -1;
-
- switch (slot)
- {
- case 1:
- if (pin == 1)
- return IRQ_NAS100D_PCI_INTA;
- break;
- case 2:
- if (pin == 1)
- return IRQ_NAS100D_PCI_INTB;
- break;
- case 3:
- if (pin == 1)
- return IRQ_NAS100D_PCI_INTC;
- if (pin == 2)
- return IRQ_NAS100D_PCI_INTD;
- if (pin == 3)
- return IRQ_NAS100D_PCI_INTE;
- break;
- }
-
- return -1;
-}
-
-struct hw_pci __initdata nas100d_pci = {
- .nr_controllers = 1,
- .preinit = nas100d_pci_preinit,
- .swizzle = pci_std_swizzle,
- .setup = ixp4xx_setup,
- .scan = ixp4xx_scan_bus,
- .map_irq = nas100d_map_irq,
-};
-
-int __init nas100d_pci_init(void)
-{
- if (machine_is_nas100d())
- pci_common_init(&nas100d_pci);
-
- return 0;
-}
-
-subsys_initcall(nas100d_pci_init);
diff --git a/packages/linux/nas100d-kernel/2.6.15/nas100d-power.c b/packages/linux/nas100d-kernel/2.6.15/nas100d-power.c
deleted file mode 100644
index 94ce5d1b46..0000000000
--- a/packages/linux/nas100d-kernel/2.6.15/nas100d-power.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/nas100d-power.c
- *
- * NAS 100d Power/Reset driver
- *
- * Copyright (C) 2005 Tower Technologies
- *
- * based on nas100d-io.c
- * Copyright (C) 2004 Karen Spearel
- *
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- * Maintainers: http://www.nslu2-linux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/module.h>
-#include <linux/reboot.h>
-#include <linux/interrupt.h>
-
-#include <asm/mach-types.h>
-
-extern void ctrl_alt_del(void);
-
-static irqreturn_t nas100d_power_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
- /* Signal init to do the ctrlaltdel action, this will bypass init if
- * it hasn't started and do a kernel_restart.
- */
- ctrl_alt_del();
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
- /* This is the paper-clip reset, it shuts the machine down directly.
- */
- machine_power_off();
-
- return IRQ_HANDLED;
-}
-
-static int __init nas100d_power_init(void)
-{
- if (!(machine_is_nas100d()))
- return 0;
-
- // *IXP4XX_GPIO_GPISR = 0x20400000; /* read the 2 irqs to clr */
-
- set_irq_type(NAS100D_RB_IRQ, IRQT_LOW);
-// set_irq_type(NAS100D_PB_IRQ, IRQT_HIGH);
-
- gpio_line_isr_clear(NAS100D_RB_GPIO);
-// gpio_line_isr_clear(NAS100D_PB_GPIO);
-
- if (request_irq(NAS100D_RB_IRQ, &nas100d_reset_handler,
- SA_INTERRUPT, "NAS100D reset button", NULL) < 0) {
-
- printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
- NAS100D_RB_IRQ);
-
- return -EIO;
- }
-/*
- if (request_irq(NAS100D_PB_IRQ, &nas100d_power_handler,
- SA_INTERRUPT, "NAS100D power button", NULL) < 0) {
-
- printk(KERN_DEBUG "Power Button IRQ %d not available\n",
- NAS100D_PB_IRQ);
-
- return -EIO;
- }
-*/
- return 0;
-}
-
-static void __exit nas100d_power_exit(void)
-{
- free_irq(NAS100D_RB_IRQ, NULL);
-// free_irq(NAS100D_PB_IRQ, NULL);
-}
-
-module_init(nas100d_power_init);
-module_exit(nas100d_power_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("NAS100D Power/Reset driver");
-MODULE_LICENSE("GPL");
diff --git a/packages/linux/nas100d-kernel/2.6.15/nas100d-setup.c b/packages/linux/nas100d-kernel/2.6.15/nas100d-setup.c
deleted file mode 100644
index 0dbb0b4e69..0000000000
--- a/packages/linux/nas100d-kernel/2.6.15/nas100d-setup.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/nas100d-setup.c
- *
- * NAS 100d board-setup
- *
- * based ixdp425-setup.c:
- * Copyright (C) 2003-2004 MontaVista Software, Inc.
- *
- * Author: Mark Rakes <mrakes at mac.com>
- * Maintainers: http://www.nslu2-linux.org/
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/serial.h>
-#include <linux/serial_8250.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-
-static struct flash_platform_data nas100d_flash_data = {
- .map_name = "cfi_probe",
- .width = 2,
-};
-
-static struct resource nas100d_flash_resource = {
- .start = NAS100D_FLASH_BASE,
- .end = NAS100D_FLASH_BASE + NAS100D_FLASH_SIZE,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device nas100d_flash = {
- .name = "IXP4XX-Flash",
- .id = 0,
- .dev.platform_data = &nas100d_flash_data,
- .num_resources = 1,
- .resource = &nas100d_flash_resource,
-};
-
-static struct ixp4xx_i2c_pins nas100d_i2c_gpio_pins = {
- .sda_pin = NAS100D_SDA_PIN,
- .scl_pin = NAS100D_SCL_PIN,
-};
-
-static struct platform_device nas100d_i2c_controller = {
- .name = "IXP4XX-I2C",
- .id = 0,
- .dev.platform_data = &nas100d_i2c_gpio_pins,
- .num_resources = 0,
-};
-
-static struct resource nas100d_uart_resources[] = {
- {
- .start = IXP4XX_UART1_BASE_PHYS,
- .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = IXP4XX_UART2_BASE_PHYS,
- .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct plat_serial8250_port nas100d_uart_data[] = {
- {
- .mapbase = IXP4XX_UART1_BASE_PHYS,
- .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
- .irq = IRQ_IXP4XX_UART1,
- .flags = UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = IXP4XX_UART_XTAL,
- },
- {
- .mapbase = IXP4XX_UART2_BASE_PHYS,
- .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
- .irq = IRQ_IXP4XX_UART2,
- .flags = UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = IXP4XX_UART_XTAL,
- },
- { }
-};
-
-static struct platform_device nas100d_uart = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
- .dev.platform_data = nas100d_uart_data,
- .num_resources = 2,
- .resource = nas100d_uart_resources,
-};
-
-static struct platform_device *nas100d_devices[] __initdata = {
- &nas100d_i2c_controller,
- &nas100d_flash,
- &nas100d_uart,
-};
-
-static void nas100d_power_off(void)
-{
- /* This causes the box to drop the power and go dead. */
-
- /* enable the pwr cntl gpio */
- gpio_line_config(NAS100D_PO_GPIO, IXP4XX_GPIO_OUT);
-
- /* do the deed */
- gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
-}
-
-static void __init nas100d_init(void)
-{
- ixp4xx_sys_init();
-
- pm_power_off = nas100d_power_off;
-
- platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
-}
-
-MACHINE_START(NAS100D, "Iomega NAS 100d")
- /* Maintainer: www.nslu2-linux.org */
- .phys_ram = PHYS_OFFSET,
- .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
- .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
- .boot_params = 0x00000100,
- .map_io = ixp4xx_map_io,
- .init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
- .init_machine = nas100d_init,
-MACHINE_END
diff --git a/packages/linux/nas100d-kernel/2.6.15/nas100d.h b/packages/linux/nas100d-kernel/2.6.15/nas100d.h
deleted file mode 100644
index 1623712b78..0000000000
--- a/packages/linux/nas100d-kernel/2.6.15/nas100d.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * include/asm-arm/arch-ixp4xx/nas100d.h
- *
- * NAS100D platform specific definitions
- *
- * Copyright (c) 2005 Tower Technologies
- *
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- *
- * based on ixdp425.h:
- * Copyright 2004 (c) MontaVista, Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H__
-#error "Do not include this directly, instead #include <asm/hardware.h>"
-#endif
-
-#define NAS100D_FLASH_BASE IXP4XX_EXP_BUS_CS0_BASE_PHYS
-#define NAS100D_FLASH_SIZE IXP4XX_EXP_BUS_CSX_REGION_SIZE
-
-#define NAS100D_SDA_PIN 5
-#define NAS100D_SCL_PIN 6
-
-/*
- * NAS100D PCI IRQs
- */
-#define NAS100D_PCI_MAX_DEV 5
-#define NAS100D_PCI_IRQ_LINES 5
-
-
-/* PCI controller GPIO to IRQ pin mappings */
-#define NAS100D_PCI_INTA_PIN 11
-#define NAS100D_PCI_INTB_PIN 10
-#define NAS100D_PCI_INTC_PIN 9
-#define NAS100D_PCI_INTD_PIN 8
-#define NAS100D_PCI_INTE_PIN 7
-
-/* GPIO */
-
-#define NAS100D_GPIO0 0
-#define NAS100D_GPIO1 1
-#define NAS100D_GPIO2 2
-#define NAS100D_GPIO3 3
-#define NAS100D_GPIO4 4
-#define NAS100D_GPIO5 5
-#define NAS100D_GPIO6 6
-#define NAS100D_GPIO7 7
-#define NAS100D_GPIO8 8
-#define NAS100D_GPIO9 9
-#define NAS100D_GPIO10 10
-#define NAS100D_GPIO11 11
-#define NAS100D_GPIO12 12
-#define NAS100D_GPIO13 13
-#define NAS100D_GPIO14 14
-#define NAS100D_GPIO15 15
-
-
-/* Buttons */
-
-#define NAS100D_PB_GPIO NAS100D_GPIO14
-#define NAS100D_RB_GPIO NAS100D_GPIO4
-#define NAS100D_PO_GPIO NAS100D_GPIO12 /* power off */
-
-#define NAS100D_PB_IRQ IRQ_IXP4XX_GPIO14
-#define NAS100D_RB_IRQ IRQ_IXP4XX_GPIO4
-
-/*
-#define NAS100D_PB_BM (1L << NAS100D_PB_GPIO)
-#define NAS100D_PO_BM (1L << NAS100D_PO_GPIO)
-#define NAS100D_RB_BM (1L << NAS100D_RB_GPIO)
-*/
diff --git a/packages/linux/nas100d-kernel_2.6.15.bb b/packages/linux/nas100d-kernel_2.6.15.bb
new file mode 100644
index 0000000000..337763b2d6
--- /dev/null
+++ b/packages/linux/nas100d-kernel_2.6.15.bb
@@ -0,0 +1,34 @@
+# Kernel for Iomega NAS 100d
+#
+# Increment PR_CONFIG for changes to the nas100d-kernel specific
+# defconfig (do *NOT* increment anything in here for changes
+# to other kernel configs!)
+PR_CONFIG = "0"
+#
+# Increment the number below (i.e. the digits after PR) when
+# making changes within this file or for changes to the patches
+# applied to the kernel.
+PR = "r1.${PR_CONFIG}"
+
+include nas100d-kernel.inc
+
+# N1K_PATCHES - full list of patches to apply
+N1K_PATCHES = "\
+ file://00-memory-h-page-shift.patch;patch=1 \
+ file://10-mtdpart-redboot-fis-byteswap.patch;patch=1 \
+ file://19-jffs2-force-be.patch;patch=1 \
+ file://40-rtc-class.patch;patch=1 \
+ file://50-nas100d-arch.patch;patch=1 \
+ file://60-nas100d-ide.patch;patch=1 \
+ file://60-nas100d-i2c.patch;patch=1 \
+ file://85-timer.patch;patch=1 \
+ file://91-maclist.patch;patch=1 \
+ file://92-nas100d-maclist.patch;patch=1 \
+ file://anonymiser.patch;patch=1 \
+"
+
+# These options get added to the kernel command line, only put things
+# specific to the bootstrap of *this* kernel in here - DISTRO specfic
+# config must be in CMDLINE_ROOT (see the full definition of CMDLINE
+# in nas100d-kernel.inc)
+CMDLINE_KERNEL_OPTIONS = "pcf8563.hctosys=1"