# 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-test1 -> 1.1469 # kernel/ksyms.c 1.209 -> 1.210 # drivers/video/pvr2fb.c 1.14 -> 1.15 # drivers/video/Makefile 1.85 -> 1.86 # fs/proc/proc_misc.c 1.81 -> 1.82 # drivers/net/wan/syncppp.c 1.13 -> 1.14 # drivers/char/watchdog/shwdt.c 1.13 -> 1.14 # arch/i386/kernel/io_apic.c 1.75 -> 1.76 # include/linux/pci.h 1.99 -> 1.100 # include/linux/namespace.h 1.5 -> 1.6 # drivers/pcmcia/hd64465_ss.c 1.13 -> 1.14 # MAINTAINERS 1.155 -> 1.156 # net/wanrouter/wanmain.c 1.16 -> 1.17 # net/ipv4/tcp_input.c 1.44 -> 1.45 # drivers/char/busmouse.c 1.8 -> 1.9 # net/ipv6/addrconf.c 1.57 -> 1.58 # include/asm-i386/hw_irq.h 1.21 -> 1.22 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/07/13 torvalds@home.osdl.org 1.1455.1.4 # Linux 2.6.0-test1 # # First "test" kernel. Same naming we used for 2.4.0 - there it took # from May to December to get to the real version. Let's see if we # can do it faster this time. # -------------------------------------------- # 03/07/13 davem@kernel.bkbits.net 1.1458 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/07/14 maneesh@in.ibm.com 1.1459 # [PATCH] vfsmount_lock-fix # # This fixes one place where I missed the replacing dcache_lock with # vfsmount_lock in put_namespace(). # # Tested with CLONE_NEWNS flag also. # -------------------------------------------- # 03/07/14 randy.dunlap@verizon.net 1.1460 # [PATCH] syncppp: incomplete function prototype # # This fixes this warning: # # syncppp.c:165: warning: function declaration isn't a prototype # # by adding "void" as the function parameter list. # -------------------------------------------- # 03/07/14 randy.dunlap@verizon.net 1.1461 # [PATCH] reduce stack usage in wanrouter # # From Jorn Engel and Randy Dunlap. # # It reduces stack usage in the WAN router by about 0x500 bytes # (from 0x520 to 0x24 when I did it in April). # -------------------------------------------- # 03/07/14 randy.dunlap@verizon.net 1.1462 # [PATCH] unchecked return code of copy_to_user in read_profile # # From Daniele Bellucci . # # Check the copy_to_user() return code in read_profile(). # -------------------------------------------- # 03/07/14 randy.dunlap@verizon.net 1.1463 # [PATCH] busmouse: fix memory leak and misc_register failure # # From Flavio B. Leitner. # # Fix a memory leak and an unchecked return code in the busmouse driver. # -------------------------------------------- # 03/07/14 alex@ssi.bg 1.1464 # [PATCH] Fix irq handling of IO-APIC edge IRQs on UP # # send_IPI_self is needed to resend irqs with IRQ_PENDING status when # enabled. # # Checked with Ingo, and it's in 2.4-ac for some time. # # This should fix ide lost interrupts on UP with IO-APIC # # Ide trigers it this way: # - disable_irq # - do stuff that triggers IRQ. # - irq is IRQ_PENDING # - enable_irq # - IRQ is lost, needs to be resend. # # I'll send the patch to fixup IDE disable_irq logic to Bart. # -------------------------------------------- # 03/07/14 chyang@clusterfs.com 1.1465 # [PATCH] unresolved symbol with moduled intermezzo # # This solves the unresolved symbol problem with modular intermezzo. Also # update the MAINTAINERS entry. # -------------------------------------------- # 03/07/14 jgarzik@pobox.com 1.1466 # [PATCH] Large PCI bus numbers # # ppc64 machines can have PCI bus numbers larger than 8 bits, but it looks # like pci_device_to_OF_node already handles this case, in both 2.4 and # 2.5. # # We just need the space to store them. # -------------------------------------------- # 03/07/14 lethal@linux-sh.org 1.1467 # [PATCH] pvr2fb update # # Here's an update for pvr2fb (with a patch this time), which makes it compile # again. # -------------------------------------------- # 03/07/14 lethal@linux-sh.org 1.1468 # [PATCH] PCMCIA: Update hd64465 driver # # This patch updates the sh-specific hd64465 pcmcia driver for the new API, as # well as fixing up some other issues (such as remap_page_range() abuse -- we # remap through P3 area instead) which caused it not to compile. Changes by # Dominik Brodowski and myself. # -------------------------------------------- # 03/07/14 lethal@linux-sh.org 1.1469 # [PATCH] shwdt update # # This patch includes quite a few changes and updates for the shwdt driver (which # brings it in sync with LinuxSH CVS HEAD). This fixes up support for the SH-2, # and also fixes up some timer brain-damage. # -------------------------------------------- # diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Mon Jul 14 11:14:58 2003 +++ b/MAINTAINERS Mon Jul 14 11:14:58 2003 @@ -973,7 +973,7 @@ S: Supported INTERMEZZO FILE SYSTEM -P: Chen Yang +P: Cluster File Systems M: intermezzo-devel@lists.sf.net W: http://www.inter-mezzo.org/ L: intermezzo-discuss@lists.sourceforge.net diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c --- a/arch/i386/kernel/io_apic.c Mon Jul 14 11:14:58 2003 +++ b/arch/i386/kernel/io_apic.c Mon Jul 14 11:14:58 2003 @@ -682,6 +682,21 @@ #else /* !SMP */ static inline void move_irq(int irq) { } + +void send_IPI_self(int vector) +{ + unsigned int cfg; + + /* + * Wait for idle. + */ + apic_wait_icr_idle(); + cfg = APIC_DM_FIXED | APIC_DEST_SELF | vector | APIC_DEST_LOGICAL; + /* + * Send the IPI. The write to APIC_ICR fires this off. + */ + apic_write_around(APIC_ICR, cfg); +} #endif /* defined(CONFIG_SMP) */ diff -Nru a/drivers/char/busmouse.c b/drivers/char/busmouse.c --- a/drivers/char/busmouse.c Mon Jul 14 11:14:58 2003 +++ b/drivers/char/busmouse.c Mon Jul 14 11:14:58 2003 @@ -357,25 +357,23 @@ { unsigned int msedev = MINOR_TO_MOUSE(ops->minor); struct busmouse_data *mse; - int ret; + int ret = -EINVAL; if (msedev >= NR_MICE) { printk(KERN_ERR "busmouse: trying to allocate mouse on minor %d\n", ops->minor); - return -EINVAL; + goto out; } + ret = -ENOMEM; mse = kmalloc(sizeof(*mse), GFP_KERNEL); if (!mse) - return -ENOMEM; + goto out; down(&mouse_sem); + ret = -EBUSY; if (busmouse_data[msedev]) - { - up(&mouse_sem); - kfree(mse); - return -EBUSY; - } + goto freemem; memset(mse, 0, sizeof(*mse)); @@ -386,14 +384,22 @@ mse->lock = (spinlock_t)SPIN_LOCK_UNLOCKED; init_waitqueue_head(&mse->wait); - busmouse_data[msedev] = mse; ret = misc_register(&mse->miscdev); - if (!ret) - ret = msedev; + + if (ret < 0) + goto freemem; + + busmouse_data[msedev] = mse; + ret = msedev; +out: up(&mouse_sem); - return ret; + + +freemem: + kfree(mse); + goto out; } /** diff -Nru a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c --- a/drivers/char/watchdog/shwdt.c Mon Jul 14 11:14:58 2003 +++ b/drivers/char/watchdog/shwdt.c Mon Jul 14 11:14:58 2003 @@ -3,7 +3,7 @@ * * Watchdog driver for integrated watchdog in the SuperH processors. * - * Copyright (C) 2001, 2002 Paul Mundt + * Copyright (C) 2001, 2002, 2003 Paul Mundt * * 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 @@ -12,6 +12,10 @@ * * 14-Dec-2001 Matt Domsch * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * + * 19-Apr-2002 Rob Radez + * Added expect close support, made emulated timeout runtime changeable + * general cleanups, add some ioctls */ #include #include @@ -22,76 +26,50 @@ #include #include #include +#include #include #include - -#if defined(CONFIG_CPU_SH5) - #define WTCNT CPRC_BASE + 0x10 - #define WTCSR CPRC_BASE + 0x18 -#elif defined(CONFIG_CPU_SH4) - #define WTCNT 0xffc00008 - #define WTCSR 0xffc0000c -#elif defined(CONFIG_CPU_SH3) - #define WTCNT 0xffffff84 - #define WTCSR 0xffffff86 -#else - #error "Can't use SuperH watchdog on this platform" -#endif - -#define WTCNT_HIGH 0x5a00 -#define WTCSR_HIGH 0xa500 - -#define WTCSR_TME 0x80 -#define WTCSR_WT 0x40 -#define WTCSR_RSTS 0x20 -#define WTCSR_WOVF 0x10 -#define WTCSR_IOVF 0x08 -#define WTCSR_CKS2 0x04 -#define WTCSR_CKS1 0x02 -#define WTCSR_CKS0 0x01 - -/* - * CKS0-2 supports a number of clock division ratios. At the time the watchdog - * is enabled, it defaults to a 41 usec overflow period .. we overload this to - * something a little more reasonable, and really can't deal with anything - * lower than WTCSR_CKS_1024, else we drop back into the usec range. - * - * Clock Division Ratio Overflow Period - * -------------------------------------------- - * 1/32 (initial value) 41 usecs - * 1/64 82 usecs - * 1/128 164 usecs - * 1/256 328 usecs - * 1/512 656 usecs - * 1/1024 1.31 msecs - * 1/2048 2.62 msecs - * 1/4096 5.25 msecs - */ -#define WTCSR_CKS_32 0x00 -#define WTCSR_CKS_64 0x01 -#define WTCSR_CKS_128 0x02 -#define WTCSR_CKS_256 0x03 -#define WTCSR_CKS_512 0x04 -#define WTCSR_CKS_1024 0x05 -#define WTCSR_CKS_2048 0x06 -#define WTCSR_CKS_4096 0x07 +#include /* - * Default clock division ratio is 5.25 msecs. Overload this at module load - * time. Any value not in the msec range will default to a timeout of one - * jiffy, which exceeds the usec overflow periods. + * Default clock division ratio is 5.25 msecs. For an additional table of + * values, consult the asm-sh/watchdog.h. Overload this at module load + * time. + * + * In order for this to work reliably we need to have HZ set to 1000 or + * something quite higher than 100 (or we need a proper high-res timer + * implementation that will deal with this properly), otherwise the 10ms + * resolution of a jiffy is enough to trigger the overflow. For things like + * the SH-4 and SH-5, this isn't necessarily that big of a problem, though + * for the SH-2 and SH-3, this isn't recommended unless the WDT is absolutely + * necssary. + * + * As a result of this timing problem, the only modes that are particularly + * feasible are the 4096 and the 2048 divisors, which yeild 5.25 and 2.62ms + * overflow periods respectively. + * + * Also, since we can't really expect userspace to be responsive enough + * before the overflow happens, we maintain two seperate timers .. One in + * the kernel for clearing out WOVF every 2ms or so (again, this depends on + * HZ == 1000), and another for monitoring userspace writes to the WDT device. + * + * As such, we currently use a configurable heartbeat interval which defaults + * to 30s. In this case, the userspace daemon is only responsible for periodic + * writes to the device before the next heartbeat is scheduled. If the daemon + * misses its deadline, the kernel timer will allow the WDT to overflow. */ static int clock_division_ratio = WTCSR_CKS_4096; -#define msecs_to_jiffies(msecs) (jiffies + ((HZ * msecs + 999) / 1000)) +#define msecs_to_jiffies(msecs) (jiffies + (HZ * msecs + 9999) / 10000) #define next_ping_period(cks) msecs_to_jiffies(cks - 4) -#define user_ping_period(cks) (next_ping_period(cks) * 10) -static unsigned long sh_is_open = 0; +static unsigned long shwdt_is_open; static struct watchdog_info sh_wdt_info; +static char shwdt_expect_close; static struct timer_list timer; static unsigned long next_heartbeat; +static int heartbeat = 30; #ifdef CONFIG_WATCHDOG_NOWAYOUT static int nowayout = 1; @@ -99,35 +77,6 @@ static int nowayout = 0; #endif -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -/** - * sh_wdt_write_cnt - Write to Counter - * - * @val: Value to write - * - * Writes the given value @val to the lower byte of the timer counter. - * The upper byte is set manually on each write. - */ -static void sh_wdt_write_cnt(__u8 val) -{ - ctrl_outw(WTCNT_HIGH | (__u16)val, WTCNT); -} - -/** - * sh_wdt_write_csr - Write to Control/Status Register - * - * @val: Value to write - * - * Writes the given value @val to the lower byte of the control/status - * register. The upper byte is set manually on each write. - */ -static void sh_wdt_write_csr(__u8 val) -{ - ctrl_outw(WTCSR_HIGH | (__u16)val, WTCSR); -} - /** * sh_wdt_start - Start the Watchdog * @@ -135,13 +84,44 @@ */ static void sh_wdt_start(void) { - timer.expires = next_ping_period(clock_division_ratio); - next_heartbeat = user_ping_period(clock_division_ratio); - add_timer(&timer); + __u8 csr; + + mod_timer(&timer, next_ping_period(clock_division_ratio)); + next_heartbeat = jiffies + (heartbeat * HZ); + + csr = sh_wdt_read_csr(); + csr |= WTCSR_WT | clock_division_ratio; + sh_wdt_write_csr(csr); - sh_wdt_write_csr(WTCSR_WT | WTCSR_CKS_4096); sh_wdt_write_cnt(0); - sh_wdt_write_csr((ctrl_inb(WTCSR) | WTCSR_TME)); + + /* + * These processors have a bit of an inconsistent initialization + * process.. starting with SH-3, RSTS was moved to WTCSR, and the + * RSTCSR register was removed. + * + * On the SH-2 however, in addition with bits being in different + * locations, we must deal with RSTCSR outright.. + */ + csr = sh_wdt_read_csr(); + csr |= WTCSR_TME; + csr &= ~WTCSR_RSTS; + sh_wdt_write_csr(csr); + +#ifdef CONFIG_CPU_SH2 + /* + * Whoever came up with the RSTCSR semantics must've been smoking + * some of the good stuff, since in addition to the WTCSR/WTCNT write + * brain-damage, it's managed to fuck things up one step further.. + * + * If we need to clear the WOVF bit, the upper byte has to be 0xa5.. + * but if we want to touch RSTE or RSTS, the upper byte has to be + * 0x5a.. + */ + csr = sh_wdt_read_rstcsr(); + csr &= ~RSTCSR_RSTS; + sh_wdt_write_rstcsr(csr); +#endif } /** @@ -151,9 +131,13 @@ */ static void sh_wdt_stop(void) { + __u8 csr; + del_timer(&timer); - sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_TME)); + csr = sh_wdt_read_csr(); + csr &= ~WTCSR_TME; + sh_wdt_write_csr(csr); } /** @@ -166,11 +150,15 @@ static void sh_wdt_ping(unsigned long data) { if (time_before(jiffies, next_heartbeat)) { - sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_IOVF)); + __u8 csr; + + csr = sh_wdt_read_csr(); + csr &= ~WTCSR_IOVF; + sh_wdt_write_csr(csr); + sh_wdt_write_cnt(0); - timer.expires = next_ping_period(clock_division_ratio); - add_timer(&timer); + mod_timer(&timer, next_ping_period(clock_division_ratio)); } } @@ -184,21 +172,12 @@ */ static int sh_wdt_open(struct inode *inode, struct file *file) { - switch (minor(inode->i_rdev)) { - case WATCHDOG_MINOR: - if (test_and_set_bit(0, &sh_is_open)) - return -EBUSY; + if (test_and_set_bit(0, &shwdt_is_open)) + return -EBUSY; + if (nowayout) + MOD_INC_USE_COUNT; - if (nowayout) { - MOD_INC_USE_COUNT; - } - - sh_wdt_start(); - - break; - default: - return -ENODEV; - } + sh_wdt_start(); return 0; } @@ -213,33 +192,20 @@ */ static int sh_wdt_close(struct inode *inode, struct file *file) { - if (minor(inode->i_rdev) == WATCHDOG_MINOR) { - if (!nowayout) { - sh_wdt_stop(); - } - clear_bit(0, &sh_is_open); + if (!nowayout && shwdt_expect_close == 42) { + sh_wdt_stop(); + } else { + printk(KERN_CRIT "shwdt: Unexpected close, not stopping watchdog!\n"); + next_heartbeat = jiffies + (heartbeat * HZ); } + + clear_bit(0, &shwdt_is_open); + shwdt_expect_close = 0; return 0; } /** - * sh_wdt_read - Read from Device - * - * @file: file handle of device - * @buf: buffer to write to - * @count: length of buffer - * @ppos: offset - * - * Unsupported. - */ -static ssize_t sh_wdt_read(struct file *file, char *buf, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -/** * sh_wdt_write - Write to Device * * @file: file handle of device @@ -257,11 +223,21 @@ return -ESPIPE; if (count) { - next_heartbeat = user_ping_period(clock_division_ratio); - return 1; + size_t i; + + shwdt_expect_close = 0; + + for (i = 0; i != count; i++) { + char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (c == 'V') + shwdt_expect_close = 42; + } + next_heartbeat = jiffies + (heartbeat * HZ); } - return 0; + return count; } /** @@ -278,6 +254,8 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + int new_timeout; + switch (cmd) { case WDIOC_GETSUPPORT: if (copy_to_user((struct watchdog_info *)arg, @@ -288,17 +266,41 @@ break; case WDIOC_GETSTATUS: - if (copy_to_user((int *)arg, - &sh_is_open, - sizeof(int))) { + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *)arg); + case WDIOC_KEEPALIVE: + next_heartbeat = jiffies + (heartbeat * HZ); + + break; + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, (int *)arg)) return -EFAULT; + if (new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */ + return -EINVAL; + heartbeat = new_timeout; + next_heartbeat = jiffies + (heartbeat * HZ); + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user(heartbeat, (int *)arg); + case WDIOC_SETOPTIONS: + { + int options, retval = -EINVAL; + + if (get_user(options, (int *)arg)) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) { + sh_wdt_stop(); + retval = 0; } - break; - case WDIOC_KEEPALIVE: - next_heartbeat = user_ping_period(clock_division_ratio); + if (options & WDIOS_ENABLECARD) { + sh_wdt_start(); + retval = 0; + } - break; + return retval; + } default: return -ENOTTY; } @@ -328,7 +330,7 @@ static struct file_operations sh_wdt_fops = { .owner = THIS_MODULE, - .read = sh_wdt_read, + .llseek = no_llseek, .write = sh_wdt_write, .ioctl = sh_wdt_ioctl, .open = sh_wdt_open, @@ -336,21 +338,20 @@ }; static struct watchdog_info sh_wdt_info = { - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, - .firmware_version = 1, - .identity = "SH WDT", + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, + .firmware_version = 1, + .identity = "SH WDT", }; static struct notifier_block sh_wdt_notifier = { - .notifier_call = sh_wdt_notify_sys, - .next = NULL, - .priority = 0 + .notifier_call = sh_wdt_notify_sys, + .priority = 0, }; static struct miscdevice sh_wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops &sh_wdt_fops, + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &sh_wdt_fops, }; /** @@ -366,23 +367,8 @@ return -EINVAL; } - if (!request_region(WTCNT, 1, "shwdt")) { - printk(KERN_ERR "shwdt: Can't request WTCNT region\n"); - misc_deregister(&sh_wdt_miscdev); - return -ENXIO; - } - - if (!request_region(WTCSR, 1, "shwdt")) { - printk(KERN_ERR "shwdt: Can't request WTCSR region\n"); - release_region(WTCNT, 1); - misc_deregister(&sh_wdt_miscdev); - return -ENXIO; - } - if (register_reboot_notifier(&sh_wdt_notifier)) { printk(KERN_ERR "shwdt: Can't register reboot notifier\n"); - release_region(WTCSR, 1); - release_region(WTCNT, 1); misc_deregister(&sh_wdt_miscdev); return -EINVAL; } @@ -403,16 +389,16 @@ static void __exit sh_wdt_exit(void) { unregister_reboot_notifier(&sh_wdt_notifier); - release_region(WTCSR, 1); - release_region(WTCNT, 1); misc_deregister(&sh_wdt_miscdev); } -MODULE_AUTHOR("Paul Mundt "); +MODULE_AUTHOR("Paul Mundt "); MODULE_DESCRIPTION("SuperH watchdog driver"); MODULE_LICENSE("GPL"); MODULE_PARM(clock_division_ratio, "i"); MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7."); +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); module_init(sh_wdt_init); module_exit(sh_wdt_exit); diff -Nru a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c --- a/drivers/net/wan/syncppp.c Mon Jul 14 11:14:58 2003 +++ b/drivers/net/wan/syncppp.c Mon Jul 14 11:14:58 2003 @@ -161,7 +161,7 @@ * then put the packet into tx_queue, and call sppp_flush_xmit() * after spinlock is released. */ -static void sppp_flush_xmit() +static void sppp_flush_xmit(void) { struct sk_buff *skb; while ((skb = skb_dequeue(&tx_queue)) != NULL) diff -Nru a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c --- a/drivers/pcmcia/hd64465_ss.c Mon Jul 14 11:14:58 2003 +++ b/drivers/pcmcia/hd64465_ss.c Mon Jul 14 11:14:58 2003 @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: hd64465_ss.c,v 1.7 2003/07/06 14:42:50 lethal Exp $ * * Device driver for the PCMCIA controller module of the * Hitachi HD64465 handheld companion chip. @@ -24,7 +24,6 @@ * * by Greg Banks * (c) 2000 PocketPenguins Inc - * */ #include @@ -37,28 +36,26 @@ #include #include #include -#include +#include #include #include -#include +#include +#include #include #include #include +#include +#include #include #include -#include #include "cs_internal.h" #define MODNAME "hd64465_ss" /* #define HD64465_DEBUG 1 */ -#ifndef HD64465_DEBUG -#define HD64465_DEBUG 0 -#endif - #if HD64465_DEBUG #define DPRINTK(args...) printk(MODNAME ": " args) #else @@ -66,7 +63,8 @@ #endif extern int hd64465_io_debug; - +extern void * p3_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags); +extern void p3_iounmap(void *addr); /*============================================================*/ @@ -74,37 +72,22 @@ typedef struct hs_socket_t { + unsigned int number; u_int irq; u_long mem_base; + void *io_base; u_long mem_length; - void (*handler)(void *info, u_int events); - void *handler_info; - u_int pending_events; u_int ctrl_base; socket_state_t state; pccard_io_map io_maps[MAX_IO_WIN]; pccard_mem_map mem_maps[MAX_WIN]; - struct vm_struct *io_vma; /* allocated kernel vm for mapping IO space */ + struct pcmcia_socket socket; } hs_socket_t; -#define HS_MAX_SOCKETS 2 -static hs_socket_t hs_sockets[HS_MAX_SOCKETS]; -static spinlock_t hs_pending_event_lock = SPIN_LOCK_UNLOCKED; -/* Calculate socket number from ptr into hs_sockets[] */ -#define hs_sockno(sp) (sp - hs_sockets) -static socket_cap_t hs_socket_cap = -{ - SS_CAP_PCCARD /* support 16 bit cards */ - |SS_CAP_STATIC_MAP /* mappings are fixed in host memory */ - , - 0xffde/*0xffff*/, /* IRQs mapped in s/w so can do any, really */ - HD64465_PCC_WINDOW, /* 16MB fixed window size */ - 0, /* no PCI support */ - 0, /* no CardBus support */ - 0 /* no bus operations needed */ -}; +#define HS_MAX_SOCKETS 2 +static hs_socket_t hs_sockets[HS_MAX_SOCKETS]; #define hs_in(sp, r) inb((sp)->ctrl_base + (r)) #define hs_out(sp, v, r) outb(v, (sp)->ctrl_base + (r)) @@ -179,7 +162,7 @@ { unsigned short cscier; - DPRINTK("hs_socket_enable_ireq(sock=%d)\n", hs_sockno(sp)); + DPRINTK("hs_socket_enable_ireq(sock=%d)\n", sp->number); cscier = hs_in(sp, CSCIER); cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK; @@ -191,7 +174,7 @@ { unsigned short cscier; - DPRINTK("hs_socket_disable_ireq(sock=%d)\n", hs_sockno(sp)); + DPRINTK("hs_socket_disable_ireq(sock=%d)\n", sp->number); cscier = hs_in(sp, CSCIER); cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK; @@ -255,7 +238,7 @@ */ static void hs_map_irq(hs_socket_t *sp, unsigned int irq) { - DPRINTK("hs_map_irq(sock=%d irq=%d)\n", hs_sockno(sp), irq); + DPRINTK("hs_map_irq(sock=%d irq=%d)\n", sp->number, irq); if (irq >= HS_NUM_MAPPED_IRQS) return; @@ -272,7 +255,7 @@ */ static void hs_unmap_irq(hs_socket_t *sp, unsigned int irq) { - DPRINTK("hs_unmap_irq(sock=%d irq=%d)\n", hs_sockno(sp), irq); + DPRINTK("hs_unmap_irq(sock=%d irq=%d)\n", sp->number, irq); if (irq >= HS_NUM_MAPPED_IRQS) return; @@ -301,7 +284,7 @@ { u_int psr; u_int vcci = 0; - u_int sock = hs_sockno(sp); + u_int sock = sp->number; DPRINTK("hs_set_voltage(%d, %d, %d)\n", sock, Vcc, Vpp); @@ -359,13 +342,12 @@ /*============================================================*/ -static int hs_init(unsigned int sock) +static int hs_init(struct pcmcia_socket *s) { - hs_socket_t *sp = &hs_sockets[sock]; + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); - DPRINTK("hs_init(%d)\n", sock); + DPRINTK("hs_init(%d)\n", sp->number); - sp->pending_events = 0; sp->state.Vcc = 0; sp->state.Vpp = 0; hs_set_voltages(sp, 0, 0); @@ -375,9 +357,12 @@ /*============================================================*/ -static int hs_suspend(unsigned int sock) +static int hs_suspend(struct pcmcia_socket *s) { - DPRINTK("hs_suspend(%d)\n", sock); +#ifdef HD64465_DEBUG + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); + DPRINTK("hs_suspend(%d)\n", sp->number); +#endif /* TODO */ @@ -386,32 +371,10 @@ /*============================================================*/ -static int hs_register_callback(unsigned int sock, - void (*handler)(void *, unsigned int), void * info) -{ - hs_socket_t *sp = &hs_sockets[sock]; - - DPRINTK("hs_register_callback(%d)\n", sock); - sp->handler = handler; - sp->handler_info = info; - return 0; -} - -/*============================================================*/ -static int hs_inquire_socket(unsigned int sock, socket_cap_t *cap) +static int hs_get_status(struct pcmcia_socket *s, u_int *value) { - DPRINTK("hs_inquire_socket(%d)\n", sock); - - *cap = hs_socket_cap; - return 0; -} - -/*============================================================*/ - -static int hs_get_status(unsigned int sock, u_int *value) -{ - hs_socket_t *sp = &hs_sockets[sock]; + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); unsigned int isr; u_int status = 0; @@ -473,9 +436,9 @@ /*============================================================*/ -static int hs_get_socket(unsigned int sock, socket_state_t *state) +static int hs_get_socket(struct pcmcia_socket *s, socket_state_t *state) { - hs_socket_t *sp = &hs_sockets[sock]; + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); DPRINTK("hs_get_socket(%d)\n", sock); @@ -485,9 +448,9 @@ /*============================================================*/ -static int hs_set_socket(unsigned int sock, socket_state_t *state) +static int hs_set_socket(struct pcmcia_socket *s, socket_state_t *state) { - hs_socket_t *sp = &hs_sockets[sock]; + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); u_long flags; u_int changed; unsigned short cscier; @@ -495,12 +458,12 @@ DPRINTK("hs_set_socket(sock=%d, flags=%x, csc_mask=%x, Vcc=%d, Vpp=%d, io_irq=%d)\n", sock, state->flags, state->csc_mask, state->Vcc, state->Vpp, state->io_irq); - save_and_cli(flags); /* Don't want interrupts happening here */ + local_irq_save(flags); /* Don't want interrupts happening here */ if (state->Vpp != sp->state.Vpp || state->Vcc != sp->state.Vcc) { if (!hs_set_voltages(sp, state->Vcc, state->Vpp)) { - restore_flags(flags); + local_irq_restore(flags); return -EINVAL; } } @@ -588,7 +551,7 @@ /* hd64465_io_debug = 0; */ sp->state = *state; - restore_flags(flags); + local_irq_restore(flags); #if HD64465_DEBUG > 10 if (state->flags & SS_OUTPUT_ENA) @@ -599,10 +562,11 @@ /*============================================================*/ -static int hs_set_io_map(unsigned int sock, struct pccard_io_map *io) +static int hs_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) { - hs_socket_t *sp = &hs_sockets[sock]; + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); int map = io->map; + int sock = sp->number; struct pccard_io_map *sio; pgprot_t prot; @@ -639,10 +603,9 @@ printk(KERN_INFO MODNAME ": MAP_0WS unimplemented\n"); if (io->flags & MAP_ACTIVE) { - unsigned long pstart, psize, paddrbase, vaddrbase; + unsigned long pstart, psize, paddrbase; paddrbase = virt_to_phys((void*)(sp->mem_base + 2 * HD64465_PCC_WINDOW)); - vaddrbase = (unsigned long)sp->io_vma->addr; pstart = io->start & PAGE_MASK; psize = ((io->stop + PAGE_SIZE) & PAGE_MASK) - pstart; @@ -653,26 +616,17 @@ * page will be mapped. But the code allows for weird cards * that might want IO ports > 4K. */ - DPRINTK("remap_page_range(vaddr=0x%08lx, paddr=0x%08lx, size=0x%08lxx)\n", - vaddrbase + pstart, paddrbase + pstart, psize); -#error This does not work. Firstly remap_page_range() uses current->mm for -#error the address space, which is wrong for kernel mappings. remap_page_range -#error also does flush_{cache,tlb}_range() which ONLY works for user mappings. -#error Next, remap_page_range() now wants to take a vm_area_struct arg. - remap_page_range(vaddrbase + pstart, paddrbase + pstart, psize, prot); + sp->io_base = p3_ioremap(paddrbase + pstart, psize, pgprot_val(prot)); /* * Change the mapping used by inb() outb() etc */ - hd64465_port_map( - io->start, + hd64465_port_map(io->start, io->stop - io->start + 1, - vaddrbase + io->start,0); + (unsigned long)sp->io_base + io->start, 0); } else { - hd64465_port_unmap( - sio->start, - sio->stop - sio->start + 1); - /* TODO: remap_page_range() to mark pages not present ? */ + hd64465_port_unmap(sio->start, sio->stop - sio->start + 1); + p3_iounmap(sp->io_base); } *sio = *io; @@ -681,9 +635,9 @@ /*============================================================*/ -static int hs_set_mem_map(unsigned int sock, struct pccard_mem_map *mem) +static int hs_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem) { - hs_socket_t *sp = &hs_sockets[sock]; + hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); struct pccard_mem_map *smem; int map = mem->map; unsigned long paddr, size; @@ -722,13 +676,6 @@ /*============================================================*/ -static void hs_proc_setup(unsigned int sock, struct proc_dir_entry *base) -{ - DPRINTK("hs_proc_setup(%d)\n", sock); -} - -/*============================================================*/ - /* * This function is registered with the HD64465 glue code to do a * secondary demux step on the PCMCIA interrupts. It handles @@ -756,35 +703,9 @@ /* * Interrupt handling routine. - * - * This uses the schedule_work() technique to cause reportable events - * such as card insertion and removal to be handled in keventd's - * process context. */ - -static void hs_events_bh(void *dummy) -{ - hs_socket_t *sp; - u_int events; - int i; - - for (i=0; ipending_events; - sp->pending_events = 0; - spin_unlock_irq(&hs_pending_event_lock); - - if (sp->handler) - sp->handler(sp->handler_info, events); - } -} - -static DECLARE_WORK(hs_events_task, hs_events_bh, NULL); - -static void hs_interrupt(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t hs_interrupt(int irq, void *dev, struct pt_regs *regs) { hs_socket_t *sp = (hs_socket_t *)dev; u_int events = 0; @@ -801,7 +722,7 @@ if ((hs_in(sp, ISR) & HD64465_PCCISR_PCD_MASK) != 0) { printk(KERN_NOTICE MODNAME ": socket %d, card not a supported card type or not inserted correctly\n", - hs_sockno(sp)); + sp->number); /* Don't do the rest unless a card is present */ cscr &= ~(HD64465_PCCCSCR_PCDC| HD64465_PCCCSCR_PRC| @@ -839,34 +760,22 @@ hs_out(sp, cscr, CSCR); - if (events) { - /* - * Arrange for events to be reported to the registered - * event handler function (from CardServices) in a process - * context (keventd) "soon". - */ - spin_lock(&hs_pending_event_lock); - sp->pending_events |= events; - spin_unlock(&hs_pending_event_lock); - - schedule_work(&hs_events_task); - } + if (events) + pcmcia_parse_events(&sp->socket, events); + + return IRQ_HANDLED; } /*============================================================*/ static struct pccard_operations hs_operations = { - .owner = THIS_MODULE, .init = hs_init, .suspend = hs_suspend, - .register_callback = hs_register_callback, - .inquire_socket = hs_inquire_socket, .get_status = hs_get_status, .get_socket = hs_get_socket, .set_socket = hs_set_socket, .set_io_map = hs_set_io_map, .set_mem_map = hs_set_mem_map, - .proc_setup = hs_proc_setup, }; static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base, @@ -886,9 +795,6 @@ for (i=0 ; imem_maps[i].map = i; - if ((sp->io_vma = get_vm_area(HS_IO_MAP_SIZE, VM_IOREMAP)) == 0) - return -ENOMEM; - hd64465_register_irq_demux(sp->irq, hs_irq_demux, sp); if ((err = request_irq(sp->irq, hs_interrupt, SA_INTERRUPT, MODNAME, sp)) < 0) @@ -925,9 +831,8 @@ hs_reset_socket(sp, 1); - printk(KERN_INFO "HD64465 PCMCIA bridge socket %d at 0x%08lx irq %d io window %ldK@0x%08lx\n", - i, sp->mem_base, sp->irq, - sp->io_vma->size>>10, (unsigned long)sp->io_vma->addr); + printk(KERN_INFO "HD64465 PCMCIA bridge socket %d at 0x%08lx irq %d\n", + i, sp->mem_base, sp->irq); return 0; } @@ -935,7 +840,10 @@ static void hs_exit_socket(hs_socket_t *sp) { unsigned short cscier, gcr; + unsigned long flags; + local_irq_save(flags); + /* turn off interrupts in hardware */ cscier = hs_in(sp, CSCIER); cscier = (cscier & IER_MASK) | IER_OFF; @@ -955,19 +863,13 @@ free_irq(sp->irq, hs_interrupt); hd64465_unregister_irq_demux(sp->irq); } - if (sp->io_vma != 0) - vfree(sp->io_vma->addr); -} -static struct pcmcia_socket_class_data hd64465_data = { - .nsock = HS_MAX_SOCKETS, - .ops = &hs_operations, -}; + local_irq_restore(flags); +} static struct device_driver hd64465_driver = { .name = "hd64465-pcmcia", .bus = &platform_bus_type, - .devclass = &pcmcia_socket_class, .suspend = pcmcia_socket_dev_suspend, .resume = pcmcia_socket_dev_resume, }; @@ -996,7 +898,8 @@ } /* hd64465_io_debug = 1; */ - register_driver(&hd64465_driver); + if (driver_register(&hd64465_driver)) + return -EINVAL; /* Wake both sockets out of STANDBY mode */ /* TODO: wait 15ms */ @@ -1014,14 +917,22 @@ v |= HD64465_PCCCSCR_PSWSEL; outb(v, HD64465_REG_PCC0CSCR); - hs_set_voltages(&hs_sockets[0], 0, 0); - hs_set_voltages(&hs_sockets[1], 0, 0); - /* * Setup hs_sockets[] structures and request system resources. * TODO: on memory allocation failure, power down the socket * before quitting. */ + for (i=0; i - * Copyright (c) 2001 Paul Mundt + * Copyright (c) 2001, 2002, 2003 Paul Mundt * * This file is part of the LinuxDC project (linuxdc.sourceforge.net). * @@ -12,14 +12,15 @@ /* * This driver is mostly based on the excellent amifb and vfb sources. It uses - * an odd scheme for converting hardware values to/from framebuffer values, here are - * some hacked-up formulas: + * an odd scheme for converting hardware values to/from framebuffer values, + * here are some hacked-up formulas: * - * The Dreamcast has screen offsets from each side of its four borders and the start - * offsets of the display window. I used these values to calculate 'pseudo' values - * (think of them as placeholders) for the fb video mode, so that when it came time - * to convert these values back into their hardware values, I could just add mode- - * specific offsets to get the correct mode settings: + * The Dreamcast has screen offsets from each side of its four borders and + * the start offsets of the display window. I used these values to calculate + * 'pseudo' values (think of them as placeholders) for the fb video mode, so + * that when it came time to convert these values back into their hardware + * values, I could just add mode- specific offsets to get the correct mode + * settings: * * left_margin = diwstart_h - borderstart_h; * right_margin = borderstop_h - (diwstart_h + xres); @@ -29,9 +30,9 @@ * hsync_len = borderstart_h + (hsync_total - borderstop_h); * vsync_len = borderstart_v + (vsync_total - borderstop_v); * - * Then, when it's time to convert back to hardware settings, the only constants - * are the borderstart_* offsets, all other values are derived from the fb video - * mode: + * Then, when it's time to convert back to hardware settings, the only + * constants are the borderstart_* offsets, all other values are derived from + * the fb video mode: * * // PAL * borderstart_h = 116; @@ -57,7 +58,6 @@ #include #include #include -#include #ifdef CONFIG_SH_DREAMCAST #include @@ -66,14 +66,9 @@ #endif #ifdef CONFIG_MTRR - #include +#include #endif -#include