# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet v2.6.0-test3 -> 1.1149 # include/asm-ppc/pmac_feature.h 1.9 -> 1.10 # arch/ppc/syslib/Makefile 1.8 -> 1.9 # arch/i386/kernel/head.S 1.27 -> 1.28 # include/asm-ppc/macio_asic.h 1.1 -> 1.2 include/asm-ppc/macio.h (moved) # drivers/char/watchdog/advantechwdt.c 1.17 -> 1.18 # drivers/isdn/hisax/st5481_b.c 1.11 -> 1.12 # drivers/isdn/hisax/st5481_d.c 1.10 -> 1.11 # drivers/video/cfbimgblt.c 1.27 -> 1.28 # drivers/char/watchdog/w83877f_wdt.c 1.17 -> 1.20 # drivers/isdn/hisax/st5481_usb.c 1.17 -> 1.18 # arch/ppc/platforms/pmac_setup.c 1.29 -> 1.30 # drivers/char/watchdog/sbc60xxwdt.c 1.27 -> 1.33 # drivers/macintosh/Makefile 1.11 -> 1.12 # arch/ppc/platforms/pmac_feature.c 1.17 -> 1.18 # (new) -> 1.1 drivers/macintosh/macio_asic.c # (new) -> 1.1 include/asm-ppc/of_device.h # (new) -> 1.1 arch/ppc/syslib/of_device.c # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/08/08 torvalds@home.osdl.org 1.1135 # Linux 2.6.0-test3 # -------------------------------------------- # 03/08/09 wim@iguana.be 1.1136 # [WATCHDOG] sbc60xxwdt.c patch # # general cleanup of trailing spaces and comments # fix possible wdt_is_open race # add KERN_* to printk's # changed watchdog_info to correctly reflect what the driver offers # added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT, WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls # made timeout (the emulated heartbeat) a module_param # made the keepalive ping an internal subroutine # added MODULE_AUTHOR and MODULE_DESCRIPTION info # -------------------------------------------- # 03/08/09 wim@iguana.be 1.1137 # [WATCHDOG] sbc60xxwdt patch2 # # report default timeout as a number # -------------------------------------------- # 03/08/09 wim@iguana.be 1.1138 # [WATCHDOG] sbc60xxwdt patch3 # # make wdt_stop and wdt_start module params # -------------------------------------------- # 03/08/09 wim@iguana.be 1.1139 # [WATCHDOG] sbc60xxwdt patch4 # # added extra printk's to report what problem occured # -------------------------------------------- # 03/08/09 wim@iguana.be 1.1140 # [WATCHDOG] sbc60xxwdt.c patch5 # # some last clean-ups # -------------------------------------------- # 03/08/09 wim@iguana.be 1.1141 # [WATCHDOG] advantechwdt.c patch2 # # some small clean-ups (use PFX + report default timeout as it's value in the MODULE_PARM_DESC) # -------------------------------------------- # 03/08/09 wim@iguana.be 1.1142 # [WATCHDOG] w83877f_wdt patch # # cleanup comments and trailing spaces # eliminate extra spin_unlock # add KERN_* tags to printks # added extra printk's to report what problem occured # -------------------------------------------- # 03/08/09 wim@iguana.be 1.1143 # [WATCHDOG] w83877f_wdt.c patch2 # # add CONFIG_WATCHDOG_NOWAYOUT support # changed watchdog_info to correctly reflect what the driver offers # added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls # use module_param # -------------------------------------------- # 03/08/09 wim@iguana.be 1.1144 # [WATCHDOG] w83877f_wdt.c patch3 (add timeout features) # # added WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT ioctls # made timeout (the emulated heartbeat) a module_param # made the keepalive ping an internal subroutine # -------------------------------------------- # 03/08/09 wim@iguana.be 1.1145 # [WATCHDOG] sbc60xxwdt.c patch6 # # some small clean-ups: do correct errorhandling # -------------------------------------------- # 03/08/09 herbert@gondor.apana.org.au 1.1146 # [PATCH] Fix usb interface change in hisax st5481_* # # This makes the HISAX ST5481 driver build again with 2.6.0-test3 where # the usb_host_config structure has changed. # -------------------------------------------- # 03/08/09 jgarzik@pobox.com 1.1147 # [PATCH] PATCH 2.6: fix X86_VENDOR_ID offset in head.S # # While reviewing my 2.4 backport of the 2.6 cpu capabilities (including # the Via RNG support), Mikael Pettersson noticed a bug in both my # backport, and 2.6: when NCAPINTS (x86_capability array size) is # increased, one must adjust the offset in arch/i386/kernel/head.S also. # # Contributed by Mikael Pettersson. # -------------------------------------------- # 03/08/09 benh@kernel.crashing.org 1.1148 # [PATCH] PowerMac: Ground work for new driver model # # This provides the necessary infrastructure for PowerMac specific drivers # (and actually some Open Firmware platform drivers on non-PowerMacs as # well provided somebody port them) to be properly probed & referenced via # the new driver model and be part of sysfs. # # As-is, this patch doesn't break anything nor change any driver. I'll # send you individual driver patches as I clean them up & get them tested # on as many machines as possible, though I don't expect much problems. # -------------------------------------------- # 03/08/09 tmolina@cablespeed.com 1.1149 # [PATCH] Re: Linux 2.6.0-test3: logo patch # # The following patch has been floating around forever. It is required # for several ARM framebuffer drivers, and several other drivers. James # has indicated that this is the correct fix back in May. # -------------------------------------------- # diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S --- a/arch/i386/kernel/head.S Sat Aug 9 16:58:28 2003 +++ b/arch/i386/kernel/head.S Sat Aug 9 16:58:28 2003 @@ -35,7 +35,7 @@ #define X86_HARD_MATH CPU_PARAMS+6 #define X86_CPUID CPU_PARAMS+8 #define X86_CAPABILITY CPU_PARAMS+12 -#define X86_VENDOR_ID CPU_PARAMS+28 +#define X86_VENDOR_ID CPU_PARAMS+36 /* * Initialize page tables diff -Nru a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c --- a/arch/ppc/platforms/pmac_feature.c Sat Aug 9 16:58:28 2003 +++ b/arch/ppc/platforms/pmac_feature.c Sat Aug 9 16:58:28 2003 @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -2187,6 +2186,8 @@ macio_chips[0] = macio_chips[1]; macio_chips[1] = temp; } + macio_chips[0].lbus.index = 0; + macio_chips[1].lbus.index = 1; return (macio_chips[0].of_node == NULL) ? -ENODEV : 0; } diff -Nru a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c --- a/arch/ppc/platforms/pmac_setup.c Sat Aug 9 16:58:28 2003 +++ b/arch/ppc/platforms/pmac_setup.c Sat Aug 9 16:58:28 2003 @@ -69,6 +69,7 @@ #include #include #include +#include #include "pmac_pic.h" #include "mem_pieces.h" @@ -670,3 +671,29 @@ } } #endif /* CONFIG_BOOTX_TEXT */ + +static int __init +pmac_declare_of_platform_devices(void) +{ + struct device_node *np; + + np = find_devices("uni-n"); + if (np) { + for (np = np->child; np != NULL; np = np->sibling) + if (strncmp(np->name, "i2c", 3) == 0) { + of_platform_device_create(np, "uni-n-i2c"); + break; + } + } + + np = find_devices("valkyrie"); + if (np) + of_platform_device_create(np, "valkyrie"); + np = find_devices("platinum"); + if (np) + of_platform_device_create(np, "platinum"); + + return 0; +} + +device_initcall(pmac_declare_of_platform_devices); diff -Nru a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile --- a/arch/ppc/syslib/Makefile Sat Aug 9 16:58:28 2003 +++ b/arch/ppc/syslib/Makefile Sat Aug 9 16:58:28 2003 @@ -27,7 +27,7 @@ ifeq ($(CONFIG_8xx),y) obj-$(CONFIG_PCI) += qspan_pci.o i8259.o endif -obj-$(CONFIG_PPC_OF) += prom_init.o prom.o +obj-$(CONFIG_PPC_OF) += prom_init.o prom.o of_device.o obj-$(CONFIG_PPC_PMAC) += open_pic.o indirect_pci.o obj-$(CONFIG_PPC_CHRP) += open_pic.o indirect_pci.o i8259.o obj-$(CONFIG_PPC_PREP) += open_pic.o indirect_pci.o i8259.o diff -Nru a/arch/ppc/syslib/of_device.c b/arch/ppc/syslib/of_device.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/syslib/of_device.c Sat Aug 9 16:58:28 2003 @@ -0,0 +1,249 @@ +#include +#include +#include +#include +#include +#include +#include + +/** + * of_match_device - Tell if an of_device structure has a matching + * of_match structure + * @ids: array of of device match structures to search in + * @dev: the of device structure to match against + * + * Used by a driver to check whether an of_device present in the + * system is in its list of supported devices. + */ +const struct of_match * +of_match_device(const struct of_match *matches, const struct of_device *dev) +{ + if (!dev->node) + return NULL; + while (matches->name || matches->type || matches->compatible) { + int match = 1; + if (matches->name && matches->name != OF_ANY_MATCH) + match &= dev->node->name + && !strcmp(matches->name, dev->node->name); + if (matches->type && matches->type != OF_ANY_MATCH) + match &= dev->node->type + && !strcmp(matches->type, dev->node->type); + if (matches->compatible && matches->compatible != OF_ANY_MATCH) + match &= device_is_compatible(dev->node, + matches->compatible); + if (match) + return matches; + matches++; + } + return NULL; +} + +static int +of_platform_bus_match(struct device *dev, struct device_driver *drv) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * of_drv = to_of_platform_driver(drv); + const struct of_match * matches = of_drv->match_table; + + if (!matches) + return 0; + + return of_match_device(matches, of_dev) != NULL; +} + +struct bus_type of_platform_bus_type = { + name: "of_platform", + match: of_platform_bus_match, +}; + +static int __init +of_bus_driver_init(void) +{ + return bus_register(&of_platform_bus_type); +} + +postcore_initcall(of_bus_driver_init); + +static int +of_device_probe(struct device *dev) +{ + int error = -ENODEV; + struct of_platform_driver *drv; + struct of_device *of_dev; + const struct of_match *match; + + drv = to_of_platform_driver(dev->driver); + of_dev = to_of_device(dev); + + if (!drv->probe) + return error; + +/* if (!try_module_get(driver->owner)) { + printk(KERN_ERR "Can't get a module reference for %s\n", driver->name); + return error; + } +*/ + match = of_match_device(drv->match_table, of_dev); + if (match) + error = drv->probe(of_dev, match); +/* + module_put(driver->owner); +*/ + return error; +} + +static int +of_device_remove(struct device *dev) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * drv = to_of_platform_driver(of_dev->dev.driver); + + if (drv && drv->remove) + drv->remove(of_dev); + return 0; +} + +static int +of_device_suspend(struct device *dev, u32 state, u32 level) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * drv = to_of_platform_driver(of_dev->dev.driver); + int error = 0; + + if (drv && drv->suspend) + error = drv->suspend(of_dev, state, level); + return error; +} + +static int +of_device_resume(struct device * dev, u32 level) +{ + struct of_device * of_dev = to_of_device(dev); + struct of_platform_driver * drv = to_of_platform_driver(of_dev->dev.driver); + int error = 0; + + if (drv && drv->resume) + error = drv->resume(of_dev, level); + return error; +} + +int +of_register_driver(struct of_platform_driver *drv) +{ + int count = 0; + + /* initialize common driver fields */ + drv->driver.name = drv->name; + drv->driver.bus = &of_platform_bus_type; + drv->driver.probe = of_device_probe; + drv->driver.resume = of_device_resume; + drv->driver.suspend = of_device_suspend; + drv->driver.remove = of_device_remove; + + /* register with core */ + count = driver_register(&drv->driver); + return count ? count : 1; +} + +void +of_unregister_driver(struct of_platform_driver *drv) +{ + driver_unregister(&drv->driver); +} + + +static ssize_t +dev_show_devspec(struct device *dev, char *buf) +{ + struct of_device *ofdev; + + ofdev = to_of_device(dev); + return sprintf(buf, "%s", ofdev->node->full_name); +} + +static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL); + +int +of_device_register(struct of_device *ofdev) +{ + int rc; + struct of_device **odprop; + + BUG_ON(ofdev->node == NULL); + + odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL); + if (!odprop) { + struct property *new_prop; + + new_prop = kmalloc(sizeof(struct property) + sizeof(struct of_device *), + GFP_KERNEL); + if (new_prop == NULL) + return -ENOMEM; + new_prop->name = "linux,device"; + new_prop->length = sizeof(sizeof(struct of_device *)); + new_prop->value = (unsigned char *)&new_prop[1]; + odprop = (struct of_device **)new_prop->value; + *odprop = NULL; + prom_add_property(ofdev->node, new_prop); + } + *odprop = ofdev; + + rc = device_register(&ofdev->dev); + if (rc) + return rc; + + device_create_file(&ofdev->dev, &dev_attr_devspec); + + return 0; +} + +void +of_device_unregister(struct of_device *ofdev) +{ + struct of_device **odprop; + + device_remove_file(&ofdev->dev, &dev_attr_devspec); + device_unregister(&ofdev->dev); + + odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL); + if (odprop) + *odprop = NULL; +} + +struct of_device* +of_platform_device_create(struct device_node *np, const char *bus_id) +{ + struct of_device *dev; + u32 *reg; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + memset(dev, 0, sizeof(*dev)); + + dev->node = np; + dev->dma_mask = 0xffffffffUL; + dev->dev.dma_mask = &dev->dma_mask; + dev->dev.parent = NULL; + dev->dev.bus = &of_platform_bus_type; + + /* XXX Make something better here ? */ + snprintf(dev->dev.name, DEVICE_NAME_SIZE, "Platform device %s", np->name); + reg = (u32 *)get_property(np, "reg", NULL); + strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); + + if (of_device_register(dev) != 0) { + kfree(dev); + return NULL; + } + + return dev; +} + +EXPORT_SYMBOL(of_match_device); +EXPORT_SYMBOL(of_platform_bus_type); +EXPORT_SYMBOL(of_register_driver); +EXPORT_SYMBOL(of_unregister_driver); +EXPORT_SYMBOL(of_device_register); +EXPORT_SYMBOL(of_device_unregister); +EXPORT_SYMBOL(of_platform_device_create); diff -Nru a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c --- a/drivers/char/watchdog/advantechwdt.c Sat Aug 9 16:58:28 2003 +++ b/drivers/char/watchdog/advantechwdt.c Sat Aug 9 16:58:28 2003 @@ -44,6 +44,7 @@ #include #define WATCHDOG_NAME "Advantech WDT" +#define PFX WATCHDOG_NAME ": " #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ static unsigned long advwdt_is_open; @@ -70,7 +71,7 @@ static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ module_param(timeout, int, 0); -MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=60."); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); #ifdef CONFIG_WATCHDOG_NOWAYOUT static int nowayout = 1; @@ -206,7 +207,7 @@ if (adv_expect_close == 42) { advwdt_disable(); } else { - printk(KERN_CRIT WATCHDOG_NAME ": Unexpected close, not stopping watchdog!\n"); + printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); advwdt_ping(); } clear_bit(0, &advwdt_is_open); @@ -268,13 +269,13 @@ if (timeout < 1 || timeout > 63) { timeout = WATCHDOG_TIMEOUT; - printk (KERN_INFO WATCHDOG_NAME ": timeout value must be 1<=x<=63, using %d\n", + printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n", timeout); } if (wdt_stop != wdt_start) { if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { - printk (KERN_ERR WATCHDOG_NAME ": I/O address 0x%04x already in use\n", + printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", wdt_stop); ret = -EIO; goto out; @@ -282,7 +283,7 @@ } if (!request_region(wdt_start, 1, WATCHDOG_NAME)) { - printk (KERN_ERR WATCHDOG_NAME ": I/O address 0x%04x already in use\n", + printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", wdt_start); ret = -EIO; goto unreg_stop; @@ -290,19 +291,19 @@ ret = register_reboot_notifier(&advwdt_notifier); if (ret != 0) { - printk (KERN_ERR WATCHDOG_NAME ": cannot register reboot notifier (err=%d)\n", + printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret); goto unreg_regions; } ret = misc_register(&advwdt_miscdev); if (ret != 0) { - printk (KERN_ERR WATCHDOG_NAME ": cannot register miscdev on minor=%d (err=%d)\n", + printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", WATCHDOG_MINOR, ret); goto unreg_reboot; } - printk (KERN_INFO WATCHDOG_NAME ": initialized. timeout=%d sec (nowayout=%d)\n", + printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", timeout, nowayout); out: diff -Nru a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c --- a/drivers/char/watchdog/sbc60xxwdt.c Sat Aug 9 16:58:28 2003 +++ b/drivers/char/watchdog/sbc60xxwdt.c Sat Aug 9 16:58:28 2003 @@ -7,51 +7,40 @@ * 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. - * - * The author does NOT admit liability nor provide warranty for - * any of this software. This material is provided "AS-IS" in - * the hope that it may be useful for others. * - * (c) Copyright 2000 Jakob Oestergaard + * The author does NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * (c) Copyright 2000 Jakob Oestergaard * * 12/4 - 2000 [Initial revision] * 25/4 - 2000 Added /dev/watchdog support * 09/5 - 2001 [smj@oro.net] fixed fop_write to "return 1" on success + * 12/4 - 2002 [rob@osinvestor.com] eliminate fop_read + * fix possible wdt_is_open race + * add CONFIG_WATCHDOG_NOWAYOUT support + * remove lock_kernel/unlock_kernel pairs + * added KERN_* to printk's + * got rid of extraneous comments + * changed watchdog_info to correctly reflect what the driver offers + * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT, + * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls + * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces + * use module_param + * made timeout (the emulated heartbeat) a module_param + * made the keepalive ping an internal subroutine + * made wdt_stop and wdt_start module params + * added extra printk's for startup problems + * added MODULE_AUTHOR and MODULE_DESCRIPTION info * * - * Theory of operation: - * A Watchdog Timer (WDT) is a hardware circuit that can - * reset the computer system in case of a software fault. - * You probably knew that already. - * - * Usually a userspace daemon will notify the kernel WDT driver - * via the /proc/watchdog special device file that userspace is - * still alive, at regular intervals. When such a notification - * occurs, the driver will usually tell the hardware watchdog - * that everything is in order, and that the watchdog should wait - * for yet another little while to reset the system. - * If userspace fails (RAM error, kernel bug, whatever), the - * notifications cease to occur, and the hardware watchdog will - * reset the system (causing a reboot) after the timeout occurs. - * - * This WDT driver is different from the other Linux WDT - * drivers in several ways: + * This WDT driver is different from the other Linux WDT + * drivers in the following ways: * *) The driver will ping the watchdog by itself, because this * particular WDT has a very short timeout (one second) and it * would be insane to count on any userspace daemon always * getting scheduled within that time frame. - * *) This driver expects the userspace daemon to send a specific - * character code ('V') to /dev/watchdog before closing the - * /dev/watchdog file. If the userspace daemon closes the file - * without sending this special character, the driver will assume - * that the daemon (and userspace in general) died, and will - * stop pinging the WDT without disabling it first. This will - * cause a reboot. - * - * Why `V' ? Well, `V' is the character in ASCII for the value 86, - * and we all know that 86 is _the_ most random number in the universe. - * Therefore it is the letter that has the slightest chance of occurring - * by chance, when the system becomes corrupted. * */ @@ -73,13 +62,19 @@ #include #define OUR_NAME "sbc60xxwdt" +#define PFX OUR_NAME ": " /* * You must set these - The driver cannot probe for the settings */ - -#define WDT_STOP 0x45 -#define WDT_START 0x443 + +static int wdt_stop = 0x45; +module_param(wdt_stop, int, 0); +MODULE_PARM_DESC(wdt_stop, "SBC60xx WDT 'stop' io port (default 0x45)"); + +static int wdt_start = 0x443; +module_param(wdt_start, int, 0); +MODULE_PARM_DESC(wdt_start, "SBC60xx WDT 'start' io port (default 0x443)"); /* * The 60xx board can use watchdog timeout values from one second @@ -92,19 +87,16 @@ /* * We must not require too good response from the userspace daemon. * Here we require the userspace daemon to send us a heartbeat - * char to /dev/watchdog every 10 seconds. - * If the daemon pulses us every 5 seconds, we can still afford + * char to /dev/watchdog every 30 seconds. + * If the daemon pulses us every 25 seconds, we can still afford * a 5 second scheduling delay on the (high priority) daemon. That * should be sufficient for a box under any load. */ -#define WDT_HEARTBEAT (HZ * 10) - -static void wdt_timer_ping(unsigned long); -static struct timer_list timer; -static unsigned long next_heartbeat; -static int wdt_is_open; -static int wdt_expect_close; +#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ +static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); #ifdef CONFIG_WATCHDOG_NOWAYOUT static int nowayout = 1; @@ -115,6 +107,12 @@ module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +static void wdt_timer_ping(unsigned long); +static struct timer_list timer; +static unsigned long next_heartbeat; +static unsigned long wdt_is_open; +static char wdt_expect_close; + /* * Whack the dog */ @@ -122,42 +120,47 @@ static void wdt_timer_ping(unsigned long data) { /* If we got a heartbeat pulse within the WDT_US_INTERVAL - * we agree to ping the WDT + * we agree to ping the WDT */ - if(time_before(jiffies, next_heartbeat)) + if(time_before(jiffies, next_heartbeat)) { - /* Ping the WDT by reading from WDT_START */ - inb_p(WDT_START); + /* Ping the WDT by reading from wdt_start */ + inb_p(wdt_start); /* Re-set the timer interval */ timer.expires = jiffies + WDT_INTERVAL; add_timer(&timer); } else { - printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); + printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); } } -/* +/* * Utility routines */ static void wdt_startup(void) { - next_heartbeat = jiffies + WDT_HEARTBEAT; + next_heartbeat = jiffies + (timeout * HZ); /* Start the timer */ - timer.expires = jiffies + WDT_INTERVAL; + timer.expires = jiffies + WDT_INTERVAL; add_timer(&timer); - printk(OUR_NAME ": Watchdog timer is now enabled.\n"); + printk(KERN_INFO PFX "Watchdog timer is now enabled.\n"); } static void wdt_turnoff(void) { /* Stop the timer */ del_timer(&timer); - inb_p(WDT_STOP); - printk(OUR_NAME ": Watchdog timer is now disabled...\n"); + inb_p(wdt_stop); + printk(KERN_INFO PFX "Watchdog timer is now disabled...\n"); } +static void wdt_keepalive(void) +{ + /* user land ping */ + next_heartbeat = jiffies + (timeout * HZ); +} /* * /dev/watchdog handling @@ -169,63 +172,58 @@ if(ppos != &file->f_pos) return -ESPIPE; - /* See if we got the magic character */ - if(count) + /* See if we got the magic character 'V' and reload the timer */ + if(count) { - size_t ofs; - - /* note: just in case someone wrote the magic character - * five months ago... */ - wdt_expect_close = 0; - - /* now scan */ - for(ofs = 0; ofs != count; ofs++) + if (!nowayout) { - char c; - if(get_user(c, buf+ofs)) - return -EFAULT; - if(c == 'V') - wdt_expect_close = 1; + size_t ofs; + + /* note: just in case someone wrote the magic character + * five months ago... */ + wdt_expect_close = 0; + + /* scan to see wether or not we got the magic character */ + for(ofs = 0; ofs != count; ofs++) + { + char c; + if(get_user(c, buf+ofs)) + return -EFAULT; + if(c == 'V') + wdt_expect_close = 42; + } } + /* Well, anyhow someone wrote to us, we should return that favour */ - next_heartbeat = jiffies + WDT_HEARTBEAT; - return 1; + wdt_keepalive(); } - return 0; + return count; } static int fop_open(struct inode * inode, struct file * file) { - switch(minor(inode->i_rdev)) - { - case WATCHDOG_MINOR: - /* Just in case we're already talking to someone... */ - if(wdt_is_open) - return -EBUSY; - if (nowayout) - __module_get(THIS_MODULE); - /* Good, fire up the show */ - wdt_is_open = 1; - wdt_startup(); - return 0; + /* Just in case we're already talking to someone... */ + if(test_and_set_bit(0, &wdt_is_open)) + return -EBUSY; - default: - return -ENODEV; - } + if (nowayout) + __module_get(THIS_MODULE); + + /* Good, fire up the show */ + wdt_startup(); + return 0; } static int fop_close(struct inode * inode, struct file * file) { - if(minor(inode->i_rdev) == WATCHDOG_MINOR) - { - if(wdt_expect_close && !nowayout) - wdt_turnoff(); - else { - del_timer(&timer); - printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); - } + if(wdt_expect_close == 42) + wdt_turnoff(); + else { + del_timer(&timer); + printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n"); } - wdt_is_open = 0; + clear_bit(0, &wdt_is_open); + wdt_expect_close = 0; return 0; } @@ -234,20 +232,58 @@ { static struct watchdog_info ident= { - .options = WDIOF_MAGICCLOSE, + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .firmware_version = 1, - .identity = "SB60xx" + .identity = "SBC60xx", }; - + switch(cmd) { default: - return -ENOTTY; + return -ENOIOCTLCMD; case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *)arg); case WDIOC_KEEPALIVE: - next_heartbeat = jiffies + WDT_HEARTBEAT; + wdt_keepalive(); return 0; + case WDIOC_SETOPTIONS: + { + int new_options, retval = -EINVAL; + + if(get_user(new_options, (int *)arg)) + return -EFAULT; + + if(new_options & WDIOS_DISABLECARD) { + wdt_turnoff(); + retval = 0; + } + + if(new_options & WDIOS_ENABLECARD) { + wdt_startup(); + retval = 0; + } + + return retval; + } + case WDIOC_SETTIMEOUT: + { + int new_timeout; + + if(get_user(new_timeout, (int *)arg)) + return -EFAULT; + + if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */ + return -EINVAL; + + timeout = new_timeout; + wdt_keepalive(); + /* Fall through */ + } + case WDIOC_GETTIMEOUT: + return put_user(timeout, (int *)arg); } } @@ -257,13 +293,13 @@ .write = fop_write, .open = fop_open, .release = fop_close, - .ioctl = fop_ioctl + .ioctl = fop_ioctl, }; static struct miscdevice wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", - .fops = &wdt_fops + .fops = &wdt_fops, }; /* @@ -273,21 +309,21 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) { - if(code==SYS_DOWN || code==SYS_HALT) + if(code==SYS_DOWN || code==SYS_HALT) wdt_turnoff(); return NOTIFY_DONE; } - + /* * The WDT needs to learn about soft shutdowns in order to - * turn the timebomb registers off. + * turn the timebomb registers off. */ - + static struct notifier_block wdt_notifier= { .notifier_call = wdt_notify_sys, .next = NULL, - .priority = 0 + .priority = 0, }; static void __exit sbc60xxwdt_unload(void) @@ -298,19 +334,41 @@ misc_deregister(&wdt_miscdev); unregister_reboot_notifier(&wdt_notifier); - release_region(WDT_START,1); -// release_region(WDT_STOP,1); + if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) + release_region(wdt_stop,1); + release_region(wdt_start,1); } static int __init sbc60xxwdt_init(void) { int rc = -EBUSY; -// We cannot reserve 0x45 - the kernel already has! -// if (!request_region(WDT_STOP, 1, "SBC 60XX WDT")) -// goto err_out; - if (!request_region(WDT_START, 1, "SBC 60XX WDT")) - goto err_out_region1; + if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */ + { + timeout = WATCHDOG_TIMEOUT; + printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n", + timeout); + } + + if (!request_region(wdt_start, 1, "SBC 60XX WDT")) + { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + wdt_start); + rc = -EIO; + goto err_out; + } + + /* We cannot reserve 0x45 - the kernel already has! */ + if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) + { + if (!request_region(wdt_stop, 1, "SBC 60XX WDT")) + { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + wdt_stop); + rc = -EIO; + goto err_out_region1; + } + } init_timer(&timer); timer.function = wdt_timer_ping; @@ -318,27 +376,39 @@ rc = misc_register(&wdt_miscdev); if (rc) + { + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + wdt_miscdev.minor, rc); goto err_out_region2; + } rc = register_reboot_notifier(&wdt_notifier); if (rc) + { + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + rc); goto err_out_miscdev; + } + + printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n", + timeout, nowayout); - printk(KERN_INFO OUR_NAME ": WDT driver for 60XX single board computer initialised.\n"); - return 0; err_out_miscdev: misc_deregister(&wdt_miscdev); err_out_region2: - release_region(WDT_START,1); + if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) + release_region(wdt_stop,1); err_out_region1: - release_region(WDT_STOP,1); -/* err_out: */ + release_region(wdt_start,1); +err_out: return rc; } module_init(sbc60xxwdt_init); module_exit(sbc60xxwdt_unload); +MODULE_AUTHOR("Jakob Oestergaard "); +MODULE_DESCRIPTION("60xx Single Board Computer Watchdog Timer driver"); MODULE_LICENSE("GPL"); diff -Nru a/drivers/char/watchdog/w83877f_wdt.c b/drivers/char/watchdog/w83877f_wdt.c --- a/drivers/char/watchdog/w83877f_wdt.c Sat Aug 9 16:58:28 2003 +++ b/drivers/char/watchdog/w83877f_wdt.c Sat Aug 9 16:58:28 2003 @@ -1,38 +1,36 @@ /* - * W83877F Computer Watchdog Timer driver for Linux 2.4.x + * W83877F Computer Watchdog Timer driver * * Based on acquirewdt.c by Alan Cox, - * and sbc60xxwdt.c by Jakob Oestergaard - * + * and sbc60xxwdt.c by Jakob Oestergaard + * * 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. - * - * The authors do NOT admit liability nor provide warranty for - * any of this software. This material is provided "AS-IS" in + * + * The authors do NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in * the hope that it may be useful for others. * * (c) Copyright 2001 Scott Jennings * * 4/19 - 2001 [Initial revision] * 9/27 - 2001 Added spinlocking - * - * - * Theory of operation: - * A Watchdog Timer (WDT) is a hardware circuit that can - * reset the computer system in case of a software fault. - * You probably knew that already. - * - * Usually a userspace daemon will notify the kernel WDT driver - * via the /proc/watchdog special device file that userspace is - * still alive, at regular intervals. When such a notification - * occurs, the driver will usually tell the hardware watchdog - * that everything is in order, and that the watchdog should wait - * for yet another little while to reset the system. - * If userspace fails (RAM error, kernel bug, whatever), the - * notifications cease to occur, and the hardware watchdog will - * reset the system (causing a reboot) after the timeout occurs. + * 4/12 - 2002 [rob@osinvestor.com] Eliminate extra comments + * Eliminate fop_read + * Eliminate extra spin_unlock + * Added KERN_* tags to printks + * add CONFIG_WATCHDOG_NOWAYOUT support + * fix possible wdt_is_open race + * changed watchdog_info to correctly reflect what the driver offers + * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT, + * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls + * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces + * added extra printk's for startup problems + * use module_param + * made timeout (the emulated heartbeat) a module_param + * made the keepalive ping an internal subroutine * * This WDT driver is different from most other Linux WDT * drivers in that the driver will ping the watchdog by itself, @@ -42,6 +40,7 @@ */ #include +#include #include #include #include @@ -57,6 +56,7 @@ #include #define OUR_NAME "w83877f_wdt" +#define PFX OUR_NAME ": " #define ENABLE_W83877F_PORT 0x3F0 #define ENABLE_W83877F 0x87 @@ -79,13 +79,26 @@ * char to /dev/watchdog every 30 seconds. */ -#define WDT_HEARTBEAT (HZ * 30) +#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ +static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); + + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); static void wdt_timer_ping(unsigned long); static struct timer_list timer; static unsigned long next_heartbeat; static unsigned long wdt_is_open; -static int wdt_expect_close; +static char wdt_expect_close; static spinlock_t wdt_spinlock; /* @@ -95,9 +108,9 @@ static void wdt_timer_ping(unsigned long data) { /* If we got a heartbeat pulse within the WDT_US_INTERVAL - * we agree to ping the WDT + * we agree to ping the WDT */ - if(time_before(jiffies, next_heartbeat)) + if(time_before(jiffies, next_heartbeat)) { /* Ping the WDT */ spin_lock(&wdt_spinlock); @@ -112,11 +125,11 @@ spin_unlock(&wdt_spinlock); } else { - printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); + printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); } } -/* +/* * Utility routines */ @@ -144,15 +157,15 @@ static void wdt_startup(void) { - next_heartbeat = jiffies + WDT_HEARTBEAT; + next_heartbeat = jiffies + (timeout * HZ); /* Start the timer */ - timer.expires = jiffies + WDT_INTERVAL; + timer.expires = jiffies + WDT_INTERVAL; add_timer(&timer); wdt_change(WDT_ENABLE); - printk(OUR_NAME ": Watchdog timer is now enabled.\n"); + printk(KERN_INFO PFX "Watchdog timer is now enabled.\n"); } static void wdt_turnoff(void) @@ -162,9 +175,14 @@ wdt_change(WDT_DISABLE); - printk(OUR_NAME ": Watchdog timer is now disabled...\n"); + printk(KERN_INFO PFX "Watchdog timer is now disabled...\n"); } +static void wdt_keepalive(void) +{ + /* user land ping */ + next_heartbeat = jiffies + (timeout * HZ); +} /* * /dev/watchdog handling @@ -176,64 +194,55 @@ if(ppos != &file->f_pos) return -ESPIPE; - /* See if we got the magic character */ - if(count) + /* See if we got the magic character 'V' and reload the timer */ + if(count) { - size_t ofs; - - /* note: just in case someone wrote the magic character - * five months ago... */ - wdt_expect_close = 0; - - /* now scan */ - for(ofs = 0; ofs != count; ofs++) + if (!nowayout) { - char c; - if (get_user(c, buf + ofs)) - return -EFAULT; - if (c == 'V') - wdt_expect_close = 1; + size_t ofs; + + /* note: just in case someone wrote the magic character + * five months ago... */ + wdt_expect_close = 0; + + /* scan to see wether or not we got the magic character */ + for(ofs = 0; ofs != count; ofs++) + { + char c; + if (get_user(c, buf + ofs)) + return -EFAULT; + if (c == 'V') + wdt_expect_close = 42; + } } /* someone wrote to us, we should restart timer */ - next_heartbeat = jiffies + WDT_HEARTBEAT; - return 1; - }; - return 0; + wdt_keepalive(); + } + return count; } static int fop_open(struct inode * inode, struct file * file) { - switch(minor(inode->i_rdev)) - { - case WATCHDOG_MINOR: - /* Just in case we're already talking to someone... */ - if(test_and_set_bit(0, &wdt_is_open)) { - /* Davej: Is this unlock bogus? */ - spin_unlock(&wdt_spinlock); - return -EBUSY; - } - /* Good, fire up the show */ - wdt_startup(); - return 0; + /* Just in case we're already talking to someone... */ + if(test_and_set_bit(0, &wdt_is_open)) + return -EBUSY; - default: - return -ENODEV; - } + /* Good, fire up the show */ + wdt_startup(); + return 0; } static int fop_close(struct inode * inode, struct file * file) { - if(minor(inode->i_rdev) == WATCHDOG_MINOR) - { - if(wdt_expect_close) - wdt_turnoff(); - else { - del_timer(&timer); - printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); - } + if(wdt_expect_close == 42) + wdt_turnoff(); + else { + del_timer(&timer); + printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n"); } clear_bit(0, &wdt_is_open); + wdt_expect_close = 0; return 0; } @@ -242,20 +251,58 @@ { static struct watchdog_info ident= { - .options = WDIOF_MAGICCLOSE, + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .firmware_version = 1, - .identity = "W83877F" + .identity = "W83877F", }; - + switch(cmd) { default: return -ENOIOCTLCMD; case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *)arg); case WDIOC_KEEPALIVE: - next_heartbeat = jiffies + WDT_HEARTBEAT; + wdt_keepalive(); return 0; + case WDIOC_SETOPTIONS: + { + int new_options, retval = -EINVAL; + + if(get_user(new_options, (int *)arg)) + return -EFAULT; + + if(new_options & WDIOS_DISABLECARD) { + wdt_turnoff(); + retval = 0; + } + + if(new_options & WDIOS_ENABLECARD) { + wdt_startup(); + retval = 0; + } + + return retval; + } + case WDIOC_SETTIMEOUT: + { + int new_timeout; + + if(get_user(new_timeout, (int *)arg)) + return -EFAULT; + + if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */ + return -EINVAL; + + timeout = new_timeout; + wdt_keepalive(); + /* Fall through */ + } + case WDIOC_GETTIMEOUT: + return put_user(timeout, (int *)arg); } } @@ -265,13 +312,13 @@ .write = fop_write, .open = fop_open, .release = fop_close, - .ioctl = fop_ioctl + .ioctl = fop_ioctl, }; static struct miscdevice wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", - .fops = &wdt_fops + .fops = &wdt_fops, }; /* @@ -281,21 +328,21 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) { - if(code==SYS_DOWN || code==SYS_HALT) + if(code==SYS_DOWN || code==SYS_HALT) wdt_turnoff(); return NOTIFY_DONE; } - + /* * The WDT needs to learn about soft shutdowns in order to - * turn the timebomb registers off. + * turn the timebomb registers off. */ - + static struct notifier_block wdt_notifier= { .notifier_call = wdt_notify_sys, .next = NULL, - .priority = 0 + .priority = 0, }; static void __exit w83877f_wdt_unload(void) @@ -316,10 +363,28 @@ spin_lock_init(&wdt_spinlock); + if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */ + { + timeout = WATCHDOG_TIMEOUT; + printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n", + timeout); + } + if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) + { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + ENABLE_W83877F_PORT); + rc = -EIO; goto err_out; + } + if (!request_region(WDT_PING, 1, "W8387FF WDT")) + { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + WDT_PING); + rc = -EIO; goto err_out_region1; + } init_timer(&timer); timer.function = wdt_timer_ping; @@ -327,14 +392,23 @@ rc = misc_register(&wdt_miscdev); if (rc) + { + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + wdt_miscdev.minor, rc); goto err_out_region2; + } rc = register_reboot_notifier(&wdt_notifier); if (rc) + { + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + rc); goto err_out_miscdev; + } + + printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n", + timeout, nowayout); - printk(KERN_INFO OUR_NAME ": WDT driver for W83877F initialised.\n"); - return 0; err_out_miscdev: diff -Nru a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c --- a/drivers/isdn/hisax/st5481_b.c Sat Aug 9 16:58:28 2003 +++ b/drivers/isdn/hisax/st5481_b.c Sat Aug 9 16:58:28 2003 @@ -254,7 +254,7 @@ DBG(4,""); - altsetting = &(dev->config->interface[0].altsetting[3]); + altsetting = &(dev->config->interface[0]->altsetting[3]); // Allocate URBs and buffers for the B channel out endpoint = &altsetting->endpoint[EP_B1_OUT - 1 + bcs->channel * 2]; diff -Nru a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c --- a/drivers/isdn/hisax/st5481_d.c Sat Aug 9 16:58:28 2003 +++ b/drivers/isdn/hisax/st5481_d.c Sat Aug 9 16:58:28 2003 @@ -658,7 +658,7 @@ DBG(2,""); - altsetting = &(dev->config->interface[0].altsetting[3]); + altsetting = &(dev->config->interface[0]->altsetting[3]); // Allocate URBs and buffers for the D channel out endpoint = &altsetting->endpoint[EP_D_OUT-1]; diff -Nru a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c --- a/drivers/isdn/hisax/st5481_usb.c Sat Aug 9 16:58:28 2003 +++ b/drivers/isdn/hisax/st5481_usb.c Sat Aug 9 16:58:28 2003 @@ -258,7 +258,7 @@ } - altsetting = &(dev->config->interface[0].altsetting[3]); + altsetting = &(dev->config->interface[0]->altsetting[3]); // Check if the config is sane if ( altsetting->desc.bNumEndpoints != 7 ) { diff -Nru a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile --- a/drivers/macintosh/Makefile Sat Aug 9 16:58:28 2003 +++ b/drivers/macintosh/Makefile Sat Aug 9 16:58:28 2003 @@ -4,6 +4,8 @@ # Each configuration option enables a list of files. +obj-$(CONFIG_PPC_PMAC) += macio_asic.o + obj-$(CONFIG_PMAC_PBOOK) += mediabay.o obj-$(CONFIG_MAC_SERIAL) += macserial.o ifneq ($(CONFIG_MAC),y) diff -Nru a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/macintosh/macio_asic.c Sat Aug 9 16:58:28 2003 @@ -0,0 +1,358 @@ +/* + * Bus & driver management routines for devices within + * a MacIO ASIC. Interface to new driver model mostly + * stolen from the PCI version. + * + * TODO: + * + * - Don't probe below media bay by default, but instead provide + * some hooks for media bay to dynamically add/remove it's own + * sub-devices. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int +macio_bus_match(struct device *dev, struct device_driver *drv) +{ + struct macio_dev * macio_dev = to_macio_device(dev); + struct macio_driver * macio_drv = to_macio_driver(drv); + const struct of_match * matches = macio_drv->match_table; + + if (!matches) + return 0; + + return of_match_device(matches, &macio_dev->ofdev) != NULL; +} + +struct bus_type macio_bus_type = { + name: "macio", + match: macio_bus_match, +}; + +static int __init +macio_bus_driver_init(void) +{ + return bus_register(&macio_bus_type); +} + +postcore_initcall(macio_bus_driver_init); + +static int +macio_device_probe(struct device *dev) +{ + int error = -ENODEV; + struct macio_driver *drv; + struct macio_dev *macio_dev; + const struct of_match *match; + + drv = to_macio_driver(dev->driver); + macio_dev = to_macio_device(dev); + + if (!drv->probe) + return error; + +/* if (!try_module_get(driver->owner)) { + printk(KERN_ERR "Can't get a module reference for %s\n", driver->name); + return error; + } +*/ + match = of_match_device(drv->match_table, &macio_dev->ofdev); + if (match) + error = drv->probe(macio_dev, match); +/* + module_put(driver->owner); +*/ + return error; +} + +static int +macio_device_remove(struct device *dev) +{ + struct macio_dev * macio_dev = to_macio_device(dev); + struct macio_driver * drv = to_macio_driver(macio_dev->ofdev.dev.driver); + + if (drv && drv->remove) + drv->remove(macio_dev); + return 0; +} + +static int +macio_device_suspend(struct device *dev, u32 state, u32 level) +{ + struct macio_dev * macio_dev = to_macio_device(dev); + struct macio_driver * drv = to_macio_driver(macio_dev->ofdev.dev.driver); + int error = 0; + + if (drv && drv->suspend) + error = drv->suspend(macio_dev, state, level); + return error; +} + +static int +macio_device_resume(struct device * dev, u32 level) +{ + struct macio_dev * macio_dev = to_macio_device(dev); + struct macio_driver * drv = to_macio_driver(macio_dev->ofdev.dev.driver); + int error = 0; + + if (drv && drv->resume) + error = drv->resume(macio_dev, level); + return error; +} + +/** + * macio_add_one_device - Add one device from OF node to the device tree + * @chip: pointer to the macio_chip holding the device + * @np: pointer to the device node in the OF tree + * @in_bay: set to 1 if device is part of a media-bay + * + * When media-bay is changed to hotswap drivers, this function will + * be exposed to the bay driver some way... + */ +static struct macio_dev * +macio_add_one_device(struct macio_chip *chip, struct device *parent, + struct device_node *np, struct macio_dev *in_bay) +{ + struct macio_dev *dev; + u32 *reg; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + memset(dev, 0, sizeof(*dev)); + + dev->bus = &chip->lbus; + dev->media_bay = in_bay; + dev->ofdev.node = np; + dev->ofdev.dma_mask = 0xffffffffUL; + dev->ofdev.dev.dma_mask = &dev->ofdev.dma_mask; + dev->ofdev.dev.parent = parent; + dev->ofdev.dev.bus = &macio_bus_type; + + /* XXX Make something better here ? */ + snprintf(dev->ofdev.dev.name, DEVICE_NAME_SIZE, "MacIO device %s", np->name); + + /* MacIO itself has a different reg, we use it's PCI base */ + if (np == chip->of_node) { + sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.8s", chip->lbus.index, +#ifdef CONFIG_PCI + pci_resource_start(chip->lbus.pdev, 0), +#else + 0, /* NuBus may want to do something better here */ +#endif + np->name); + } else { + reg = (u32 *)get_property(np, "reg", NULL); + sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.8s", chip->lbus.index, + reg ? *reg : 0, np->name); + } + + if (of_device_register(&dev->ofdev) != 0) { + kfree(dev); + return NULL; + } + + return dev; +} + +static int +macio_skip_device(struct device_node *np) +{ + if (strncmp(np->name, "battery", 7) == 0) + return 1; + if (strncmp(np->name, "escc-legacy", 11) == 0) + return 1; + return 0; +} + +/** + * macio_pci_add_devices - Adds sub-devices of mac-io to the device tree + * @chip: pointer to the macio_chip holding the devices + * + * This function will do the job of extracting devices from the + * Open Firmware device tree, build macio_dev structures and add + * them to the Linux device tree. + * + * For now, childs of media-bay are added now as well. This will + * change rsn though. + */ +static void +macio_pci_add_devices(struct macio_chip *chip) +{ + struct device_node *np; + struct macio_dev *rdev, *mdev, *mbdev = NULL, *sdev = NULL; + struct device *parent = NULL; + + /* Add a node for the macio bus itself */ +#ifdef CONFIG_PCI + if (chip->lbus.pdev) + parent = &chip->lbus.pdev->dev; +#endif + rdev = macio_add_one_device(chip, parent, chip->of_node, NULL); + if (rdev == NULL) + return; + + /* First scan 1st level */ + for (np = chip->of_node->child; np != NULL; np = np->sibling) { + if (!macio_skip_device(np)) { + mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL); + if (strncmp(np->name, "media-bay", 9) == 0) + mbdev = mdev; + else if (strncmp(np->name, "escc", 4) == 0) + sdev = mdev; + } + } + + /* Add media bay devices if any */ + if (mbdev) { + for (np = mbdev->ofdev.node->child; np != NULL; np = np->sibling) + if (!macio_skip_device(np)) + macio_add_one_device(chip, &mbdev->ofdev.dev, np, mbdev); + } + /* Add serial ports if any */ + if (sdev) { + for (np = sdev->ofdev.node->child; np != NULL; np = np->sibling) + if (!macio_skip_device(np)) + macio_add_one_device(chip, &sdev->ofdev.dev, np, NULL); + } +} + + +/** + * macio_register_driver - Registers a new MacIO device driver + * @drv: pointer to the driver definition structure + */ +int +macio_register_driver(struct macio_driver *drv) +{ + int count = 0; + + /* initialize common driver fields */ + drv->driver.name = drv->name; + drv->driver.bus = &macio_bus_type; + drv->driver.probe = macio_device_probe; + drv->driver.resume = macio_device_resume; + drv->driver.suspend = macio_device_suspend; + drv->driver.remove = macio_device_remove; + + /* register with core */ + count = driver_register(&drv->driver); + return count ? count : 1; +} + +/** + * macio_unregister_driver - Unregisters a new MacIO device driver + * @drv: pointer to the driver definition structure + */ +void +macio_unregister_driver(struct macio_driver *drv) +{ + driver_unregister(&drv->driver); +} + +#ifdef CONFIG_PCI + +static int __devinit +macio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct device_node* np; + struct macio_chip* chip; + + if (ent->vendor != PCI_VENDOR_ID_APPLE) + return -ENODEV; + + np = pci_device_to_OF_node(pdev); + if (np == NULL) + return -ENODEV; + + chip = macio_find(np, macio_unknown); + if (chip == NULL) + return -ENODEV; + + /* XXX Need locking */ + if (chip->lbus.pdev == NULL) { + chip->lbus.pdev = pdev; + chip->lbus.chip = chip; +// INIT_LIST_HEAD(&chip->lbus.devices); + pci_set_drvdata(pdev, &chip->lbus); + pci_set_master(pdev); + } + + printk(KERN_INFO "MacIO PCI driver attached to %s chipset\n", + chip->name); + + macio_pci_add_devices(chip); + + return 0; +} + +static void __devexit +macio_pci_remove(struct pci_dev* pdev) +{ + panic("removing of macio-asic not supported !\n"); +} + +/* + * MacIO is matched against any Apple ID, it's probe() function + * will then decide wether it applies or not + */ +static const struct pci_device_id __devinitdata pci_ids [] = { { + .vendor = PCI_VENDOR_ID_APPLE, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + + }, { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE (pci, pci_ids); + +/* pci driver glue; this is a "new style" PCI driver module */ +static struct pci_driver macio_pci_driver = { + .name = (char *) "macio", + .id_table = pci_ids, + + .probe = macio_pci_probe, + .remove = macio_pci_remove, +}; + +#endif /* CONFIG_PCI */ + +static int __init +macio_module_init (void) +{ +#ifdef CONFIG_PCI + int rc; + + rc = pci_module_init(&macio_pci_driver); + if (rc) + return rc; +#endif /* CONFIG_PCI */ + return 0; +} + +/* +static void __exit +macio_module_cleanup (void) +{ +#ifdef CONFIG_PCI + pci_unregister_driver(&macio_pci_driver); +#endif +} +module_exit(macio_module_cleanup); +*/ +module_init(macio_module_init); + +EXPORT_SYMBOL(macio_register_driver); +EXPORT_SYMBOL(macio_unregister_driver); diff -Nru a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c --- a/drivers/video/cfbimgblt.c Sat Aug 9 16:58:28 2003 +++ b/drivers/video/cfbimgblt.c Sat Aug 9 16:58:28 2003 @@ -325,7 +325,7 @@ else slow_imageblit(image, p, dst1, fgcolor, bgcolor, start_index, pitch_index); - } else if (image->depth == bpp) + } else if (image->depth <= bpp) color_imageblit(image, p, dst1, start_index, pitch_index); } diff -Nru a/include/asm-ppc/macio.h b/include/asm-ppc/macio.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ppc/macio.h Sat Aug 9 16:58:28 2003 @@ -0,0 +1,68 @@ +#ifndef __MACIO_ASIC_H__ +#define __MACIO_ASIC_H__ + +#include + +extern struct bus_type macio_bus_type; + +/* MacIO device driver is defined later */ +struct macio_driver; +struct macio_chip; + +#define MACIO_DEV_COUNT_RESOURCE 8 +#define MACIO_DEV_COUNT_IRQS 8 + +/* + * the macio_bus structure is used to describe a "virtual" bus + * within a MacIO ASIC. It's typically provided by a macio_pci_asic + * PCI device, but could be provided differently as well (nubus + * machines using a fake OF tree). + * + * The pdev field can be NULL on non-PCI machines + */ +struct macio_bus +{ + struct macio_chip *chip; /* macio_chip (private use) */ + int index; /* macio chip index in system */ +#ifdef CONFIG_PCI + struct pci_dev *pdev; /* PCI device hosting this bus */ +#endif +}; + +/* + * the macio_dev structure is used to describe a device + * within an Apple MacIO ASIC. + */ +struct macio_dev +{ + struct macio_bus *bus; /* macio bus this device is on */ + struct macio_dev *media_bay; /* Device is part of a media bay */ + struct of_device ofdev; +}; +#define to_macio_device(d) container_of(d, struct macio_dev, ofdev.dev) +#define of_to_macio_device(d) container_of(d, struct macio_dev, ofdev) + +/* + * A driver for a mac-io chip based device + */ +struct macio_driver +{ + char *name; + struct of_match *match_table; + struct module *owner; + + int (*probe)(struct macio_dev* dev, const struct of_match *match); + int (*remove)(struct macio_dev* dev); + + int (*suspend)(struct macio_dev* dev, u32 state, u32 level); + int (*resume)(struct macio_dev* dev, u32 level); + int (*shutdown)(struct macio_dev* dev); + + struct device_driver driver; +}; +#define to_macio_driver(drv) container_of(drv,struct macio_driver, driver) + +extern int macio_register_driver(struct macio_driver *); +extern void macio_unregister_driver(struct macio_driver *); + +#endif /* __MACIO_ASIC_H__ */ diff -Nru a/include/asm-ppc/macio_asic.h b/include/asm-ppc/macio_asic.h --- a/include/asm-ppc/macio_asic.h Sat Aug 9 16:58:28 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,80 +0,0 @@ -#ifndef __MACIO_ASIC_H__ -#define __MACIO_ASIC_H__ - -#include - -extern struct bus_type macio_bus_type; - -/* MacIO device driver is defined later */ -struct macio_driver; -struct macio_chip; - -#define MACIO_DEV_COUNT_RESOURCE 8 -#define MACIO_DEV_COUNT_IRQS 8 - -/* - * the macio_bus structure is used to describe a "virtual" bus - * within a MacIO ASIC. It's typically provided by a macio_pci_asic - * PCI device, but could be provided differently as well (nubus - * machines using a fake OF tree). - */ -struct macio_bus -{ - struct macio_chip *chip; /* macio_chip (private use) */ - struct pci_dev *pdev; /* PCI device hosting this bus */ - struct list_head devices; /* list of devices on this bus */ -}; - -/* - * the macio_dev structure is used to describe a device - * within an Apple MacIO ASIC. - */ -struct macio_dev -{ - struct macio_bus *bus; /* virtual bus this device is on */ - - struct device_node *node; /* OF node */ - struct macio_driver *driver; /* which driver allocated this device */ - void *driver_data; /* placeholder for driver specific stuffs */ - struct resource resources[MACIO_DEV_COUNT_RESOURCE]; /* I/O */ - int irqs[MACIO_DEV_COUNT_IRQS]; - - struct device dev; /* Generic device interface */ -}; -#define to_macio_device(d) container_of(d, struct macio_dev, dev) - -/* - * Struct used for matching a device - */ -struct macio_match -{ - char *name; - char *type; - char *compatible; -}; -#define MACIO_ANY_MATCH ((char *)-1L) - -/* - * A driver for a mac-io chip based device - */ -struct macio_driver -{ - struct list_head node; - char *name; - struct macio_match *match_table; - - int (*probe)(struct macio_dev* dev, const struct macio_match *match); - int (*remove)(struct macio_dev* dev); - - int (*suspend)(struct macio_dev* dev, u32 state, u32 level); - int (*resume)(struct macio_dev* dev, u32 level); - int (*shutdown)(struct macio_dev* dev); - - struct device_driver driver; -}; -#define to_macio_driver(drv) container_of(drv,struct macio_driver, driver) - -extern int macio_register_driver(struct macio_driver *); -extern void macio_unregister_driver(struct macio_driver *); - -#endif /* __MACIO_ASIC_H__ */ diff -Nru a/include/asm-ppc/of_device.h b/include/asm-ppc/of_device.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ppc/of_device.h Sat Aug 9 16:58:28 2003 @@ -0,0 +1,70 @@ +#ifndef __OF_DEVICE_H__ +#define __OF_DEVICE_H__ + +#include +#include + +/* + * The of_platform_bus_type is a bus type used by drivers that do not + * attach to a macio or similar bus but still use OF probing + * mecanism + */ +extern struct bus_type of_platform_bus_type; + +/* + * The of_device is a kind of "base class" that is a superset of + * struct device for use by devices attached to an OF node and + * probed using OF properties + */ +struct of_device +{ + struct device_node *node; /* OF device node */ + u64 dma_mask; /* DMA mask */ + struct device dev; /* Generic device interface */ +}; +#define to_of_device(d) container_of(d, struct of_device, dev) + +/* + * Struct used for matching a device + */ +struct of_match +{ + char *name; + char *type; + char *compatible; + void *data; +}; +#define OF_ANY_MATCH ((char *)-1L) + +extern const struct of_match *of_match_device( + const struct of_match *matches, const struct of_device *dev); + +/* + * An of_platform_driver driver is attached to a basic of_device on + * the "platform bus" (of_platform_bus_type) + */ +struct of_platform_driver +{ + char *name; + struct of_match *match_table; + struct module *owner; + + int (*probe)(struct of_device* dev, const struct of_match *match); + int (*remove)(struct of_device* dev); + + int (*suspend)(struct of_device* dev, u32 state, u32 level); + int (*resume)(struct of_device* dev, u32 level); + int (*shutdown)(struct of_device* dev); + + struct device_driver driver; +}; +#define to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver) + +extern int of_register_driver(struct of_platform_driver *drv); +extern void of_unregister_driver(struct of_platform_driver *drv); +extern int of_device_register(struct of_device *ofdev); +extern void of_device_unregister(struct of_device *ofdev); +extern struct of_device *of_platform_device_create(struct device_node *np, const char *bus_id); + +#endif /* __OF_DEVICE_H__ */ + diff -Nru a/include/asm-ppc/pmac_feature.h b/include/asm-ppc/pmac_feature.h --- a/include/asm-ppc/pmac_feature.h Sat Aug 9 16:58:28 2003 +++ b/include/asm-ppc/pmac_feature.h Sat Aug 9 16:58:28 2003 @@ -31,7 +31,7 @@ #ifndef __PPC_ASM_PMAC_FEATURE_H #define __PPC_ASM_PMAC_FEATURE_H -#include +#include /* * Known Mac motherboard models